feat(statusbar): highlight cycling-list object on row hover

Add a scene hover_highlight handle that renders an entity with the
selection colour without joining the real selection. The cycling list
box sets it on row enter / clears on exit, so hovering a row glows the
matching object in the drawing.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-06-05 00:00:52 +03:00
1 parent bcbda65746
commit a9228b9021
4 files changed
+45 -6

No files matched your search

+2
View File
@@ -767,6 +767,8 @@ pub enum Message {
ToggleSelectionCycling,
/// Add an object from the selection-cycling list box to the selection.
CycleSelect(acadrust::Handle),
/// Preview (highlight) a cycling-list row's object, or clear with `None`.
CycleHover(Option<acadrust::Handle>),
/// Dismiss the selection-cycling list box without picking.
CycleCancel,
/// Toggle the selection-filter type picker open/closed.
+8
View File
@@ -3631,19 +3631,27 @@ impl OpenCADStudio {
Message::ToggleSelectionCycling => {
self.selection_cycling ^= true;
self.cycle_candidates = None;
self.tabs[self.active_tab].scene.set_hover_highlight(None);
Task::none()
}
Message::CycleSelect(handle) => {
// Add the picked object to the current selection (accumulate).
self.cycle_candidates = None;
let i = self.active_tab;
self.tabs[i].scene.set_hover_highlight(None);
self.tabs[i].scene.select_entity(handle, false);
self.tabs[i].scene.expand_selection_for_groups(&[handle]);
self.refresh_properties();
Task::none()
}
Message::CycleHover(handle) => {
let i = self.active_tab;
self.tabs[i].scene.set_hover_highlight(handle);
Task::none()
}
Message::CycleCancel => {
self.cycle_candidates = None;
self.tabs[self.active_tab].scene.set_hover_highlight(None);
Task::none()
}
Message::ToggleSelectionFilterPopup => {
+26 -1
View File
@@ -553,6 +553,9 @@ pub struct Scene {
/// `tessellate_block`'s visibility test skips these, so they neither
/// render nor hit-test until isolation ends.
pub hidden: HashSet<Handle>,
/// Entity drawn with the selection-highlight colour without being part
/// of the real selection — used to preview a row in the cycling list box.
pub hover_highlight: Option<Handle>,
/// Whether entity transparency is honoured on screen. When false the
/// wire shader forces every line opaque (a uniform toggle, no retessellate).
pub transparency_display: bool,
@@ -704,6 +707,7 @@ impl Scene {
document: CadDocument::new(),
selected: HashSet::new(),
hidden: HashSet::new(),
hover_highlight: None,
transparency_display: true,
selection_filter: HashSet::new(),
preview_wires: vec![],
@@ -1334,6 +1338,15 @@ impl Scene {
!self.hidden.is_empty()
}
/// Set (or clear) the previewed entity that renders with the selection
/// highlight without joining the real selection. Re-tessellates on change.
pub fn set_hover_highlight(&mut self, handle: Option<Handle>) {
if self.hover_highlight != handle {
self.hover_highlight = handle;
self.bump_geometry();
}
}
/// Hide every drawable entity except the current selection (Isolate).
pub fn isolate_selected(&mut self) {
if self.selected.is_empty() {
@@ -2005,7 +2018,19 @@ impl Scene {
// Tessellate in parallel across all available CPU cores.
use rayon::prelude::*;
let doc = &self.document;
let sel = &self.selected;
// Fold the hover-preview entity into the highlight set so it renders
// selected without being part of the real selection.
let hl_set;
let sel: &HashSet<Handle> = if let Some(h) = self.hover_highlight {
hl_set = {
let mut s = self.selected.clone();
s.insert(h);
s
};
&hl_set
} else {
&self.selected
};
let avp = self.active_viewport;
// A paper-space content viewport renders MODEL block entities while
// the user is sitting in a paper layout — that path expects
+9 -5
View File
@@ -15,7 +15,7 @@ pub fn cycle_popup_overlay(
) -> Element<'static, Message> {
let rows: Vec<Element<'static, Message>> = items
.into_iter()
.map(|(handle, label)| item_row(label, Message::CycleSelect(handle)))
.map(|(handle, label)| item_row(handle, label))
.collect();
let panel = container(column(rows))
@@ -43,10 +43,10 @@ pub fn cycle_popup_overlay(
mouse_area(positioned).on_press(Message::CycleCancel).into()
}
fn item_row(label: String, msg: Message) -> Element<'static, Message> {
fn item_row(handle: acadrust::Handle, label: String) -> Element<'static, Message> {
let content = text(label).size(11).color(LABEL).align_y(iced::Center);
button(content)
.on_press(msg)
let btn = button(content)
.on_press(Message::CycleSelect(handle))
.style(|_: &Theme, status| button::Style {
background: Some(Background::Color(match status {
button::Status::Hovered => ROW_HOVER,
@@ -55,7 +55,11 @@ fn item_row(label: String, msg: Message) -> Element<'static, Message> {
..Default::default()
})
.width(Fill)
.padding([4, 10])
.padding([4, 10]);
// Highlight the underlying object while the cursor is over this row.
mouse_area(btn)
.on_enter(Message::CycleHover(Some(handle)))
.on_exit(Message::CycleHover(None))
.into()
}