╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ User.zig ─────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
150 151 var self = View{ .box = box, .data = data, .session = session }; 152 self.getFocus().child_id = box.children.keys()[header_index]; 153 return self; 154 } 155 156 pub fn deinit(self: *View, allocator: std.mem.Allocator) void { 157 self.box.deinit(allocator); 158 } 159 160 pub fn build(self: *View, allocator: std.mem.Allocator, constraint: layout.Constraint, root_focus: *Focus) !void { 161 self.clearGrid(); 162 const header = &self.box.children.values()[header_index].widget.user_header; 163 const stack = &self.box.children.values()[stack_index].widget.stack; 164 165 // each header tab maps 1:1 to a stack child by position. mirror the 166 // selection into current_page so the host can push the matching url; 167 // all user tabs share the .user parent, so this stays on the page 168 // rather than navigating. 169 if (header.getSelectedIndex()) |index| { 170 stack.getFocus().child_id = stack.children.keys()[index]; 171 const name = self.data.route_name; 172 switch (index) { 173 1 => self.session.data.current_page = .{ .user_settings = name }, 174 2 => self.session.data.current_page = .{ .user_auth = name }, 175 // the quit tab is tty-only and not a route, so leave current_page 176 // alone (nothing to mirror into the url). 177 3 => {}, 178 else => self.session.data.current_page = .{ .user = name }, 179 } 180 } 181 try self.box.build(allocator, constraint, root_focus); 182 } 183 184 pub fn input(self: *View, allocator: std.mem.Allocator, key: inp.Key, root_focus: *Focus) !void { 185 if (self.getFocus().child_id) |child_id| { 186 if (self.box.children.getIndex(child_id)) |current_index| { 187 const child = &self.box.children.values()[current_index].widget; 188 var index = current_index; 189 190 const Direction = enum { up, down, none }; 191 const direction: Direction = switch (key) { 192 .arrow_up => .up, 193 .arrow_down => .down, 194 .mouse => |mouse| if (mouse.action == .scroll) 195 (if (mouse.action.scroll == .up) .up else .down) 196 else 197 .none, 198 else => .none, 199 }; 200 201 switch (direction) { 202 .up => { 203 switch (child.*) { 204 .user_header => { 205 try child.input(allocator, key, root_focus); 206 }, 207 .stack => { 208 if (child.stack.getSelected()) |selected_widget| { 209 const at_top = switch (selected_widget.*) { 210 .flow_box_scroll => |*v| v.getSelectedIndex() == 0, 211 .home_settings => |*v| v.getSelectedIndex() == 0, 212 .home_auth => |*v| v.getSelectedIndex() == 0, 213 .quit => |*v| v.getSelectedIndex() == 0, 214 else => false, 215 }; 216 if (at_top) { 217 index = header_index; 218 } else { 219 try child.input(allocator, key, root_focus); 220 } 221 } 222 }, 223 else => {}, 224 } 225 }, 226 .down => { 227 switch (child.*) { 228 .user_header => { 229 index = stack_index; 230 }, 231 .stack => { 232 try child.input(allocator, key, root_focus); 233 }, 234 else => {}, 235 } 236 }, 237 .none => { 238 try child.input(allocator, key, root_focus); 239 }, 240 } 241 242 if (index != current_index) { 243 try root_focus.setFocus(self.box.children.keys()[index]); 244 } 245 } 246 } 247 } 248 249 pub fn clearGrid(self: *View) void { 250 self.box.clearGrid(); 251 } 252 253 pub fn getGrid(self: View) ?Grid { 254 return self.box.getGrid(); 255 } 256 257 pub fn getFocus(self: *View) *Focus { 258 return self.box.getFocus(); 259 } 260 }; 261