feat(attedit): enhanced attribute editor with 3 tabs

Grow the attribute editor into a three-tab enhanced editor:
- Attribute: the tag/prompt/value list; click a row to select it, edit
  its value below.
- Text Options: the selected attribute's Text Style, Justification,
  Height, Rotation, Width Factor, Oblique Angle, Backwards, Upside down.
- Properties: the selected attribute's Layer, Linetype, Color,
  Lineweight (the colour list also surfaces a non-standard current
  colour so it displays and round-trips).

Applying writes value, text-formatting and common-property edits back to
each attribute positionally (guarded on block name + count), with undo
and a repaint. OK/Cancel are replaced by a single Apply button in a top
toolbar that commits but keeps the dialog open, matching the other modal
windows — the frame ✕ closes and discards un-applied edits. The frame
adopts the shared style-window palette, tab styling and sizing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan Seven 2026-07-01 09:06:03 +03:00
commit 0b60bcc075
6 changed files with 717 additions and 165 deletions

View file

@ -1363,7 +1363,7 @@ impl OpenCADStudio {
OverwriteWarning => (420, 180),
SaveDialog => (560, 480),
PointStyle => (360, 470),
AttributeEditor => (460, 440),
AttributeEditor => (640, 500),
};
Some((w as f32 + EXTRA_W, h as f32 + EXTRA_H))
}

View file

@ -511,14 +511,36 @@ impl OpenCADStudio {
360,
470,
),
super::super::ModalKind::AttributeEditor => sized(
crate::ui::window::attribute_editor::view_window(
&self.attr_editor_block,
&self.attr_editor_fields,
),
460,
440,
),
super::super::ModalKind::AttributeEditor => {
let doc = &self.tabs[self.active_tab].scene.document;
let layers: Vec<String> = doc.layers.iter().map(|l| l.name.clone()).collect();
let mut linetypes: Vec<String> = vec!["ByLayer".to_string()];
linetypes.extend(
doc.line_types
.iter()
.map(|lt| lt.name.clone())
.filter(|n| !n.is_empty() && n != "ByLayer"),
);
let styles: Vec<String> = doc
.text_styles
.iter()
.map(|s| s.name.trim().to_string())
.filter(|n| !n.is_empty())
.collect();
sized(
crate::ui::window::attribute_editor::view_window(
&self.attr_editor_block,
&self.attr_editor_rows,
self.attr_editor_selected,
self.attr_editor_tab,
layers,
linetypes,
styles,
),
640,
500,
)
}
super::super::ModalKind::SaveDialog => sized(
save_as_dialog_window(
&self.save_dialog_filename,