diff --git a/crates/ui-egui/src/canvas.rs b/crates/ui-egui/src/canvas.rs index c26b108d..c5b939bf 100644 --- a/crates/ui-egui/src/canvas.rs +++ b/crates/ui-egui/src/canvas.rs @@ -2684,7 +2684,10 @@ pub fn document_area(app: &mut PdfCraftApp, index: usize, ui: &mut egui::Ui) { view.clicks = release_clicks; } let clicks = if view.clicks > 2 && tool != QuickTool::Select { 1 } else { view.clicks }; - if clicks >= 2 && over_text { + // Only on the frame egui reports the multi-click: `view.clicks` outlives it, and + // acting on every frame re-selected the word as soon as a selection was cleared + // (a highlight made by the double-click left its word selected). + if release_clicks > 0 && clicks >= 2 && over_text { if view.selection.is_none() { let span = text.nearest(vx, vy).and_then(|a| match clicks { 2 => text.word_at(a), diff --git a/crates/ui-egui/tests/ui_group/text_select.rs b/crates/ui-egui/tests/ui_group/text_select.rs index 12b89aa2..d6f970de 100644 --- a/crates/ui-egui/tests/ui_group/text_select.rs +++ b/crates/ui-egui/tests/ui_group/text_select.rs @@ -77,6 +77,16 @@ fn quick_clicks_with_the_highlighter_mark_only_the_word() { let (mut h, at) = harness(|app| assert!(app.execute("comment.highlight"))); for _ in 0..4 { click(&mut h, at); + // The double-click's highlight re-renders the page; give its text layer up to 8 frames + // to come back (still well inside egui's 0.3 s multi-click window at 1/60 s a frame), so + // a loaded machine doesn't make the later clicks land on a page with no text yet. + for _ in 0..8 { + if !h.state().render_pending() { + break; + } + std::thread::sleep(std::time::Duration::from_millis(20)); + h.run_steps(1); + } } h.run_steps(3); // Under load the mark can land a few frames later; wait for it (egui's clock is fixed per