╭ changed ────╮ │build.zig.zon│ ╰─────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 3 .version = "0.0.0", │ │ 4 .dependencies = .{ │ │ 5 .xit = .{ │ │ 6 - .url = "git+https://github.com/xit-vcs/xit#39499e85a5c7da041ea461709ac711660b4cc09d",│ │ 7 - .hash = "xit-0.0.0-Ub3nDBZNHQAHbw9yZ4Hfg-1nsbOSKVAhLs2C4XhkFeqx", │ │ 6 + .url = "git+https://github.com/xit-vcs/xit#5d96c0d1215a56caf01e5e5c4a9aed6a3f157d56",│ │ 7 + .hash = "xit-0.0.0-Ub3nDPpIHQCPjOX_0kf3poH95XwG_FanenCbOX2I45Pg", │ │ 8 }, │ │ 9 }, │ │10 .paths = .{ │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ────────╮ │src/main_wasm.zig│ ╰─────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │169 const root_focus = root_ptr.getFocus(); │ │170 if (ui.inPageLink(root_focus, focus_id, session.data) != null) { │ │171 const rect = (root_focus.children.get(focus_id) orelse return).rect; │ │172 - try root_ptr.input(allocator, .{ .mouse = .{ .x = @intCast(rect.x), .y = @intCast(rect.y), .action = .{ .press = .left } } }, root_focus);│ │172 + try root_ptr.input(allocator, .{ .mouse = .{ .x = @intCast(rect.x), .y = @intCast(rect.y), .button = .left } }, root_focus); │ │173 } │ │174 } │ │175 │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─╮ │src/ui.zig│ ╰──────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2669 try root.input(allocator, key, root_focus); │ │2670 }, │ │2671 .mouse => |mouse| { │ │2672 - if (mouse.action == .press and mouse.action.press == .left) { │ │2672 + if (mouse.button == .left) { │ │2673 if (cellPageLink(root, mouse.x, mouse.y, session.data)) |route| return session.navigate(route);│ │2674 if (root_focus.hitTest(mouse.x, mouse.y)) |hit| { │ │2675 const focus_id = hit.id; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │2704 .event => |event| switch (event) { │ │2705 .background => |rgb| session.terminal_background = rgb, │ │2706 .resize => try root.input(allocator, key, root_focus), │ │2707 + }, │ │2708 + // a scroll tick goes to the pane under the pointer, focusing it first │ │2709 + .scroll_up, .scroll_down => |position| { │ │2710 + if (scrollUnder(root_focus, position)) |scroll_id| { │ │2711 + if (!focusInside(root_focus, scroll_id)) root_focus.setFocus(scroll_id);│ │2712 + } │ │2713 + try root.input(allocator, key, root_focus); │ │2714 }, │ │2715 else => try root.input(allocator, key, root_focus), │ │2716 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2721 if (inPageLink(root_focus, focus_id, session.data)) |route| session.data.current_page = route; │ │2722 } │ │2723 │ │2724 +// the innermost vertically scrolling widget laid out under `position` │ │2725 +fn scrollUnder(root_focus: *const Focus, position: xitui.input.Position) ?usize { │ │2726 + var found: ?usize = null; │ │2727 + var found_area: usize = std.math.maxInt(usize); │ │2728 + var iter = root_focus.children.iterator(); │ │2729 + while (iter.next()) |entry| { │ │2730 + const info = entry.value_ptr.focus.scroll orelse continue; │ │2731 + if (info.direction == .horiz) continue; │ │2732 + const r = entry.value_ptr.rect; │ │2733 + if (position.x < r.x or position.y < r.y or position.x >= r.x + r.size.width or position.y >= r.y + r.size.height) continue;│ │2734 + // a nested scroll lies within its parent, so the smallest is innermost │ │2735 + const area = r.size.width * r.size.height; │ │2736 + if (area < found_area) { │ │2737 + found = entry.key_ptr.*; │ │2738 + found_area = area; │ │2739 + } │ │2740 + } │ │2741 + return found; │ │2742 +} │ │2743 + │ │2744 +// whether the focused widget is `id` or lies under it │ │2745 +fn focusInside(root_focus: *const Focus, id: usize) bool { │ │2746 + var current = root_focus.grandchild_id orelse return false; │ │2747 + while (true) { │ │2748 + if (current == id) return true; │ │2749 + const child = root_focus.children.get(current) orelse return false; │ │2750 + current = child.parent_id; │ │2751 + } │ │2752 +} │ │2753 + │ │2754 // a link to bytes the server serves directly rather than to a page route, so │ │2755 // it never resolves to a RoutablePage │ │2756 pub const raw_link_prefix = "ax:"; │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ────────────╮ │src/ui/Home/About.zig│ ╰─────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │75 .page_down => sc.y += 10, │ │76 .home => sc.y = 0, │ │77 .end => sc.y = std.math.maxInt(isize), │ │78 - .mouse => |mouse| switch (mouse.action) { │ │79 - .scroll => |dir| sc.y += if (dir == .up) -5 else 5, │ │80 - else => {}, │ │81 - }, │ │78 + .scroll_up => sc.y -= 5, │ │79 + .scroll_down => sc.y += 5, │ │80 .tab, .back_tab => try self.markdownView().stepLink(allocator, root_focus, sc, 0, 0, key == .tab),│ │81 else => {}, │ │82 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────────────╮ │src/ui/Repo/Commits.zig│ ╰───────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │439 try box.children.put(allocator, detail_outer.getFocus().id, .{ .widget = .{ .box = detail_outer }, .rect = null, .min_size = .{ .width = detail_min_width, .height = null } });│ │440 } │ │441 │ │442 - box.getFocus().child_id = box.children.keys()[if (data.commits.len > 0) detail_index else list_index]; │ │442 + // the page opens on the list, unless the url names a commit │ │443 + box.getFocus().child_id = box.children.keys()[if (data.ref_or_oid == .object) detail_index else list_index]; │ │444 try outer.children.put(allocator, box.getFocus().id, .{ .widget = .{ .box = box }, .rect = null, .min_size = null }); │ │445 │ │446 // focus lives in the split, except that search results start in the │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ────────────╮ │src/ui/Repo/Files.zig│ ╰─────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────╮ │845 // terminal scrolls by offset (the wheel five rows at a time) and reaching│ │846 // the top then pressing up crosses back up to the link; on the web │ │847 // vertical scrolling is the browser's job so up just crosses to the link.│ │848 - const step: isize = if (key == .mouse) 5 else 1; │ │848 + const step: isize = switch (key) { │ │849 + .scroll_up, .scroll_down => 5, │ │850 + else => 1, │ │851 + }; │ │852 switch (inp.vertDirection(key)) { │ │853 .up => { │ │854 if (!on_content) return; │ ╰───────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ───────╮ │src/ui/input.zig│ ╰────────────────╯ ╭────────────────────────────────────────────────────────────────╮ │ 9 │ │10 pub fn vertDirection(key: Key) Direction { │ │11 return switch (key) { │ │12 - .arrow_up => .up, │ │13 - .arrow_down => .down, │ │14 - .mouse => |mouse| if (mouse.action == .scroll) │ │15 - (if (mouse.action.scroll == .up) .up else .down)│ │16 - else │ │17 - .none, │ │12 + .arrow_up, .scroll_up => .up, │ │13 + .arrow_down, .scroll_down => .down, │ │14 else => .none, │ │15 }; │ │16 } │ ╰────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────╮ │26 .page_down => return 10, │ │27 .home => return -count, │ │28 .end => return count, │ │33 - .mouse => |mouse| switch (mouse.action) { │ │34 - .scroll => |dir| return if (dir == .up) -1 else 1,│ │35 - else => {}, │ │36 - }, │ │29 + .scroll_up => return -1, │ │30 + .scroll_down => return 1, │ │31 else => {}, │ │32 } │ │33 return null; │ ╰──────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯