代码拉取完成,页面将自动刷新
const std = @import("std");
const builtin = @import("builtin");
pub const config = @import("config");
pub const c = @cImport({
@cInclude("signal.h");
@cInclude("awtk.h");
@cInclude("base/assets_manager.h");
@cInclude("mvvm/mvvm.h");
});
pub const Emitter = c.emitter_t;
pub const Object = c.tk_object_t;
pub const ObjectVTable = c.object_vtable_t;
pub const Value = c.value_t;
const Allocator = std.mem.Allocator;
pub var gallocator: Allocator = undefined;
var mallocator: if (builtin.mode == .Debug or builtin.mode == .ReleaseSafe) MAllocator else void = undefined;
pub var glanguage: Language = .English;
// @typeName(type) : dirName.fileName.Type
// baseTypeName(type): Type
pub fn baseTypeName(Type: type) [:0]const u8 {
const type_name = @typeName(Type);
const p = std.mem.lastIndexOfScalar(u8, type_name, '.') orelse return type_name;
return type_name[p + 1 ..];
}
pub const String = struct {
array: std.ArrayList(u8) = undefined,
pub fn init(num: usize) String {
var string = String{
.array = std.ArrayList(u8).initCapacity(gallocator, num) catch unreachable,
};
string.array.append(0) catch unreachable;
return string;
}
pub fn initWithStr(s: []const u8) String {
var string = String.init(32);
string.setStr(s) catch unreachable;
return string;
}
pub fn initWithEnumOptions(Enum: type) String {
var string = String.init(32);
inline for (@typeInfo(Enum).Enum.fields) |field| {
string.append(field.name ++ ";") catch unreachable;
}
return string;
}
pub fn deinit(self: *String) void {
self.array.deinit();
}
pub fn format(self: String, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
_ = options;
if (comptime std.mem.eql(u8, fmt, "s")) {
try std.fmt.format(writer, "{s}", .{self.array.items});
} else {
try std.fmt.format(writer, "len: {d}", .{self.array.items.len});
}
}
pub fn setStr(self: *String, s: []const u8) !void {
self.array.clearRetainingCapacity();
try self.array.appendSlice(s);
try self.array.append(0); // C语言字符串以0结尾
//std.log.debug("awtk.String: len: {d}, address: {*}", .{ self.array.items.len, self.array.items.ptr });
}
pub fn setCStr(self: *String, cs: [*c]const u8) !void {
const s = cStrToSlice(cs) orelse "";
try self.setStr(s);
}
pub fn append(self: *String, s: []const u8) !void {
if (self.array.getLastOrNull()) |last| {
if (last == 0) {
try self.array.insertSlice(self.array.items.len - 1, s);
try self.array.append(0);
return;
}
}
try self.array.appendSlice(s);
try self.array.append(0);
}
pub fn cstr(self: String) [*c]const u8 {
return self.array.items.ptr;
}
pub fn str(self: String) [:0]const u8 {
var s: [:0]const u8 = undefined;
s.len = self.len();
s.ptr = @ptrCast(self.array.items.ptr);
return s;
}
pub fn len(self: String) usize {
const l = self.array.items.len;
return if (l == 0) 0 else l - 1;
}
pub fn eql(self: String, s: []const u8) bool {
return std.mem.eql(u8, self.str(), s);
}
};
/// 转换zig的内存分配器为C的内存分配器
const MAllocator = struct {
mem_allocator: c.mem_allocator_t,
allocator: std.mem.Allocator,
const Self = @This();
const SpaceType = usize;
const head_size: SpaceType = @sizeOf(SpaceType); // 存储内存块大小信息的空间的大小
const vtable: c.mem_allocator_vtable_t = .{
.alloc = alloc,
.realloc = realloc,
.free = free,
.destroy = destroy,
.dump = dump,
};
pub fn init(self: *Self, allocator: std.mem.Allocator) *c.mem_allocator_t {
self.allocator = allocator;
self.mem_allocator.vt = &vtable;
return &self.mem_allocator;
}
/// zig的内存分配器在realloc及free时需要知晓内存块的大小,而C的内存管理并不能提供此信息
/// 故分配内存时,在每块内存块前端多分配usize个字节用于存储其大小信息
fn alloc(callocator: ?*c.mem_allocator_t, size: u32, func: ?[*:0]const u8, line: u32) callconv(.C) ?*anyopaque {
_ = func;
_ = line;
const mem_allocator = callocator orelse return null;
const space: SpaceType = size + head_size;
const self: *Self = @ptrCast(mem_allocator);
const slice = self.allocator.alloc(u8, @intCast(space)) catch return null;
@memcpy(slice[0..head_size], std.mem.toBytes(space)[0..]); // 在内存块前端存储其大小信息
return @ptrCast(&slice[head_size]); // 返回内存块的大小信息之后的内存地址
}
fn realloc(callocator: ?*c.mem_allocator_t, cptr: ?*anyopaque, size: u32, func: ?[*:0]const u8, line: u32) callconv(.c) ?*anyopaque {
const mem_allocator = callocator orelse return null;
const ptr = cptr orelse return alloc(callocator, size, func, line);
const pdata: [*]u8 = @ptrCast(ptr);
const phead = pdata - head_size; // 内存块的首地址
const old_space = std.mem.bytesToValue(u32, phead[0..head_size]);
const self: *Self = @ptrCast(mem_allocator);
const space: SpaceType = size + head_size;
const slice = self.allocator.realloc(phead[0..old_space], @intCast(space)) catch return null;
@memcpy(slice[0..head_size], std.mem.toBytes(space)[0..]); // 更新内存块的大小信息
return @ptrCast(&slice[head_size]);
}
fn free(callocator: ?*c.mem_allocator_t, cptr: ?*anyopaque) callconv(.C) void {
const mem_allocator = callocator orelse return;
const ptr = cptr orelse return;
const pdata: [*]u8 = @ptrCast(ptr);
const phead = pdata - head_size; // 内存块的首地址
const old_size = std.mem.bytesToValue(u32, phead[0..head_size]);
const self: *Self = @ptrCast(mem_allocator);
self.allocator.free(phead[0..old_size]);
}
fn destroy(callocator: ?*c.mem_allocator_t) callconv(.C) c.ret_t {
_ = callocator;
return c.RET_OK;
}
fn dump(callocator: ?*c.mem_allocator_t) callconv(.C) c.ret_t {
_ = callocator;
return c.RET_OK;
}
};
pub const Language = enum(u8) {
English,
Chinese,
pub fn fromInt(iv: u8) !Language {
if (iv > @intFromEnum(Language.Chinese)) {
return error.InvalidEnumValue;
}
return @enumFromInt(iv);
}
pub fn apply(self: Language) !void {
const locale: struct {
language: [:0]const u8,
country: [:0]const u8,
} = switch (self) {
.English => .{ .language = "en", .country = "US" },
.Chinese => .{ .language = "zh", .country = "CN" },
};
const ret = c.locale_info_change(c.locale_info(), locale.language, locale.country);
if (ret == c.RET_OK) {
std.log.debug("language changed: {s}", .{@tagName(self)});
} else {
return error.LanguageChangeError;
}
}
};
pub fn tr(str: [:0]const u8) [:0]const u8 {
const cstr = c.locale_info_tr(c.locale_info(), str);
return cStrToSlice(cstr) orelse str;
}
pub fn getLanguage() Language {
return glanguage;
}
pub fn setLanguage(new_language: Language) !void {
if (new_language != glanguage) {
try new_language.apply();
glanguage = new_language;
}
}
// a.b.c => a
pub fn frontName(path: []const u8) []const u8 {
const idx = std.mem.indexOfScalar(u8, path, '.') orelse return path;
return path[0..idx];
}
// a.b.c => b.c
pub fn subPath(path: []const u8) []const u8 {
const idx = std.mem.indexOfScalar(u8, path, '.') orelse return "";
return path[idx + 1 ..];
}
fn onSignal(sid: c_int) callconv(.C) void {
std.log.warn("AWTK exit by signal: {d}", .{sid});
quit();
}
fn assetsInit() !void {
std.log.info("assets init", .{});
const am = c.assets_manager();
_ = c.assets_manager_set_theme(am, "default");
_ = c.assets_manager_preload(am, c.ASSET_TYPE_STYLE, "default");
const ret = c.tk_init_assets();
if (ret != c.RET_OK) {
return error.CFail;
}
}
pub fn init(allocator: Allocator) !void {
std.log.info("awtk init", .{});
gallocator = allocator;
if (@sizeOf(@TypeOf(mallocator)) > 0 and @hasField(c, "tk_mem_set_allocator")) {
std.log.info("set zig allocator for awtk", .{});
_ = c.tk_mem_set_allocator(mallocator.init(allocator));
}
_ = c.tk_pre_init();
const w: c.wh_t = @intCast(config.width);
const h: c.wh_t = @intCast(config.high);
const ret = c.tk_init(w, h, c.APP_SIMULATOR, @ptrCast(config.app_name), null);
if (ret != c.RET_OK) {
return error.AwtkInitFailed;
}
_ = c.signal(c.SIGINT, onSignal);
_ = c.signal(c.SIGTERM, onSignal);
_ = c.font_manager_set_standard_font_size(c.font_manager(), false);
_ = c.system_info_set_default_font(c.system_info(), "default");
try assetsInit();
_ = c.locale_info_reload(c.locale_info());
_ = c.tk_ext_widgets_init();
_ = c.log_set_log_level(c.LOG_LEVEL_DEBUG);
}
pub fn deinit() void {
_ = c.tk_exit();
}
pub fn run() u8 {
return @intCast(c.tk_run());
}
pub fn quit() void {
_ = c.tk_quit();
}
pub const Notify = enum {
NotImpl,
Ok,
Fail,
PropertyChanged,
ItemsChanged,
pub fn toRet(self: Notify) c.ret_t {
return switch (self) {
.Ok => c.RET_OK,
.Fail => c.RET_FAIL,
.PropertyChanged => c.RET_OBJECT_CHANGED,
.ItemsChanged => c.RET_ITEMS_CHANGED,
else => c.RET_NOT_IMPL,
};
}
};
// C的指针可以指向单项或多项数据,而zig的单项指针和多项指针是明确区分的
// 故zig调用C时将C指针转换为[*c]T型指针,此类指针可转换为zig的单项指针或多项指针
// 此处自动将cstr由[*c]const u8字符串转换为?[*:0]const u8
pub fn cStrEql(cstr: ?[*:0]const u8, slice: []const u8, ignore_first_cast: bool) bool {
const str = cstr orelse return false;
var i: usize = 0;
while (true) : (i += 1) {
if (str[i] == 0 and slice.len == i) {
break;
}
if (i >= slice.len) {
return false;
}
var sc = slice[i];
var cc = str[i];
if (ignore_first_cast and i == 0) {
sc = std.ascii.toLower(sc);
cc = std.ascii.toLower(cc);
}
if (sc != cc) {
return false;
}
}
return true;
}
pub fn cStrToSlice(cstr: [*c]const u8) ?[:0]const u8 {
const str = cstr orelse return null;
return std.mem.sliceTo(str, 0);
}
pub fn notify(obj: *Object, event_type: u32) void {
_ = c.emitter_dispatch_simple_event(c.EMITTER(obj), event_type);
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。