╭ Settings.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 const logged_in = session.data.user_id != null; 30 31 var box = wgt.Box(ui.Widget).init(.{ .border_style = null, .rounded_corners = true, .direction = .vert }); 32 errdefer box.deinit(allocator); 33 // when logged in, the toggle posts to a page-scoped /ansi path so the 34 // server sends us back to this page's settings tab; logged out, the 35 // empty action blocks the POST and the input goes to the TUI instead. 36 box.getFocus().kind = .{ .custom = if (!logged_in) "form:" else switch (session.data.current_page) { 37 .user, .user_settings, .user_auth => |name| try std.fmt.allocPrint(session.page_arena.allocator(), "form:/user/{s}/ansi", .{name.slice()}), 38 else => "form:/ansi", 39 } }; 40 41 var button_id: usize = undefined; 42 { 43 var button = try wgt.TextBox(ui.Widget).init(allocator, labelFor(session), .{ .border_style = .single, .rounded_corners = true, .wrap_kind = .none }); 44 errdefer button.deinit(allocator); 45 button.getFocus().focusable = true; 46 // the renderer distinguishes plain clickables from buttons that 47 // should POST to a server route by this kind. 48 button.getFocus().kind = .{ .custom = "submit" }; 49 button_id = button.getFocus().id; 50 try box.children.put(allocator, button.getFocus().id, .{ 51 .widget = .{ .text_box = button }, 52 .rect = null, 53 .min_size = null, 54 }); 55 } 56 57 box.getFocus().child_id = button_id; 58 59 return .{ 60 .center = try ui.Center.init(allocator, .{ .box = box }, .both), 61 .data = data, 62 .session = session, 63 .button_id = button_id, 64 }; 65 } 66 67 pub fn deinit(self: *View, allocator: std.mem.Allocator) void { 68 self.center.deinit(allocator); 69 } 70 71 pub fn build(self: *View, allocator: std.mem.Allocator, constraint: layout.Constraint, root_focus: *Focus) !void { 72 const box = &self.center.child.box; 73 if (box.children.values().len > 0) { 74 const button = &box.children.values()[button_index].widget.text_box; 75 button.box.children.values()[0].widget.text.content = labelFor(self.session); 76 } 77 try self.center.build(allocator, constraint, root_focus); 78 } 79 80 pub fn input(self: *View, allocator: std.mem.Allocator, key: inp.Key, root_focus: *Focus) !void { 81 _ = allocator; 82 switch (key) { 83 .enter => try self.toggle(), 84 .mouse => |mouse| { 85 if (mouse.action == .press and mouse.action.press == .left) { 86 if (root_focus.children.get(self.button_id)) |entry| { 87 const r = entry.rect; 88 if (mouse.x >= r.x and mouse.y >= r.y and 89 mouse.x < r.x + r.size.width and mouse.y < r.y + r.size.height) 90 { 91 try self.toggle(); 92 } 93 } 94 } 95 }, 96 else => {}, 97 } 98 } 99 100 // enqueue the toggle; the host drains it (applying + persisting) this frame. 101 fn toggle(self: *View) !void { 102 try self.session.push(.toggle_ansi); 103 } 104 105 pub fn clearGrid(self: *View) void { 106 self.center.clearGrid(); 107 } 108 109 pub fn getGrid(self: View) ?Grid { 110 return self.center.getGrid(); 111 } 112 113 pub fn getFocus(self: *View) *Focus { 114 return self.center.getFocus(); 115 } 116 117 pub fn getSelectedIndex(self: View) ?usize { 118 _ = self; 119 return 0; 120 } 121 }; 122 123 fn labelFor(session: *const ui.Session) []const u8 { 124 return if (session.data.enable_ansi) label_on else label_off; 125 } 126