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 <noreply@anthropic.com>
This commit is contained in:
parent
bcbda65746
commit
a9228b9021
4 changed files with 45 additions and 6 deletions
|
|
@ -767,6 +767,8 @@ pub enum Message {
|
||||||
ToggleSelectionCycling,
|
ToggleSelectionCycling,
|
||||||
/// Add an object from the selection-cycling list box to the selection.
|
/// Add an object from the selection-cycling list box to the selection.
|
||||||
CycleSelect(acadrust::Handle),
|
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.
|
/// Dismiss the selection-cycling list box without picking.
|
||||||
CycleCancel,
|
CycleCancel,
|
||||||
/// Toggle the selection-filter type picker open/closed.
|
/// Toggle the selection-filter type picker open/closed.
|
||||||
|
|
|
||||||
|
|
@ -3631,19 +3631,27 @@ impl OpenCADStudio {
|
||||||
Message::ToggleSelectionCycling => {
|
Message::ToggleSelectionCycling => {
|
||||||
self.selection_cycling ^= true;
|
self.selection_cycling ^= true;
|
||||||
self.cycle_candidates = None;
|
self.cycle_candidates = None;
|
||||||
|
self.tabs[self.active_tab].scene.set_hover_highlight(None);
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
Message::CycleSelect(handle) => {
|
Message::CycleSelect(handle) => {
|
||||||
// Add the picked object to the current selection (accumulate).
|
// Add the picked object to the current selection (accumulate).
|
||||||
self.cycle_candidates = None;
|
self.cycle_candidates = None;
|
||||||
let i = self.active_tab;
|
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.select_entity(handle, false);
|
||||||
self.tabs[i].scene.expand_selection_for_groups(&[handle]);
|
self.tabs[i].scene.expand_selection_for_groups(&[handle]);
|
||||||
self.refresh_properties();
|
self.refresh_properties();
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
Message::CycleHover(handle) => {
|
||||||
|
let i = self.active_tab;
|
||||||
|
self.tabs[i].scene.set_hover_highlight(handle);
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
Message::CycleCancel => {
|
Message::CycleCancel => {
|
||||||
self.cycle_candidates = None;
|
self.cycle_candidates = None;
|
||||||
|
self.tabs[self.active_tab].scene.set_hover_highlight(None);
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
Message::ToggleSelectionFilterPopup => {
|
Message::ToggleSelectionFilterPopup => {
|
||||||
|
|
|
||||||
|
|
@ -553,6 +553,9 @@ pub struct Scene {
|
||||||
/// `tessellate_block`'s visibility test skips these, so they neither
|
/// `tessellate_block`'s visibility test skips these, so they neither
|
||||||
/// render nor hit-test until isolation ends.
|
/// render nor hit-test until isolation ends.
|
||||||
pub hidden: HashSet<Handle>,
|
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
|
/// Whether entity transparency is honoured on screen. When false the
|
||||||
/// wire shader forces every line opaque (a uniform toggle, no retessellate).
|
/// wire shader forces every line opaque (a uniform toggle, no retessellate).
|
||||||
pub transparency_display: bool,
|
pub transparency_display: bool,
|
||||||
|
|
@ -704,6 +707,7 @@ impl Scene {
|
||||||
document: CadDocument::new(),
|
document: CadDocument::new(),
|
||||||
selected: HashSet::new(),
|
selected: HashSet::new(),
|
||||||
hidden: HashSet::new(),
|
hidden: HashSet::new(),
|
||||||
|
hover_highlight: None,
|
||||||
transparency_display: true,
|
transparency_display: true,
|
||||||
selection_filter: HashSet::new(),
|
selection_filter: HashSet::new(),
|
||||||
preview_wires: vec![],
|
preview_wires: vec![],
|
||||||
|
|
@ -1334,6 +1338,15 @@ impl Scene {
|
||||||
!self.hidden.is_empty()
|
!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).
|
/// Hide every drawable entity except the current selection (Isolate).
|
||||||
pub fn isolate_selected(&mut self) {
|
pub fn isolate_selected(&mut self) {
|
||||||
if self.selected.is_empty() {
|
if self.selected.is_empty() {
|
||||||
|
|
@ -2005,7 +2018,19 @@ impl Scene {
|
||||||
// Tessellate in parallel across all available CPU cores.
|
// Tessellate in parallel across all available CPU cores.
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
let doc = &self.document;
|
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;
|
let avp = self.active_viewport;
|
||||||
// A paper-space content viewport renders MODEL block entities while
|
// A paper-space content viewport renders MODEL block entities while
|
||||||
// the user is sitting in a paper layout — that path expects
|
// the user is sitting in a paper layout — that path expects
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ pub fn cycle_popup_overlay(
|
||||||
) -> Element<'static, Message> {
|
) -> Element<'static, Message> {
|
||||||
let rows: Vec<Element<'static, Message>> = items
|
let rows: Vec<Element<'static, Message>> = items
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(handle, label)| item_row(label, Message::CycleSelect(handle)))
|
.map(|(handle, label)| item_row(handle, label))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let panel = container(column(rows))
|
let panel = container(column(rows))
|
||||||
|
|
@ -43,10 +43,10 @@ pub fn cycle_popup_overlay(
|
||||||
mouse_area(positioned).on_press(Message::CycleCancel).into()
|
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);
|
let content = text(label).size(11).color(LABEL).align_y(iced::Center);
|
||||||
button(content)
|
let btn = button(content)
|
||||||
.on_press(msg)
|
.on_press(Message::CycleSelect(handle))
|
||||||
.style(|_: &Theme, status| button::Style {
|
.style(|_: &Theme, status| button::Style {
|
||||||
background: Some(Background::Color(match status {
|
background: Some(Background::Color(match status {
|
||||||
button::Status::Hovered => ROW_HOVER,
|
button::Status::Hovered => ROW_HOVER,
|
||||||
|
|
@ -55,7 +55,11 @@ fn item_row(label: String, msg: Message) -> Element<'static, Message> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.width(Fill)
|
.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()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue