feat(attedit): attribute editor dialog for blocks

Double-clicking a block reference that has attributes, or running ATTEDIT
on one, now opens an editor dialog listing every attribute (tag + editable
value) with OK / Cancel. OK writes the values back to the block, with undo
and a repaint; Cancel discards. A block with no attributes still enters
in-place block edit (REFEDIT) on double-click as before. (#192)

ATTEDIT opens the dialog directly when a suitable block is already
selected; otherwise it runs the pick command and the dialog opens once a
block is chosen. This replaces the earlier command-line, per-attribute
prompt flow, which is removed along with its __ATTEDIT__ sentinel path and
the now-unused attedit_set_attrs trait hook; the ATTEDIT command is reduced
to a plain block picker.

The dialog is a tab-scoped in-canvas modal (Plan B): its working copy holds
a document-local handle, so closing that tab or switching away dismisses the
editor rather than risk applying edits to another tab's document.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan Seven 2026-07-01 08:05:25 +03:00
commit 86a59d6c7e
12 changed files with 346 additions and 192 deletions

View file

@ -196,13 +196,33 @@ impl OpenCADStudio {
self.tabs[i].active_cmd = Some(Box::new(cmd_obj));
}
// Bare ATTEDIT (and the ATE alias) launch the interactive attribute
// editor; the command-line -ATTEDIT form is handled in the draw family.
// Bare ATTEDIT (and the ATE alias) open the attribute editor dialog.
// If a single block with attributes is already selected it opens on
// that block; otherwise the pick command runs and the editor opens
// once a block is chosen (see `command_driver`).
"ATTEDIT" | "ATE" => {
use crate::modules::draw::modify::attedit::AtteditCommand;
let cmd_obj = AtteditCommand::new();
self.command_line.push_info(&cmd_obj.prompt());
self.tabs[i].active_cmd = Some(Box::new(cmd_obj));
let selected_attr_insert = {
let sel = self.tabs[i].scene.selected_entities();
if sel.len() == 1 {
let (h, e) = sel[0];
match e {
acadrust::EntityType::Insert(ins) if !ins.attributes.is_empty() => {
Some(h)
}
_ => None,
}
} else {
None
}
};
if let Some(handle) = selected_attr_insert {
self.open_attribute_editor(handle);
} else {
use crate::modules::draw::modify::attedit::AtteditCommand;
let cmd_obj = AtteditCommand::new();
self.command_line.push_info(&cmd_obj.prompt());
self.tabs[i].active_cmd = Some(Box::new(cmd_obj));
}
}
// ── REFEDIT — in-place block editing ─────────────────────────────