ATTDEF dialog error band and multi-line editor; ATTDISP sets ATTMODE

Validation messages show in the dialogs, the Default value of a multi-line
definition can be edited in the multi-line text editor, "Specify on-screen"
is kept for the session, ATTDISP sets ATTMODE with the reference prompt
instead of changing the definitions, and Insert > Block gets the Edit
Attribute (Single / Multiple) and attribute display lists.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ramox81andClaude Opus 5.5 committed 2026-10-01 17:11:45 +03:00
1 parent c992b73cdf
commit 7f55043210
29 files changed
+449 -70

No files matched your search

+9
View File
@@ -4044,6 +4044,15 @@ insert =
.attdef-define-attributes = Define Attributes
.attdef-manage-attributes = Manage Attributes
.attdef-set-base-point = Set Base Point
.attdef-attmode-retain = Retain Attribute Display
.attdef-attmode-all = Display All Attributes
.attdef-attmode-none = Hide All Attributes
.attdef-edit-attribute = Edit Attribute
.attdef-multiline-editor = Multiline editor
.attdef-tag-empty = The tag cannot be empty.
.attdef-tag-spaces = The tag may not contain spaces.
.attdef-positive = Value must be positive and nonzero.
.attdef-angle = Requires valid numeric angle or second point.
model =
.create = إنشاء
.boolean = عمليات منطقية
+9
View File
@@ -4031,6 +4031,15 @@ insert =
.attdef-define-attributes = Define Attributes
.attdef-manage-attributes = Manage Attributes
.attdef-set-base-point = Set Base Point
.attdef-attmode-retain = Retain Attribute Display
.attdef-attmode-all = Display All Attributes
.attdef-attmode-none = Hide All Attributes
.attdef-edit-attribute = Edit Attribute
.attdef-multiline-editor = Multiline editor
.attdef-tag-empty = The tag cannot be empty.
.attdef-tag-spaces = The tag may not contain spaces.
.attdef-positive = Value must be positive and nonzero.
.attdef-angle = Requires valid numeric angle or second point.
model =
.create = Създаване
.boolean = Булеви операции
+9
View File
@@ -4029,6 +4029,15 @@ insert =
.attdef-define-attributes = Define Attributes
.attdef-manage-attributes = Manage Attributes
.attdef-set-base-point = Set Base Point
.attdef-attmode-retain = Retain Attribute Display
.attdef-attmode-all = Display All Attributes
.attdef-attmode-none = Hide All Attributes
.attdef-edit-attribute = Edit Attribute
.attdef-multiline-editor = Multiline editor
.attdef-tag-empty = The tag cannot be empty.
.attdef-tag-spaces = The tag may not contain spaces.
.attdef-positive = Value must be positive and nonzero.
.attdef-angle = Requires valid numeric angle or second point.
model =
.create = Vytvořit
.boolean = Booleovské operace
+9
View File
@@ -4030,6 +4030,15 @@ insert =
.attdef-define-attributes = Define Attributes
.attdef-manage-attributes = Manage Attributes
.attdef-set-base-point = Set Base Point
.attdef-attmode-retain = Retain Attribute Display
.attdef-attmode-all = Display All Attributes
.attdef-attmode-none = Hide All Attributes
.attdef-edit-attribute = Edit Attribute
.attdef-multiline-editor = Multiline editor
.attdef-tag-empty = The tag cannot be empty.
.attdef-tag-spaces = The tag may not contain spaces.
.attdef-positive = Value must be positive and nonzero.
.attdef-angle = Requires valid numeric angle or second point.
model =
.create = Erstellen
.boolean = Boolesche Operationen
+9
View File
@@ -4032,6 +4032,15 @@ insert =
.attdef-define-attributes = Define Attributes
.attdef-manage-attributes = Manage Attributes
.attdef-set-base-point = Set Base Point
.attdef-attmode-retain = Retain Attribute Display
.attdef-attmode-all = Display All Attributes
.attdef-attmode-none = Hide All Attributes
.attdef-edit-attribute = Edit Attribute
.attdef-multiline-editor = Multiline editor
.attdef-tag-empty = The tag cannot be empty.
.attdef-tag-spaces = The tag may not contain spaces.
.attdef-positive = Value must be positive and nonzero.
.attdef-angle = Requires valid numeric angle or second point.
model =
.create = Δημιουργία
.boolean = Δυαδική πράξη
+9
View File
@@ -4033,6 +4033,15 @@ insert =
.attdef-define-attributes = Define Attributes
.attdef-manage-attributes = Manage Attributes
.attdef-set-base-point = Set Base Point
.attdef-attmode-retain = Retain Attribute Display
.attdef-attmode-all = Display All Attributes
.attdef-attmode-none = Hide All Attributes
.attdef-edit-attribute = Edit Attribute
.attdef-multiline-editor = Multiline editor
.attdef-tag-empty = The tag cannot be empty.
.attdef-tag-spaces = The tag may not contain spaces.
.attdef-positive = Value must be positive and nonzero.
.attdef-angle = Requires valid numeric angle or second point.
model =
.create = Create
.boolean = Boolean
+9
View File
@@ -4032,6 +4032,15 @@ insert =
.attdef-define-attributes = Define Attributes
.attdef-manage-attributes = Manage Attributes
.attdef-set-base-point = Set Base Point
.attdef-attmode-retain = Retain Attribute Display
.attdef-attmode-all = Display All Attributes
.attdef-attmode-none = Hide All Attributes
.attdef-edit-attribute = Edit Attribute
.attdef-multiline-editor = Multiline editor
.attdef-tag-empty = The tag cannot be empty.
.attdef-tag-spaces = The tag may not contain spaces.
.attdef-positive = Value must be positive and nonzero.
.attdef-angle = Requires valid numeric angle or second point.
model =
.create = Crear
.boolean = Booleanas
+9
View File
@@ -4031,6 +4031,15 @@ insert =
.attdef-define-attributes = Define Attributes
.attdef-manage-attributes = Manage Attributes
.attdef-set-base-point = Set Base Point
.attdef-attmode-retain = Retain Attribute Display
.attdef-attmode-all = Display All Attributes
.attdef-attmode-none = Hide All Attributes
.attdef-edit-attribute = Edit Attribute
.attdef-multiline-editor = Multiline editor
.attdef-tag-empty = The tag cannot be empty.
.attdef-tag-spaces = The tag may not contain spaces.
.attdef-positive = Value must be positive and nonzero.
.attdef-angle = Requires valid numeric angle or second point.
model =
.create = Luo
.boolean = Boolen operaatiot
+9
View File
@@ -4032,6 +4032,15 @@ insert =
.attdef-define-attributes = Define Attributes
.attdef-manage-attributes = Manage Attributes
.attdef-set-base-point = Set Base Point
.attdef-attmode-retain = Retain Attribute Display
.attdef-attmode-all = Display All Attributes
.attdef-attmode-none = Hide All Attributes
.attdef-edit-attribute = Edit Attribute
.attdef-multiline-editor = Multiline editor
.attdef-tag-empty = The tag cannot be empty.
.attdef-tag-spaces = The tag may not contain spaces.
.attdef-positive = Value must be positive and nonzero.
.attdef-angle = Requires valid numeric angle or second point.
model =
.create = Créer
.boolean = Opérations booléennes
+9
View File
@@ -4020,6 +4020,15 @@ insert =
.attdef-define-attributes = Define Attributes
.attdef-manage-attributes = Manage Attributes
.attdef-set-base-point = Set Base Point
.attdef-attmode-retain = Retain Attribute Display
.attdef-attmode-all = Display All Attributes
.attdef-attmode-none = Hide All Attributes
.attdef-edit-attribute = Edit Attribute
.attdef-multiline-editor = Multiline editor
.attdef-tag-empty = The tag cannot be empty.
.attdef-tag-spaces = The tag may not contain spaces.
.attdef-positive = Value must be positive and nonzero.
.attdef-angle = Requires valid numeric angle or second point.
model =
.create = बनाएँ
.boolean = बूलियन संक्रियाएँ
+9
View File
@@ -4031,6 +4031,15 @@ insert =
.attdef-define-attributes = Define Attributes
.attdef-manage-attributes = Manage Attributes
.attdef-set-base-point = Set Base Point
.attdef-attmode-retain = Retain Attribute Display
.attdef-attmode-all = Display All Attributes
.attdef-attmode-none = Hide All Attributes
.attdef-edit-attribute = Edit Attribute
.attdef-multiline-editor = Multiline editor
.attdef-tag-empty = The tag cannot be empty.
.attdef-tag-spaces = The tag may not contain spaces.
.attdef-positive = Value must be positive and nonzero.
.attdef-angle = Requires valid numeric angle or second point.
model =
.create = Létrehozás
.boolean = Logikai műveletek
+9
View File
@@ -4031,6 +4031,15 @@ insert =
.attdef-define-attributes = Define Attributes
.attdef-manage-attributes = Manage Attributes
.attdef-set-base-point = Set Base Point
.attdef-attmode-retain = Retain Attribute Display
.attdef-attmode-all = Display All Attributes
.attdef-attmode-none = Hide All Attributes
.attdef-edit-attribute = Edit Attribute
.attdef-multiline-editor = Multiline editor
.attdef-tag-empty = The tag cannot be empty.
.attdef-tag-spaces = The tag may not contain spaces.
.attdef-positive = Value must be positive and nonzero.
.attdef-angle = Requires valid numeric angle or second point.
model =
.create = Crea
.boolean = Operazioni booleane
+9
View File
@@ -4020,6 +4020,15 @@ insert =
.attdef-define-attributes = Define Attributes
.attdef-manage-attributes = Manage Attributes
.attdef-set-base-point = Set Base Point
.attdef-attmode-retain = Retain Attribute Display
.attdef-attmode-all = Display All Attributes
.attdef-attmode-none = Hide All Attributes
.attdef-edit-attribute = Edit Attribute
.attdef-multiline-editor = Multiline editor
.attdef-tag-empty = The tag cannot be empty.
.attdef-tag-spaces = The tag may not contain spaces.
.attdef-positive = Value must be positive and nonzero.
.attdef-angle = Requires valid numeric angle or second point.
model =
.create = 作成
.boolean = ブール演算
+9
View File
@@ -4031,6 +4031,15 @@ insert =
.attdef-define-attributes = Define Attributes
.attdef-manage-attributes = Manage Attributes
.attdef-set-base-point = Set Base Point
.attdef-attmode-retain = Retain Attribute Display
.attdef-attmode-all = Display All Attributes
.attdef-attmode-none = Hide All Attributes
.attdef-edit-attribute = Edit Attribute
.attdef-multiline-editor = Multiline editor
.attdef-tag-empty = The tag cannot be empty.
.attdef-tag-spaces = The tag may not contain spaces.
.attdef-positive = Value must be positive and nonzero.
.attdef-angle = Requires valid numeric angle or second point.
model =
.create = 생성
.boolean = 불리언 연산
+9
View File
@@ -4030,6 +4030,15 @@ insert =
.attdef-define-attributes = Define Attributes
.attdef-manage-attributes = Manage Attributes
.attdef-set-base-point = Set Base Point
.attdef-attmode-retain = Retain Attribute Display
.attdef-attmode-all = Display All Attributes
.attdef-attmode-none = Hide All Attributes
.attdef-edit-attribute = Edit Attribute
.attdef-multiline-editor = Multiline editor
.attdef-tag-empty = The tag cannot be empty.
.attdef-tag-spaces = The tag may not contain spaces.
.attdef-positive = Value must be positive and nonzero.
.attdef-angle = Requires valid numeric angle or second point.
model =
.create = Maken
.boolean = Booleaanse bewerkingen
+9
View File
@@ -4031,6 +4031,15 @@ insert =
.attdef-define-attributes = Define Attributes
.attdef-manage-attributes = Manage Attributes
.attdef-set-base-point = Set Base Point
.attdef-attmode-retain = Retain Attribute Display
.attdef-attmode-all = Display All Attributes
.attdef-attmode-none = Hide All Attributes
.attdef-edit-attribute = Edit Attribute
.attdef-multiline-editor = Multiline editor
.attdef-tag-empty = The tag cannot be empty.
.attdef-tag-spaces = The tag may not contain spaces.
.attdef-positive = Value must be positive and nonzero.
.attdef-angle = Requires valid numeric angle or second point.
model =
.create = Utwórz
.boolean = Operacje boolowskie
+9
View File
@@ -4032,6 +4032,15 @@ insert =
.attdef-define-attributes = Define Attributes
.attdef-manage-attributes = Manage Attributes
.attdef-set-base-point = Set Base Point
.attdef-attmode-retain = Retain Attribute Display
.attdef-attmode-all = Display All Attributes
.attdef-attmode-none = Hide All Attributes
.attdef-edit-attribute = Edit Attribute
.attdef-multiline-editor = Multiline editor
.attdef-tag-empty = The tag cannot be empty.
.attdef-tag-spaces = The tag may not contain spaces.
.attdef-positive = Value must be positive and nonzero.
.attdef-angle = Requires valid numeric angle or second point.
model =
.create = Criar
.boolean = Operações booleanas
+9
View File
@@ -4033,6 +4033,15 @@ insert =
.attdef-define-attributes = Define Attributes
.attdef-manage-attributes = Manage Attributes
.attdef-set-base-point = Set Base Point
.attdef-attmode-retain = Retain Attribute Display
.attdef-attmode-all = Display All Attributes
.attdef-attmode-none = Hide All Attributes
.attdef-edit-attribute = Edit Attribute
.attdef-multiline-editor = Multiline editor
.attdef-tag-empty = The tag cannot be empty.
.attdef-tag-spaces = The tag may not contain spaces.
.attdef-positive = Value must be positive and nonzero.
.attdef-angle = Requires valid numeric angle or second point.
model =
.create = Создание
.boolean = Булевы операции
+9
View File
@@ -3992,6 +3992,15 @@ insert =
.attdef-define-attributes = Öznitelik Tanımla
.attdef-manage-attributes = Öznitelikleri Yönet
.attdef-set-base-point = Taban Noktası Belirle
.attdef-attmode-retain = Öznitelik görünümünü koru
.attdef-attmode-all = Tüm öznitelikleri göster
.attdef-attmode-none = Tüm öznitelikleri gizle
.attdef-edit-attribute = Öznitelik Düzenle
.attdef-multiline-editor = Çok satırlı düzenleyici
.attdef-tag-empty = Etiket boş olamaz.
.attdef-tag-spaces = Etiket boşluk içeremez.
.attdef-positive = Değer pozitif ve sıfırdan farklı olmalı.
.attdef-angle = Geçerli bir sayısal açı veya ikinci nokta gerekir.
model =
.create = Oluştur
.boolean = Boole işlemleri
+9
View File
@@ -4015,6 +4015,15 @@ insert =
.attdef-define-attributes = Define Attributes
.attdef-manage-attributes = Manage Attributes
.attdef-set-base-point = Set Base Point
.attdef-attmode-retain = Retain Attribute Display
.attdef-attmode-all = Display All Attributes
.attdef-attmode-none = Hide All Attributes
.attdef-edit-attribute = Edit Attribute
.attdef-multiline-editor = Multiline editor
.attdef-tag-empty = The tag cannot be empty.
.attdef-tag-spaces = The tag may not contain spaces.
.attdef-positive = Value must be positive and nonzero.
.attdef-angle = Requires valid numeric angle or second point.
model =
.create = 创建
.boolean = 布尔运算
+9
View File
@@ -4027,6 +4027,15 @@ insert =
.attdef-define-attributes = Define Attributes
.attdef-manage-attributes = Manage Attributes
.attdef-set-base-point = Set Base Point
.attdef-attmode-retain = Retain Attribute Display
.attdef-attmode-all = Display All Attributes
.attdef-attmode-none = Hide All Attributes
.attdef-edit-attribute = Edit Attribute
.attdef-multiline-editor = Multiline editor
.attdef-tag-empty = The tag cannot be empty.
.attdef-tag-spaces = The tag may not contain spaces.
.attdef-positive = Value must be positive and nonzero.
.attdef-angle = Requires valid numeric angle or second point.
model =
.create = 建立
.boolean = 布林運算
+47 -8
View File
@@ -46,6 +46,19 @@ impl OpenCADStudio {
self.push_ucs_to_cmd(i);
Some(Task::none())
}
"ATTMODE0" => self.dispatch_draw("ATTDISP OFF", i),
"ATTMODE1" => self.dispatch_draw("ATTDISP NORMAL", i),
"ATTMODE2" => self.dispatch_draw("ATTDISP ON", i),
"_ATTDEF_VALUE" => {
let value = attdef::session().editor_value.take();
if let Some(state) = self.attdef_dialog.as_mut() {
if let Some(value) = value {
state.default = value;
}
self.active_modal = Some(crate::app::ModalKind::AttDef);
}
Some(Task::none())
}
cmd if cmd == "_ATTDEF_PICKED" || cmd.starts_with("_ATTDEF_PICKED ") => {
let mut parts = cmd.split_whitespace().skip(1);
if let (Some(kind), Some(value), Some(state)) =
@@ -116,10 +129,11 @@ impl OpenCADStudio {
height: short(defaults.height),
rotation: "0".into(),
width: "0".into(),
on_screen: true,
on_screen: session.on_screen,
coords: ["0".into(), "0".into(), "0".into()],
align_below: false,
can_align_below: session.last.is_some(),
error: None,
});
drop(session);
self.tabs[i].active_cmd = None;
@@ -139,6 +153,7 @@ impl OpenCADStudio {
prompt: a.prompt.clone(),
default: a.default_value.clone(),
constant: a.flags.constant,
error: None,
});
self.active_modal = Some(crate::app::ModalKind::AttDefEdit);
}
@@ -155,6 +170,7 @@ impl OpenCADStudio {
.as_ref(),
),
AttdefDialogMsg::EditOk => return self.attdef_edit_ok(i),
AttdefDialogMsg::DismissError => edit.error = None,
_ => {}
}
return Task::none();
@@ -201,30 +217,50 @@ impl OpenCADStudio {
.as_ref(),
),
AttdefDialogMsg::Ok => return self.attdef_dialog_ok(i),
AttdefDialogMsg::DismissError => state.error = None,
AttdefDialogMsg::EditValue => {
// The dialog waits while the multi-line editor collects the value.
let initial = state.default.clone();
let height = state.height.trim().parse::<f64>().ok().filter(|h| *h > 0.0).unwrap_or(2.5);
self.active_modal = None;
attdef::session().editor_value = None;
self.tabs[i].active_cmd = Some(Box::new(attdef::AttdefValueCommand));
let pos = self.tabs[i].scene.camera.borrow().target;
return self.apply_cmd_result(crate::command::CmdResult::SuspendForMTextInput {
pos,
initial,
height,
});
}
_ => {}
}
Task::none()
}
/// Show a validation message in the dialog; it stays open.
fn attdef_dialog_error(&mut self, error: &str) -> Task<Message> {
if let Some(state) = self.attdef_dialog.as_mut() {
state.error = Some(crate::t!(error).into_owned());
}
Task::none()
}
fn attdef_dialog_ok(&mut self, i: usize) -> Task<Message> {
let Some(state) = self.attdef_dialog.clone() else {
return Task::none();
};
if let Some(error) = tag_error(&state.tag) {
self.command_line.push_error(error);
return Task::none();
return self.attdef_dialog_error(error);
}
let number = |s: &str| s.trim().parse::<f64>().ok().filter(|v| v.is_finite());
let height = match number(&state.height) {
Some(v) if v > 0.0 => v,
_ => {
self.command_line.push_error("Value must be positive and nonzero.");
return Task::none();
return self.attdef_dialog_error("Value must be positive and nonzero.");
}
};
let Some(rotation) = number(&state.rotation) else {
self.command_line.push_error("Requires valid numeric angle or second point.");
return Task::none();
return self.attdef_dialog_error("Requires valid numeric angle or second point.");
};
let width = number(&state.width).unwrap_or(0.0).max(0.0);
let defaults =
@@ -250,6 +286,7 @@ impl OpenCADStudio {
let mut session = attdef::session();
session.aflags = spec.aflags;
session.annotative = spec.annotative;
session.on_screen = state.on_screen;
}
self.reset_command_start_state(i);
if state.align_below {
@@ -288,7 +325,9 @@ impl OpenCADStudio {
return Task::none();
};
if let Some(error) = tag_error(&state.tag) {
self.command_line.push_error(error);
if let Some(edit) = self.attdef_edit.as_mut() {
edit.error = Some(crate::t!(error).into_owned());
}
return Task::none();
}
self.attdef_edit = None;
+19 -55
View File
@@ -183,68 +183,32 @@ impl OpenCADStudio {
}
}
// ATTDISP — control attribute display visibility.
// ATTDISP ON — make all AttributeDefinitions visible
// ATTDISP OFF — make all AttributeDefinitions invisible
// ATTDISP NORMAL — restore: show only those without the invisible flag
// ATTDISP sets ATTMODE: 0 hides every attribute, 1 shows the
// visible ones, 2 shows them all. The definitions are not touched.
"ATTDISP" => {
use crate::command::KeywordCommand;
let c = KeywordCommand::new(
"ATTDISP",
"ATTDISP attribute display [On / Off / Normal]:",
vec![
("On", "ON", None),
("Off", "OFF", None),
("Normal", "NORMAL", None),
],
let command = crate::modules::draw::draw::attdef::AttdispCommand::new(
self.tabs[i].scene.document.header.attribute_visibility,
);
self.command_line.push_info(&c.prompt());
self.tabs[i].active_cmd = Some(Box::new(c));
self.command_line.push_info(&command.prompt());
self.tabs[i].active_cmd = Some(Box::new(command));
}
cmd if cmd.starts_with("ATTDISP ") => {
let sub = cmd.split_whitespace().nth(1).unwrap_or("").to_uppercase();
match sub.as_str() {
"ON" | "OFF" | "NORMAL" => {
let handles: Vec<_> = self.tabs[i]
.scene
.document
.entities()
.filter_map(|entity| {
matches!(entity, codec::EntityType::AttributeDefinition(_))
.then_some(entity.common().handle)
})
.filter(|handle| !self.tabs[i].scene.is_layer_locked(*handle))
.collect();
self.push_undo_snapshot(i, "ATTDISP");
let mut count = 0usize;
for handle in handles {
if let Some(codec::EntityType::AttributeDefinition(ad)) =
self.tabs[i].scene.document.get_entity_mut(handle)
{
match sub.as_str() {
"ON" => {
ad.flags.invisible = false;
count += 1;
}
"OFF" => {
ad.flags.invisible = true;
count += 1;
}
_ => {}
}
}
}
self.tabs[i].dirty = true;
self.command_line.push_output(
crate::tf!("ATTDISP {sub}: {count} attribute definition(s) updated.")
.as_ref(),
);
}
let mode = match cmd[8..].trim().to_ascii_uppercase().as_str() {
"OFF" => 0,
"ON" => 2,
"NORMAL" | "N" => 1,
_ => {
self.command_line
.push_info(crate::t!("Usage: ATTDISP ON | OFF | NORMAL").as_ref());
self.command_line.push_error("Invalid option keyword.");
return Some(Task::none());
}
};
if self.tabs[i].scene.document.header.attribute_visibility != mode {
self.push_undo_snapshot(i, "ATTDISP");
self.tabs[i].scene.document.header.attribute_visibility = mode;
self.tabs[i].dirty = true;
self.tabs[i].scene.bump_geometry();
}
self.command_line.push_output("Regenerating model.");
}
"DONUT" => {
+3
View File
@@ -666,6 +666,9 @@ inventory::submit!(crate::command::CommandRegistration {
"POINTCLOUDPOINTMAXLEGACY",
"XCLIPFRAME",
"WIPEOUTFRAME",
"ATTMODE0",
"ATTMODE1",
"ATTMODE2",
"FRAMES0",
"FRAMES1",
"FRAMES3",
+6
View File
@@ -344,6 +344,12 @@ impl OpenCADStudio {
_ => "FRAMES3",
};
self.ribbon.set_dropdown_current("FRAMES_DROPDOWN", current);
let attmode = match tab.scene.document.header.attribute_visibility {
0 => "ATTMODE0",
2 => "ATTMODE2",
_ => "ATTMODE1",
};
self.ribbon.set_dropdown_current("ATTMODE_DROPDOWN", attmode);
}
fn update_message(&mut self, msg: Message) -> Task<Message> {
+9
View File
@@ -175,6 +175,15 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static
"Define Attributes" => Some(("insert", "attdef-define-attributes")),
"Manage Attributes" => Some(("insert", "attdef-manage-attributes")),
"Set Base Point" => Some(("insert", "attdef-set-base-point")),
"Retain Attribute Display" => Some(("insert", "attdef-attmode-retain")),
"Display All Attributes" => Some(("insert", "attdef-attmode-all")),
"Hide All Attributes" => Some(("insert", "attdef-attmode-none")),
"Edit Attribute" => Some(("insert", "attdef-edit-attribute")),
"Multiline editor" => Some(("insert", "attdef-multiline-editor")),
"The tag cannot be empty." => Some(("insert", "attdef-tag-empty")),
"The tag may not contain spaces." => Some(("insert", "attdef-tag-spaces")),
"Value must be positive and nonzero." => Some(("insert", "attdef-positive")),
"Requires valid numeric angle or second point." => Some(("insert", "attdef-angle")),
"Stylization" => Some(("properties", "stylization")),
"Color scheme" => Some(("properties", "color-scheme")),
"Scan Colors" => Some(("properties", "scan-colors")),
+95
View File
@@ -32,12 +32,18 @@ pub struct AttdefSession {
pub aflags: u8,
pub annotative: bool,
pub last: Option<AttributeDefinition>,
/// The dialog's "Specify on-screen" choice, kept for the session.
pub on_screen: bool,
/// Text the multi-line editor handed back to the dialog's Default field.
pub editor_value: Option<String>,
}
pub static SESSION: Mutex<AttdefSession> = Mutex::new(AttdefSession {
aflags: AFLAG_LOCK,
annotative: false,
last: None,
on_screen: true,
editor_value: None,
});
pub fn session() -> std::sync::MutexGuard<'static, AttdefSession> {
@@ -1046,3 +1052,92 @@ impl CadCommand for AttdefPickCommand {
CmdResult::Dispatch("_ATTDEF_PICKED".into())
}
}
/// ATTDISP: `Enter attribute visibility setting [Normal/ON/OFF] <current>:`.
/// Hands the chosen setting back as `ATTDISP <word>`; Enter keeps the current
/// one.
pub struct AttdispCommand {
current: &'static str,
}
impl AttdispCommand {
/// `mode` is ATTMODE: 0 OFF, 1 Normal, 2 ON.
pub fn new(mode: i16) -> Self {
Self { current: attdisp_word(mode) }
}
}
/// The ATTDISP keyword for an ATTMODE value.
pub fn attdisp_word(mode: i16) -> &'static str {
match mode {
0 => "OFF",
2 => "ON",
_ => "Normal",
}
}
impl CadCommand for AttdispCommand {
fn name(&self) -> &'static str {
"ATTDISP"
}
fn prompt(&self) -> String {
format!("Enter attribute visibility setting [Normal/ON/OFF] <{}>:", self.current)
}
fn input_kind(&self) -> InputKind {
InputKind::SingleToken
}
fn on_text_input(&mut self, text: &str) -> Option<CmdResult> {
let word = text.trim().trim_start_matches('_').to_ascii_uppercase();
if word.is_empty() {
return Some(self.on_enter());
}
let mode = match word.as_str() {
"N" | "NORMAL" => "NORMAL",
"ON" => "ON",
"OF" | "OFF" => "OFF",
_ => return Some(CmdResult::ReportError("Invalid option keyword.".into())),
};
Some(CmdResult::Dispatch(format!("ATTDISP {mode}")))
}
fn on_point(&mut self, _pt: DVec3) -> CmdResult {
CmdResult::NeedPoint
}
fn on_enter(&mut self) -> CmdResult {
CmdResult::Cancel
}
}
/// The dialog's "…" button: the default value is edited in the multi-line
/// text editor, then handed back to the dialog (`_ATTDEF_VALUE`).
pub struct AttdefValueCommand;
impl CadCommand for AttdefValueCommand {
fn name(&self) -> &'static str {
"ATTDEF"
}
fn prompt(&self) -> String {
String::new()
}
fn on_point(&mut self, _pt: DVec3) -> CmdResult {
CmdResult::NeedPoint
}
fn on_enter(&mut self) -> CmdResult {
CmdResult::NeedPoint
}
fn on_editor_text(&mut self, value: String) {
session().editor_value = Some(value);
}
fn on_editor_closed(&mut self, _committed: bool) -> CmdResult {
CmdResult::Dispatch("_ATTDEF_VALUE".into())
}
}
+22 -1
View File
@@ -105,7 +105,28 @@ impl CadModule for InsertModule {
tools: vec![
RibbonItem::LargeTool(mview_block::tool()),
RibbonItem::LargeTool(insert_block::tool()),
RibbonItem::LargeTool(attedit::tool()),
RibbonItem::LabeledDropdown {
id: "ATTEDIT_DROPDOWN",
label: "Edit Attribute",
icon: attedit::ICON,
items: vec![
("ATTEDIT", "Single", attedit::ICON),
("-ATTEDIT", "Multiple", attedit::ICON),
],
default: "ATTEDIT",
},
// ATTMODE: the face shows the drawing's current setting.
RibbonItem::LabeledDropdown {
id: "ATTMODE_DROPDOWN",
label: "",
icon: attedit::ICON,
items: vec![
("ATTMODE1", "Retain Attribute Display", attedit::ICON),
("ATTMODE2", "Display All Attributes", attedit::ICON),
("ATTMODE0", "Hide All Attributes", attedit::ICON),
],
default: "ATTMODE1",
},
],
},
// ── Block Definition (slide-out: Set Base Point, Synchronize) ─────
+59 -6
View File
@@ -34,6 +34,9 @@ pub enum AttdefDialogMsg {
PickHeight,
PickRotation,
PickWidth,
/// Edit the default value in the multi-line text editor.
EditValue,
DismissError,
Ok,
Help,
EditTag(String),
@@ -71,6 +74,8 @@ pub struct AttdefDialogState {
pub align_below: bool,
/// A definition was placed before in this session.
pub can_align_below: bool,
/// Validation message shown above the buttons.
pub error: Option<String>,
}
/// The Edit Attribute Definition dialog's fields.
@@ -81,6 +86,7 @@ pub struct AttdefEditState {
pub prompt: String,
pub default: String,
pub constant: bool,
pub error: Option<String>,
}
fn msg(m: AttdefDialogMsg) -> Message {
@@ -131,6 +137,36 @@ fn mode<'a>(label: String, on: bool, bit: u8) -> Element<'a, Message> {
.into()
}
/// The validation message band, as in the Write Block dialog.
fn error_band<'a>(error: &Option<String>) -> Option<Element<'a, Message>> {
let error = error.clone()?;
Some(
container(
row![
crate::ui::icons::semantic(ICON_WARN, 14.0),
text(error).size(11),
Space::new().width(Fill),
button(text("×").size(12))
.on_press(msg(AttdefDialogMsg::DismissError))
.style(button_style(false))
.padding([1, 6]),
]
.spacing(8)
.align_y(iced::Center),
)
.padding([6, 10])
.width(Fill)
.style(|theme: &iced::Theme| container::Style {
background: Some(iced::Background::Color(theme.palette().danger.base.color.scale_alpha(0.18))),
border: iced::Border { radius: 4.0.into(), ..Default::default() },
..Default::default()
})
.into(),
)
}
static ICON_WARN: &[u8] = include_bytes!("../../../assets/icons/ui/warning_triangle.svg");
fn footer<'a>(action: std::borrow::Cow<'static, str>, ok: AttdefDialogMsg) -> Element<'a, Message> {
row![
button(text("?").size(12))
@@ -194,11 +230,18 @@ pub fn view<'a>(state: &'a AttdefDialogState, sizing: crate::ui::modal::ModalSiz
),
labelled(
if constant { t!("Value") } else { t!("Default") }.into_owned(),
row![
input(&state.default, true, AttdefDialogMsg::Default),
{
let mut value = row![input(&state.default, true, AttdefDialogMsg::Default)].spacing(6);
if multiline {
value = value.push(pick(
"…",
t!("Multiline editor").into_owned(),
Some(AttdefDialogMsg::EditValue),
));
}
// No field picker in this application yet.
pick("ƒ", t!("Insert field").into_owned(), None),
]
value.push(pick("ƒ", t!("Insert field").into_owned(), None))
}
.spacing(6)
.into(),
true
@@ -295,7 +338,12 @@ pub fn view<'a>(state: &'a AttdefDialogState, sizing: crate::ui::modal::ModalSiz
column![attribute, settings].spacing(10).width(Fill),
]
.spacing(10);
column![body, align, footer(t!("Define"), AttdefDialogMsg::Ok)]
let mut content = column![body, align];
if let Some(band) = error_band(&state.error) {
content = content.push(band);
}
content
.push(footer(t!("Define"), AttdefDialogMsg::Ok))
.spacing(10)
.padding([10, 12])
.width(sizing.width)
@@ -331,7 +379,12 @@ pub fn view_edit<'a>(state: &'a AttdefEditState, sizing: crate::ui::modal::Modal
]
.spacing(8),
);
column![content, footer(t!("Apply"), AttdefDialogMsg::EditOk)]
let mut content = column![content];
if let Some(band) = error_band(&state.error) {
content = content.push(band);
}
content
.push(footer(t!("Apply"), AttdefDialogMsg::EditOk))
.spacing(10)
.padding([10, 12])
.width(sizing.width)