╭ changed ─────────────╮ │src/ui/Repo/Events.zig│ ╰──────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │421 errdefer list_scroll.deinit(allocator); │ │422 try content_box.children.put(allocator, list_scroll.getFocus().id, .{ .widget = .{ .scroll = list_scroll }, .rect = null, .min_size = .{ .width = list_max_width, .height = null }, .max_size = .{ .width = list_max_width, .height = null } });│ │423 │ │424 - var detail_box = try wgt.Box(ui.Widget).init(allocator, .{ .border = null, .direction = .vert }); │ │425 - errdefer detail_box.deinit(allocator); │ │426 - var detail_scroll = try wgt.Scroll(ui.Widget).init(allocator, .{ .box = detail_box }, .{ .direction = .vert, .web_native = !session.is_terminal, .fill = true }); │ │427 - errdefer detail_scroll.deinit(allocator); │ │428 - detail_scroll.getFocus().mode = .mouse; │ │429 - try content_box.children.put(allocator, detail_scroll.getFocus().id, .{ .widget = .{ .scroll = detail_scroll }, .rect = null, .min_size = .{ .width = detail_min_width, .height = null } }); │ │424 + // the detail scroll, below the way back to a hidden list │ │425 + var frame = try wgt.Box(ui.Widget).init(allocator, .{ .border = null, .direction = .vert }); │ │426 + errdefer frame.deinit(allocator); │ │427 + try ui.widget.addListBack(allocator, &frame, "← back to event list"); │ │428 + { │ │429 + var detail_box = try wgt.Box(ui.Widget).init(allocator, .{ .border = null, .direction = .vert }); │ │430 + errdefer detail_box.deinit(allocator); │ │431 + var detail_scroll = try wgt.Scroll(ui.Widget).init(allocator, .{ .box = detail_box }, .{ .direction = .vert, .web_native = !session.is_terminal, .fill = true }); │ │432 + errdefer detail_scroll.deinit(allocator); │ │433 + detail_scroll.getFocus().mode = .mouse; │ │434 + frame.getFocus().child_id = detail_scroll.getFocus().id; │ │435 + try frame.children.put(allocator, detail_scroll.getFocus().id, .{ .widget = .{ .scroll = detail_scroll }, .rect = null, .min_size = null }); │ │436 + } │ │437 + try content_box.children.put(allocator, frame.getFocus().id, .{ .widget = .{ .box = frame }, .rect = null, .min_size = .{ .width = detail_min_width, .height = null } }); │ │438 │ │439 content_box.getFocus().child_id = content_box.children.keys()[if (event_window.events.len > 0) detail_index else list_index]; │ │440 return content_box; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────╮ │481 │ │482 fn listBox(self: *View) *wgt.Box(ui.Widget) { │ │483 return &self.listScroll().child.box; │ │484 + } │ │485 + │ │486 + fn detailFrame(self: *View) *wgt.Box(ui.Widget) { │ │487 + return &self.content().children.values()[detail_index].widget.box;│ │488 } │ │489 │ │490 fn detailScroll(self: *View) *wgt.Scroll(ui.Widget) { │ ╰───────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────╮ │479 - return &self.content().children.values()[detail_index].widget.scroll; │ │491 + return &self.detailFrame().children.values()[ui.widget.list_pane_index].widget.scroll;│ │492 } │ │493 │ │494 fn detailBox(self: *View) *wgt.Box(ui.Widget) { │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────╮ │496 } │ │497 │ │498 fn detailActive(self: *View) bool { │ │487 - return self.content().getFocus().child_id == self.detailScroll().getFocus().id;│ │499 + return self.content().getFocus().child_id == self.detailFrame().getFocus().id; │ │500 } │ │501 │ │502 fn headerActive(self: *View) bool { │ ╰────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │522 }; │ │523 │ │524 const both_fit = if (constraint.max_size.width) |width| width >= list_max_width + detail_min_width else true; │ │525 + ui.widget.showListBack(self.detailFrame(), !both_fit); │ │526 self.content().children.values()[list_index].max_size = if (both_fit) .{ .width = list_max_width, .height = null } else null; │ │527 const detail_width = if (constraint.max_size.width) |width| if (both_fit) width - list_max_width else width else detail_min_width;│ │528 self.content().children.values()[detail_index].min_size = .{ .width = detail_width, .height = null }; │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │564 self.detailScroll().x = 0; │ │565 self.detailScroll().y = 0; │ │566 self.detailScroll().getFocus().version +%= 1; │ │567 + ui.widget.setListBackLink(self.detailFrame(), self.listBox().children.values()[index].widget.text_box.getFocus().kind.custom);│ │568 detailed_index.* = index; │ │569 } │ │570 │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │575 if (direction == .down) root_focus.setFocus(self.content().getFocus().id) else try self.header().input(allocator, key, root_focus);│ │576 return; │ │577 } │ │578 + // the way back to the list, by enter or a click │ │579 + if (self.detailActive()) if (ui.widget.listBackId(self.detailFrame())) |id| { │ │580 + if (inp.activated(root_focus, id, key)) return self.focusList(root_focus); │ │581 + if (root_focus.grandchild_id == id) return switch (direction) { │ │582 + .up => self.header().focusCurrent(root_focus), │ │583 + .down => root_focus.setFocus(self.detailScroll().getFocus().id), │ │584 + .none => if (key == .arrow_left) self.focusList(root_focus), │ │585 + }; │ │586 + if (direction == .up and self.contentAtTop()) return root_focus.setFocus(id); │ │587 + }; │ │588 if (direction == .up and self.contentAtTop()) { │ │589 self.header().focusCurrent(root_focus); │ │590 return; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │591 } │ │592 if (self.detailActive()) { │ │593 if (key == .arrow_left) { │ │570 - root_focus.setFocus(self.listScroll().getFocus().id); │ │594 + self.focusList(root_focus); │ │595 } else if (inp.rowDelta(key, @intCast(self.detailBox().children.count()))) |delta| { │ │596 ui.widget.moveRowFocus(self.detailBox(), self.detailScroll(), root_focus, delta);│ │597 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │598 } else if (inp.rowDelta(key, @intCast(self.listBox().children.count()))) |delta| { │ │599 ui.widget.moveRowFocus(self.listBox(), self.listScroll(), root_focus, delta); │ │600 } else switch (key) { │ │577 - .arrow_right => if (self.detailBox().children.count() > 0) root_focus.setFocus(self.detailScroll().getFocus().id),│ │578 - .enter => if (self.selectedEventIndex() != null) root_focus.setFocus(self.detailScroll().getFocus().id), │ │601 + .arrow_right => if (self.detailBox().children.count() > 0) self.focusDetail(root_focus), │ │602 + .enter => if (self.selectedEventIndex() != null) self.focusDetail(root_focus), │ │603 else => {}, │ │604 } │ │605 + } │ │606 + │ │607 + // enter the detail pane, landing on the way back to the list when it shows │ │608 + fn focusDetail(self: *View, root_focus: *Focus) void { │ │609 + if (ui.widget.listBackId(self.detailFrame()) != null) return ui.widget.focusListBack(self.detailFrame(), root_focus); │ │610 + root_focus.setFocus(self.detailScroll().getFocus().id); │ │611 } │ │612 │ │613 + fn focusList(self: *View, root_focus: *Focus) void { │ │614 + root_focus.setFocus(self.listScroll().getFocus().id); │ │615 + } │ │616 + │ │617 fn contentAtTop(self: *View) bool { │ │618 const box = if (self.detailActive()) self.detailBox() else self.listBox(); │ │619 const scroll = if (self.detailActive()) self.detailScroll() else self.listScroll(); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ───────────╮ │src/ui/Repo/Undo.zig│ ╰────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │431 errdefer scroll.deinit(allocator); │ │432 try box.children.put(allocator, scroll.getFocus().id, .{ .widget = .{ .scroll = scroll }, .rect = null, .min_size = .{ .width = list_max_width, .height = null }, .max_size = .{ .width = list_max_width, .height = null } });│ │433 } │ │434 + // the detail scroll, below the way back to a hidden list │ │435 { │ │436 + var frame = try wgt.Box(ui.Widget).init(allocator, .{ .border = null, .direction = .vert }); │ │437 + errdefer frame.deinit(allocator); │ │438 + try ui.widget.addListBack(allocator, &frame, "← back to undo list"); │ │439 var scroll = blk: { │ │440 var details = try wgt.Box(ui.Widget).init(allocator, .{ .border = null, .direction = .vert }); │ │441 errdefer details.deinit(allocator); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯