This branch will implement the necessary changes for the widgets and their implementations to use the new renderer correctly.
140 lines
4.1 KiB
Zig
140 lines
4.1 KiB
Zig
const std = @import("std");
|
|
const zterm = @import("zterm");
|
|
|
|
const App = zterm.App(
|
|
union(enum) {
|
|
view: union(enum) {
|
|
tui, // view instance to the corresponding view for 'tui'
|
|
},
|
|
},
|
|
zterm.Renderer.Buffered,
|
|
true,
|
|
);
|
|
const Cell = zterm.Cell;
|
|
const Key = zterm.Key;
|
|
const Layout = App.Layout;
|
|
const Widget = App.Widget;
|
|
const View = App.View;
|
|
|
|
const Tui = struct {
|
|
const Events = std.ArrayList(App.Event);
|
|
allocator: std.mem.Allocator,
|
|
layout: Layout,
|
|
|
|
pub fn init(allocator: std.mem.Allocator) *Tui {
|
|
var tui = allocator.create(Tui) catch @panic("Out of memory: tui.zig");
|
|
tui.allocator = allocator;
|
|
tui.layout = Layout.createFrom(Layout.VStack.init(allocator, .{
|
|
Layout.createFrom(Layout.HStack.init(allocator, .{
|
|
Widget.createFrom(Widget.Text.init(allocator, .left, &[1]Cell{
|
|
.{ .rune = 'Y', .style = .{ .fg = .{ .index = 6 }, .bold = true } },
|
|
})),
|
|
Widget.createFrom(Widget.Text.init(allocator, .left, &[1]Cell{
|
|
.{ .rune = 'F', .style = .{ .fg = .{ .index = 6 }, .bold = true } },
|
|
})),
|
|
Widget.createFrom(Widget.Text.init(allocator, .left, &[1]Cell{
|
|
.{ .rune = 'C', .style = .{ .fg = .{ .index = 6 }, .bold = true } },
|
|
})),
|
|
})),
|
|
// .{
|
|
// Layout.createFrom(Layout.Margin.init(allocator, .{ .left = 15, .right = 15 }, .{
|
|
// .widget = Widget.createFrom(Widget.Text.init(allocator, .default, &[1]Cell{
|
|
// .{ .rune = 'D', .style = .{ .ul = .default, .ul_style = .single } },
|
|
// })),
|
|
// })),
|
|
// 90,
|
|
// },
|
|
}));
|
|
return tui;
|
|
}
|
|
|
|
pub fn deinit(this: *Tui) void {
|
|
this.layout.deinit();
|
|
this.allocator.destroy(this);
|
|
}
|
|
|
|
pub fn enable(this: *Tui) void {
|
|
_ = this;
|
|
}
|
|
|
|
pub fn disable(this: *Tui) void {
|
|
_ = this;
|
|
}
|
|
|
|
pub fn handle(this: *Tui, event: App.Event) !*Events {
|
|
return try this.layout.handle(event);
|
|
}
|
|
|
|
pub fn render(this: *Tui, renderer: *App.Renderer) !void {
|
|
try this.layout.render(renderer);
|
|
}
|
|
};
|
|
|
|
// TODO: create additional example with a bit more complex functionality for
|
|
// dynamic layouts, switching views, etc.
|
|
|
|
const log = std.log.scoped(.tui);
|
|
|
|
pub fn main() !void {
|
|
errdefer |err| log.err("Application Error: {any}", .{err});
|
|
|
|
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
|
defer arena.deinit();
|
|
|
|
const allocator = arena.allocator();
|
|
|
|
var app: App = .{};
|
|
var renderer = App.Renderer.init(allocator);
|
|
defer renderer.deinit();
|
|
|
|
var view: View = undefined;
|
|
|
|
var tui_view = View.createFrom(Tui.init(allocator));
|
|
defer tui_view.deinit();
|
|
|
|
view = tui_view;
|
|
try app.start(null);
|
|
defer app.stop() catch unreachable;
|
|
|
|
// App.Event loop
|
|
while (true) {
|
|
const event = app.nextEvent();
|
|
|
|
switch (event) {
|
|
.quit => break,
|
|
.resize => |size| {
|
|
renderer.resize(size);
|
|
},
|
|
.key => |key| {
|
|
// ctrl+c to quit
|
|
if (Key.matches(key, .{ .cp = 'c', .mod = .{ .ctrl = true } })) {
|
|
app.quit();
|
|
}
|
|
},
|
|
.err => |err| {
|
|
log.err("Received {any} with message: {s}", .{ err.err, err.msg });
|
|
},
|
|
.view => |v| {
|
|
switch (v) {
|
|
.tui => {
|
|
view = tui_view;
|
|
// NOTE: report potentially new screen size
|
|
const events = try view.handle(.{ .resize = renderer.size });
|
|
for (events.items) |e| {
|
|
app.postEvent(e);
|
|
}
|
|
},
|
|
}
|
|
},
|
|
else => {},
|
|
}
|
|
|
|
const events = try view.handle(event);
|
|
for (events.items) |e| {
|
|
app.postEvent(e);
|
|
}
|
|
try view.render(&renderer);
|
|
try renderer.flush();
|
|
}
|
|
}
|