From 2c1713e90ba5626e1387d8d8d4694b30f1d6a972 Mon Sep 17 00:00:00 2001 From: bflatastic Date: Thu, 29 Oct 2026 19:13:01 +0700 Subject: [PATCH 1/3] Fix #4518: a dialog or floating panel over the canvas hides the pointer from it The document point under the pointer (Object Highlighting, the rulers' marks, the status bar and the Info panel) was taken wherever the pointer was over the canvas's rectangle, even over a dialog, a floating panel or a menu on top of it, so objects under the Print or Export for Screens dialog lit up as the pointer moved over the dialog. It now takes the same check as the tool's hover (the canvas's own layer under the pointer), except during a drag that began on the canvas. --- crates/ui-egui/src/canvas.rs | 9 +++++++-- crates/ui-egui/src/canvas/tests.rs | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/crates/ui-egui/src/canvas.rs b/crates/ui-egui/src/canvas.rs index 6d3b98f64..29ff0a1ac 100644 --- a/crates/ui-egui/src/canvas.rs +++ b/crates/ui-egui/src/canvas.rs @@ -354,9 +354,14 @@ fn canvas_input(app: &mut VectorcraftApp, ui: &Ui, resp: &egui::Response, rect: handle_input(app, ui, resp, rect); // `hover_doc` is the document point under the pointer in the view `handle_input` left. The // wheel, a pan, a Rotate View drag, the Zoom tool and a Presentation Mode click move the view - // there. + // there. A dialog, floating panel or menu over the canvas hides it (Object Highlighting + // showed through them: #4518), unless a drag that began on the canvas goes on there. let moved = Xf::new(rect, app.view().unwrap_or(&View::default())); - app.hover_doc = ui.input(|i| i.pointer.hover_pos()).filter(|p| rect.contains(*p)).map(|p| moved.to_doc(p)); + let dragging = ui.data(|d| d.get_temp::(drag_id()).is_some()); + app.hover_doc = ui + .input(|i| i.pointer.hover_pos()) + .filter(|p| rect.contains(*p) && (dragging || drag::on_canvas(ui, resp, *p))) + .map(|p| moved.to_doc(p)); } } diff --git a/crates/ui-egui/src/canvas/tests.rs b/crates/ui-egui/src/canvas/tests.rs index 7b2ddba66..2d6abcbe0 100644 --- a/crates/ui-egui/src/canvas/tests.rs +++ b/crates/ui-egui/src/canvas/tests.rs @@ -7328,6 +7328,25 @@ fn distance_guides_follow_what_lies_under_a_still_pointer() { assert_eq!(gap_label(&run(&mut app, vec![])), None, "another document"); } +/// #4518: a floating panel or a modal dialog over the canvas hides the pointer from it, so Object +/// Highlighting, the rulers and the Info panel don't follow a pointer that is over the dialog. +#[test] +fn a_panel_or_dialog_over_the_canvas_hides_the_pointer_from_it() { + let (mut app, ctx, _, over, _) = distance_scene(true); + let run = |app: &mut VectorcraftApp, events, cover| distance_frame_covered(app, &ctx, events, cover); + run(&mut app, vec![egui::Event::PointerMoved(over)], None); + run(&mut app, vec![], None); + assert!(app.hover_doc.is_some(), "over the canvas"); + for cover in [Cover::Panel(egui::Rect::from_center_size(over, vec2(120.0, 120.0))), Cover::Dialog] { + run(&mut app, vec![], Some(cover)); + run(&mut app, vec![], Some(cover)); + assert_eq!(app.hover_doc, None, "under it"); + run(&mut app, vec![], None); + run(&mut app, vec![], None); + assert!(app.hover_doc.is_some(), "back once it closes"); + } +} + /// The 800 × 600 window [`frame`] draws the canvas in. const WINDOW: egui::Rect = egui::Rect { min: Pos2::ZERO, max: Pos2 { x: 800.0, y: 600.0 } }; From 8f5d14c7f704cdb769b6f9acc53131c3b3a1f81d Mon Sep 17 00:00:00 2001 From: bflatastic Date: Thu, 29 Oct 2026 19:26:36 +0700 Subject: [PATCH 2/3] Format --- crates/ui-egui/src/canvas.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/ui-egui/src/canvas.rs b/crates/ui-egui/src/canvas.rs index 29ff0a1ac..7f2856f48 100644 --- a/crates/ui-egui/src/canvas.rs +++ b/crates/ui-egui/src/canvas.rs @@ -358,10 +358,8 @@ fn canvas_input(app: &mut VectorcraftApp, ui: &Ui, resp: &egui::Response, rect: // showed through them: #4518), unless a drag that began on the canvas goes on there. let moved = Xf::new(rect, app.view().unwrap_or(&View::default())); let dragging = ui.data(|d| d.get_temp::(drag_id()).is_some()); - app.hover_doc = ui - .input(|i| i.pointer.hover_pos()) - .filter(|p| rect.contains(*p) && (dragging || drag::on_canvas(ui, resp, *p))) - .map(|p| moved.to_doc(p)); + app.hover_doc = + ui.input(|i| i.pointer.hover_pos()).filter(|p| rect.contains(*p) && (dragging || drag::on_canvas(ui, resp, *p))).map(|p| moved.to_doc(p)); } } From 536a98d17fe29ed118d79e4314335d82ab82f39b Mon Sep 17 00:00:00 2001 From: bflatastic Date: Thu, 29 Oct 2026 19:49:25 +0700 Subject: [PATCH 3/3] Tests: give the covering window its sizing pass --- crates/ui-egui/src/canvas/tests.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/ui-egui/src/canvas/tests.rs b/crates/ui-egui/src/canvas/tests.rs index 2d6abcbe0..4616338c1 100644 --- a/crates/ui-egui/src/canvas/tests.rs +++ b/crates/ui-egui/src/canvas/tests.rs @@ -7338,11 +7338,14 @@ fn a_panel_or_dialog_over_the_canvas_hides_the_pointer_from_it() { run(&mut app, vec![], None); assert!(app.hover_doc.is_some(), "over the canvas"); for cover in [Cover::Panel(egui::Rect::from_center_size(over, vec2(120.0, 120.0))), Cover::Dialog] { - run(&mut app, vec![], Some(cover)); - run(&mut app, vec![], Some(cover)); + // A new window takes a sizing pass before it covers anything, as in the test above. + for _ in 0..3 { + run(&mut app, vec![], Some(cover)); + } assert_eq!(app.hover_doc, None, "under it"); - run(&mut app, vec![], None); - run(&mut app, vec![], None); + for _ in 0..3 { + run(&mut app, vec![], None); + } assert!(app.hover_doc.is_some(), "back once it closes"); } }