feat(win32 gui): add font selection palette

closes #102
This commit is contained in:
CJ van den Berg 2025-01-17 20:32:20 +01:00
parent 3e953981fe
commit e1b1591167
Signed by: neurocyte
GPG key ID: 8EB1E1BB660E3FB9
10 changed files with 184 additions and 14 deletions

View file

@ -37,6 +37,7 @@ const menu_commands = if (build_options.gui) &[_][]const u8{
"open_keybind_config",
"toggle_input_mode",
"change_theme",
"change_fontface",
"quit",
} else &[_][]const u8{
"open_help",
@ -101,9 +102,13 @@ fn add_menu_command(self: *Self, comptime command_name: []const u8, menu: anytyp
var buf: [64]u8 = undefined;
var fis = std.io.fixedBufferStream(&buf);
const writer = fis.writer();
try writer.print("{s} ..", .{description});
const leader = if (hint.len > 0) "." else " ";
_ = try writer.write(description);
_ = try writer.write(" ");
_ = try writer.write(leader);
_ = try writer.write(leader);
for (0..(self.max_desc_len - label_len - 5)) |_|
try writer.print(".", .{});
_ = try writer.write(leader);
try writer.print(" :{s}", .{hint});
const label = fis.getWritten();
try menu.add_item_with_handler(label, menu_action(command_name));

View file

@ -0,0 +1,78 @@
const std = @import("std");
const cbor = @import("cbor");
const tp = @import("thespian");
const Widget = @import("../../Widget.zig");
const tui = @import("../../tui.zig");
pub const Type = @import("palette.zig").Create(@This());
pub const label = "Select font face";
pub const name = " font";
pub const description = "font";
pub const Entry = struct {
label: []const u8,
};
pub const Match = struct {
label: []const u8,
score: i32,
matches: []const usize,
};
var previous_fontface: ?[]const u8 = null;
pub fn deinit(palette: *Type) void {
if (previous_fontface) |fontface|
palette.allocator.free(fontface);
previous_fontface = null;
for (palette.entries.items) |entry|
palette.allocator.free(entry.label);
}
pub fn load_entries(palette: *Type) !usize {
var idx: usize = 0;
previous_fontface = try palette.allocator.dupe(u8, tui.current().fontface);
const fontfaces = tui.current().fontfaces orelse return 0;
tui.current().fontfaces = null;
for (fontfaces.items) |fontface| {
idx += 1;
(try palette.entries.addOne()).* = .{ .label = fontface };
if (previous_fontface) |previous_fontface_| if (std.mem.eql(u8, fontface, previous_fontface_)) {
palette.initial_selected = idx;
};
}
return 0;
}
pub fn add_menu_entry(palette: *Type, entry: *Entry, matches: ?[]const usize) !void {
var value = std.ArrayList(u8).init(palette.allocator);
defer value.deinit();
const writer = value.writer();
try cbor.writeValue(writer, entry.label);
try cbor.writeValue(writer, matches orelse &[_]usize{});
try palette.menu.add_item_with_handler(value.items, select);
palette.items += 1;
}
fn select(menu: **Type.MenuState, button: *Type.ButtonState) void {
var label_: []const u8 = undefined;
var iter = button.opts.label;
if (!(cbor.matchString(&iter, &label_) catch false)) return;
tp.self_pid().send(.{ "cmd", "exit_overlay_mode" }) catch |e| menu.*.opts.ctx.logger.err("fontface_palette", e);
tp.self_pid().send(.{ "cmd", "set_fontface", .{label_} }) catch |e| menu.*.opts.ctx.logger.err("fontface_palette", e);
}
pub fn updated(palette: *Type, button_: ?*Type.ButtonState) !void {
const button = button_ orelse return cancel(palette);
var label_: []const u8 = undefined;
var iter = button.opts.label;
if (!(cbor.matchString(&iter, &label_) catch false)) return;
tp.self_pid().send(.{ "cmd", "set_fontface", .{label_} }) catch |e| palette.logger.err("fontface_palette upated", e);
}
pub fn cancel(palette: *Type) !void {
if (previous_fontface) |prev|
tp.self_pid().send(.{ "cmd", "set_fontface", .{prev} }) catch |e| palette.logger.err("fontface_palette cancel", e);
}

View file

@ -76,7 +76,6 @@ pub fn Create(options: type) type {
try self.start_query(0);
try mv.floating_views.add(self.modal.widget());
try mv.floating_views.add(self.menu.container_widget);
if (self.initial_selected) |idx| self.select(idx);
var mode = try keybind.mode("overlay/palette", allocator, .{
.insert_command = "overlay_insert_bytes",
});
@ -154,7 +153,7 @@ pub fn Create(options: type) type {
fn on_resize_menu(self: *Self, _: *Menu.State(*Self), _: Widget.Box) void {
self.do_resize();
self.start_query(0) catch {};
// self.start_query(0) catch {};
}
fn do_resize(self: *Self) void {
@ -231,13 +230,18 @@ pub fn Create(options: type) type {
} else {
_ = try self.query_entries(self.inputbox.text.items);
}
self.menu.select_down();
var i = n;
while (i > 0) : (i -= 1)
if (self.initial_selected) |idx| {
self.initial_selected = null;
self.select(idx);
} else {
self.menu.select_down();
self.do_resize();
tui.current().refresh_hover();
self.selection_updated();
var i = n;
while (i > 0) : (i -= 1)
self.menu.select_down();
self.do_resize();
tui.current().refresh_hover();
self.selection_updated();
}
}
fn query_entries(self: *Self, query: []const u8) error{OutOfMemory}!usize {

View file

@ -54,6 +54,8 @@ render_pending: bool = false,
keepalive_timer: ?tp.Cancellable = null,
mouse_idle_timer: ?tp.Cancellable = null,
default_cursor: keybind.CursorShape = .default,
fontface: []const u8 = "",
fontfaces: ?std.ArrayList([]const u8) = null,
const keepalive = std.time.us_per_day * 365; // one year
const idle_frames = 0;
@ -381,6 +383,27 @@ fn receive_safe(self: *Self, from: tp.pid_ref, m: tp.message) !void {
return;
}
if (try m.match(.{ "fontface", "done" })) {
return self.enter_overlay_mode(@import("mode/overlay/fontface_palette.zig").Type);
}
var fontface: []const u8 = undefined;
if (try m.match(.{ "fontface", "current", tp.extract(&fontface) })) {
if (self.fontface.len > 0) self.allocator.free(self.fontface);
self.fontface = "";
self.fontface = try self.allocator.dupe(u8, fontface);
return;
}
if (try m.match(.{ "fontface", tp.extract(&fontface) })) {
var fontfaces = if (self.fontfaces) |*p| p else blk: {
self.fontfaces = std.ArrayList([]const u8).init(self.allocator);
break :blk &self.fontfaces.?;
};
try fontfaces.append(try self.allocator.dupe(u8, fontface));
return;
}
return tp.unexpected(m);
}
@ -798,6 +821,12 @@ const cmds = struct {
}
pub const change_file_type_meta = .{ .description = "Change file type" };
pub fn change_fontface(self: *Self, _: Ctx) Result {
if (build_options.gui)
self.rdr.get_fontfaces();
}
pub const change_fontface_meta = .{ .description = "Select font face" };
pub fn exit_overlay_mode(self: *Self, _: Ctx) Result {
self.rdr.cursor_disable();
if (self.input_mode_outer == null) return;