╭ changed ───────────────╮ │src/ui/widget/thread.zig│ ╰────────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────────────────────────────────────────────────────────────────────────────╮ │490 // the common sub-header used by each thread page: the search box, then the │ │491 // tab strip │ │492 pub const Header = struct { │ │493 - box: wgt.Box(Widget), │ │493 + scroll: widget.HeaderScroll, │ │494 // focus id -> semantic stack index; some pages omit unavailable tabs │ │495 tab_ids: std.AutoArrayHashMapUnmanaged(usize, usize), │ │496 // the tab whose view the stack shows. focus lands on the search box too,│ ╰──────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │501 const search_index: usize = 0; │ │502 │ │503 pub fn init(allocator: std.mem.Allocator, session: *ui.Session, search: ?[]const u8, search_label: []const u8) !Header {│ │504 - var box = try wgt.Box(Widget).init(allocator, .{ .border = null, .direction = .horiz }); │ │505 - errdefer box.deinit(allocator); │ │504 + var scroll = try widget.HeaderScroll.init(allocator, session); │ │505 + errdefer scroll.deinit(allocator); │ │506 + const box = scroll.row(); │ │507 │ │508 { │ │509 var search_box = try widget.SearchBox.init(allocator, session, search_label, "search", search); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │512 try box.children.put(allocator, search_box.getFocus().id, .{ .widget = .{ .search_box = search_box }, .rect = null, .min_size = widget.SearchBox.min_size });│ │513 } │ │514 │ │514 - return .{ .box = box, .tab_ids = .empty }; │ │515 + return .{ .scroll = scroll, .tab_ids = .empty }; │ │516 } │ │517 │ │518 pub fn addTab(self: *Header, allocator: std.mem.Allocator, label: []const u8, bottom_label: []const u8, link: []const u8, view_index: usize) !void { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────╮ │521 text_box.getFocus().mode = .all; │ │522 text_box.getFocus().kind = .{ .custom = link }; │ │523 try self.tab_ids.put(allocator, text_box.getFocus().id, view_index); │ │523 - try self.box.children.put(allocator, text_box.getFocus().id, .{ │ │524 + try self.scroll.row().children.put(allocator, text_box.getFocus().id, .{ │ │525 .widget = .{ .text_box = text_box }, │ │526 .rect = null, │ │527 .min_size = .{ .width = @max(label.len, bottom_label.len) + 2, .height = null },│ ╰─────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────╮ │538 } │ │539 │ │540 pub fn deinit(self: *Header, allocator: std.mem.Allocator) void {│ │540 - self.box.deinit(allocator); │ │541 + self.scroll.deinit(allocator); │ │542 self.tab_ids.deinit(allocator); │ │543 } │ │544 │ ╰──────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ │549 if (self.currentTabIndex()) |tab| self.selected_tab = tab; │ │550 // only the selected tab shows its border │ │551 const selected_id = if (self.selectedTab()) |tab| self.tab_ids.keys()[tab] else null;│ │551 - for (self.box.children.keys(), self.box.children.values()) |id, *child| { │ │552 + const row = self.scroll.row(); │ │553 + for (row.children.keys(), row.children.values()) |id, *child| { │ │554 switch (child.widget) { │ │555 .text_box => |*tb| widget.markSelected(tb, selected_id == id), │ │556 else => {}, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │560 // parent sets no min, which would make it lay the focused content out first. │ │561 var header_constraint = constraint; │ │562 header_constraint.min_size.height = @max(constraint.min_size.height orelse 0, 4); │ │561 - try self.box.build(allocator, header_constraint, root_focus); │ │563 + try self.scroll.build(allocator, header_constraint, root_focus); │ │564 } │ │565 │ │566 pub fn input(self: *Header, allocator: std.mem.Allocator, key: Key, root_focus: *Focus) !void {│ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────╮ │567 const search_box = self.searchBox(); │ │566 - if (self.box.getFocus().child_id == search_box.getFocus().id) { │ │568 + if (self.scroll.row().getFocus().child_id == search_box.getFocus().id) {│ │569 // tab, and right-arrow past the last character, step to the tabs │ │570 if (key == .tab or (key == .arrow_right and search_box.atEnd())) { │ │571 root_focus.setFocus(self.tab_ids.keys()[0]); │ ╰─────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────╮ │589 // caller owns the returned text. │ │590 pub fn submittedText(self: *Header, allocator: std.mem.Allocator) !?[]u8 { │ │591 const search_box = self.searchBox(); │ │590 - if (self.box.getFocus().child_id != search_box.getFocus().id) return null; │ │592 + if (self.scroll.row().getFocus().child_id != search_box.getFocus().id) return null;│ │593 return try search_box.text(allocator); │ │594 } │ │595 │ ╰────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────╮ │596 fn searchBox(self: *Header) *widget.SearchBox { │ │595 - return &self.box.children.values()[search_index].widget.search_box; │ │597 + return &self.scroll.row().children.values()[search_index].widget.search_box;│ │598 } │ │599 │ │600 pub fn clearGrid(self: *Header) void { │ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯