╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─────────────╮ │src/ui/Repo/Header.zig│ ╰──────────────────────╯ ╭───────────────────────────────────────╮ │1 const std = @import("std"); │ │2 const ui = @import("../../ui.zig"); │ │3 +const inp = @import("../input.zig");│ │4 const xit = @import("xit"); │ │5 const xitui = xit.xitui; │ │6 const wgt = xitui.widget; │ ╰───────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │251 pub fn input(self: *View, allocator: std.mem.Allocator, key: Key, root_focus: *Focus) !void {│ │252 _ = allocator; │ │253 const current_tab = self.currentTabIndex() orelse return; │ │253 - var new_tab = current_tab; │ │254 - switch (key) { │ │255 - .arrow_left => new_tab -|= 1, │ │256 - .arrow_right => if (new_tab + 1 < self.tab_ids.count()) { │ │257 - new_tab += 1; │ │258 - }, │ │259 - else => {}, │ │260 - } │ │261 - if (new_tab != current_tab) { │ │254 + if (inp.moveTab(key, current_tab, self.tab_ids.count())) |new_tab| { │ │255 root_focus.setFocus(self.tab_ids.keys()[new_tab]); │ │256 } │ │257 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ───────────╮ │src/ui/Repo/Refs.zig│ ╰────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────╮ │278 // same row offset. the parent (Repo) intercepts up at the top row to move│ │279 // focus to the header. │ │280 if (inp.rowDelta(key, self.columnRowCount())) |delta| { │ │281 - return self.moveRow(root_focus, delta); │ │281 + const scroll = self.activeScroll() orelse return; │ │282 + ui.moveRowFocus(&scroll.child.box, scroll, root_focus, delta); │ │283 + return; │ │284 } │ │285 switch (key) { │ │286 .arrow_left => try self.switchColumn(root_focus, left_col), │ ╰───────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────╮ │305 return &(self.activeScroll() orelse return null).child.box; │ │306 } │ │307 │ │306 - fn moveRow(self: *View, root_focus: *Focus, delta: isize) !void { │ │307 - const scroll = self.activeScroll() orelse return; │ │308 - const col = &scroll.child.box; │ │309 - const keys = col.children.keys(); │ │310 - if (keys.len == 0) return; │ │311 - const cur_id = col.getFocus().child_id orelse return; │ │312 - const cur: isize = @intCast(col.children.getIndex(cur_id) orelse return);│ │313 - // clamp a delta past either end to the first/last row. │ │314 - const last: isize = @intCast(keys.len - 1); │ │315 - const next: usize = @intCast(std.math.clamp(cur + delta, 0, last)); │ │316 - if (next == @as(usize, @intCast(cur))) return; │ │317 - root_focus.setFocus(keys[next]); │ │318 - if (col.children.values()[next].rect) |rect| scroll.scrollToRect(rect); │ │319 - } │ │320 - │ │308 fn switchColumn(self: *View, root_focus: *Focus, target: usize) !void { │ │309 if (target >= self.box.children.count()) return; │ │310 const cur_col = self.activeColumn() orelse return; │ ╰──────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────────╮ │src/ui/Settings.zig│ ╰───────────────────╯ ╭──────────────────────────────────────╮ │1 const std = @import("std"); │ │2 const ui = @import("../ui.zig"); │ │3 +const inp = @import("./input.zig");│ │4 const xit = @import("xit"); │ │5 const xitui = xit.xitui; │ │6 const wgt = xitui.widget; │ ╰──────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────╮ │106 switch (key) { │ │107 .enter => try self.toggle(), │ │108 .mouse => |mouse| { │ │108 - if (mouse.action == .press and mouse.action.press == .left) { │ │109 - if (root_focus.children.get(self.button_id)) |entry| { │ │110 - const r = entry.rect; │ │111 - if (mouse.x >= r.x and mouse.y >= r.y and │ │112 - mouse.x < r.x + r.size.width and mouse.y < r.y + r.size.height)│ │113 - { │ │114 - try self.toggle(); │ │115 - } │ │116 - } │ │109 + if (inp.leftClickOn(root_focus, self.button_id, mouse)) { │ │110 + try self.toggle(); │ │111 } │ │112 }, │ │113 else => {}, │ ╰────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────────╮ │src/ui/User/Header.zig│ ╰──────────────────────╯ ╭───────────────────────────────────────╮ │1 const std = @import("std"); │ │2 const ui = @import("../../ui.zig"); │ │3 +const inp = @import("../input.zig");│ │4 const xit = @import("xit"); │ │5 const xitui = xit.xitui; │ │6 const wgt = xitui.widget; │ ╰───────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │184 pub fn input(self: *View, allocator: std.mem.Allocator, key: Key, root_focus: *Focus) !void {│ │185 _ = allocator; │ │186 const current_tab = self.currentTabIndex() orelse return; │ │186 - var new_tab = current_tab; │ │187 - switch (key) { │ │188 - .arrow_left => new_tab -|= 1, │ │189 - .arrow_right => if (new_tab + 1 < self.tab_ids.count()) { │ │190 - new_tab += 1; │ │191 - }, │ │192 - else => {}, │ │193 - } │ │194 - if (new_tab != current_tab) { │ │187 + if (inp.moveTab(key, current_tab, self.tab_ids.count())) |new_tab| { │ │188 root_focus.setFocus(self.tab_ids.keys()[new_tab]); │ │189 } │ │190 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ───────╮ │src/ui/input.zig│ ╰────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────╮ │1 const xit = @import("xit"); │ │2 const xitui = xit.xitui; │ │3 const Key = xitui.input.Key; │ │4 +const Mouse = xitui.input.Mouse; │ │5 +const Focus = xitui.focus.Focus; │ │6 │ │7 /// the vertical direction of a navigation key press, including mouse scroll│ │8 pub const Direction = enum { up, down, none }; │ ╰───────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │37 else => {}, │ │38 } │ │39 return null; │ │40 +} │ │41 + │ │42 +/// whether `mouse` is a left press inside the rect of `focus_id`'s focus entry│ │43 +pub fn leftClickOn(root_focus: *Focus, focus_id: usize, mouse: Mouse) bool { │ │44 + if (mouse.action != .press or mouse.action.press != .left) return false; │ │45 + const entry = root_focus.children.get(focus_id) orelse return false; │ │46 + const r = entry.rect; │ │47 + return mouse.x >= r.x and mouse.y >= r.y and │ │48 + mouse.x < r.x + r.size.width and mouse.y < r.y + r.size.height; │ │49 } │ │50 │ │51 +/// the tab index after a left/right arrow press, clamped to the ends, │ │52 +/// or null when the key doesn't move the selection │ │53 +pub fn moveTab(key: Key, current_tab: usize, tab_count: usize) ?usize { │ │54 + var new_tab = current_tab; │ │55 + switch (key) { │ │56 + .arrow_left => new_tab -|= 1, │ │57 + .arrow_right => if (new_tab + 1 < tab_count) { │ │58 + new_tab += 1; │ │59 + }, │ │60 + else => {}, │ │61 + } │ │62 + return if (new_tab != current_tab) new_tab else null; │ │63 +} │ ╰───────────────────────────────────────────────────────────────────────────────────╯