From 23c47b5c6fede48f7e0391005fe31e7b524b872c Mon Sep 17 00:00:00 2001 From: SlavenDj Date: Wed, 21 Oct 2026 04:46:57 +0200 Subject: [PATCH] #3368: right-clicking a link hides the hover tooltip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The link tooltip (URL + "Ctrl/⌘+Click to follow link") stayed open when the context menu opened. Tooltips draw above menus, so the URL box covered the menu's first items (Cut, Copy, Paste, Font…) and the menu looked truncated. The tooltip now stands down while the context menu is open, as the mini toolbar already does, and while the secondary button is opening it. Regression test: hover a link (tooltip shown), right-click, assert the menu is open and the tooltip is gone. --- crates/ui-egui/src/canvas.rs | 40 +++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/crates/ui-egui/src/canvas.rs b/crates/ui-egui/src/canvas.rs index fabe1d43d..6006d43d3 100644 --- a/crates/ui-egui/src/canvas.rs +++ b/crates/ui-egui/src/canvas.rs @@ -2582,9 +2582,13 @@ fn mouse(app: &mut WordApp, ui: &Ui, resp: &egui::Response, rects: &[Rect], layo let _ = app.run("edit.pasteFormat", json!({})); } } - // Hover a link: show its target. + // Hover a link: show its target, unless the context menu is opening or open: a tooltip draws + // above the menu and would cover its first items (#3368). if resp.hovered() && !app.canvas.dragging + && !app.canvas.context_menu_open + && !resp.secondary_clicked() + && !ui.input(|i| i.pointer.secondary_down()) && let Some(pos) = layout.hit(page, x, y, story) && let Some(link) = link_under(app, layout, page, x, y, &pos) { @@ -4981,6 +4985,40 @@ mod tests { assert_eq!(s.sel.focus, start, "at the bookmark's start"); } + /// #3368: right-clicking a link dismisses the hover tooltip. A tooltip draws above the + /// context menu and covered its first items (Cut, Copy, Paste, Font…), so the menu looked + /// truncated; the tooltip must stand down while the menu owns the pointer. + #[test] + fn right_clicking_a_link_hides_the_hover_tooltip() { + use egui_kittest::kittest::Queryable; + let mut a = WordApp::new(wordcraft_engine::Session::new(wordcraft_doc::Document::from_text("See here")), Default::default()); + a.run("select.text", json!({"text": "here"})).unwrap(); + a.run("insert.link", json!({"url": "https://example.com/very/long/tracking/url?with=parameters&and=still-more"})).unwrap(); + let mut h = egui_kittest::Harness::builder().with_size(egui::vec2(1440.0, 900.0)).build_ui_state( + |ui, app: &mut WordApp| { + let ctx = ui.ctx().clone(); + app.logic(&ctx); + app.ui(ui); + }, + a, + ); + steps(&mut h, 6); + // Between the link's "h" and "e". + let c = h.state_mut().session.layout().caret(&Pos { story: StoryRef::Body, path: wordcraft_doc::Path::top(0), off: 5 }).unwrap(); + let at = screen(&mut h, c.x, c.top + c.height / 2.0); + h.event(egui::Event::PointerMoved(at)); + steps(&mut h, 2); + let tips = |h: &egui_kittest::Harness<'_, WordApp>| h.query_all_by_label_contains("Click to follow link").count(); + assert!(tips(&h) > 0, "hovering the link shows its target"); + for pressed in [true, false] { + h.event(egui::Event::PointerButton { pos: at, button: egui::PointerButton::Secondary, pressed, modifiers: Default::default() }); + h.step(); + } + steps(&mut h, 2); + assert!(h.state().canvas.context_menu_open, "the context menu is open"); + assert_eq!(tips(&h), 0, "the link tooltip is gone, so it can't cover the menu"); + } + /// #688: the drag auto-scroll waits in the middle, ramps in from both edges and never leaves /// the scrollable range. #[test]