Files
zterm/examples/container.zig
Yves Biener 09a659ba70 ref(event): split resize event into viewport and size event
Viewport event reflects the absolut position and size of a given
container (and propagates them to its children). While the size
event propagates the content size to its children (and sets their
corresponding member values accordingly).

Both events are currently only emitted by `Container`s meaning that they
don't need to be part of the event loop and that they might be removed
later.
2025-02-15 09:55:30 +01:00

104 lines
3.3 KiB
Zig

const std = @import("std");
const zterm = @import("zterm");
const App = zterm.App(union(enum) {});
const Key = zterm.Key;
const log = std.log.scoped(.example);
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(.{}){};
defer {
const deinit_status = gpa.deinit();
if (deinit_status == .leak) {
log.err("memory lead", .{});
}
}
const allocator = gpa.allocator();
var app: App = .{};
var renderer = zterm.Renderer.Buffered.init(allocator);
defer renderer.deinit();
var container = try App.Container.init(allocator, .{
.border = .{
.color = .blue,
.corners = .rounded,
.sides = .all(),
.separator = .{ .enabled = false },
},
.layout = .{
.padding = .all(5),
.direction = .horizontal,
},
});
var box = try App.Container.init(allocator, .{
.rectangle = .{ .fill = .blue },
.layout = .{
.gap = 1,
.direction = .vertical,
.padding = .vertical(1),
},
});
try box.append(try App.Container.init(allocator, .{
.rectangle = .{ .fill = .light_green },
}));
try box.append(try App.Container.init(allocator, .{
.rectangle = .{ .fill = .light_green },
}));
try box.append(try App.Container.init(allocator, .{
.rectangle = .{ .fill = .light_green },
}));
try container.append(box);
try container.append(try App.Container.init(allocator, .{
.border = .{ .color = .light_blue, .corners = .squared },
}));
try container.append(try App.Container.init(allocator, .{
.rectangle = .{ .fill = .blue },
}));
defer container.deinit();
// NOTE: should the min-size here be required?
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 => {
try container.handle(event);
continue; // do not render
},
.quit => break,
.resize => |size| try renderer.resize(size),
.key => |key| {
if (key.matches(.{ .cp = 'q' })) app.quit();
if (key.matches(.{ .cp = 'n', .mod = .{ .ctrl = true } })) {
try app.interrupt();
defer app.start() catch @panic("could not start app event loop");
var child = std.process.Child.init(&.{"hx"}, allocator);
_ = child.spawnAndWait() catch |err| app.postEvent(.{
.err = .{
.err = err,
.msg = "Spawning $EDITOR failed",
},
});
}
},
.err => |err| log.err("Received {any} with message: {s}", .{ @errorName(err.err), err.msg }),
else => {},
}
try container.handle(event);
try renderer.render(@TypeOf(container), &container);
try renderer.flush();
}
}