mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-14 19:27:04 -04:00
* fix(ui): preserve scroll position when collapsing or resizing sidebars (#1056) * Run cargo fmt --------- Co-authored-by: Brandon Thomas <[email protected]>
This commit is contained in:
1 parent
6f96c40eaa
commit
bed9a48ccd
2 files changed
+83
No files matched your search
@@ -1803,7 +1803,27 @@ pub fn document_area(app: &mut PdfCraftApp, index: usize, ui: &mut egui::Ui) {
|
||||
let avail = ui.available_rect_before_wrap();
|
||||
view.viewport_w = avail.width();
|
||||
view.viewport_h = avail.height();
|
||||
let old_zoom = view.zoom;
|
||||
view.fit_zoom(info);
|
||||
if view.shown && view.zoom_anchor.is_none() && view.goto.is_none() && view.goto_point.is_none() && (view.zoom - old_zoom).abs() > 1e-4 {
|
||||
let prev_viewport = view.viewport_screen;
|
||||
let top_y = prev_viewport.min.y;
|
||||
let anchor = view
|
||||
.screen_rects
|
||||
.iter()
|
||||
.find(|(_, r)| r.min.y <= top_y && r.max.y > top_y)
|
||||
.map(|(p, r)| {
|
||||
let fy = if r.height() > 0.0 { ((top_y - r.min.y) / r.height()).clamp(0.0, 1.0) } else { 0.0 };
|
||||
(*p, fy, 0.0f32)
|
||||
})
|
||||
.or_else(|| view.screen_rects.iter().find(|(_, r)| r.min.y >= top_y).map(|(p, r)| (*p, 0.0f32, (r.min.y - top_y).max(0.0))))
|
||||
.or_else(|| view.screen_rects.last().map(|(p, r)| (*p, 1.0f32, (r.max.y - top_y).max(0.0))));
|
||||
if let Some((page, fy, rel_y)) = anchor {
|
||||
view.zoom_anchor = Some((page, 0.5, fy, vec2(avail.width() / 2.0, rel_y)));
|
||||
} else {
|
||||
view.zoom_anchor = Some((view.current, 0.5, 0.0, vec2(avail.width() / 2.0, MARGIN)));
|
||||
}
|
||||
}
|
||||
|
||||
// Pinch / ctrl+scroll zoom, anchored on the current page.
|
||||
let zoom_delta = ui.input(|i| i.zoom_delta());
|
||||
|
||||
@@ -920,3 +920,66 @@ trailer << /Root 1 0 R >>
|
||||
let first = detail(&mut h);
|
||||
assert!(first * 10 > sharp * 7, "the first frame after zooming lost its detail: {first} against {sharp}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sidebar_collapse_and_resize_preserves_scroll_position() {
|
||||
use pdfcraft_ui_egui::canvas::Fit;
|
||||
let mut h = Harness::builder().with_size(egui::vec2(1400.0, 900.0)).build_eframe(|_cc| {
|
||||
let mut app = PdfCraftApp::new();
|
||||
app.set_option("language", "en").unwrap();
|
||||
app.open_bytes("pages.pdf", None, PAGES.to_vec()).expect("opens");
|
||||
app.set_option("left", "closed").unwrap();
|
||||
app.set_option("panel", "bookmarks").unwrap();
|
||||
app.set_option("layout", "continuous").unwrap();
|
||||
app
|
||||
});
|
||||
let mut width = 0.0;
|
||||
for _ in 0..400 {
|
||||
h.run_steps(1);
|
||||
let w = h.state().views[0].viewport_rect().width();
|
||||
if w == width {
|
||||
break;
|
||||
}
|
||||
width = w;
|
||||
}
|
||||
h.state_mut().views[0].go_to_page(2);
|
||||
h.run_steps(6);
|
||||
|
||||
let v = &h.state().views[0];
|
||||
assert_eq!(v.current, 2);
|
||||
assert_eq!(v.fit, Fit::Width);
|
||||
let zoom_before = v.zoom;
|
||||
let rect_before = v.page_screen_rect(2).expect("page 2 on screen");
|
||||
let vp_before = v.viewport_rect();
|
||||
let rel_y_before = rect_before.min.y - vp_before.min.y;
|
||||
|
||||
// Collapse bookmarks panel: available width increases, so fit-width zoom increases.
|
||||
h.state_mut().set_option("panel", "none").unwrap();
|
||||
h.run_steps(6);
|
||||
|
||||
let v = &h.state().views[0];
|
||||
let zoom_after = v.zoom;
|
||||
assert!(zoom_after > zoom_before, "zoom increased when panel collapsed: {zoom_after} vs {zoom_before}");
|
||||
assert_eq!(v.current, 2, "still on page 2 after panel collapsed");
|
||||
let rect_after = v.page_screen_rect(2).expect("page 2 still on screen");
|
||||
let vp_after = v.viewport_rect();
|
||||
let rel_y_after = rect_after.min.y - vp_after.min.y;
|
||||
assert!((rel_y_after - rel_y_before).abs() < 1.0, "page 2 scroll position preserved: before {rel_y_before}, after {rel_y_after}");
|
||||
|
||||
// Reopen bookmarks panel: available width decreases, so fit-width zoom decreases.
|
||||
h.state_mut().set_option("panel", "bookmarks").unwrap();
|
||||
for _ in 0..400 {
|
||||
h.run_steps(1);
|
||||
let w = h.state().views[0].viewport_rect().width();
|
||||
if w == width {
|
||||
break;
|
||||
}
|
||||
width = w;
|
||||
}
|
||||
let v = &h.state().views[0];
|
||||
assert_eq!(v.current, 2, "still on page 2 after panel reopened");
|
||||
let rect_reopened = v.page_screen_rect(2).expect("page 2 still on screen");
|
||||
let vp_reopened = v.viewport_rect();
|
||||
let rel_y_reopened = rect_reopened.min.y - vp_reopened.min.y;
|
||||
assert!((rel_y_reopened - rel_y_before).abs() < 1.0, "page 2 scroll position preserved on reopen: before {rel_y_before}, after {rel_y_reopened}");
|
||||
}
|
||||
Reference in new issue
Block a user