forked from 1b-agent/opencadstudio-upstream
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:
1 parent
bcbda65746
commit
a9228b9021
4 files changed
+45
-6
No files matched your search
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user