feat(select): Select Similar + Quick Select panel (#28)
Two ways to extend the current selection by entity type + layer: * `Select Similar` (right-click → Select Similar, or `SELECTSIMILAR` / `SELSIM`): for every (type, layer) pair in the current selection, add every entity in the active layout that matches the pair. The seed selection stays selected; matches already selected are not double-counted. * `Quick Select` (right-click → Quick Select…, or `QSELECT` / `QS`): opens a centred floating panel with Object-type and Layer pick_lists (populated only with values that actually exist in the active layout) and an "Append to current selection" checkbox. `(Any)` in either slot skips that filter. Apply replaces the selection (or extends it with Append on) and reports the match count on the command line. Cancel, Esc, and outside-click all dismiss without applying. When opened with a selection present, the panel pre-fills both filters from the first selected entity so QSelect doubles as an editable Select Similar. Scoped to entities owned by the active layout's block-record so a paper layout's QSELECT never reaches into model-space entities (and vice versa). Entity-type names live in a single `entity_type_name` helper in `entities::traits` to keep the UI strings and the filter keys aligned. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
cf925be861
commit
9db206f310
6 changed files with 436 additions and 0 deletions
|
|
@ -1242,6 +1242,9 @@ impl OpenCADStudio {
|
|||
}
|
||||
// Cancel layout rename / context menus first, then fall through.
|
||||
let i_e = self.active_tab;
|
||||
if self.qselect.take().is_some() {
|
||||
return Task::none();
|
||||
}
|
||||
{
|
||||
let mut sel = self.tabs[i_e].scene.selection.borrow_mut();
|
||||
if sel.context_menu.is_some() {
|
||||
|
|
@ -3376,6 +3379,82 @@ impl OpenCADStudio {
|
|||
Task::none()
|
||||
}
|
||||
|
||||
Message::SelectSimilar => {
|
||||
let i = self.active_tab;
|
||||
self.tabs[i].scene.selection.borrow_mut().context_menu = None;
|
||||
let added = self.tabs[i].scene.select_similar();
|
||||
self.command_line
|
||||
.push_output(&format!("Select Similar: {} added.", added));
|
||||
self.refresh_properties();
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::QSelectOpen => {
|
||||
let i = self.active_tab;
|
||||
self.tabs[i].scene.selection.borrow_mut().context_menu = None;
|
||||
// Seed filters from the first selected entity (if any) so
|
||||
// a right-click → Quick Select on a known object pre-fills
|
||||
// the panel — same idea as Select Similar but exposes the
|
||||
// pairing for editing.
|
||||
let mut type_filter: Option<String> = None;
|
||||
let mut layer_filter: Option<String> = None;
|
||||
if let Some(&h) = self.tabs[i].scene.selected.iter().next() {
|
||||
if let Some(e) = self.tabs[i].scene.document.get_entity(h) {
|
||||
use crate::entities::traits::entity_type_name;
|
||||
type_filter = Some(entity_type_name(e).to_string());
|
||||
layer_filter = Some(e.as_entity().layer().to_string());
|
||||
}
|
||||
}
|
||||
self.qselect = Some(crate::app::QSelectState {
|
||||
type_filter,
|
||||
layer_filter,
|
||||
append: false,
|
||||
});
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::QSelectClose => {
|
||||
self.qselect = None;
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::QSelectSetType(t) => {
|
||||
if let Some(state) = self.qselect.as_mut() {
|
||||
state.type_filter = t;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::QSelectSetLayer(l) => {
|
||||
if let Some(state) = self.qselect.as_mut() {
|
||||
state.layer_filter = l;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::QSelectSetAppend(b) => {
|
||||
if let Some(state) = self.qselect.as_mut() {
|
||||
state.append = b;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::QSelectApply => {
|
||||
let Some(state) = self.qselect.take() else {
|
||||
return Task::none();
|
||||
};
|
||||
let i = self.active_tab;
|
||||
let matched = self.tabs[i].scene.qselect(
|
||||
state.type_filter.as_deref(),
|
||||
state.layer_filter.as_deref(),
|
||||
state.append,
|
||||
);
|
||||
self.command_line
|
||||
.push_output(&format!("QSELECT: {} object(s) selected.", matched));
|
||||
self.refresh_properties();
|
||||
Task::none()
|
||||
}
|
||||
|
||||
// ── Properties panel messages ─────────────────────────────────
|
||||
Message::PropSelectionGroupChanged(group) => {
|
||||
self.tabs[self.active_tab].properties.selected_group = Some(group);
|
||||
|
|
|
|||
Loading…
Reference in a new issue