╭ AuthTab.zig ──────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
1 const std = @import("std"); 2 const evt = @import("../event.zig"); 3 const ui = @import("../ui.zig"); 4 const xit = @import("xit"); 5 const xitui = xit.xitui; 6 const wgt = xitui.widget; 7 const layout = xitui.layout; 8 const Key = xitui.input.Key; 9 const Grid = xitui.grid.Grid; 10 const Focus = xitui.focus.Focus; 11 12 const Self = @This(); 13 14 pub fn init() Self { 15 return .{}; 16 } 17 18 pub const View = struct { 19 text_box: wgt.TextBox(ui.Widget), 20 session: *ui.Session, 21 // backs the tab's text, which borrows it. sized for the longest name, so 22 // build never allocates. 23 text_buf: [logout_prefix.len + evt.User.name_max_len]u8, 24 25 const logout_prefix = "logout "; 26 27 pub fn init(allocator: std.mem.Allocator, session: *ui.Session) !View { 28 var text_box = try wgt.TextBox(ui.Widget).init(allocator, "login", .{ .border_style = .single, .rounded_corners = true, .wrap_kind = .none }); 29 errdefer text_box.deinit(allocator); 30 text_box.getFocus().focusable = true; 31 text_box.getFocus().kind = .{ .custom = "ai:/auth" }; 32 return .{ 33 .text_box = text_box, 34 .session = session, 35 .text_buf = undefined, 36 }; 37 } 38 39 pub fn deinit(self: *View, allocator: std.mem.Allocator) void { 40 self.text_box.deinit(allocator); 41 } 42 43 // the action the tab performs, naming whoever is logged in 44 fn text(self: *View) []const u8 { 45 if (self.session.data.user_id == null) return "login"; 46 const name = self.session.data.user_name orelse return "logout"; 47 // validateName caps the name, so the buffer always fits it 48 return std.fmt.bufPrint(&self.text_buf, logout_prefix ++ "{s}", .{name}) catch unreachable; 49 } 50 51 // what the tab's text needs, plus its border 52 pub fn minWidth(self: *View) usize { 53 return self.text().len + 2; 54 } 55 56 pub fn build(self: *View, allocator: std.mem.Allocator, constraint: layout.Constraint, root_focus: *Focus) !void { 57 // update the displayed text based on session state. the inner Text 58 // widget's content is just a slice, so we can repoint it without 59 // re-allocating. 60 if (self.text_box.box.children.values().len > 0) { 61 const text_widget = &self.text_box.box.children.values()[0].widget.text; 62 text_widget.content = self.text(); 63 } 64 try self.text_box.build(allocator, constraint, root_focus); 65 } 66 67 pub fn input(self: *View, allocator: std.mem.Allocator, key: Key, root_focus: *Focus) !void { 68 try self.text_box.input(allocator, key, root_focus); 69 } 70 71 pub fn clearGrid(self: *View) void { 72 self.text_box.clearGrid(); 73 } 74 75 pub fn getGrid(self: View) ?Grid { 76 return self.text_box.getGrid(); 77 } 78 79 pub fn getFocus(self: *View) *Focus { 80 return self.text_box.getFocus(); 81 } 82 }; 83