feat(win32 gui): add gui_config.json config file

This commit is contained in:
CJ van den Berg 2025-01-08 12:51:35 +01:00
parent 6d7a316abb
commit eaa7ad87b7
Signed by: neurocyte
GPG key ID: 8EB1E1BB660E3FB9
6 changed files with 40 additions and 21 deletions

View file

@ -252,6 +252,13 @@ pub fn build_exe(
},
});
const gui_config_mod = b.createModule(.{
.root_source_file = b.path("src/gui_config.zig"),
.imports = &.{
.{ .name = "cbor", .module = cbor_mod },
},
});
const log_mod = b.createModule(.{
.root_source_file = b.path("src/log.zig"),
.imports = &.{
@ -324,6 +331,7 @@ pub fn build_exe(
// TODO: we should be able to work without these modules
.{ .name = "vaxis", .module = vaxis_mod },
.{ .name = "color", .module = color_mod },
.{ .name = "gui_config", .module = gui_config_mod },
},
});
gui_mod.addIncludePath(b.path("src/win32"));

4
src/gui_config.zig Normal file
View file

@ -0,0 +1,4 @@
fontface: [] const u8 = "Cascadia Code",
fontsize: f32 = 17.5,
config_files: []const u8 = "",

View file

@ -389,28 +389,26 @@ pub fn exit(status: u8) noreturn {
std.posix.exit(status);
}
const config = @import("config");
pub fn free_config(allocator: std.mem.Allocator, bufs: [][]const u8) void {
for (bufs) |buf| allocator.free(buf);
}
pub fn read_config(allocator: std.mem.Allocator) struct { config, [][]const u8 } {
pub fn read_config(T: type, allocator: std.mem.Allocator) struct { T, [][]const u8 } {
var bufs: [][]const u8 = &[_][]const u8{};
const file_name = get_app_config_file_name(application_name) catch return .{ .{}, bufs };
var conf: config = .{};
read_config_file(allocator, &conf, &bufs, file_name);
read_nested_config_files(allocator, &conf, &bufs);
const file_name = get_app_config_file_name(application_name, @typeName(T)) catch return .{ .{}, bufs };
var conf: T = .{};
read_config_file(T, allocator, &conf, &bufs, file_name);
read_nested_config_files(T, allocator, &conf, &bufs);
return .{ conf, bufs };
}
fn read_config_file(allocator: std.mem.Allocator, conf: *config, bufs: *[][]const u8, file_name: []const u8) void {
read_json_config_file(allocator, conf, bufs, file_name) catch |e|
fn read_config_file(T: type, allocator: std.mem.Allocator, conf: *T, bufs: *[][]const u8, file_name: []const u8) void {
read_json_config_file(T, allocator, conf, bufs, file_name) catch |e|
log.logger("config").print_err("read_config", "error reading config file: {any}", .{e});
return;
}
fn read_json_config_file(allocator: std.mem.Allocator, conf: *config, bufs_: *[][]const u8, file_name: []const u8) !void {
fn read_json_config_file(T: type, allocator: std.mem.Allocator, conf: *T, bufs_: *[][]const u8, file_name: []const u8) !void {
const cbor = @import("cbor");
var file = std.fs.openFileAbsolute(file_name, .{ .mode = .read_only }) catch |e| switch (e) {
error.FileNotFound => return,
@ -429,7 +427,7 @@ fn read_json_config_file(allocator: std.mem.Allocator, conf: *config, bufs_: *[]
while (len > 0) : (len -= 1) {
var field_name: []const u8 = undefined;
if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidConfig;
inline for (@typeInfo(config).Struct.fields) |field_info|
inline for (@typeInfo(T).Struct.fields) |field_info|
if (comptime std.mem.eql(u8, "config_files", field_info.name)) {
if (std.mem.eql(u8, field_name, field_info.name)) {
var value: field_info.type = undefined;
@ -448,14 +446,14 @@ fn read_json_config_file(allocator: std.mem.Allocator, conf: *config, bufs_: *[]
}
}
fn read_nested_config_files(allocator: std.mem.Allocator, conf: *config, bufs: *[][]const u8) void {
fn read_nested_config_files(T: type, allocator: std.mem.Allocator, conf: *T, bufs: *[][]const u8) void {
if (conf.config_files.len == 0) return;
var it = std.mem.splitScalar(u8, conf.config_files, std.fs.path.delimiter);
while (it.next()) |path| read_config_file(allocator, conf, bufs, path);
while (it.next()) |path| read_config_file(T, allocator, conf, bufs, path);
}
pub fn write_config(conf: config, allocator: std.mem.Allocator) !void {
return write_json_file(config, conf, allocator, try get_app_config_file_name(application_name));
pub fn write_config(conf: anytype, allocator: std.mem.Allocator) !void {
return write_json_file(@TypeOf(conf), conf, allocator, try get_app_config_file_name(application_name, @typeName(@TypeOf(conf))));
}
fn write_json_file(comptime T: type, data: T, allocator: std.mem.Allocator, file_name: []const u8) !void {
@ -638,12 +636,15 @@ fn get_app_state_dir(appname: []const u8) ![]const u8 {
return state_dir;
}
fn get_app_config_file_name(appname: []const u8) ![]const u8 {
fn get_app_config_file_name(appname: []const u8, comptime base_name: []const u8) ![]const u8 {
return get_app_config_dir_file_name(appname, base_name ++ ".json");
}
fn get_app_config_dir_file_name(appname: []const u8, comptime config_file_name: []const u8) ![]const u8 {
const local = struct {
var config_file_buffer: [std.posix.PATH_MAX]u8 = undefined;
var config_file: ?[]const u8 = null;
};
const config_file_name = "config.json";
const config_file = if (local.config_file) |file|
file
else
@ -652,8 +653,8 @@ fn get_app_config_file_name(appname: []const u8) ![]const u8 {
return config_file;
}
pub fn get_config_file_name() ![]const u8 {
return get_app_config_file_name(application_name);
pub fn get_config_file_name(T: type) ![]const u8 {
return get_app_config_file_name(application_name, @typeName(T));
}
pub fn get_restore_file_name() ![]const u8 {

View file

@ -378,7 +378,7 @@ const cmds = struct {
pub const open_help_meta = .{ .description = "Open help" };
pub fn open_config(_: *Self, _: Ctx) Result {
const file_name = try root.get_config_file_name();
const file_name = try root.get_config_file_name(@TypeOf(tui.current().config));
try tp.self_pid().send(.{ "cmd", "navigate", .{ .file = file_name } });
}
pub const open_config_meta = .{ .description = "Edit configuration file" };

View file

@ -83,7 +83,7 @@ fn start(args: StartArgs) tp.result {
fn init(allocator: Allocator) !*Self {
var self = try allocator.create(Self);
var conf, const conf_bufs = root.read_config(allocator);
var conf, const conf_bufs = root.read_config(config, allocator);
defer root.free_config(allocator, conf_bufs);
const theme = get_theme_by_name(conf.theme) orelse get_theme_by_name("dark_modern") orelse return tp.exit("unknown theme");

View file

@ -1,4 +1,5 @@
const std = @import("std");
const root = @import("root");
const c = @cImport({
@cInclude("ResourceNames.h");
@ -10,6 +11,7 @@ const ddui = @import("ddui");
const cbor = @import("cbor");
const thespian = @import("thespian");
const vaxis = @import("vaxis");
const gui_config = @import("gui_config");
const RGB = @import("color").RGB;
const input = @import("input");
@ -381,6 +383,7 @@ fn calcWindowPlacement() WindowPlacement {
const CreateWindowArgs = struct {
allocator: std.mem.Allocator,
pid: thespian.pid,
conf: gui_config,
};
pub fn start() !std.Thread {
@ -418,9 +421,12 @@ fn entry(pid: thespian.pid) !void {
win32.GetLastError(),
);
const conf, _ = root.read_config(gui_config, arena_instance.allocator());
var create_args = CreateWindowArgs{
.allocator = arena_instance.allocator(),
.pid = pid,
.conf = conf,
};
const hwnd = win32.CreateWindowExW(
window_style_ex,