ATTSYNC: rebuild attributes from the definitions

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ramox81andClaude Opus 5.5 committed 2026-10-14 17:32:44 +03:00
1 parent d583d9d421
commit eaa44cccc1
1 file changed
+37 -18
+37 -18
View File
@@ -160,13 +160,16 @@ impl OpenCADStudio {
glam::DVec3::new(base.x, base.y, base.z) glam::DVec3::new(base.x, base.y, base.z)
} }
/// Reconcile every editable reference of `block` with the block's /// Rebuild the attributes of every editable reference of `block` from the
/// attribute definitions: attributes whose tag is gone are dropped, new /// block's attribute definitions, in their order: each attribute takes
/// ones are added with their default value, and the values of the rest /// its definition's placement and text settings through the reference's
/// are kept. /// transform, keeps the value it had (new ones take the default), and
/// attributes whose definition is gone are dropped. Constant definitions
/// carry no attribute.
pub(in crate::app) fn attsync_block(&mut self, i: usize, block: &str) { pub(in crate::app) fn attsync_block(&mut self, i: usize, block: &str) {
use codec::Entity as _;
let doc = &self.tabs[i].scene.document; let doc = &self.tabs[i].scene.document;
let attdefs: Vec<(String, String)> = doc let attdefs: Vec<codec::entities::AttributeDefinition> = doc
.block_records .block_records
.get(block) .get(block)
.map(|br| { .map(|br| {
@@ -174,14 +177,15 @@ impl OpenCADStudio {
.iter() .iter()
.filter_map(|h| doc.get_entity(*h)) .filter_map(|h| doc.get_entity(*h))
.filter_map(|e| match e { .filter_map(|e| match e {
codec::EntityType::AttributeDefinition(a) => { codec::EntityType::AttributeDefinition(a) if !a.flags.constant => {
Some((a.tag.clone(), a.default_value.clone())) Some(a.clone())
} }
_ => None, _ => None,
}) })
.collect() .collect()
}) })
.unwrap_or_default(); .unwrap_or_default();
let base = crate::scene::render_graph::block_base_point(doc, block);
let inserts: Vec<_> = doc let inserts: Vec<_> = doc
.entities() .entities()
.filter_map(|entity| match entity { .filter_map(|entity| match entity {
@@ -200,22 +204,37 @@ impl OpenCADStudio {
self.push_undo_snapshot(i, "ATTSYNC"); self.push_undo_snapshot(i, "ATTSYNC");
let mut changes = Vec::new(); let mut changes = Vec::new();
for handle in inserts { for handle in inserts {
let Some(codec::EntityType::Insert(ins)) = let Some(codec::EntityType::Insert(ins)) = self.tabs[i].scene.document.get_entity(handle)
self.tabs[i].scene.document.get_entity_mut(handle)
else { else {
continue; continue;
}; };
ins.attributes let transform = crate::scene::render_graph::insert_transform_with_base(ins, base);
.retain(|a| attdefs.iter().any(|(t, _)| t.eq_ignore_ascii_case(&a.tag))); let mut rebuilt = Vec::with_capacity(attdefs.len());
for (tag, default) in &attdefs { for def in &attdefs {
if !ins.attributes.iter().any(|a| a.tag.eq_ignore_ascii_case(tag)) { let previous = ins
ins.attributes.push(codec::entities::AttributeEntity::new( .attributes
tag.clone(), .iter()
default.clone(), .find(|a| a.tag.eq_ignore_ascii_case(&def.tag));
)); let mut attribute = codec::entities::AttributeEntity::from_definition(
def,
previous.map(|a| a.value.clone()),
);
attribute.apply_transform(&transform);
attribute.common.handle = previous.map_or(codec::Handle::NULL, |a| a.common.handle);
attribute.common.owner_handle = handle;
rebuilt.push(attribute);
}
for attribute in &mut rebuilt {
if attribute.common.handle.is_null() {
attribute.common.handle = self.tabs[i].scene.document.allocate_handle();
} }
} }
changes.push((ins.common.handle, crate::scene::ChangeKind::Modified)); if let Some(codec::EntityType::Insert(ins)) =
self.tabs[i].scene.document.get_entity_mut(handle)
{
ins.attributes = rebuilt;
changes.push((handle, crate::scene::ChangeKind::Modified));
}
} }
self.tabs[i].scene.bump_entities(&changes); self.tabs[i].scene.bump_entities(&changes);
self.tabs[i].dirty = true; self.tabs[i].dirty = true;