M3: a link followed in full screen cancels the click's pending page turn (#1459)

Review on #2070: a click on the page schedules a turn after the
double-click time, and a link clicked before then jumped and then the page
still moved on. Following a link now drops the pending turn.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q
This commit is contained in:
mtlcl410
2026-10-19 16:21:20 +08:00
co-authored by Claude Opus 5.5
parent 14e17ece3b
commit 3fff309dd3
2 changed files with 37 additions and 2 deletions
+3 -2
View File
@@ -4049,14 +4049,15 @@ pub fn document_area(app: &mut PdfCraftApp, index: usize, ui: &mut egui::Ui) {
// Full screen: the click turns the page unless it did something else first. It waits out the
// double-click time: turning on the first click's release sent a double-click's second click,
// meant to select a word, to the next page (review on #2070). A selection cancels it, and so
// does leaving full screen; a double-click elsewhere still turns once.
// do a link followed meanwhile and leaving full screen; a double-click elsewhere still turns
// once.
let now = ui.input(|i| i.time);
if present_click && clicked_link.is_none() && view.selection.is_none() && view.clicks < 2 {
let delay = ui.ctx().options(|o| o.input_options.max_double_click_delay);
view.present_turn = Some((now + delay, !present_back));
}
if let Some((due, forward)) = view.present_turn {
if view.selection.is_some() || view.presentation.is_none() {
if clicked_link.is_some() || view.selection.is_some() || view.presentation.is_none() {
view.present_turn = None;
} else if now >= due {
view.present_turn = None;
@@ -545,6 +545,40 @@ fn coalesced_primary_clicks_select_line_then_spaced_click_clears() {
}
}
/// Review on #2070: a click on the page in full screen waits out the double-click time before
/// it turns the page, and a link clicked meanwhile used to leave that turn pending: the link
/// jumped to page 3, then the page moved on to page 4.
#[test]
fn full_screen_link_click_cancels_the_pending_page_turn() {
let page = "<< /Type /Page /Parent 2 0 R /MediaBox [0 0 300 200] /Contents 4 0 R /Resources << /Font << /F1 5 0 R >> >> >>";
let four_pages = String::from_utf8(two_lines())
.unwrap()
.replace("/Kids [3 0 R] /Count 1", "/Kids [3 0 R 6 0 R 7 0 R 8 0 R] /Count 4")
.replace("/Contents 4 0 R /Resources", "/Annots [9 0 R] /Contents 4 0 R /Resources")
.replace(
"trailer",
&format!(
"6 0 obj {page} endobj\n7 0 obj {page} endobj\n8 0 obj {page} endobj\n9 0 obj << /Type /Annot /Subtype /Link /Rect [200 20 280 60] /Border [0 0 0] /Dest [7 0 R /Fit] >> endobj\ntrailer"
),
)
.into_bytes();
let (mut h, _) = harness_with(four_pages, |_| {});
h.state_mut().apply_full_screen(true);
crate::support::wait_until(&mut h, "the page in full screen", |app| app.views[0].glyph_screen_pos(0, 5).is_some() && !app.render_pending());
let r = h.state().views[0].page_screen_rect(0).expect("page 1 on screen");
let at = |x: f32, y: f32| egui::pos2(r.left() + x / 300.0 * r.width(), r.top() + (200.0 - y) / 200.0 * r.height());
// A click on blank page area, then, within the double-click time, a click on the link.
h.hover_at(at(150.0, 90.0));
h.run_steps(1);
click(&mut h, at(150.0, 90.0));
h.run_steps(3);
h.hover_at(at(240.0, 40.0));
h.run_steps(1);
click(&mut h, at(240.0, 40.0));
h.run_steps(30);
assert_eq!(h.state().views[0].current, 2, "the link's page, and no turn after it");
}
/// Review on #2070: in full screen a click goes forward a page, but a double-click selects the
/// word and stays: the click waits out the double-click time before turning. Turning on the first
/// click's release had sent the second click to the next page. Leaving full screen meanwhile