Automation select: refuse handles inside block definitions

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
ramox81andClaude Opus 5.5 committed 2026-10-07 11:28:26 +03:00
1 parent d425a1d921
commit a1d59e5b17
1 file changed
+66 -13
+66 -13
View File
@@ -200,6 +200,42 @@ fn serve_socket_with_idle(
}
}
/// The entities inside block definitions: owned by (or listed in) a block
/// record that is not a layout's model or paper space.
fn definition_members(document: &codec::CadDocument) -> std::collections::HashSet<codec::Handle> {
let mut layouts: std::collections::HashSet<codec::Handle> = document
.objects
.values()
.filter_map(|object| match object {
codec::objects::ObjectType::Layout(layout) if !layout.block_record.is_null() => Some(layout.block_record),
_ => None,
})
.collect();
layouts.extend(document.block_records.iter().filter_map(|record| {
let name = record.name.to_ascii_uppercase();
(name.starts_with("*MODEL_SPACE") || name.starts_with("*PAPER_SPACE")).then_some(record.handle)
}));
let definitions: std::collections::HashSet<codec::Handle> = document
.block_records
.iter()
.filter(|record| !layouts.contains(&record.handle))
.map(|record| record.handle)
.collect();
let mut members: std::collections::HashSet<codec::Handle> = document
.block_records
.iter()
.filter(|record| definitions.contains(&record.handle))
.flat_map(|record| record.entity_handles.iter().copied())
.collect();
members.extend(
document
.entities()
.filter(|e| definitions.contains(&e.common().owner_handle))
.map(|e| e.common().handle),
);
members
}
fn err(msg: impl std::fmt::Display) -> Value {
json!({ "ok": false, "error": msg.to_string() })
}
@@ -794,21 +830,38 @@ impl OpenCADStudio {
}
"select" => {
let i = self.active_tab;
// By explicit handles (hex, as returned by `query`). An entity
// inside a block definition is not selectable on its own.
let explicit: Vec<codec::Handle> = req["handles"]
.as_array()
.map(|arr| {
arr.iter()
.filter_map(|h| h.as_str())
.filter_map(|h| {
let h = h.strip_prefix("0x").or_else(|| h.strip_prefix("0X")).unwrap_or(h);
u64::from_str_radix(h, 16).ok().map(codec::Handle::new)
})
.collect()
})
.unwrap_or_default();
if req["clear"].as_bool() != Some(true) {
let inside = definition_members(&self.tabs[i].scene.document);
let refused: Vec<String> = explicit
.iter()
.filter(|h| inside.contains(h))
.map(|h| format!("{:X}", h.value()))
.collect();
if !refused.is_empty() {
return err(format!(
"select: inside a block definition, not selectable: {}",
refused.join(", ")
));
}
}
self.tabs[i].scene.deselect_all();
if req["clear"].as_bool() != Some(true) {
// By explicit handles (hex, as returned by `query`).
if let Some(arr) = req["handles"].as_array() {
for h in arr.iter().filter_map(|h| h.as_str()) {
let h = h
.strip_prefix("0x")
.or_else(|| h.strip_prefix("0X"))
.unwrap_or(h);
if let Ok(v) = u64::from_str_radix(h, 16) {
self.tabs[i]
.scene
.select_entity(codec::Handle::new(v), false);
}
}
for h in explicit {
self.tabs[i].scene.select_entity(h, false);
}
// Or by type / layer.
let type_filter = req["type"].as_str();