From caee008d50e20bb72264a8c019fd85d68119b045 Mon Sep 17 00:00:00 2001 From: Yves Biener Date: Sat, 1 Mar 2025 17:12:28 +0100 Subject: [PATCH] test: streamline examples with quit texts Improve some examples to provide visual feedback, i.e. for the button exmample, with fixes to make them compilable with the `Scrollable` element changes. --- examples/elements/button.zig | 47 ++++++++++++++++++++++++++++---- examples/elements/input.zig | 32 ++++++++++++++++++++-- examples/elements/scrollable.zig | 40 ++++++++++++++++++++++----- examples/styles/palette.zig | 3 +- examples/styles/text.zig | 9 +++--- 5 files changed, 110 insertions(+), 21 deletions(-) diff --git a/examples/elements/button.zig b/examples/elements/button.zig index 2b28288..a3f820c 100644 --- a/examples/elements/button.zig +++ b/examples/elements/button.zig @@ -7,10 +7,37 @@ const App = zterm.App(union(enum) { const log = std.log.scoped(.default); -pub const Clickable = struct { +const QuitText = struct { + const text = "Press ctrl+c to quit."; + + pub fn element(this: *@This()) App.Element { + return .{ .ptr = this, .vtable = &.{ .content = content } }; + } + + pub fn content(ctx: *anyopaque, cells: []zterm.Cell, size: zterm.Size) !void { + _ = ctx; + std.debug.assert(cells.len == @as(usize, size.cols) * @as(usize, size.rows)); + + const row = 2; + const col = size.cols / 2 -| (text.len / 2); + const anchor = (row * size.cols) + col; + + for (text, 0..) |cp, idx| { + cells[anchor + idx].style.fg = .white; + cells[anchor + idx].style.bg = .black; + cells[anchor + idx].cp = cp; + + // NOTE: do not write over the contents of this `Container`'s `Size` + if (anchor + idx == cells.len - 1) break; + } + } +}; + +const Clickable = struct { const text = "Press me"; queue: *App.Queue, + color: zterm.Color = .black, pub fn element(this: *@This()) App.Element { return .{ @@ -25,13 +52,20 @@ pub const Clickable = struct { fn handle(ctx: *anyopaque, event: App.Event) !void { const this: *@This() = @ptrCast(@alignCast(ctx)); switch (event) { - .mouse => |mouse| this.queue.push(.{ .click = @tagName(mouse.button) }), + .mouse => |mouse| { + var value = @intFromEnum(this.color); + value += 1; + value %= 17; + if (value == 0) value = 1; + this.color = @enumFromInt(value); + this.queue.push(.{ .click = @tagName(mouse.button) }); + }, else => {}, } } fn content(ctx: *anyopaque, cells: []zterm.Cell, size: zterm.Size) !void { - _ = ctx; + const this: *@This() = @ptrCast(@alignCast(ctx)); std.debug.assert(cells.len == @as(usize, size.cols) * @as(usize, size.rows)); const row = size.rows / 2 -| (text.len / 2); @@ -39,7 +73,8 @@ pub const Clickable = struct { const anchor = (row * size.cols) + col; for (text, 0..) |cp, idx| { - cells[anchor + idx].style.fg = .black; + cells[anchor + idx].style.fg = this.color; + cells[anchor + idx].style.emphasis = &.{.bold}; cells[anchor + idx].cp = cp; // NOTE: do not write over the contents of this `Container`'s `Size` @@ -63,10 +98,12 @@ pub fn main() !void { var clickable: Clickable = .{ .queue = &app.queue }; const element = clickable.element(); + var quit_text: QuitText = .{}; + var container = try App.Container.init(allocator, .{ .rectangle = .{ .fill = .grey }, .layout = .{ .padding = .all(5) }, - }, .{}); + }, quit_text.element()); defer container.deinit(); try container.append(try App.Container.init(allocator, .{ .rectangle = .{ .fill = .light_grey } }, element)); diff --git a/examples/elements/input.zig b/examples/elements/input.zig index 31b5c08..cb8ece8 100644 --- a/examples/elements/input.zig +++ b/examples/elements/input.zig @@ -7,7 +7,33 @@ const App = zterm.App(union(enum) { const log = std.log.scoped(.default); -pub const InputField = struct { +const QuitText = struct { + const text = "Press ctrl+c to quit."; + + pub fn element(this: *@This()) App.Element { + return .{ .ptr = this, .vtable = &.{ .content = content } }; + } + + pub fn content(ctx: *anyopaque, cells: []zterm.Cell, size: zterm.Size) !void { + _ = ctx; + std.debug.assert(cells.len == @as(usize, size.cols) * @as(usize, size.rows)); + + const row = 2; + const col = size.cols / 2 -| (text.len / 2); + const anchor = (row * size.cols) + col; + + for (text, 0..) |cp, idx| { + cells[anchor + idx].style.fg = .white; + cells[anchor + idx].style.bg = .black; + cells[anchor + idx].cp = cp; + + // NOTE: do not write over the contents of this `Container`'s `Size` + if (anchor + idx == cells.len - 1) break; + } + } +}; + +const InputField = struct { input: std.ArrayList(u21), queue: *App.Queue, @@ -83,12 +109,14 @@ pub fn main() !void { var input_field: InputField = .init(allocator, &app.queue); defer input_field.deinit(); + var quit_text: QuitText = .{}; + const element = input_field.element(); var container = try App.Container.init(allocator, .{ .rectangle = .{ .fill = .grey }, .layout = .{ .padding = .all(5) }, - }, .{}); + }, quit_text.element()); defer container.deinit(); try container.append(try App.Container.init(allocator, .{ .rectangle = .{ .fill = .light_grey } }, element)); diff --git a/examples/elements/scrollable.zig b/examples/elements/scrollable.zig index f107f93..f4872c7 100644 --- a/examples/elements/scrollable.zig +++ b/examples/elements/scrollable.zig @@ -6,7 +6,33 @@ const App = zterm.App(union(enum) {}); const log = std.log.scoped(.default); -pub const HelloWorldText = packed struct { +const QuitText = struct { + const text = "Press ctrl+c to quit."; + + pub fn element(this: *@This()) App.Element { + return .{ .ptr = this, .vtable = &.{ .content = content } }; + } + + pub fn content(ctx: *anyopaque, cells: []zterm.Cell, size: zterm.Size) !void { + _ = ctx; + std.debug.assert(cells.len == @as(usize, size.cols) * @as(usize, size.rows)); + + const row = 2; + const col = size.cols / 2 -| (text.len / 2); + const anchor = (row * size.cols) + col; + + for (text, 0..) |cp, idx| { + cells[anchor + idx].style.fg = .white; + cells[anchor + idx].style.bg = .black; + cells[anchor + idx].cp = cp; + + // NOTE: do not write over the contents of this `Container`'s `Size` + if (anchor + idx == cells.len - 1) break; + } + } +}; + +const HelloWorldText = packed struct { const text = "Hello World"; pub fn element(this: *@This()) App.Element { @@ -52,6 +78,8 @@ pub fn main() !void { var element_wrapper: HelloWorldText = .{}; const element = element_wrapper.element(); + var quit_text: QuitText = .{}; + var top_box = try App.Container.init(allocator, .{ .rectangle = .{ .fill = .blue }, .layout = .{ @@ -59,7 +87,6 @@ pub fn main() !void { .direction = .vertical, .padding = .vertical(1), }, - .min_size = .{ .rows = 50 }, }, .{}); try top_box.append(try App.Container.init(allocator, .{ .rectangle = .{ .fill = .light_green }, @@ -85,7 +112,6 @@ pub fn main() !void { .direction = .vertical, .padding = .vertical(1), }, - .min_size = .{ .rows = 30 }, }, .{}); try bottom_box.append(try App.Container.init(allocator, .{ .rectangle = .{ .fill = .grey }, @@ -105,17 +131,17 @@ pub fn main() !void { .enabled = true, .line = .double, }, - .padding = .all(5), + .padding = .{ .top = 5, .bottom = 3, .left = 3, .right = 3 }, .direction = .vertical, }, - }, .{}); + }, quit_text.element()); defer container.deinit(); // place empty container containing the element of the scrollable Container. - var scrollable_top: App.Scrollable = .init(top_box); + var scrollable_top: App.Scrollable = .init(top_box, .{ .rows = 50 }); try container.append(try App.Container.init(allocator, .{}, scrollable_top.element())); - var scrollable_bottom: App.Scrollable = .init(bottom_box); + var scrollable_bottom: App.Scrollable = .init(bottom_box, .{ .rows = 30 }); try container.append(try App.Container.init(allocator, .{}, scrollable_bottom.element())); try app.start(); diff --git a/examples/styles/palette.zig b/examples/styles/palette.zig index 4688cae..6358144 100644 --- a/examples/styles/palette.zig +++ b/examples/styles/palette.zig @@ -56,7 +56,6 @@ pub fn main() !void { var box = try App.Container.init(allocator, .{ .layout = .{ .direction = .horizontal }, - .min_size = .{ .cols = 3 * std.meta.fields(zterm.Color).len }, // ensure enough columns to render all colors -> scrollable otherwise }, .{}); defer box.deinit(); @@ -64,7 +63,7 @@ pub fn main() !void { if (comptime field.value == 0) continue; // zterm.Color.default == 0 -> skip try box.append(try App.Container.init(allocator, .{ .rectangle = .{ .fill = @enumFromInt(field.value) } }, .{})); } - var scrollable: App.Scrollable = .init(box); + var scrollable: App.Scrollable = .init(box, .{ .cols = 3 * std.meta.fields(zterm.Color).len }); // ensure enough columns to render all colors -> scrollable otherwise try container.append(try App.Container.init(allocator, .{}, scrollable.element())); try app.start(); diff --git a/examples/styles/text.zig b/examples/styles/text.zig index 7e44b3e..0ade9c5 100644 --- a/examples/styles/text.zig +++ b/examples/styles/text.zig @@ -109,14 +109,13 @@ pub fn main() !void { var box = try App.Container.init(allocator, .{ .layout = .{ .direction = .vertical }, - .min_size = .{ - .rows = (std.meta.fields(zterm.Color).len - 1) * (std.meta.fields(zterm.Color).len - 2), - .cols = std.meta.fields(zterm.Style.Emphasis).len * TextStyles.text.len, - }, // ensure enough rows and/or columns to render all text styles -> scrollable otherwise }, text_styles.element()); defer box.deinit(); - var scrollable: App.Scrollable = .init(box); + var scrollable: App.Scrollable = .init(box, .{ + .rows = (std.meta.fields(zterm.Color).len - 1) * (std.meta.fields(zterm.Color).len - 2), + .cols = std.meta.fields(zterm.Style.Emphasis).len * TextStyles.text.len, + }); // ensure enough rows and/or columns to render all text styles -> scrollable otherwise try container.append(try App.Container.init(allocator, .{}, scrollable.element())); try app.start();