From db8c5dc43f82d13d14b610353c07bf2de12695df Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Fri, 5 Jun 2026 10:15:23 +0300 Subject: [PATCH] feat(scene): rollover highlight for the entity under the cursor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that selection/hover are decoupled from tessellation, highlighting the entity under the cursor only refreshes the GPU xray overlay — no re-tessellation — so a general rollover is cheap. On an idle ViewportMove (no active command, no drag) hit-test at the cursor and set_hover_highlight the result; clear it during commands/drags and on ViewportExit so it doesn't stick over the ribbon. hit_test_wires is the cached entity-wire Arc, so the per-move cost is just the existing click_hit projection — the same the command-hover path already pays. Co-Authored-By: Claude Opus 4.8 --- src/app/update.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/app/update.rs b/src/app/update.rs index ff99976cc..fb165dba2 100644 --- a/src/app/update.rs +++ b/src/app/update.rs @@ -2180,6 +2180,27 @@ impl OpenCADStudio { self.tabs[i].last_cursor_world = world; } + // Rollover highlight: when idle (no active command, no drag), + // highlight the entity under the cursor. Decoupling selection + // from tessellation makes this cheap — it only refreshes the GPU + // xray overlay via `bump_selection`, never re-tessellates. + if !dragging && self.tabs[i].active_cmd.is_none() { + let bounds = iced::Rectangle { + x: 0.0, + y: 0.0, + width: vp_size.0, + height: vp_size.1, + }; + let view_proj = self.tabs[i].scene.camera.borrow().view_proj(bounds); + let all_wires = self.tabs[i].scene.hit_test_wires(); + let hovered = scene::hit_test::click_hit(p, &all_wires[..], view_proj, bounds) + .and_then(|s| Scene::handle_from_wire_name(s)); + self.tabs[i].scene.set_hover_highlight(hovered); + } else { + // Suppress the rollover during a command or a drag. + self.tabs[i].scene.set_hover_highlight(None); + } + if self.tabs[i].active_cmd.is_some() { let (vw, vh) = vp_size; let bounds = iced::Rectangle { @@ -2375,6 +2396,11 @@ impl OpenCADStudio { sel.poly_active = false; sel.poly_points.clear(); sel.poly_crossing = false; + drop(sel); + // Clear the rollover highlight when the cursor leaves the + // viewport so it doesn't stick while the mouse is over the + // ribbon / panels. + self.tabs[i].scene.set_hover_highlight(None); // Don't touch `context_menu` here. ViewportExit also fires // when an upper overlay (the right-click menu panel) takes // the cursor, so clearing the menu state on every exit