╭ changed ────────╮ │src/ui/widget.zig│ ╰─────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │178 const cur: isize = @intCast(box.children.getIndex(cur_id) orelse return); │ │179 // home and end jump straight to the ends │ │180 if (@abs(delta) < keys.len) if (box.children.values()[@intCast(cur)].rect) |rect| if (scrollThroughRow(scroll, rect, delta)) return;│ │181 - const view_h = viewHeight(scroll); │ │181 const last: isize = @intCast(keys.len - 1); │ │182 const next: usize = @intCast(std.math.clamp(cur + delta, 0, last)); │ │183 if (next == @as(usize, @intCast(cur))) return; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ │184 root_focus.setFocus(keys[next]); │ │186 - const rect = box.children.values()[next].rect orelse return; │ │187 - // a tall row shows the end it was entered from │ │188 - if (view_h) |h| if (@as(isize, @intCast(rect.size.height)) > h) { │ │189 - scroll.y = if (delta > 0) rect.y else rectBottom(rect) - h; │ │190 - return; │ │191 - }; │ │192 - scroll.scrollToRect(rect); │ │185 + if (box.children.values()[next].rect) |rect| scrollToEnteredRow(scroll, rect, delta > 0);│ │186 +} │ │187 + │ │188 +// bring `rect`, a row in `scroll`'s content just entered from above (`down`) │ │189 +// or below, into view. a row taller than the view keeps the view while the │ │190 +// edge it was entered from is in it, so the following steps scroll through it, │ │191 +// and otherwise shows that edge. │ │192 +pub fn scrollToEnteredRow(scroll: *wgt.Scroll(Widget), rect: layout.IRect, down: bool) void {│ │193 + const grid = scroll.grid orelse return; │ │194 + const h: isize = @intCast(grid.size.height - scroll.bar_h); │ │195 + if (@as(isize, @intCast(rect.size.height)) <= h) return scroll.scrollToRect(rect); │ │196 + const edge = if (down) rect.y else rectBottom(rect) - 1; │ │197 + if (edge >= scroll.y and edge < scroll.y + h) return; │ │198 + scroll.y = if (down) rect.y else rectBottom(rect) - h; │ │199 } │ │200 │ │201 // step across the boxes of `box`'s selected row, false when it isn't a row or │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │210 │ │211 // scroll a step through `rect`, a row in `scroll`'s content, when it extends │ │212 // past the view in `delta`'s direction. false when it doesn't, and on the web, │ │207 -// which scrolls natively. │ │213 +// where scrollFocusedWidget in script.js handles scrolling. │ │214 pub fn scrollThroughRow(scroll: *wgt.Scroll(Widget), rect: layout.IRect, delta: isize) bool { │ │209 - // how far one step scrolls │ │210 - const step_lines = 5; │ │215 + const step_lines = 3; // how far a step scrolls (see stepLines in script.js for the web equivalent)│ │216 const h = viewHeight(scroll) orelse return false; │ │217 const hidden = if (delta > 0) rectBottom(rect) - (scroll.y + h) else scroll.y - rect.y; │ │218 if (hidden <= 0) return false; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯