diff --git a/crates/ui-egui/src/canvas.rs b/crates/ui-egui/src/canvas.rs index 90464d90d6..61a266da88 100644 --- a/crates/ui-egui/src/canvas.rs +++ b/crates/ui-egui/src/canvas.rs @@ -2873,9 +2873,6 @@ fn shown_row(view: &DocView, rects: &[Rect]) -> Vec { } } -/// Full screen: a click on the document goes forward a page and a shift-click back, as in -/// Acrobat, unless the click did something else (a link, a word selected). Decided once the pages -/// have had the click. `Some(back)` on the frame of a click, `back` when it was a shift-click. /// The pages' context menu, except in full screen, where a right-click turns back a page instead /// ([`presentation_click_state`]). fn page_context_menu(resp: &egui::Response, presenting: bool, add: impl FnOnce(&mut egui::Ui)) { @@ -2884,6 +2881,9 @@ fn page_context_menu(resp: &egui::Response, presenting: bool, add: impl FnOnce(& } } +/// Full screen: a click on the document goes forward a page and a shift-click back, as in +/// Acrobat, unless the click did something else (a link, a word selected). Decided once the pages +/// have had the click. `Some(back)` on the frame of a click, `back` when it was a shift-click. fn presentation_click_state(ui: &egui::Ui, view: &DocView, navigation_rect: Rect, enabled: bool) -> Option { let presenting = view.presentation.is_some() && enabled; // A right-click goes back a page, as a left click goes forward (*Adobe Acrobat Help*, 2019, diff --git a/crates/ui-egui/src/canvas/presenter.rs b/crates/ui-egui/src/canvas/presenter.rs index 8b98a8b4f6..b130a1b9e3 100644 --- a/crates/ui-egui/src/canvas/presenter.rs +++ b/crates/ui-egui/src/canvas/presenter.rs @@ -122,8 +122,10 @@ pub(super) fn frame( Some(Turn { from_page, from, to_page: page, effect, seconds, started: None }) }); // Its display time starts once the page is on screen, not while it still says Rendering… - // (or at once for a page the renderer can't draw, which never will be). - let ready = view.pages.contains_key(&page) || view.errors.contains_key(&page); + // (or at once for a page the renderer can't draw, which never will be). In two-page view + // that is every page of the spread, so the spread isn't turned before both were shown. + let drawn = |p: &usize| view.pages.contains_key(p) || view.errors.contains_key(p); + let ready = drawn(&page) && view.screen_rects.iter().all(|(p, _)| drawn(p)); view.presenter.shown = if turn.is_some() || !ready { None } else { Some((page, now)) }; view.presenter.turn = turn; } diff --git a/crates/ui-egui/src/canvas/tests.rs b/crates/ui-egui/src/canvas/tests.rs index 3efa809d74..c10f3a35be 100644 --- a/crates/ui-egui/src/canvas/tests.rs +++ b/crates/ui-egui/src/canvas/tests.rs @@ -2147,3 +2147,40 @@ fn a_display_time_starts_once_the_page_has_rendered() { presenter_frame(&ctx, &mut v, &info, 6.6); assert_eq!(v.current, 1, "its second on screen is up"); } + +/// In two-page view a display time counts from when the whole spread is on screen: one page of +/// it still showing Rendering… holds the spread (#5316 review). +#[test] +fn a_display_time_in_two_page_view_waits_for_the_whole_spread() { + use pdfcraft_render::PageTransition; + let page = pdfcraft_render::PageInfo { width: 300.0, height: 400.0, label: String::new(), crop: [0.0, 0.0, 300.0, 400.0], rotation: 0 }; + let timed = PageTransition { + page: 0, + style: None, + duration: 1.0, + horizontal: false, + inward: false, + direction: Some(0), + scale: 1.0, + opaque: false, + display: Some(1.0), + }; + let info = DocInfo { pages: vec![page.clone(), page.clone(), page.clone(), page], transitions: vec![timed], ..Default::default() }; + let mut v = DocView::new(DocId(1), &info, ViewDefaults { layout: PageLayout::TwoUp, continuous: false, ..Default::default() }); + v.enter_presentation(); + let ctx = egui::Context::default(); + let tex = |ctx: &egui::Context| ctx.load_texture("page", egui::ColorImage::new([4, 4], vec![Color32::WHITE; 16]), Default::default()); + let r = Rect::from_min_size(Pos2::ZERO, egui::vec2(300.0, 400.0)); + v.screen_rects = vec![(0, r), (1, r.translate(egui::vec2(300.0, 0.0)))]; + v.pages.insert(0, super::cache::PageTex { tag: 0, tex: tex(&ctx) }); + for now in [0.0, 1.0, 2.0, 5.0] { + presenter_frame(&ctx, &mut v, &info, now); + } + assert_eq!(v.current, 0, "page 2 of the spread is still rendering: the spread's second has not started"); + v.pages.insert(1, super::cache::PageTex { tag: 0, tex: tex(&ctx) }); + presenter_frame(&ctx, &mut v, &info, 5.5); + presenter_frame(&ctx, &mut v, &info, 6.0); + assert_eq!(v.current, 0, "half of its second on screen"); + presenter_frame(&ctx, &mut v, &info, 6.6); + assert_eq!(v.current, 2, "its second on screen is up: the next spread"); +} diff --git a/docs/ui-parity.md b/docs/ui-parity.md index b1b41c7212..eabfb9da1f 100644 --- a/docs/ui-parity.md +++ b/docs/ui-parity.md @@ -31,7 +31,7 @@ No dump of Acrobat's menu tree has been diffed against the registry yet (gap 24) | Document tabs | yes | yes, with unsaved marker | shipped | | Multiple windows, drag a tab out | yes | no | planned | | Split window, spreadsheet split | yes | no | planned | -| Read mode, full screen | yes | yes; full screen is one fitted page at a time on black, click/keys turn pages (#1459), a right-click or Shift+Enter goes back, page transitions and display times play (#379), a still pointer hides | shipped; loop after the last page and the full-screen preferences planned | +| Read mode, full screen | yes | yes; full screen is one fitted page or spread at a time on black, and background clicks and keys turn pages while clicks on links, comments, fields and other page objects do not (#1459), a right-click or Shift+Enter goes back, page transitions and display times play (#379), a still pointer hides | shipped; loop after the last page and the full-screen preferences planned | | Light, dark, system theme | yes | yes | shipped | | Side panels: thumbnails, bookmarks, attachments, layers, comments, fields, signatures | yes | yes; panels keep their width (#704); the Pages inspector has a 50–150% thumbnail size slider and buttons (#3808) | shipped | | Destinations, articles, model tree, Tags, Order, Content panels | yes | no | planned |