add(widget): Text widget to display static Cell contents

This commit is contained in:
2024-11-15 21:01:50 +01:00
parent 273da37020
commit 58982a53f2
4 changed files with 86 additions and 38 deletions

View File

@@ -32,41 +32,46 @@ pub fn build(b: *std.Build) void {
lib.addImport("interface", interface.module("interface")); lib.addImport("interface", interface.module("interface"));
lib.addImport("code_point", zg.module("code_point")); lib.addImport("code_point", zg.module("code_point"));
const exe = b.addExecutable(.{ // example executables
.name = "zterm", const stack_example = b.addExecutable(.{
.root_source_file = b.path("src/main.zig"), .name = "stack",
.root_source_file = b.path("examples/stack.zig"),
.target = target, .target = target,
.optimize = optimize, .optimize = optimize,
}); });
exe.root_module.addImport("zterm", lib); stack_example.root_module.addImport("zterm", lib);
const container_example = b.addExecutable(.{
.name = "container",
.root_source_file = b.path("examples/container.zig"),
.target = target,
.optimize = optimize,
});
container_example.root_module.addImport("zterm", lib);
const padding_example = b.addExecutable(.{
.name = "padding",
.root_source_file = b.path("examples/padding.zig"),
.target = target,
.optimize = optimize,
});
padding_example.root_module.addImport("zterm", lib);
const exec_example = b.addExecutable(.{
.name = "exec",
.root_source_file = b.path("examples/exec.zig"),
.target = target,
.optimize = optimize,
});
exec_example.root_module.addImport("zterm", lib);
// This declares intent for the executable to be installed into the // This declares intent for the executable to be installed into the
// standard location when the user invokes the "install" step (the default // standard location when the user invokes the "install" step (the default
// step when running `zig build`). // step when running `zig build`).
b.installArtifact(exe); b.installArtifact(stack_example);
b.installArtifact(container_example);
// This *creates* a Run step in the build graph, to be executed when another b.installArtifact(padding_example);
// step is evaluated that depends on it. The next line below will establish b.installArtifact(exec_example);
// such a dependency.
const run_cmd = b.addRunArtifact(exe);
// By making the run step depend on the install step, it will be run from the
// installation directory rather than directly from within the cache directory.
// This is not necessary, however, if the application depends on other installed
// files, this ensures they will be present and in the expected location.
run_cmd.step.dependOn(b.getInstallStep());
// This allows the user to pass arguments to the application in the build
// command itself, like this: `zig build run -- arg1 arg2 etc`
if (b.args) |args| {
run_cmd.addArgs(args);
}
// This creates a build step. It will be visible in the `zig build --help` menu,
// and can be selected like this: `zig build run`
// This will evaluate the `run` step rather than the default, which is "install".
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
// Creates a step for unit testing. This only builds the test executable // Creates a step for unit testing. This only builds the test executable
// but does not run it. // but does not run it.
@@ -79,18 +84,9 @@ pub fn build(b: *std.Build) void {
const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests); const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);
const exe_unit_tests = b.addTest(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
// Similar to creating the run step earlier, this exposes a `test` step to // Similar to creating the run step earlier, this exposes a `test` step to
// the `zig build --help` menu, providing a way for the user to request // the `zig build --help` menu, providing a way for the user to request
// running the unit tests. // running the unit tests.
const test_step = b.step("test", "Run unit tests"); const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_lib_unit_tests.step); test_step.dependOn(&run_lib_unit_tests.step);
test_step.dependOn(&run_exe_unit_tests.step);
} }

View File

@@ -2,7 +2,7 @@ const std = @import("std");
pub const Style = @import("Style.zig"); pub const Style = @import("Style.zig");
style: Style = .{}, style: Style = .{},
content: []u8 = undefined, content: []const u8 = undefined,
pub const Result = struct { pub const Result = struct {
idx: usize, idx: usize,

View File

@@ -91,11 +91,13 @@ pub fn Widget(comptime Event: type, comptime Renderer: type) type {
} }
// import and export of `Widget` implementations // import and export of `Widget` implementations
pub const Text = @import("widget/Text.zig").Widget(Event, Renderer);
pub const RawText = @import("widget/RawText.zig").Widget(Event, Renderer); pub const RawText = @import("widget/RawText.zig").Widget(Event, Renderer);
pub const Spacer = @import("widget/Spacer.zig").Widget(Event, Renderer); pub const Spacer = @import("widget/Spacer.zig").Widget(Event, Renderer);
}; };
// test widget implementation satisfies the interface // test widget implementation satisfies the interface
comptime Type.Interface.satisfiedBy(Type); comptime Type.Interface.satisfiedBy(Type);
comptime Type.Interface.satisfiedBy(Type.Text);
comptime Type.Interface.satisfiedBy(Type.RawText); comptime Type.Interface.satisfiedBy(Type.RawText);
comptime Type.Interface.satisfiedBy(Type.Spacer); comptime Type.Interface.satisfiedBy(Type.Spacer);
return Type; return Type;

50
src/widget/Text.zig Normal file
View File

@@ -0,0 +1,50 @@
const std = @import("std");
const terminal = @import("../terminal.zig");
const isTaggedUnion = @import("../event.zig").isTaggedUnion;
const Error = @import("../event.zig").Error;
const Cell = terminal.Cell;
const log = std.log.scoped(.widget_text);
pub fn Widget(comptime Event: type, comptime Renderer: type) type {
if (!isTaggedUnion(Event)) {
@compileError("Provided user event `Event` for `Layout(comptime Event: type)` is not of type `union(enum)`.");
}
return struct {
contents: []const Cell = undefined,
size: terminal.Size = undefined,
require_render: bool = false,
pub fn init(contents: []const Cell) @This() {
return .{
.contents = contents,
};
}
pub fn deinit(this: *@This()) void {
this.* = undefined;
}
pub fn handle(this: *@This(), event: Event) ?Event {
switch (event) {
// store the received size
.resize => |size| {
this.size = size;
this.require_render = true;
},
else => {},
}
return null;
}
pub fn render(this: *@This(), renderer: *Renderer) !void {
if (!this.require_render) {
return;
}
try renderer.clear(this.size);
try renderer.render(this.size, this.contents);
this.require_render = false;
}
};
}