refactor: button, menu and widget stack apis
This commit is contained in:
parent
dcd9e119da
commit
2f9a0e2eb0
9 changed files with 348 additions and 130 deletions
124
src/tui/home.zig
124
src/tui/home.zig
|
@ -11,16 +11,19 @@ const command = @import("command.zig");
|
|||
const fonts = @import("fonts.zig");
|
||||
|
||||
a: std.mem.Allocator,
|
||||
background: nc.Plane,
|
||||
plane: nc.Plane,
|
||||
parent: nc.Plane,
|
||||
fire: ?Fire = null,
|
||||
commands: Commands = undefined,
|
||||
menu: *Menu,
|
||||
menu: *Menu.State(*Self),
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub fn create(a: std.mem.Allocator, parent: Widget) !Widget {
|
||||
const self: *Self = try a.create(Self);
|
||||
var background = try nc.Plane.init(&(Widget.Box{}).opts("background"), parent.plane.*);
|
||||
errdefer background.deinit();
|
||||
var n = try nc.Plane.init(&(Widget.Box{}).opts("editor"), parent.plane.*);
|
||||
errdefer n.deinit();
|
||||
|
||||
|
@ -28,35 +31,28 @@ pub fn create(a: std.mem.Allocator, parent: Widget) !Widget {
|
|||
self.* = .{
|
||||
.a = a,
|
||||
.parent = parent.plane.*,
|
||||
.background = background,
|
||||
.plane = n,
|
||||
.menu = try Menu.create(a, w),
|
||||
.menu = try Menu.create(*Self, a, w, .{ .ctx = self, .on_render = menu_on_render }),
|
||||
};
|
||||
try self.commands.init(self);
|
||||
try self.menu.add_item("Help ······················· :h", menu_action_help);
|
||||
try self.menu.add_item("Open file ·················· :o", menu_action_open_file);
|
||||
try self.menu.add_item("Open recent file ····(wip)·· :e", menu_action_open_recent_file);
|
||||
try self.menu.add_item("Open recent project ·(wip)·· :r", menu_action_open_recent_project);
|
||||
try self.menu.add_item("Show/Run commands ···(wip)·· :p", menu_action_show_commands);
|
||||
try self.menu.add_item("Open config file ··········· :c", menu_action_open_config);
|
||||
try self.menu.add_item("Quit/Close ················· :q", menu_action_quit);
|
||||
try self.menu.add_item_with_handler("Help ······················· :h", menu_action_help);
|
||||
try self.menu.add_item_with_handler("Open file ·················· :o", menu_action_open_file);
|
||||
try self.menu.add_item_with_handler("Open recent file ····(wip)·· :e", menu_action_open_recent_file);
|
||||
try self.menu.add_item_with_handler("Open recent project ·(wip)·· :r", menu_action_open_recent_project);
|
||||
try self.menu.add_item_with_handler("Show/Run commands ···(wip)·· :p", menu_action_show_commands);
|
||||
try self.menu.add_item_with_handler("Open config file ··········· :c", menu_action_open_config);
|
||||
try self.menu.add_item_with_handler("Quit/Close ················· :q", menu_action_quit);
|
||||
self.menu.resize(.{ .y = 15, .x = 9, .w = 32 });
|
||||
command.executeName("enter_mode", command.Context.fmt(.{"home"})) catch {};
|
||||
return w;
|
||||
}
|
||||
|
||||
fn menu_item(self: *Self, label: []const u8, on_click: *const fn (_: *void, _: *Button.State(void)) void) !void {
|
||||
try self.menu.add(try Button.create({}, self.a, self.parent, .{
|
||||
.on_layout = menu_layout,
|
||||
.label = label,
|
||||
.on_click = on_click,
|
||||
.on_render = render_menu_item,
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self, a: std.mem.Allocator) void {
|
||||
self.menu.deinit(a);
|
||||
self.commands.deinit();
|
||||
self.plane.deinit();
|
||||
self.background.deinit();
|
||||
if (self.fire) |*fire| fire.deinit();
|
||||
a.destroy(self);
|
||||
}
|
||||
|
@ -73,47 +69,85 @@ pub fn receive(_: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
|||
var hover: bool = false;
|
||||
if (try m.match(.{ "H", tp.extract(&hover) })) {
|
||||
tui.current().request_mouse_cursor_default(hover);
|
||||
tui.need_render();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn menu_layout(_: *void, _: *Button.State(void)) Widget.Layout {
|
||||
return .{ .static = 1 };
|
||||
fn set_style(plane: nc.Plane, style: Widget.Theme.Style) void {
|
||||
var channels: u64 = 0;
|
||||
if (style.fg) |fg| {
|
||||
nc.channels_set_fg_rgb(&channels, fg) catch {};
|
||||
nc.channels_set_fg_alpha(&channels, nc.ALPHA_OPAQUE) catch {};
|
||||
}
|
||||
if (style.bg) |bg| {
|
||||
nc.channels_set_bg_rgb(&channels, bg) catch {};
|
||||
nc.channels_set_bg_alpha(&channels, nc.ALPHA_TRANSPARENT) catch {};
|
||||
}
|
||||
plane.set_channels(channels);
|
||||
if (style.fs) |fs| switch (fs) {
|
||||
.normal => plane.set_styles(nc.style.none),
|
||||
.bold => plane.set_styles(nc.style.bold),
|
||||
.italic => plane.set_styles(nc.style.italic),
|
||||
.underline => plane.set_styles(nc.style.underline),
|
||||
.strikethrough => plane.set_styles(nc.style.struck),
|
||||
};
|
||||
}
|
||||
|
||||
fn menu_action_help(_: *void, _: *Button.State(void)) void {
|
||||
fn menu_on_render(_: *Self, button: *Button.State(*Menu.State(*Self)), theme: *const Widget.Theme) bool {
|
||||
const style_base = if (button.active) theme.editor_cursor else if (button.hover) theme.editor_selection else theme.editor;
|
||||
const bg_alpha: c_uint = if (button.active or button.hover) nc.ALPHA_OPAQUE else nc.ALPHA_TRANSPARENT;
|
||||
try tui.set_base_style_alpha(button.plane, " ", style_base, nc.ALPHA_OPAQUE, bg_alpha);
|
||||
button.plane.erase();
|
||||
button.plane.home();
|
||||
const style_subtext = if (tui.find_scope_style(theme, "comment")) |sty| sty.style else theme.editor;
|
||||
const style_text = if (tui.find_scope_style(theme, "keyword")) |sty| sty.style else theme.editor;
|
||||
const style_keybind = if (tui.find_scope_style(theme, "entity.name")) |sty| sty.style else theme.editor;
|
||||
const sep = std.mem.indexOfScalar(u8, button.opts.label, ':') orelse button.opts.label.len;
|
||||
set_style(button.plane, style_subtext);
|
||||
set_style(button.plane, style_text);
|
||||
_ = button.plane.print(" {s}", .{button.opts.label[0..sep]}) catch {};
|
||||
set_style(button.plane, style_keybind);
|
||||
_ = button.plane.print("{s}", .{button.opts.label[sep + 1 ..]}) catch {};
|
||||
return false;
|
||||
}
|
||||
|
||||
fn menu_action_help(_: *Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
||||
command.executeName("open_help", .{}) catch {};
|
||||
}
|
||||
|
||||
fn menu_action_open_file(_: *void, _: *Button.State(void)) void {
|
||||
fn menu_action_open_file(_: *Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
||||
command.executeName("enter_open_file_mode", .{}) catch {};
|
||||
}
|
||||
|
||||
fn menu_action_open_recent_file(_: *void, _: *Button.State(void)) void {
|
||||
fn menu_action_open_recent_file(_: *Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
||||
tp.self_pid().send(.{ "log", "home", "open recent file not implemented" }) catch {};
|
||||
}
|
||||
|
||||
fn menu_action_open_recent_project(_: *void, _: *Button.State(void)) void {
|
||||
fn menu_action_open_recent_project(_: *Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
||||
tp.self_pid().send(.{ "log", "home", "open recent project not implemented" }) catch {};
|
||||
}
|
||||
|
||||
fn menu_action_show_commands(_: *void, _: *Button.State(void)) void {
|
||||
fn menu_action_show_commands(_: *Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
||||
tp.self_pid().send(.{ "log", "home", "open command palette not implemented" }) catch {};
|
||||
}
|
||||
|
||||
fn menu_action_open_config(_: *void, _: *Button.State(void)) void {
|
||||
fn menu_action_open_config(_: *Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
||||
command.executeName("open_config", .{}) catch {};
|
||||
}
|
||||
|
||||
fn menu_action_quit(_: *void, _: *Button.State(void)) void {
|
||||
fn menu_action_quit(_: *Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
||||
command.executeName("quit", .{}) catch {};
|
||||
}
|
||||
|
||||
pub fn render(self: *Self, theme: *const Widget.Theme) bool {
|
||||
const more = self.menu.render(theme);
|
||||
|
||||
tui.set_base_style(&self.plane, " ", theme.editor);
|
||||
try tui.set_base_style_alpha(self.background, " ", theme.editor, nc.ALPHA_OPAQUE, nc.ALPHA_TRANSPARENT);
|
||||
self.background.erase();
|
||||
self.background.home();
|
||||
try tui.set_base_style_alpha(self.plane, "", theme.editor, nc.ALPHA_TRANSPARENT, nc.ALPHA_TRANSPARENT);
|
||||
self.plane.erase();
|
||||
self.plane.home();
|
||||
if (self.fire) |*fire| fire.render() catch unreachable;
|
||||
|
@ -125,56 +159,42 @@ pub fn render(self: *Self, theme: *const Widget.Theme) bool {
|
|||
const subtext = "a programmer's text editor";
|
||||
|
||||
if (self.plane.dim_x() > 120 and self.plane.dim_y() > 22) {
|
||||
tui.set_style(&self.plane, style_title);
|
||||
set_style(self.plane, style_title);
|
||||
self.plane.cursor_move_yx(2, 4) catch return more;
|
||||
fonts.print_string_large(self.plane, title) catch return more;
|
||||
|
||||
tui.set_style(&self.plane, style_subtext);
|
||||
set_style(self.plane, style_subtext);
|
||||
self.plane.cursor_move_yx(10, 8) catch return more;
|
||||
fonts.print_string_medium(self.plane, subtext) catch return more;
|
||||
|
||||
self.menu.resize(.{ .y = 15, .x = 10, .w = 32 });
|
||||
} else if (self.plane.dim_x() > 55 and self.plane.dim_y() > 16) {
|
||||
tui.set_style(&self.plane, style_title);
|
||||
set_style(self.plane, style_title);
|
||||
self.plane.cursor_move_yx(2, 4) catch return more;
|
||||
fonts.print_string_medium(self.plane, title) catch return more;
|
||||
|
||||
tui.set_style(&self.plane, style_subtext);
|
||||
set_style(self.plane, style_subtext);
|
||||
self.plane.cursor_move_yx(7, 6) catch return more;
|
||||
_ = self.plane.print(subtext, .{}) catch {};
|
||||
|
||||
self.menu.resize(.{ .y = 9, .x = 8, .w = 32 });
|
||||
} else {
|
||||
tui.set_style(&self.plane, style_title);
|
||||
set_style(self.plane, style_title);
|
||||
self.plane.cursor_move_yx(1, 4) catch return more;
|
||||
_ = self.plane.print(title, .{}) catch return more;
|
||||
|
||||
tui.set_style(&self.plane, style_subtext);
|
||||
set_style(self.plane, style_subtext);
|
||||
self.plane.cursor_move_yx(3, 6) catch return more;
|
||||
_ = self.plane.print(subtext, .{}) catch {};
|
||||
|
||||
self.menu.resize(.{ .y = 5, .x = 8, .w = 32 });
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn render_menu_item(_: *void, button: *Button.State(void), theme: *const Widget.Theme) bool {
|
||||
tui.set_base_style(&button.plane, " ", if (button.active) theme.editor_cursor else if (button.hover) theme.editor_selection else theme.editor);
|
||||
button.plane.erase();
|
||||
button.plane.home();
|
||||
const style_subtext = if (tui.find_scope_style(theme, "comment")) |sty| sty.style else theme.editor;
|
||||
const style_text = if (tui.find_scope_style(theme, "keyword")) |sty| sty.style else theme.editor;
|
||||
const style_keybind = if (tui.find_scope_style(theme, "entity.name")) |sty| sty.style else theme.editor;
|
||||
const sep = std.mem.indexOfScalar(u8, button.opts.label, ':') orelse button.opts.label.len;
|
||||
tui.set_style(&button.plane, style_subtext);
|
||||
tui.set_style(&button.plane, style_text);
|
||||
_ = button.plane.print(" {s}", .{button.opts.label[0..sep]}) catch {};
|
||||
tui.set_style(&button.plane, style_keybind);
|
||||
_ = button.plane.print("{s}", .{button.opts.label[sep + 1 ..]}) catch {};
|
||||
return false;
|
||||
return more or self.fire != null;
|
||||
}
|
||||
|
||||
pub fn handle_resize(self: *Self, pos: Widget.Box) void {
|
||||
self.background.move_yx(@intCast(pos.y), @intCast(pos.x)) catch return;
|
||||
self.background.resize_simple(@intCast(pos.h), @intCast(pos.w)) catch return;
|
||||
self.plane.move_yx(@intCast(pos.y), @intCast(pos.x)) catch return;
|
||||
self.plane.resize_simple(@intCast(pos.h), @intCast(pos.w)) catch return;
|
||||
if (self.fire) |*fire| {
|
||||
|
@ -193,7 +213,7 @@ const cmds = struct {
|
|||
self.fire = if (self.fire) |*fire| ret: {
|
||||
fire.deinit();
|
||||
break :ret null;
|
||||
} else Fire.init(self.a, self.plane, Widget.Box.from(self.plane)) catch |e| return tp.exit_error(e);
|
||||
} else Fire.init(self.a, self.background, Widget.Box.from(self.background)) catch |e| return tp.exit_error(e);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue