fix(selection): individual picks accumulate; Shift+click removes
Single-click picking cleared the selection first (exclusive), so clicking a second object dropped the first (issue #47). Plain clicks now add to the selection and Shift+click removes the picked entity; empty-space click and Esc still clear. Shift state is tracked from keyboard ModifiersChanged events since mouse click messages carry no modifiers. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
e4668c66e7
commit
1b3760913e
4 changed files with 33 additions and 2 deletions
|
|
@ -246,6 +246,10 @@ pub(super) struct OpenCADStudio {
|
||||||
clipboard: Vec<acadrust::EntityType>,
|
clipboard: Vec<acadrust::EntityType>,
|
||||||
/// Centroid of the clipboard entities (XZ plane, Y-up).
|
/// Centroid of the clipboard entities (XZ plane, Y-up).
|
||||||
clipboard_centroid: glam::Vec3,
|
clipboard_centroid: glam::Vec3,
|
||||||
|
/// True while the Shift key is held — drives subtractive pick (Shift+click
|
||||||
|
/// removes the picked entity from the selection). Tracked from keyboard
|
||||||
|
/// modifier-change events since mouse click messages carry no modifiers.
|
||||||
|
shift_down: bool,
|
||||||
/// Which layout tab has its context menu open (None = closed).
|
/// Which layout tab has its context menu open (None = closed).
|
||||||
layout_context_menu: Option<String>,
|
layout_context_menu: Option<String>,
|
||||||
/// Inline rename state: (original_name, current_edit_value).
|
/// Inline rename state: (original_name, current_edit_value).
|
||||||
|
|
@ -702,6 +706,9 @@ pub enum Message {
|
||||||
/// Extend the current selection with every entity in the active
|
/// Extend the current selection with every entity in the active
|
||||||
/// layout that matches a selected entity by (type, layer).
|
/// layout that matches a selected entity by (type, layer).
|
||||||
SelectSimilar,
|
SelectSimilar,
|
||||||
|
/// Keyboard modifier state changed — tracks whether Shift is held so the
|
||||||
|
/// pick path can do subtractive (Shift+click) selection.
|
||||||
|
SetShiftDown(bool),
|
||||||
// ── Draw Order context menu ─────────────────────────────────────────
|
// ── Draw Order context menu ─────────────────────────────────────────
|
||||||
/// Toggle the Draw Order sub-items in the viewport context menu.
|
/// Toggle the Draw Order sub-items in the viewport context menu.
|
||||||
DrawOrderSubmenuToggle,
|
DrawOrderSubmenuToggle,
|
||||||
|
|
@ -941,6 +948,7 @@ impl OpenCADStudio {
|
||||||
update_notice_body: None,
|
update_notice_body: None,
|
||||||
clipboard: Vec::new(),
|
clipboard: Vec::new(),
|
||||||
clipboard_centroid: glam::Vec3::ZERO,
|
clipboard_centroid: glam::Vec3::ZERO,
|
||||||
|
shift_down: false,
|
||||||
layout_context_menu: None,
|
layout_context_menu: None,
|
||||||
layout_rename_state: None,
|
layout_rename_state: None,
|
||||||
last_vp_click_time: None,
|
last_vp_click_time: None,
|
||||||
|
|
|
||||||
|
|
@ -2782,8 +2782,16 @@ impl OpenCADStudio {
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
if let Some(handle) = hit {
|
if let Some(handle) = hit {
|
||||||
self.tabs[i].scene.select_entity(handle, true);
|
// Individual picks accumulate (issue #47):
|
||||||
self.tabs[i].scene.expand_selection_for_groups(&[handle]);
|
// each plain click adds to the selection,
|
||||||
|
// Shift+click removes the picked entity.
|
||||||
|
// Esc / empty-space click clears.
|
||||||
|
if self.shift_down {
|
||||||
|
self.tabs[i].scene.deselect_entity(handle);
|
||||||
|
} else {
|
||||||
|
self.tabs[i].scene.select_entity(handle, false);
|
||||||
|
self.tabs[i].scene.expand_selection_for_groups(&[handle]);
|
||||||
|
}
|
||||||
self.refresh_properties();
|
self.refresh_properties();
|
||||||
selection_just_completed = true;
|
selection_just_completed = true;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -3380,6 +3388,11 @@ impl OpenCADStudio {
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Message::SetShiftDown(down) => {
|
||||||
|
self.shift_down = down;
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
|
||||||
Message::DrawOrderSubmenuToggle => {
|
Message::DrawOrderSubmenuToggle => {
|
||||||
let i = self.active_tab;
|
let i = self.active_tab;
|
||||||
let mut sel = self.tabs[i].scene.selection.borrow_mut();
|
let mut sel = self.tabs[i].scene.selection.borrow_mut();
|
||||||
|
|
|
||||||
|
|
@ -995,6 +995,9 @@ impl OpenCADStudio {
|
||||||
iced::Event::Window(window::Event::Resized(sz)) => {
|
iced::Event::Window(window::Event::Resized(sz)) => {
|
||||||
Some(Message::WindowResized(sz.width as f32, sz.height as f32))
|
Some(Message::WindowResized(sz.width as f32, sz.height as f32))
|
||||||
}
|
}
|
||||||
|
iced::Event::Keyboard(keyboard::Event::ModifiersChanged(m)) => {
|
||||||
|
Some(Message::SetShiftDown(m.shift()))
|
||||||
|
}
|
||||||
iced::Event::Keyboard(keyboard::Event::KeyPressed {
|
iced::Event::Keyboard(keyboard::Event::KeyPressed {
|
||||||
key, modifiers, text, ..
|
key, modifiers, text, ..
|
||||||
}) => {
|
}) => {
|
||||||
|
|
|
||||||
|
|
@ -3808,6 +3808,13 @@ impl Scene {
|
||||||
self.bump_geometry();
|
self.bump_geometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove a single entity from the selection (Shift+click subtractive pick).
|
||||||
|
pub fn deselect_entity(&mut self, handle: Handle) {
|
||||||
|
if self.selected.remove(&handle) {
|
||||||
|
self.bump_geometry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn selected_entities(&self) -> Vec<(Handle, &EntityType)> {
|
pub fn selected_entities(&self) -> Vec<(Handle, &EntityType)> {
|
||||||
self.selected
|
self.selected
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue