╭ Home.zig ─────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
1 const std = @import("std"); 2 const ui = @import("../ui.zig"); 3 const xit = @import("xit"); 4 const rp = xit.repo; 5 const xitui = xit.xitui; 6 const wgt = xitui.widget; 7 const layout = xitui.layout; 8 const inp = xitui.input; 9 const Grid = xitui.grid.Grid; 10 const Focus = xitui.focus.Focus; 11 12 pub const Users = @import("./Home/Users.zig"); 13 pub const Repos = @import("./Home/Repos.zig"); 14 pub const Header = @import("./Home/Header.zig"); 15 pub const Ansi = @import("./Home/Ansi.zig"); 16 pub const Auth = @import("./Home/Auth.zig"); 17 18 header: Header, 19 users: Users, 20 repos: Repos, 21 ansi: Ansi, 22 auth: Auth, 23 24 const Self = @This(); 25 26 pub fn init( 27 comptime repo_opts: rp.RepoOpts(.xit), 28 arena: *std.heap.ArenaAllocator, 29 haxy_moment: rp.Repo(.xit, repo_opts).DB.HashMap(.read_only), 30 ) !Self { 31 return .{ 32 .header = try Header.init(arena), 33 .users = try Users.init(repo_opts, arena, haxy_moment), 34 .repos = try Repos.init(repo_opts, arena, haxy_moment), 35 .ansi = Ansi.init(), 36 .auth = Auth.init(), 37 }; 38 } 39 40 pub const View = struct { 41 box: wgt.Box(ui.Widget), 42 data: *const Self, 43 session: *ui.Session, 44 45 const header_index: usize = 0; 46 const stack_index: usize = 1; 47 48 pub fn init(allocator: std.mem.Allocator, data: *const Self, session: *ui.Session) !View { 49 var box = wgt.Box(ui.Widget).init(.{ .border_style = null, .rounded_corners = true, .direction = .vert }); 50 errdefer box.deinit(allocator); 51 52 // build the header first so we can grab the users-tab focus id and 53 // hand it to login/logout 54 var users_tab_id: usize = undefined; 55 { 56 var header_view = try Header.View.init(allocator, &data.header, session); 57 errdefer header_view.deinit(allocator); 58 users_tab_id = header_view.tab_ids[0]; 59 try box.children.put(allocator, header_view.getFocus().id, .{ .widget = .{ .home_header = header_view }, .rect = null, .min_size = null }); 60 } 61 62 { 63 var stack = wgt.Stack(ui.Widget).init(); 64 errdefer stack.deinit(allocator); 65 66 { 67 var users_view = try Users.View.init(allocator, &data.users); 68 errdefer users_view.deinit(allocator); 69 try stack.children.put(allocator, users_view.getFocus().id, .{ .home_users = users_view }); 70 } 71 72 { 73 var repos_view = try Repos.View.init(allocator, &data.repos); 74 errdefer repos_view.deinit(allocator); 75 try stack.children.put(allocator, repos_view.getFocus().id, .{ .home_repos = repos_view }); 76 } 77 78 { 79 var ansi_view = try Ansi.View.init(allocator, &data.ansi, session); 80 errdefer ansi_view.deinit(allocator); 81 try stack.children.put(allocator, ansi_view.getFocus().id, .{ .home_ansi = ansi_view }); 82 } 83 84 { 85 var auth_view = try Auth.View.init(allocator, &data.auth, session, users_tab_id); 86 errdefer auth_view.deinit(allocator); 87 try stack.children.put(allocator, auth_view.getFocus().id, .{ .home_auth = auth_view }); 88 } 89 90 try box.children.put(allocator, stack.getFocus().id, .{ .widget = .{ .stack = stack }, .rect = null, .min_size = null }); 91 } 92 93 var self = View{ 94 .box = box, 95 .data = data, 96 .session = session, 97 }; 98 self.getFocus().child_id = box.children.keys()[header_index]; 99 return self; 100 } 101 102 pub fn deinit(self: *View, allocator: std.mem.Allocator) void { 103 self.box.deinit(allocator); 104 } 105 106 pub fn build(self: *View, allocator: std.mem.Allocator, constraint: layout.Constraint, root_focus: *Focus) !void { 107 self.clearGrid(); 108 const header = &self.box.children.values()[header_index].widget.home_header; 109 const stack = &self.box.children.values()[stack_index].widget.stack; 110 111 // each header tab maps 1:1 to a stack child by position 112 if (header.getSelectedIndex()) |index| { 113 stack.getFocus().child_id = stack.children.keys()[index]; 114 self.session.data.current_page = switch (index) { 115 0 => .home_users, 116 1 => .home_repos, 117 2 => .home_ansi, 118 3 => .home_auth, 119 else => .home_users, 120 }; 121 } 122 try self.box.build(allocator, constraint, root_focus); 123 } 124 125 pub fn input(self: *View, allocator: std.mem.Allocator, key: inp.Key, root_focus: *Focus) !void { 126 if (self.getFocus().child_id) |child_id| { 127 if (self.box.children.getIndex(child_id)) |current_index| { 128 const child = &self.box.children.values()[current_index].widget; 129 var index = current_index; 130 131 const Direction = enum { up, down, none }; 132 const direction: Direction = switch (key) { 133 .arrow_up => .up, 134 .arrow_down => .down, 135 .mouse => |mouse| if (mouse.action == .scroll) 136 (if (mouse.action.scroll == .up) .up else .down) 137 else 138 .none, 139 else => .none, 140 }; 141 142 switch (direction) { 143 .up => { 144 switch (child.*) { 145 .home_header => { 146 try child.input(allocator, key, root_focus); 147 }, 148 .stack => { 149 if (child.stack.getSelected()) |selected_widget| { 150 const at_top = switch (selected_widget.*) { 151 .home_users => |*v| v.getSelectedIndex() == 0, 152 .home_repos => |*v| v.getSelectedIndex() == 0, 153 .home_ansi => |*v| v.getSelectedIndex() == 0, 154 .home_auth => |*v| v.getSelectedIndex() == 0, 155 else => false, 156 }; 157 if (at_top) { 158 index = header_index; 159 } else { 160 try child.input(allocator, key, root_focus); 161 } 162 } 163 }, 164 else => {}, 165 } 166 }, 167 .down => { 168 switch (child.*) { 169 .home_header => { 170 index = stack_index; 171 }, 172 .stack => { 173 try child.input(allocator, key, root_focus); 174 }, 175 else => {}, 176 } 177 }, 178 .none => { 179 try child.input(allocator, key, root_focus); 180 }, 181 } 182 183 if (index != current_index) { 184 try root_focus.setFocus(self.box.children.keys()[index]); 185 } 186 } 187 } 188 } 189 190 pub fn clearGrid(self: *View) void { 191 self.box.clearGrid(); 192 } 193 194 pub fn getGrid(self: View) ?Grid { 195 return self.box.getGrid(); 196 } 197 198 pub fn getFocus(self: *View) *Focus { 199 return self.box.getFocus(); 200 } 201 }; 202