╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ───────────╮ │src/ui/Repo/Refs.zig│ ╰────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │180 try header.children.put(allocator, spacer.getFocus().id, .{ .widget = .{ .spacer = spacer }, .rect = null, .min_size = null }); │ │181 } │ │182 // a row taller than the box, leaving a blank line above the columns │ │182 - try outer.children.put(allocator, header.getFocus().id, .{ .widget = .{ .box = header }, .rect = null, .min_size = .{ .width = null, .height = 4 } }); │ │183 + try outer.children.put(allocator, header_scroll.getFocus().id, .{ .widget = .{ .header_scroll = header_scroll }, .rect = null, .min_size = .{ .width = null, .height = 4 } });│ │184 } │ │185 │ │186 // with both columns empty, the empty message stands in for them │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │359 } │ │360 │ │361 fn searchBox(self: *View) *ui.widget.SearchBox { │ │361 - return &self.box.children.values()[header_index].widget.box.children.values()[0].widget.search_box; │ │362 + return &self.box.children.values()[header_index].widget.header_scroll.row().children.values()[0].widget.search_box;│ │363 } │ │364 │ │365 fn headerActive(self: *View) bool { │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ───────────────╮ │src/ui/Repo/Settings.zig│ ╰────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │74 errdefer box.deinit(allocator); │ │75 │ │76 { │ │77 - var header = try wgt.Box(ui.Widget).init(allocator, .{ .border = null, .direction = .horiz });│ │78 - errdefer header.deinit(allocator); │ │77 + var header_scroll = try ui.widget.HeaderScroll.init(allocator, session); │ │78 + errdefer header_scroll.deinit(allocator); │ │79 + const header = header_scroll.row(); │ │80 const on_tab = switch (session.data.current_page) { │ │81 .repo_settings, .repo_members, .repo_branches => true, │ │82 else => false, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │91 } │ │92 header.getFocus().child_id = header.children.keys()[@backingInt(data.view)]; │ │93 // a row taller than the header, leaving a blank line beneath it │ │93 - try box.children.put(allocator, header.getFocus().id, .{ .widget = .{ .box = header }, .rect = null, .min_size = .{ .width = null, .height = 4 } }); │ │94 + try box.children.put(allocator, header_scroll.getFocus().id, .{ .widget = .{ .header_scroll = header_scroll }, .rect = null, .min_size = .{ .width = null, .height = 4 } });│ │95 } │ │96 │ │97 { │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────╮ │124 } │ │125 │ │126 fn headerBox(self: *View) *wgt.Box(ui.Widget) { │ │126 - return &self.box.children.values()[header_index].widget.box; │ │127 + return self.box.children.values()[header_index].widget.header_scroll.row();│ │128 } │ │129 │ │130 fn contentStack(self: *View) *wgt.Stack(ui.Widget) { │ ╰────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │132 } │ │133 │ │134 fn headerActive(self: *View) bool { │ │134 - return self.box.getFocus().child_id == self.headerBox().getFocus().id; │ │135 + return self.box.getFocus().child_id == self.box.children.keys()[header_index]; │ │136 } │ │137 │ │138 pub fn build(self: *View, allocator: std.mem.Allocator, constraint: layout.Constraint, root_focus: *Focus) !void {│ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ───────────╮ │src/ui/Repo/Undo.zig│ ╰────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │395 │ │396 // the sub header carries the tab's only action │ │397 { │ │398 - var header = try wgt.Box(ui.Widget).init(allocator, .{ .border = null, .direction = .horiz }); │ │399 - errdefer header.deinit(allocator); │ │398 + var header_scroll = try ui.widget.HeaderScroll.init(allocator, session); │ │399 + errdefer header_scroll.deinit(allocator); │ │400 + const header = header_scroll.row(); │ │401 const route = ui.RoutablePage.repoUndoClearRoute(data.identity) orelse return error.RouteTooLong; │ │402 const link = try session.page_arena.allocator().print("a:{s}", .{try route.toUrl(session.page_arena)}); │ │402 - try addText(allocator, &header, "clear undo history", link, .single); │ │403 + const clear_label = "clear undo history"; │ │404 + try addText(allocator, header, clear_label, link, .single); │ │405 + // one line wide, so a narrow window scrolls the row instead of wrapping it │ │406 + header.children.values()[0].min_size = .{ .width = clear_label.len + 2, .height = null }; │ │407 header.getFocus().child_id = header.children.keys()[0]; │ │408 // a row taller than the header, leaving a blank line beneath it │ │405 - try outer.children.put(allocator, header.getFocus().id, .{ .widget = .{ .box = header }, .rect = null, .min_size = .{ .width = null, .height = 4 } }); │ │409 + try outer.children.put(allocator, header_scroll.getFocus().id, .{ .widget = .{ .header_scroll = header_scroll }, .rect = null, .min_size = .{ .width = null, .height = 4 } });│ │410 } │ │411 │ │412 // the clear form, or the empty message when there is no history or failure to show │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────╮ │513 } │ │514 │ │515 fn headerBox(self: *View) *wgt.Box(ui.Widget) { │ │512 - return &self.box.children.values()[header_index].widget.box; │ │516 + return self.box.children.values()[header_index].widget.header_scroll.row(); │ │517 } │ │518 fn headerActive(self: *View) bool { │ │515 - return self.box.getFocus().child_id == self.headerBox().getFocus().id; │ │519 + return self.box.getFocus().child_id == self.box.children.keys()[header_index];│ │520 } │ │521 fn contentBox(self: *View) *wgt.Box(ui.Widget) { │ │522 return &self.box.children.values()[content_index].widget.box; │ ╰───────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────╮ │src/ui/User.zig│ ╰───────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │387 errdefer box.deinit(allocator); │ │388 │ │389 { │ │390 - var header = try wgt.Box(ui.Widget).init(allocator, .{ .border = null, .direction = .horiz }); │ │391 - errdefer header.deinit(allocator); │ │390 + var header_scroll = try ui.widget.HeaderScroll.init(allocator, session); │ │391 + errdefer header_scroll.deinit(allocator); │ │392 + const header = header_scroll.row(); │ │393 { │ │394 var search_box = try ui.widget.SearchBox.init(allocator, session, " search ", "search", data.repos_search);│ │395 errdefer search_box.deinit(allocator); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │402 errdefer spacer.deinit(allocator); │ │403 try header.children.put(allocator, spacer.getFocus().id, .{ .widget = .{ .spacer = spacer }, .rect = null, .min_size = null }); │ │404 } │ │404 - try box.children.put(allocator, header.getFocus().id, .{ .widget = .{ .box = header }, .rect = null, .min_size = .{ .width = null, .height = ui.widget.SearchBox.min_size.height } }); │ │405 + try box.children.put(allocator, header_scroll.getFocus().id, .{ .widget = .{ .header_scroll = header_scroll }, .rect = null, .min_size = .{ .width = null, .height = ui.widget.SearchBox.min_size.height } });│ │406 } │ │407 │ │408 // an empty first window has no rows, not even paging ones │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯