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:
@@ -11,6 +11,9 @@ pub fn main() !void {
|
|||||||
defer renderer.deinit();
|
defer renderer.deinit();
|
||||||
|
|
||||||
var container: App.Container = try .init(gpa, .{
|
var container: App.Container = try .init(gpa, .{
|
||||||
|
.border = .{
|
||||||
|
.sides = .all,
|
||||||
|
},
|
||||||
.layout = .{
|
.layout = .{
|
||||||
.direction = .horizontal,
|
.direction = .horizontal,
|
||||||
.separator = .{ .enabled = true },
|
.separator = .{ .enabled = true },
|
||||||
@@ -30,10 +33,58 @@ pub fn main() !void {
|
|||||||
.rectangle = .{ .fill = .green },
|
.rectangle = .{ .fill = .green },
|
||||||
}, .{}));
|
}, .{}));
|
||||||
|
|
||||||
container.resize(&app.model, try renderer.resize());
|
try app.start(); // needs to become configurable, as what should be enabled / disabled (i.e. show cursor, hide cursor, use alternate screen, etc.)
|
||||||
container.reposition(&app.model, .{});
|
defer app.stop() catch |err| log.err("Failed to stop application: {any}", .{err});
|
||||||
try renderer.render(@TypeOf(container), &container, App.Model, &app.model);
|
|
||||||
try renderer.flush();
|
// 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;
|
pub const panic = App.panic_handler;
|
||||||
|
|||||||
20
src/app.zig
20
src/app.zig
@@ -71,21 +71,21 @@ pub fn App(comptime M: type, comptime E: type) type {
|
|||||||
this.quit_event.reset();
|
this.quit_event.reset();
|
||||||
this.thread = try Thread.spawn(.{}, @This().run, .{this});
|
this.thread = try Thread.spawn(.{}, @This().run, .{this});
|
||||||
|
|
||||||
var termios: posix.termios = undefined;
|
//var termios: posix.termios = undefined;
|
||||||
try terminal.enableRawMode(&termios);
|
//try terminal.enableRawMode(&termios);
|
||||||
if (this.termios) |_| {} else this.termios = termios;
|
//if (this.termios) |_| {} else this.termios = termios;
|
||||||
|
|
||||||
try terminal.enterAltScreen();
|
//try terminal.enterAltScreen();
|
||||||
try terminal.saveScreen();
|
//try terminal.saveScreen();
|
||||||
try terminal.hideCursor();
|
//try terminal.hideCursor();
|
||||||
try terminal.enableMouseSupport();
|
//try terminal.enableMouseSupport();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interrupt(this: *@This()) !void {
|
pub fn interrupt(this: *@This()) !void {
|
||||||
this.quit_event.set();
|
this.quit_event.set();
|
||||||
try terminal.disableMouseSupport();
|
//try terminal.disableMouseSupport();
|
||||||
try terminal.restoreScreen();
|
//try terminal.restoreScreen();
|
||||||
try terminal.exitAltScreen();
|
//try terminal.exitAltScreen();
|
||||||
if (this.thread) |*thread| {
|
if (this.thread) |*thread| {
|
||||||
thread.join();
|
thread.join();
|
||||||
this.thread = null;
|
this.thread = null;
|
||||||
|
|||||||
Reference in New Issue
Block a user