feat(select): invert selection from the right-click menu
Add an Invert Selection entry to the selection context menu (below Select Similar): it replaces the current selection with every other selectable object in the active layout. Candidates come from the visible wire set, so objects on off/frozen layers stay excluded. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
e562738d9e
commit
fd15dd0aac
4 changed files with 38 additions and 0 deletions
|
|
@ -1289,6 +1289,9 @@ pub enum Message {
|
|||
/// Extend the current selection with every entity in the active
|
||||
/// layout that matches a selected entity by (type, layer).
|
||||
SelectSimilar,
|
||||
/// Replace the current selection with every other selectable object in
|
||||
/// the active layout (the complement of what's selected now).
|
||||
InvertSelection,
|
||||
/// Keyboard modifier state changed — tracks whether Shift is held so the
|
||||
/// pick path can do subtractive (Shift+click) selection.
|
||||
SetShiftDown(bool),
|
||||
|
|
|
|||
|
|
@ -4971,6 +4971,16 @@ impl OpenCADStudio {
|
|||
Task::none()
|
||||
}
|
||||
|
||||
Message::InvertSelection => {
|
||||
let i = self.active_tab;
|
||||
self.tabs[i].scene.selection.borrow_mut().context_menu = None;
|
||||
let count = self.tabs[i].scene.invert_selection();
|
||||
self.command_line
|
||||
.push_output(&format!("Invert Selection: {} object(s) selected.", count));
|
||||
self.refresh_properties();
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::QSelectOpen => {
|
||||
let i = self.active_tab;
|
||||
self.tabs[i].scene.selection.borrow_mut().context_menu = None;
|
||||
|
|
|
|||
|
|
@ -2907,6 +2907,10 @@ fn viewport_context_menu_overlay(
|
|||
));
|
||||
items.push(sep());
|
||||
items.push(item("Select Similar".to_string(), Message::SelectSimilar));
|
||||
items.push(item(
|
||||
"Invert Selection".to_string(),
|
||||
Message::InvertSelection,
|
||||
));
|
||||
}
|
||||
if isolation_active {
|
||||
items.push(item(
|
||||
|
|
|
|||
|
|
@ -4896,6 +4896,27 @@ impl Scene {
|
|||
added
|
||||
}
|
||||
|
||||
/// Replace the selection with its complement: every selectable object
|
||||
/// in the active layout that isn't currently selected. The candidate
|
||||
/// set is the visible wire set, so objects on off/frozen layers (which
|
||||
/// can't be picked anyway) are excluded. Returns the new count.
|
||||
pub fn invert_selection(&mut self) -> usize {
|
||||
let prev: rustc_hash::FxHashSet<Handle> = self.selected.iter().copied().collect();
|
||||
let all: Vec<Handle> = self
|
||||
.entity_wires()
|
||||
.iter()
|
||||
.filter_map(|w| Self::handle_from_wire_name(&w.name))
|
||||
.collect();
|
||||
self.selected.clear();
|
||||
for h in all {
|
||||
if !prev.contains(&h) {
|
||||
self.selected.insert(h);
|
||||
}
|
||||
}
|
||||
self.bump_selection();
|
||||
self.selected.len()
|
||||
}
|
||||
|
||||
/// Replaces (or extends, when `append` is true) the current
|
||||
/// selection with every entity in the active layout that matches
|
||||
/// the filter. Returns the number of newly-matching entities.
|
||||
|
|
|
|||
Loading…
Reference in a new issue