WIP make example interactive

Handle inputs as per usual (which however is a bit weak, is it goes through
key by key and not the entire line), batch all events such that all events
are handled before the next frame is rendered. For this the `App.start`
function needs to become configurable, such that it changes the termios as
configured (hence it is currently all commented out for testing).
This commit is contained in:
2026-01-20 11:54:28 +01:00
parent 4a3bec3edc
commit c29c60bd89
2 changed files with 65 additions and 14 deletions

View File

@@ -11,6 +11,9 @@ pub fn main() !void {
defer renderer.deinit();
var container: App.Container = try .init(gpa, .{
.border = .{
.sides = .all,
},
.layout = .{
.direction = .horizontal,
.separator = .{ .enabled = true },
@@ -30,10 +33,58 @@ pub fn main() !void {
.rectangle = .{ .fill = .green },
}, .{}));
container.resize(&app.model, try renderer.resize());
container.reposition(&app.model, .{});
try renderer.render(@TypeOf(container), &container, App.Model, &app.model);
try renderer.flush();
try app.start(); // needs to become configurable, as what should be enabled / disabled (i.e. show cursor, hide cursor, use alternate screen, etc.)
defer app.stop() catch |err| log.err("Failed to stop application: {any}", .{err});
// event loop
event: while (true) {
// batch events since last iteration
const len = blk: {
app.queue.poll();
app.queue.lock();
defer app.queue.unlock();
break :blk app.queue.len();
};
// handle events
for (0..len) |_| {
const event = app.queue.pop();
//log.debug("received event: {s}", .{@tagName(event)});
// pre event handling
switch (event) {
// NOTE maybe I want to decouple the `key`s from the user input too? i.e. this only makes sense if the output is not echoed!
// otherwise just use gnu's `readline`?
.key => |key| {
if (key.eql(.{ .cp = 'c', .mod = .{ .ctrl = true } })) app.quit();
},
// NOTE errors could be displayed in another container in case one was received, etc. to provide the user with feedback
.err => |err| log.err("Received {s} with message: {s}", .{ @errorName(err.err), err.msg }),
else => {},
}
// NOTE returned errors should be propagated back to the application
container.handle(&app.model, event) catch |err| app.postEvent(.{
.err = .{
.err = err,
.msg = "Container Event handling failed",
},
});
// post event handling
switch (event) {
.quit => break :event,
else => {},
}
}
// if there are more events to process continue handling them otherwise I can render the next frame
if (app.queue.len() > 0) continue :event;
container.resize(&app.model, try renderer.resize());
container.reposition(&app.model, .{});
try renderer.render(@TypeOf(container), &container, App.Model, &app.model);
try renderer.flush();
}
}
pub const panic = App.panic_handler;