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.
104 lines
3.3 KiB
Zig
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();
|
|
}
|
|
}
|