diff --git a/crates/ui-egui/src/dialogs/preferences.rs b/crates/ui-egui/src/dialogs/preferences.rs index 883d0b68a6..fc574b9c0c 100644 --- a/crates/ui-egui/src/dialogs/preferences.rs +++ b/crates/ui-egui/src/dialogs/preferences.rs @@ -710,37 +710,75 @@ fn card_documents_and_view(ui: &mut egui::Ui, app: &mut PdfCraftApp, t: &Tokens, ctx.label_secondary(ui, tl!("Used when opening PDFs. An explicit launch or control mode takes precedence for the session."), t); ui.add_space(6.0); - let defaults = &mut app.view_defaults; + let mut layout_choice = app.view_defaults.layout; + let mut continuous = app.view_defaults.continuous; + let mut layout_changed = false; + let mut continuous_changed = false; ui.horizontal(|ui| { ctx.label_primary(ui, tl!("Default page display"), t); - let mut layout_choice = defaults.layout; if ctx.pill_choice(ui, t, &mut layout_choice, &[(PageLayout::Single, tl!("Single page")), (PageLayout::TwoUp, tl!("Two-page view"))]) { - defaults.layout = layout_choice; + app.view_defaults.layout = layout_choice; + layout_changed = true; } - let mut continuous = defaults.continuous; if ctx.toggle_pill(ui, t, &mut continuous, tl!("Continuous scrolling")) { - defaults.continuous = continuous; + app.view_defaults.continuous = continuous; + continuous_changed = true; } }); - ctx.checkbox(ui, &mut defaults.show_page_gaps, tl!("Show gaps between pages"), t); + let mut show_page_gaps = app.view_defaults.show_page_gaps; + let gaps_changed = ctx.checkbox(ui, &mut show_page_gaps, tl!("Show gaps between pages"), t).changed(); + if gaps_changed { + app.view_defaults.show_page_gaps = show_page_gaps; + } ctx.label_secondary(ui, tl!("Hide gaps to join page edges. Margins inside the PDF remain unchanged."), t); ui.add_space(6.0); + let mut fit_changed = false; + let mut zoom_changed = false; ui.horizontal(|ui| { ctx.label_primary(ui, tl!("Default zoom"), t); - ctx.pill_choice( - ui, - t, - &mut defaults.fit, - &[(Fit::Width, tl!("Fit to width")), (Fit::Page, tl!("Zoom to page level")), (Fit::None, tl!("Custom"))], - ); - let mut percent = defaults.zoom * 100.0; + let mut fit = app.view_defaults.fit; + if ctx.pill_choice(ui, t, &mut fit, &[(Fit::Width, tl!("Fit to width")), (Fit::Page, tl!("Zoom to page level")), (Fit::None, tl!("Custom"))]) + { + app.view_defaults.fit = fit; + fit_changed = true; + } + let mut percent = app.view_defaults.zoom * 100.0; if ui.add(egui::DragValue::new(&mut percent).range(8.0..=6400.0).max_decimals(0).suffix("%")).changed() { - (defaults.fit, defaults.zoom) = (Fit::None, percent / 100.0); + (app.view_defaults.fit, app.view_defaults.zoom) = (Fit::None, percent / 100.0); + zoom_changed = true; } }); ctx.label_secondary(ui, tl!("Used when a PDF doesn't ask for a layout or zoom. Continuous scrolling never snaps between pages."), t); - ctx.checkbox(ui, &mut app.always_default_view, tl!("Always use my default zoom and page layout"), t); + let always_changed = ctx.checkbox(ui, &mut app.always_default_view, tl!("Always use my default zoom and page layout"), t).changed(); + + if app.always_default_view && (always_changed || layout_changed || continuous_changed || gaps_changed || fit_changed || zoom_changed) { + let defaults = app.view_defaults; + for view in &mut app.views { + view.set_display(defaults.layout, defaults.continuous); + view.show_page_gaps = defaults.show_page_gaps; + match defaults.fit { + Fit::None => view.set_zoom(defaults.zoom), + fit => view.set_fit(fit), + } + } + } else if let Some(i) = app.active { + if layout_changed { + app.views[i].set_layout(layout_choice); + } + if continuous_changed { + app.views[i].set_continuous(continuous); + } + if gaps_changed { + app.views[i].show_page_gaps = show_page_gaps; + } + if fit_changed { + app.views[i].set_fit(app.view_defaults.fit); + } + if zoom_changed { + app.views[i].set_zoom(app.view_defaults.zoom); + } + } ctx.checkbox(ui, &mut app.text_links, tl!("Open web and email addresses written in the page text"), t); ctx.label_secondary(ui, tl!("Only web (http, https) and email addresses open, and PdfCraft asks first, as for other links."), t); ui.add_space(6.0); diff --git a/crates/ui-egui/src/persist/last_view.rs b/crates/ui-egui/src/persist/last_view.rs index 13012b1d60..901e987112 100644 --- a/crates/ui-egui/src/persist/last_view.rs +++ b/crates/ui-egui/src/persist/last_view.rs @@ -112,14 +112,16 @@ impl PdfCraftApp { let pages = doc.info.pages.len(); let Some(last) = self.last_views.iter().find(|l| l.path == path).cloned() else { return }; let Some(view) = self.views.get_mut(index) else { return }; - if let Some((layout, continuous)) = canvas::parse_display_token(&last.display) { - view.set_display(layout, continuous); - } - view.set_cover(last.cover); - if let Some(defaults) = ViewDefaults::default().with_zoom(&last.zoom) { - match defaults.fit { - canvas::Fit::None => view.set_zoom(defaults.zoom), - fit => view.set_fit(fit), + if !self.always_default_view { + if let Some((layout, continuous)) = canvas::parse_display_token(&last.display) { + view.set_display(layout, continuous); + } + view.set_cover(last.cover); + if let Some(defaults) = ViewDefaults::default().with_zoom(&last.zoom) { + match defaults.fit { + canvas::Fit::None => view.set_zoom(defaults.zoom), + fit => view.set_fit(fit), + } } } if last.page < pages { diff --git a/crates/ui-egui/tests/it/view.rs b/crates/ui-egui/tests/it/view.rs index e290f73b26..bb435f4d2f 100644 --- a/crates/ui-egui/tests/it/view.rs +++ b/crates/ui-egui/tests/it/view.rs @@ -1255,6 +1255,39 @@ fn preferences_turn_on_always_use_my_default_zoom_and_page_layout() { assert!(h.state().always_default_view); } +#[test] +fn preferences_turn_on_always_use_my_default_zoom_and_page_layout_updates_open_documents() { + use egui_kittest::kittest::Queryable; + let mut h = harness(&[("continuous", "off"), ("zoom", "50")]); + assert!(!h.state().views[0].continuous()); + assert_ne!(h.state().views[0].fit, pdfcraft_ui_egui::canvas::Fit::Width); + assert!(h.state_mut().execute("app.preferences")); + h.run_steps(3); + h.get_by_label("Always use my default zoom and page layout").scroll_to_me(); + h.run_steps(4); + h.get_by_label("Always use my default zoom and page layout").click(); + h.run_steps(2); + assert!(h.state().always_default_view); + assert!(h.state().views[0].continuous(), "continuous scrolling is applied"); + assert_eq!(h.state().views[0].fit, pdfcraft_ui_egui::canvas::Fit::Width, "default fit width is applied"); +} + +#[test] +fn preferences_toggle_continuous_scrolling_updates_active_document() { + use egui_kittest::kittest::Queryable; + let mut h = harness(&[("default-continuous", "off"), ("continuous", "off")]); + assert!(!h.state().view_defaults.continuous); + assert!(!h.state().views[0].continuous()); + assert!(h.state_mut().execute("app.preferences")); + h.run_steps(3); + h.get_by_label("Continuous scrolling").scroll_to_me(); + h.run_steps(4); + h.get_by_label("Continuous scrolling").click(); + h.run_steps(2); + assert!(h.state().view_defaults.continuous, "defaults are updated"); + assert!(h.state().views[0].continuous(), "active document view is updated"); +} + #[test] fn preferences_set_the_default_zoom() { use egui_kittest::kittest::Queryable; diff --git a/crates/ui-egui/tests/it/viewer_prefs.rs b/crates/ui-egui/tests/it/viewer_prefs.rs index 781e461668..5ecd4a1a82 100644 --- a/crates/ui-egui/tests/it/viewer_prefs.rs +++ b/crates/ui-egui/tests/it/viewer_prefs.rs @@ -231,6 +231,21 @@ fn a_remembered_zoom_wins_over_the_layouts_fit_page() { assert_eq!((v.fit, v.zoom, v.current), (Fit::None, 0.625, 1)); } +#[test] +fn always_default_view_wins_over_a_remembered_view() { + let path = std::env::temp_dir().join(format!("pdfcraft-viewer-prefs-always-default-{}.pdf", std::process::id())).to_string_lossy().into_owned(); + let mut app = PdfCraftApp::new(); + let json_path = serde_json::to_string(&path).unwrap(); + app.restore(&format!( + r#"{{"last_views": [{{"path": {json_path}, "page": 1, "zoom": "62.5%", "display": "single"}}], "always_default_view": true}}"# + )); + assert!(app.always_default_view); + assert!(app.restore_last_view); + app.open_bytes("x.pdf", Some(path), fixture("/PageLayout /SinglePage")).unwrap(); + let v = &app.views[0]; + assert_eq!((v.fit, v.layout, v.continuous(), v.current), (Fit::Width, pdfcraft_ui_egui::canvas::PageLayout::Single, true, 1)); +} + /// The last `InnerSize` and `OuterPosition` asked for over `frames` frames. fn window_commands(h: &mut Harness<'static, PdfCraftApp>, frames: usize) -> (Option, Option) { let (mut size, mut at) = (None, None);