╭ CloneUrl.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 Key = xitui.input.Key; 8 const Grid = xitui.grid.Grid; 9 const Focus = xitui.focus.Focus; 10 const inp = @import("input.zig"); 11 12 pub const View = struct { 13 box: wgt.Box(ui.Widget), 14 session: *ui.Session, 15 urls: [2][]const u8, 16 selected: usize = 0, 17 18 const http_index: usize = 0; 19 const ssh_index: usize = 1; 20 const input_index: usize = 2; 21 22 pub fn init(allocator: std.mem.Allocator, session: *ui.Session, identity: []const u8) !View { 23 const http_port = session.data.clone_http_port orelse return error.MissingClonePort; 24 const ssh_port = session.data.clone_ssh_port orelse return error.MissingClonePort; 25 const aa = session.page_arena.allocator(); 26 const urls = [2][]const u8{ 27 try std.fmt.allocPrint(aa, "http://localhost:{d}/repo/{s}", .{ http_port, identity }), 28 try std.fmt.allocPrint(aa, "ssh://localhost:{d}/repo/{s}", .{ ssh_port, identity }), 29 }; 30 31 var box = try wgt.Box(ui.Widget).init(allocator, .{ .border_style = null, .direction = .horiz }); 32 errdefer box.deinit(allocator); 33 box.getFocus().kind = .{ .custom = "form:" }; 34 35 inline for ([_][]const u8{ "http", "ssh" }) |protocol| { 36 var label = try wgt.TextBox(ui.Widget).init(allocator, protocol, .{ .border_style = .hidden, .wrap_kind = .none }); 37 errdefer label.deinit(allocator); 38 label.getFocus().focusable = true; 39 try box.children.put(allocator, label.getFocus().id, .{ .widget = .{ .text_box = label }, .rect = null, .min_size = .{ .width = protocol.len + 2, .height = 3 } }); 40 } 41 42 var url_input = try wgt.TextInput(ui.Widget).init(allocator, .{ 43 .border_style = .single, 44 .label = " clone ", 45 .render_content = session.is_terminal, 46 .visible_width = @max(urls[0].len, urls[1].len), 47 }); 48 errdefer url_input.deinit(allocator); 49 url_input.getFocus().focusable = true; 50 try url_input.setContent(allocator, urls[0]); 51 box.getFocus().child_id = url_input.getFocus().id; 52 try box.children.put(allocator, url_input.getFocus().id, .{ .widget = .{ .text_input = url_input }, .rect = null, .min_size = .{ .width = @max(urls[0].len, urls[1].len) + 2, .height = 3 } }); 53 54 return .{ .box = box, .session = session, .urls = urls }; 55 } 56 57 pub fn minWidth(self: *const View) usize { 58 return "http".len + "ssh".len + 4 + @max(self.urls[0].len, self.urls[1].len) + 2; 59 } 60 61 pub fn deinit(self: *View, allocator: std.mem.Allocator) void { 62 self.box.deinit(allocator); 63 } 64 65 pub fn build(self: *View, allocator: std.mem.Allocator, constraint: layout.Constraint, root_focus: *Focus) !void { 66 self.clearGrid(); 67 68 if (root_focus.grandchild_id) |id| { 69 const clicked = if (id == self.protocolLabel(http_index).getFocus().id) 70 http_index 71 else if (id == self.protocolLabel(ssh_index).getFocus().id) 72 ssh_index 73 else 74 null; 75 if (clicked) |selected| { 76 if (selected != self.selected) { 77 self.selected = selected; 78 try self.urlInput().setContent(allocator, self.urls[selected]); 79 } 80 root_focus.setFocus(self.urlInput().getFocus().id); 81 } 82 } 83 84 const focused = root_focus.grandchild_id == self.urlInput().getFocus().id; 85 for (0..2) |i| { 86 self.protocolLabel(i).options.border_style = if (i == self.selected) 87 (if (focused) .double else .single) 88 else 89 .hidden; 90 } 91 self.urlInput().options.border_style = .single; 92 self.urlInput().cursor = 0; 93 self.urlInput().scroll_offset = 0; 94 try self.box.build(allocator, constraint, root_focus); 95 96 if (!self.session.is_terminal) { 97 const aa = self.session.arena.allocator(); 98 const id = self.urlInput().getFocus().id; 99 try self.session.text_inputs.put(aa, id, self.urlInput()); 100 try self.session.input_values.put(aa, id, self.urls[self.selected]); 101 } 102 } 103 104 pub fn input(self: *View, allocator: std.mem.Allocator, key: Key, root_focus: *Focus) !void { 105 const next = switch (key) { 106 .arrow_left => if (self.selected == ssh_index) http_index else return, 107 .arrow_right => if (self.selected == http_index) ssh_index else return, 108 .enter => { 109 if (self.session.is_terminal) self.session.host_request = .{ .clone_url = self.urls[self.selected] }; 110 return; 111 }, 112 .mouse => |mouse| if (inp.leftClickOn(root_focus, self.protocolLabel(http_index).getFocus().id, mouse)) 113 http_index 114 else if (inp.leftClickOn(root_focus, self.protocolLabel(ssh_index).getFocus().id, mouse)) 115 ssh_index 116 else if (inp.leftClickOn(root_focus, self.urlInput().getFocus().id, mouse)) { 117 if (self.session.is_terminal) self.session.host_request = .{ .clone_url = self.urls[self.selected] }; 118 return; 119 } else return, 120 else => return, 121 }; 122 self.selected = next; 123 try self.urlInput().setContent(allocator, self.urls[next]); 124 } 125 126 fn urlInput(self: *View) *wgt.TextInput(ui.Widget) { 127 return &self.box.children.values()[input_index].widget.text_input; 128 } 129 130 fn protocolLabel(self: *View, index: usize) *wgt.TextBox(ui.Widget) { 131 return &self.box.children.values()[index].widget.text_box; 132 } 133 134 pub fn clearGrid(self: *View) void { 135 self.box.clearGrid(); 136 } 137 138 pub fn getGrid(self: View) ?Grid { 139 return self.box.getGrid(); 140 } 141 142 pub fn getFocus(self: *View) *Focus { 143 return self.box.getFocus(); 144 } 145 }; 146