╭ Ansi.zig ─────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
1 const std = @import("std"); 2 const ui = @import("../../ui.zig"); 3 const xit = @import("xit"); 4 const xitui = xit.xitui; 5 const wgt = xitui.widget; 6 const layout = xitui.layout; 7 const inp = xitui.input; 8 const Grid = xitui.grid.Grid; 9 const Focus = xitui.focus.Focus; 10 11 const Self = @This(); 12 13 const label_on = "turn off ANSI art"; 14 const label_off = "turn on ANSI art"; 15 16 pub fn init() Self { 17 return .{}; 18 } 19 20 pub const View = struct { 21 center: ui.Center, 22 data: *const Self, 23 session: *ui.Session, 24 button_id: usize, 25 26 const button_index: usize = 0; 27 28 pub fn init(allocator: std.mem.Allocator, data: *const Self, session: *ui.Session) !View { 29 // only logged-in users get a real HTML form to POST to the server 30 const logged_in = session.data.user_id != null; 31 32 var box = wgt.Box(ui.Widget).init(.{ .border_style = null, .rounded_corners = true, .direction = .vert }); 33 errdefer box.deinit(allocator); 34 // marks this subtree as an HTML form scope for the web overlay 35 if (logged_in) box.getFocus().kind = .{ .custom = "form:/ansi" }; 36 37 var button_id: usize = undefined; 38 { 39 var button = try wgt.TextBox(ui.Widget).init(allocator, labelFor(session), .{ .border_style = .single, .rounded_corners = true, .wrap_kind = .none }); 40 errdefer button.deinit(allocator); 41 button.getFocus().focusable = true; 42 // the renderer distinguishes plain clickables from buttons that 43 // should POST to a server route by this kind. 44 if (logged_in) button.getFocus().kind = .{ .custom = "submit" }; 45 button_id = button.getFocus().id; 46 try box.children.put(allocator, button.getFocus().id, .{ 47 .widget = .{ .text_box = button }, 48 .rect = null, 49 .min_size = null, 50 }); 51 } 52 53 box.getFocus().child_id = button_id; 54 55 return .{ 56 .center = try ui.Center.init(allocator, .{ .box = box }, .both), 57 .data = data, 58 .session = session, 59 .button_id = button_id, 60 }; 61 } 62 63 pub fn deinit(self: *View, allocator: std.mem.Allocator) void { 64 self.center.deinit(allocator); 65 } 66 67 pub fn build(self: *View, allocator: std.mem.Allocator, constraint: layout.Constraint, root_focus: *Focus) !void { 68 const box = &self.center.child.box; 69 if (box.children.values().len > 0) { 70 const button = &box.children.values()[button_index].widget.text_box; 71 button.box.children.values()[0].widget.text.content = labelFor(self.session); 72 } 73 try self.center.build(allocator, constraint, root_focus); 74 } 75 76 pub fn input(self: *View, allocator: std.mem.Allocator, key: inp.Key, root_focus: *Focus) !void { 77 _ = allocator; 78 switch (key) { 79 .enter => self.toggle(), 80 .mouse => |mouse| { 81 if (mouse.action == .press and mouse.action.press == .left) { 82 if (root_focus.children.get(self.button_id)) |entry| { 83 const r = entry.rect; 84 if (mouse.x >= r.x and mouse.y >= r.y and 85 mouse.x < r.x + r.size.width and mouse.y < r.y + r.size.height) 86 { 87 self.toggle(); 88 } 89 } 90 } 91 }, 92 else => {}, 93 } 94 } 95 96 fn toggle(self: *View) void { 97 self.session.data.enable_ansi = !self.session.data.enable_ansi; 98 } 99 100 pub fn clearGrid(self: *View) void { 101 self.center.clearGrid(); 102 } 103 104 pub fn getGrid(self: View) ?Grid { 105 return self.center.getGrid(); 106 } 107 108 pub fn getFocus(self: *View) *Focus { 109 return self.center.getFocus(); 110 } 111 112 pub fn getSelectedIndex(self: View) ?usize { 113 _ = self; 114 return 0; 115 } 116 }; 117 118 fn labelFor(session: *const ui.Session) []const u8 { 119 return if (session.data.enable_ansi) label_on else label_off; 120 } 121