feat(properties): show & edit block attributes in panel

Selecting an INSERT with attributes now adds an editable "Attributes"
section to the Properties panel — each tag is a row whose value can be
changed inline (Enter commits, undo works, the attribute text repaints).
Previously attribute values could only be reached through ATTEDIT, which
didn't let them be changed (#192).

Attribute tags are runtime strings, so they can't ride the geometry
edit path whose field key is `&'static str`; a dedicated PropValue::
AttrText variant plus PropAttrInput/PropAttrCommit messages carry the
tag. Values are stored verbatim (no expression evaluation, since
attribute text is free-form).

Also guard the panel's in-progress edit buffer: it now only carries
across a rebuild when the selection is unchanged (a commit-triggered
refresh), so a typed-but-uncommitted value can't display or commit onto
a different entity — e.g. two title blocks sharing a REV1 tag. This
closes a latent stale-buffer leak that affected geometry fields too.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-07-01 07:42:50 +03:00
1 parent 3da81571a1
commit 5f2e920b75
7 files changed
+133 -1

No files matched your search

+37 -1
View File
@@ -15,6 +15,9 @@ impl OpenCADStudio {
// closes, matching the deselect / reselect / click-away expectation.
let color_palette_open = self.tabs[i].properties.color_palette_open;
let edit_buf = std::mem::take(&mut self.tabs[i].properties.edit_buf);
// Which entities the previous panel was built for — an uncommitted
// edit buffer only survives a rebuild for the *same* selection.
let prev_handles = std::mem::take(&mut self.tabs[i].properties.source_handles);
let selected_group = self.tabs[i].properties.selected_group.clone();
// Seed the per-thread unit context from the document header so the
@@ -207,6 +210,30 @@ impl OpenCADStudio {
}
}
// Block attributes: expose each attribute tag as an
// editable value row so a block reference's attributes can
// be read and changed directly from the panel.
if let acadrust::EntityType::Insert(ins) = entity {
if !ins.attributes.is_empty() {
let props = ins
.attributes
.iter()
.map(|a| crate::scene::model::object::Property {
label: a.tag.clone(),
field: "attr",
value: crate::scene::model::object::PropValue::AttrText {
tag: a.tag.clone(),
value: a.get_value().to_string(),
},
})
.collect();
sections.push(crate::scene::model::object::PropSection {
title: "Attributes".to_string(),
props,
});
}
}
if !group_names.is_empty() {
let label = group_names.join(", ");
if let Some(general) = sections.first_mut() {
@@ -310,7 +337,16 @@ impl OpenCADStudio {
}
};
panel.color_palette_open = color_palette_open;
panel.edit_buf = edit_buf;
let new_handles: Vec<acadrust::Handle> = selected.iter().map(|(h, _)| *h).collect();
// Carry the in-progress edits only when the selection is unchanged
// (a commit-triggered rebuild); a genuine selection change starts
// with a clean buffer so no stale value leaks onto the new entity.
panel.edit_buf = if prev_handles == new_handles {
edit_buf
} else {
Default::default()
};
panel.source_handles = new_handles;
panel
};