╭ changed ─╮ │src/ui.zig│ ╰──────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 7 const inp = xitui.input; │ │ 8 const Grid = xitui.grid.Grid; │ │ 9 const Focus = xitui.focus.Focus; │ │10 + │ │11 +pub fn run(io: std.Io, allocator: std.mem.Allocator) !void { │ │12 + var root = try initRoot(allocator); │ │13 + defer root.deinit(); │ │14 │ │11 -const html_width = 80; │ │12 -const html_height = 24; │ │15 + var terminal = try term.Terminal.init(io, allocator); │ │16 + defer terminal.deinit(io); │ │17 + │ │18 + var last_size = layout.Size{ .width = 0, .height = 0 }; │ │19 + var last_grid = try Grid.init(allocator, last_size); │ │20 + defer last_grid.deinit(); │ │21 + │ │22 + while (!term.quit.load(.monotonic)) { │ │23 + const grid_changed = try terminal.render(&root, &last_grid, &last_size); │ │24 + │ │25 + // process any inputs. │ │26 + // │ │27 + // if the grid didn't change, then first do a blocking │ │28 + // read, so the thread will sleep until further input. │ │29 + // after that, all remaining reads are non-blocking so │ │30 + // we can process the rest of the queued inputs. │ │31 + // │ │32 + // if the grid *did* change, then only do non-blocking │ │33 + // reads. we do not want to sleep the thread because │ │34 + // there may be an animation that requires more looping. │ │35 + var blocking = !grid_changed; │ │36 + while (try terminal.readKey(io, blocking)) |key| { │ │37 + switch (key) { │ │38 + .codepoint => |cp| if (cp == 'q') return else try root.input(key, root.getFocus()),│ │39 + else => try root.input(key, root.getFocus()), │ │40 + } │ │41 + blocking = false; │ │42 + } │ │43 + │ │44 + try root.build(.{ │ │45 + .min_size = .{ .width = null, .height = null }, │ │46 + .max_size = .{ .width = last_size.width, .height = last_size.height }, │ │47 + }, root.getFocus()); │ │48 + } │ │49 +} │ │50 │ │51 pub fn initRoot(allocator: std.mem.Allocator) !Widget { │ │52 var root = Widget{ .widget_list = try WidgetList.init(allocator) }; │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────╮ │53 errdefer root.deinit(); │ │54 │ │18 - try buildRoot(&root, html_width, html_height); │ │55 + try root.build(.{ │ │56 + .min_size = .{ .width = null, .height = null },│ │57 + .max_size = .{ .width = 80, .height = 24 }, │ │58 + }, root.getFocus()); │ │59 if (root.getFocus().child_id) |child_id| { │ │60 try root.getFocus().setFocus(child_id); │ │61 } │ ╰───────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────╮ │63 return root; │ │64 } │ │65 │ │26 -pub fn buildRoot(root: *Widget, width: usize, height: usize) !void { │ │27 - try root.build(.{ │ │28 - .min_size = .{ .width = null, .height = null }, │ │29 - .max_size = .{ .width = width, .height = height }, │ │30 - }, root.getFocus()); │ │31 -} │ │32 - │ │66 pub fn generateHtml(allocator: std.mem.Allocator, root: *Widget) ![]const u8 {│ │67 const grid = root.getGrid() orelse return error.MissingGrid; │ │68 │ ╰──────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │78 } │ │79 │ │80 return try out.toOwnedSlice(allocator); │ │48 -} │ │49 - │ │50 -pub fn run(io: std.Io, allocator: std.mem.Allocator) !void { │ │51 - var root = try initRoot(allocator); │ │52 - defer root.deinit(); │ │53 - │ │54 - var terminal = try term.Terminal.init(io, allocator); │ │55 - defer terminal.deinit(io); │ │56 - │ │57 - var last_size = layout.Size{ .width = 0, .height = 0 }; │ │58 - var last_grid = try Grid.init(allocator, last_size); │ │59 - defer last_grid.deinit(); │ │60 - │ │61 - while (!term.quit) { │ │62 - try terminal.render(&root, &last_grid, &last_size); │ │63 - │ │64 - while (try terminal.readKey(io)) |key| { │ │65 - switch (key) { │ │66 - .codepoint => |cp| if (cp == 'q') { │ │67 - term.quit = true; │ │68 - return; │ │69 - }, │ │70 - else => {}, │ │71 - } │ │72 - try root.input(key, root.getFocus()); │ │73 - } │ │74 - │ │75 - try buildRoot(&root, last_size.width, last_size.height); │ │76 - │ │77 - try std.Io.sleep(io, .fromMilliseconds(5), .real); │ │78 - } │ │81 } │ │82 │ │83 fn appendEscapedHtml(allocator: std.mem.Allocator, out: *std.ArrayList(u8), input: []const u8) !void {│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯