diff options
| author | Gabriel Schneider <[email protected]> | 2026-08-02 19:45:52 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-08-10 09:17:07 -0300 |
| commit | 820ff337d156831d250ff0fcef5139fe69474e4e (patch) | |
| tree | 37edb736e3d1de90809a7d32dbd4bb91427f3c51 /src/tty/tty.zig | |
| parent | 7c51e3f616aa0535948e6aacafec142732e1288b (diff) | |
| download | pardes-820ff337d156831d250ff0fcef5139fe69474e4e.tar.gz pardes-820ff337d156831d250ff0fcef5139fe69474e4e.zip | |
fix PDF mouse-wheel scrolling jumping multiple pages
Diffstat (limited to 'src/tty/tty.zig')
| -rw-r--r-- | src/tty/tty.zig | 41 |
1 files changed, 38 insertions, 3 deletions
diff --git a/src/tty/tty.zig b/src/tty/tty.zig index 6f7cc5ba..343452b5 100644 --- a/src/tty/tty.zig +++ b/src/tty/tty.zig @@ -176,6 +176,31 @@ fn kittyImageRepresentable(place: pardes.ImagePlace) bool { place.iw <= std.math.maxInt(u16) and place.ih <= std.math.maxInt(u16); } +const PdfWheelTarget = struct { pane: usize, page: usize }; + +/// A native PDF's page geometry is invalid between `setPdfPage` and the next +/// render. Remember the page under a vertical wheel press so the input batch +/// can stop exactly when that press crosses a page boundary. The following +/// queued wheel report then sees the newly rastered page instead of treating +/// missing geometry as another page-wise fallback. +fn nativePdfWheelTarget(core: *const pardes.Pardes, mouse: vaxis.Mouse) ?PdfWheelTarget { + if (comptime !pardes.pdf_enabled) return null; + if (!core.native_images or mouse.type != .press or + (mouse.button != .wheel_up and mouse.button != .wheel_down) or + mouse.col < 0 or mouse.row < 0) return null; + const col: u16 = @intCast(mouse.col); + const row: u16 = @intCast(mouse.row); + for (core.panes, 0..) |slot, id| { + const pane = slot orelse continue; + const rect = core.rects[id]; + if (col < rect.x or col >= rect.x + rect.w or + row < rect.y or row >= rect.y + rect.h) continue; + const page = pane.pdfPage() orelse return null; + return .{ .pane = id, .page = page }; + } + return null; +} + pub fn run(init: std.process.Init, opts: pardes.Options) !void { const io = init.io; const gpa = init.gpa; @@ -353,12 +378,15 @@ pub fn run(init: std.process.Init, opts: pardes.Options) !void { const tz_event = tracy.zone(@src(), "event"); // Apply every queued INPUT event, then render ONCE — the gui shell // drains SDL's queue the same way. Without this a wheel flick is fifty - // full render+repaint (and re-highlight) cycles instead of one. - // pty output keeps a frame per chunk: progress paints as it arrives. + // full render+repaint (and re-highlight) cycles instead of one. A + // native PDF page crossing is the one input boundary below: its next + // wheel report needs geometry produced by this render. Pty output also + // keeps a frame per chunk so progress paints as it arrives. var stop = false; var batch: usize = 0; while (true) { var output = false; + var native_pdf_page_changed = false; switch (event) { .nop, .tick => {}, .quit => stop = true, @@ -390,6 +418,7 @@ pub fn run(init: std.process.Init, opts: pardes.Options) !void { .shift = key.mods.shift, } }), .mouse => |m| { + const pdf_before = nativePdfWheelTarget(core, m); const button: ?pardes.Mouse.Button = switch (m.button) { .left => .left, .middle => .middle, @@ -413,6 +442,12 @@ pub fn run(init: std.process.Init, opts: pardes.Options) !void { .row = @intCast(m.row), .ctrl = m.mods.ctrl, } }); + if (pdf_before) |before| { + if (core.panes[before.pane]) |pane| { + if (pane.pdfPage()) |page| + native_pdf_page_changed = page != before.page; + } + } }, .paste => |bytes| { core.update(.{ .paste = bytes }); @@ -434,7 +469,7 @@ pub fn run(init: std.process.Init, opts: pardes.Options) !void { }, } batch += 1; - if (stop or output or batch >= 64) break; + if (stop or output or native_pdf_page_changed or batch >= 64) break; event = (try loop.tryEvent()) orelse break; } tz_event.end(); |
