From c29c60bd898a7d17360919c28ac9932038fe7b6a Mon Sep 17 00:00:00 2001 From: Yves Biener Date: Tue, 20 Jan 2026 11:54:28 +0100 Subject: [PATCH] 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). --- examples/direct.zig | 59 ++++++++++++++++++++++++++++++++++++++++++--- src/app.zig | 20 +++++++-------- 2 files changed, 65 insertions(+), 14 deletions(-) diff --git a/examples/direct.zig b/examples/direct.zig index 329aa5b..817a2e4 100644 --- a/examples/direct.zig +++ b/examples/direct.zig @@ -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; diff --git a/src/app.zig b/src/app.zig index 92e9eae..d79db80 100644 --- a/src/app.zig +++ b/src/app.zig @@ -71,21 +71,21 @@ pub fn App(comptime M: type, comptime E: type) type { this.quit_event.reset(); this.thread = try Thread.spawn(.{}, @This().run, .{this}); - var termios: posix.termios = undefined; - try terminal.enableRawMode(&termios); - if (this.termios) |_| {} else this.termios = termios; + //var termios: posix.termios = undefined; + //try terminal.enableRawMode(&termios); + //if (this.termios) |_| {} else this.termios = termios; - try terminal.enterAltScreen(); - try terminal.saveScreen(); - try terminal.hideCursor(); - try terminal.enableMouseSupport(); + //try terminal.enterAltScreen(); + //try terminal.saveScreen(); + //try terminal.hideCursor(); + //try terminal.enableMouseSupport(); } pub fn interrupt(this: *@This()) !void { this.quit_event.set(); - try terminal.disableMouseSupport(); - try terminal.restoreScreen(); - try terminal.exitAltScreen(); + //try terminal.disableMouseSupport(); + //try terminal.restoreScreen(); + //try terminal.exitAltScreen(); if (this.thread) |*thread| { thread.join(); this.thread = null;