╭ changed ─╮ │src/ui.zig│ ╰──────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────────────────────────────────╮ │1427 tag_flow: TagFlow, │ │1428 spacer: Spacer, │ │1429 center: Center, │ │1430 + section_label: SectionLabel,│ │1431 + submit_button: SubmitButton,│ │1432 background: AnsiBackground, │ │1433 home: Home.View, │ │1434 user: User.View, │ ╰──────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2075 │ │2076 // a single-child wrapper that builds the child at its natural size and │ │2077 // positions its grid in the middle of the area granted by the parent │ │2078 +// a bordered label, indented past the content it precedes │ │2079 +pub const SectionLabel = struct { │ │2080 + box: wgt.Box(Widget), │ │2081 + │ │2082 + pub fn init(allocator: std.mem.Allocator, content: []const u8) !SectionLabel { │ │2083 + var box = try wgt.Box(Widget).init(allocator, .{ .border_style = null, .direction = .horiz }); │ │2084 + errdefer box.deinit(allocator); │ │2085 + │ │2086 + { │ │2087 + var gap = try wgt.Text(Widget).init(allocator, " "); │ │2088 + errdefer gap.deinit(allocator); │ │2089 + try box.children.put(allocator, gap.getFocus().id, .{ .widget = .{ .text = gap }, .rect = null, .min_size = null }); │ │2090 + } │ │2091 + │ │2092 + { │ │2093 + var tb = try wgt.TextBox(Widget).init(allocator, content, .{ .border_style = .single, .rounded_corners = true, .wrap_kind = .none }); │ │2094 + errdefer tb.deinit(allocator); │ │2095 + tb.getFocus().focusable = true; │ │2096 + try box.children.put(allocator, tb.getFocus().id, .{ .widget = .{ .text_box = tb }, .rect = null, .min_size = null }); │ │2097 + } │ │2098 + │ │2099 + box.getFocus().child_id = box.children.keys()[1]; │ │2100 + return .{ .box = box }; │ │2101 + } │ │2102 + │ │2103 + pub fn deinit(self: *SectionLabel, allocator: std.mem.Allocator) void { │ │2104 + self.box.deinit(allocator); │ │2105 + } │ │2106 + │ │2107 + pub fn build(self: *SectionLabel, allocator: std.mem.Allocator, constraint: layout.Constraint, root_focus: *Focus) !void { │ │2108 + try self.box.build(allocator, constraint, root_focus); │ │2109 + } │ │2110 + │ │2111 + pub fn input(self: *SectionLabel, allocator: std.mem.Allocator, key: Key, root_focus: *Focus) !void { │ │2112 + _ = self; │ │2113 + _ = allocator; │ │2114 + _ = key; │ │2115 + _ = root_focus; │ │2116 + } │ │2117 + │ │2118 + pub fn clearGrid(self: *SectionLabel) void { │ │2119 + self.box.clearGrid(); │ │2120 + } │ │2121 + │ │2122 + pub fn getGrid(self: SectionLabel) ?Grid { │ │2123 + return self.box.getGrid(); │ │2124 + } │ │2125 + │ │2126 + pub fn getFocus(self: *SectionLabel) *Focus { │ │2127 + return self.box.getFocus(); │ │2128 + } │ │2129 +}; │ │2130 + │ │2131 +// a submit button, indented past its form's content. the web overlay POSTs │ │2132 +// the button's form; terminal hosts detect presses through `buttonId`. │ │2133 +pub const SubmitButton = struct { │ │2134 + box: wgt.Box(Widget), │ │2135 + │ │2136 + pub fn init(allocator: std.mem.Allocator) !SubmitButton { │ │2137 + var box = try wgt.Box(Widget).init(allocator, .{ .border_style = null, .direction = .horiz }); │ │2138 + errdefer box.deinit(allocator); │ │2139 + │ │2140 + { │ │2141 + var gap = try wgt.Text(Widget).init(allocator, " "); │ │2142 + errdefer gap.deinit(allocator); │ │2143 + try box.children.put(allocator, gap.getFocus().id, .{ .widget = .{ .text = gap }, .rect = null, .min_size = null }); │ │2144 + } │ │2145 + │ │2146 + { │ │2147 + const label = "submit"; │ │2148 + var button = try wgt.TextBox(Widget).init(allocator, label, .{ .border_style = .single, .rounded_corners = true, .wrap_kind = .none }); │ │2149 + errdefer button.deinit(allocator); │ │2150 + button.getFocus().focusable = true; │ │2151 + // the renderer distinguishes plain clickables from buttons that │ │2152 + // should POST to a server route by this kind. │ │2153 + button.getFocus().kind = .{ .custom = "submit" }; │ │2154 + try box.children.put(allocator, button.getFocus().id, .{ .widget = .{ .text_box = button }, .rect = null, .min_size = .{ .width = label.len + 2, .height = null } });│ │2155 + } │ │2156 + │ │2157 + box.getFocus().child_id = box.children.keys()[1]; │ │2158 + return .{ .box = box }; │ │2159 + } │ │2160 + │ │2161 + pub fn deinit(self: *SubmitButton, allocator: std.mem.Allocator) void { │ │2162 + self.box.deinit(allocator); │ │2163 + } │ │2164 + │ │2165 + pub fn build(self: *SubmitButton, allocator: std.mem.Allocator, constraint: layout.Constraint, root_focus: *Focus) !void { │ │2166 + try self.box.build(allocator, constraint, root_focus); │ │2167 + } │ │2168 + │ │2169 + pub fn input(self: *SubmitButton, allocator: std.mem.Allocator, key: Key, root_focus: *Focus) !void { │ │2170 + _ = self; │ │2171 + _ = allocator; │ │2172 + _ = key; │ │2173 + _ = root_focus; │ │2174 + } │ │2175 + │ │2176 + pub fn clearGrid(self: *SubmitButton) void { │ │2177 + self.box.clearGrid(); │ │2178 + } │ │2179 + │ │2180 + pub fn getGrid(self: SubmitButton) ?Grid { │ │2181 + return self.box.getGrid(); │ │2182 + } │ │2183 + │ │2184 + pub fn getFocus(self: *SubmitButton) *Focus { │ │2185 + return self.box.getFocus(); │ │2186 + } │ │2187 + │ │2188 + // the button's focus id, for click hit-testing │ │2189 + pub fn buttonId(self: *const SubmitButton) usize { │ │2190 + return self.box.children.keys()[1]; │ │2191 + } │ │2192 +}; │ │2193 + │ │2194 pub const Center = struct { │ │2195 focus: *Focus, │ │2196 grid: ?Grid, │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯