All checks were successful
Zig Project Action / Lint, Spell-check and test zig project (push) Successful in 23s
Added corresponding test cases to test the corresponding rendering of scrollable elements.
148 lines
4.6 KiB
Zig
148 lines
4.6 KiB
Zig
const std = @import("std");
|
|
const zterm = @import("zterm");
|
|
|
|
const input = zterm.input;
|
|
const App = zterm.App(union(enum) {});
|
|
|
|
const log = std.log.scoped(.default);
|
|
|
|
pub const HelloWorldText = packed struct {
|
|
const text = "Hello World";
|
|
|
|
pub fn element(this: *@This()) App.Element {
|
|
return .{
|
|
.ptr = this,
|
|
.vtable = &.{ .content = content },
|
|
};
|
|
}
|
|
|
|
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));
|
|
|
|
// NOTE: error should only be returned here in case an in-recoverable exception has occurred
|
|
const row = size.rows / 2;
|
|
const col = size.cols / 2 -| (text.len / 2);
|
|
const anchor = (row * size.cols) + col;
|
|
|
|
for (0.., text) |idx, char| {
|
|
cells[anchor + idx].style.fg = .black;
|
|
cells[anchor + idx].cp = char;
|
|
}
|
|
}
|
|
};
|
|
|
|
pub fn main() !void {
|
|
errdefer |err| log.err("Application Error: {any}", .{err});
|
|
|
|
// TODO: maybe create own allocator as some sort of arena allocator to have consistent memory usage
|
|
var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
|
|
defer {
|
|
const deinit_status = gpa.deinit();
|
|
if (deinit_status == .leak) {
|
|
log.err("memory leak", .{});
|
|
}
|
|
}
|
|
const allocator = gpa.allocator();
|
|
|
|
var app: App = .init;
|
|
var renderer = zterm.Renderer.Buffered.init(allocator);
|
|
defer renderer.deinit();
|
|
|
|
var element_wrapper: HelloWorldText = .{};
|
|
const element = element_wrapper.element();
|
|
|
|
var top_box = try App.Container.init(allocator, .{
|
|
.rectangle = .{ .fill = .blue },
|
|
.layout = .{
|
|
.gap = 1,
|
|
.direction = .vertical,
|
|
.padding = .vertical(1),
|
|
},
|
|
.min_size = .{ .rows = 50 },
|
|
}, .{});
|
|
try top_box.append(try App.Container.init(allocator, .{
|
|
.rectangle = .{ .fill = .light_green },
|
|
}, .{}));
|
|
try top_box.append(try App.Container.init(allocator, .{
|
|
.rectangle = .{ .fill = .light_green },
|
|
}, element));
|
|
try top_box.append(try App.Container.init(allocator, .{
|
|
.rectangle = .{ .fill = .light_green },
|
|
}, .{}));
|
|
defer top_box.deinit();
|
|
|
|
var bottom_box = try App.Container.init(allocator, .{
|
|
.border = .{
|
|
.sides = .all,
|
|
.color = .blue,
|
|
},
|
|
.layout = .{
|
|
.separator = .{
|
|
.enabled = true,
|
|
.color = .red,
|
|
},
|
|
.direction = .vertical,
|
|
.padding = .vertical(1),
|
|
},
|
|
.min_size = .{ .rows = 30 },
|
|
}, .{});
|
|
try bottom_box.append(try App.Container.init(allocator, .{
|
|
.rectangle = .{ .fill = .grey },
|
|
}, .{}));
|
|
try bottom_box.append(try App.Container.init(allocator, .{
|
|
.rectangle = .{ .fill = .grey },
|
|
}, element));
|
|
try bottom_box.append(try App.Container.init(allocator, .{
|
|
.rectangle = .{ .fill = .grey },
|
|
}, .{}));
|
|
defer bottom_box.deinit();
|
|
|
|
var container = try App.Container.init(allocator, .{
|
|
.layout = .{
|
|
.gap = 2,
|
|
.separator = .{
|
|
.enabled = true,
|
|
.line = .double,
|
|
},
|
|
.padding = .all(5),
|
|
.direction = .vertical,
|
|
},
|
|
}, .{});
|
|
defer container.deinit();
|
|
|
|
// place empty container containing the element of the scrollable Container.
|
|
var scrollable_top: App.Scrollable = .init(top_box);
|
|
try container.append(try App.Container.init(allocator, .{}, scrollable_top.element()));
|
|
|
|
var scrollable_bottom: App.Scrollable = .init(bottom_box);
|
|
try container.append(try App.Container.init(allocator, .{}, scrollable_bottom.element()));
|
|
|
|
try app.start();
|
|
defer app.stop() catch |err| log.err("Failed to stop application: {any}", .{err});
|
|
|
|
// event loop
|
|
while (true) {
|
|
const event = app.nextEvent();
|
|
log.debug("received event: {s}", .{@tagName(event)});
|
|
|
|
switch (event) {
|
|
.init => continue,
|
|
.quit => break,
|
|
.resize => |size| try renderer.resize(size),
|
|
.key => |key| if (key.eql(.{ .cp = 'c', .mod = .{ .ctrl = true } })) app.quit(),
|
|
.err => |err| log.err("Received {s} with message: {s}", .{ @errorName(err.err), err.msg }),
|
|
else => {},
|
|
}
|
|
|
|
container.handle(event) catch |err| app.postEvent(.{
|
|
.err = .{
|
|
.err = err,
|
|
.msg = "Container Event handling failed",
|
|
},
|
|
});
|
|
try renderer.render(@TypeOf(container), &container);
|
|
try renderer.flush();
|
|
}
|
|
}
|