diff --git a/locales/ar-SA/opencadstudio.ftl b/locales/ar-SA/opencadstudio.ftl index 34db39d32..90ca7ab4d 100644 --- a/locales/ar-SA/opencadstudio.ftl +++ b/locales/ar-SA/opencadstudio.ftl @@ -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 = عمليات منطقية diff --git a/locales/bg-BG/opencadstudio.ftl b/locales/bg-BG/opencadstudio.ftl index b67ac4bf5..2db9fb1be 100644 --- a/locales/bg-BG/opencadstudio.ftl +++ b/locales/bg-BG/opencadstudio.ftl @@ -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 = Булеви операции diff --git a/locales/cs-CZ/opencadstudio.ftl b/locales/cs-CZ/opencadstudio.ftl index d32997df1..568d18c19 100644 --- a/locales/cs-CZ/opencadstudio.ftl +++ b/locales/cs-CZ/opencadstudio.ftl @@ -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 diff --git a/locales/de-DE/opencadstudio.ftl b/locales/de-DE/opencadstudio.ftl index f2a104e7e..854583d3c 100644 --- a/locales/de-DE/opencadstudio.ftl +++ b/locales/de-DE/opencadstudio.ftl @@ -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 diff --git a/locales/el-GR/opencadstudio.ftl b/locales/el-GR/opencadstudio.ftl index e8f306d87..1bc916265 100644 --- a/locales/el-GR/opencadstudio.ftl +++ b/locales/el-GR/opencadstudio.ftl @@ -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 = Δυαδική πράξη diff --git a/locales/en-US/opencadstudio.ftl b/locales/en-US/opencadstudio.ftl index a3f43b6d6..fc3a39030 100644 --- a/locales/en-US/opencadstudio.ftl +++ b/locales/en-US/opencadstudio.ftl @@ -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 diff --git a/locales/es-ES/opencadstudio.ftl b/locales/es-ES/opencadstudio.ftl index 8c2857ee7..8154c0646 100644 --- a/locales/es-ES/opencadstudio.ftl +++ b/locales/es-ES/opencadstudio.ftl @@ -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 diff --git a/locales/fi-FI/opencadstudio.ftl b/locales/fi-FI/opencadstudio.ftl index 2d88f63da..c49419d28 100644 --- a/locales/fi-FI/opencadstudio.ftl +++ b/locales/fi-FI/opencadstudio.ftl @@ -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 diff --git a/locales/fr-FR/opencadstudio.ftl b/locales/fr-FR/opencadstudio.ftl index 741de7b31..8a393e26d 100644 --- a/locales/fr-FR/opencadstudio.ftl +++ b/locales/fr-FR/opencadstudio.ftl @@ -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 diff --git a/locales/hi-IN/opencadstudio.ftl b/locales/hi-IN/opencadstudio.ftl index 8cdb4a8ce..ff357f061 100644 --- a/locales/hi-IN/opencadstudio.ftl +++ b/locales/hi-IN/opencadstudio.ftl @@ -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 = बूलियन संक्रियाएँ diff --git a/locales/hu-HU/opencadstudio.ftl b/locales/hu-HU/opencadstudio.ftl index d0d7ee442..053a20ff4 100644 --- a/locales/hu-HU/opencadstudio.ftl +++ b/locales/hu-HU/opencadstudio.ftl @@ -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 diff --git a/locales/it-IT/opencadstudio.ftl b/locales/it-IT/opencadstudio.ftl index e005dd34c..541650845 100644 --- a/locales/it-IT/opencadstudio.ftl +++ b/locales/it-IT/opencadstudio.ftl @@ -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 diff --git a/locales/ja-JP/opencadstudio.ftl b/locales/ja-JP/opencadstudio.ftl index a76a30075..0a7379a95 100644 --- a/locales/ja-JP/opencadstudio.ftl +++ b/locales/ja-JP/opencadstudio.ftl @@ -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 = ブール演算 diff --git a/locales/ko-KR/opencadstudio.ftl b/locales/ko-KR/opencadstudio.ftl index 81e62ae84..6103f015b 100644 --- a/locales/ko-KR/opencadstudio.ftl +++ b/locales/ko-KR/opencadstudio.ftl @@ -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 = 불리언 연산 diff --git a/locales/nl-NL/opencadstudio.ftl b/locales/nl-NL/opencadstudio.ftl index a5963eb1d..79975ad46 100644 --- a/locales/nl-NL/opencadstudio.ftl +++ b/locales/nl-NL/opencadstudio.ftl @@ -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 diff --git a/locales/pl-PL/opencadstudio.ftl b/locales/pl-PL/opencadstudio.ftl index ba1116512..f1c5ceae0 100644 --- a/locales/pl-PL/opencadstudio.ftl +++ b/locales/pl-PL/opencadstudio.ftl @@ -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 diff --git a/locales/pt-BR/opencadstudio.ftl b/locales/pt-BR/opencadstudio.ftl index b7fc9bbe4..1c3ddf058 100644 --- a/locales/pt-BR/opencadstudio.ftl +++ b/locales/pt-BR/opencadstudio.ftl @@ -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 diff --git a/locales/ru-RU/opencadstudio.ftl b/locales/ru-RU/opencadstudio.ftl index 92913c7ae..96391bb95 100644 --- a/locales/ru-RU/opencadstudio.ftl +++ b/locales/ru-RU/opencadstudio.ftl @@ -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 = Булевы операции diff --git a/locales/tr-TR/opencadstudio.ftl b/locales/tr-TR/opencadstudio.ftl index 83ea6e9bc..e7d0a2914 100644 --- a/locales/tr-TR/opencadstudio.ftl +++ b/locales/tr-TR/opencadstudio.ftl @@ -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 diff --git a/locales/zh-CN/opencadstudio.ftl b/locales/zh-CN/opencadstudio.ftl index 6357efdd5..8a71f831c 100644 --- a/locales/zh-CN/opencadstudio.ftl +++ b/locales/zh-CN/opencadstudio.ftl @@ -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 = 布尔运算 diff --git a/locales/zh-TW/opencadstudio.ftl b/locales/zh-TW/opencadstudio.ftl index f5f77d4e8..ec5f8dc6c 100644 --- a/locales/zh-TW/opencadstudio.ftl +++ b/locales/zh-TW/opencadstudio.ftl @@ -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 = 布林運算 diff --git a/src/app/commands/attdef.rs b/src/app/commands/attdef.rs index 65dca2328..ff5dabea1 100644 --- a/src/app/commands/attdef.rs +++ b/src/app/commands/attdef.rs @@ -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::().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 { + 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 { 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::().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; diff --git a/src/app/commands/draw.rs b/src/app/commands/draw.rs index e85c5c522..bb529a6ff 100644 --- a/src/app/commands/draw.rs +++ b/src/app/commands/draw.rs @@ -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" => { diff --git a/src/app/commands/mod.rs b/src/app/commands/mod.rs index ac09175ad..6c0027791 100644 --- a/src/app/commands/mod.rs +++ b/src/app/commands/mod.rs @@ -666,6 +666,9 @@ inventory::submit!(crate::command::CommandRegistration { "POINTCLOUDPOINTMAXLEGACY", "XCLIPFRAME", "WIPEOUTFRAME", + "ATTMODE0", + "ATTMODE1", + "ATTMODE2", "FRAMES0", "FRAMES1", "FRAMES3", diff --git a/src/app/update/mod.rs b/src/app/update/mod.rs index 7702bf6a6..bb7e0318e 100644 --- a/src/app/update/mod.rs +++ b/src/app/update/mod.rs @@ -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 { diff --git a/src/locale_catalog.rs b/src/locale_catalog.rs index f0f3e1557..7a4ba7dc3 100644 --- a/src/locale_catalog.rs +++ b/src/locale_catalog.rs @@ -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")), diff --git a/src/modules/draw/draw/attdef.rs b/src/modules/draw/draw/attdef.rs index d6e5c83a9..f2d1e0366 100644 --- a/src/modules/draw/draw/attdef.rs +++ b/src/modules/draw/draw/attdef.rs @@ -32,12 +32,18 @@ pub struct AttdefSession { pub aflags: u8, pub annotative: bool, pub last: Option, + /// 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, } pub static SESSION: Mutex = 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] :`. +/// Hands the chosen setting back as `ATTDISP `; 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 { + 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()) + } +} diff --git a/src/modules/insert/mod.rs b/src/modules/insert/mod.rs index 976901322..92ee61dcd 100644 --- a/src/modules/insert/mod.rs +++ b/src/modules/insert/mod.rs @@ -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) ───── diff --git a/src/ui/window/attdef_dialog.rs b/src/ui/window/attdef_dialog.rs index 66bee80d4..c74c81f08 100644 --- a/src/ui/window/attdef_dialog.rs +++ b/src/ui/window/attdef_dialog.rs @@ -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, } /// 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, } 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) -> Option> { + 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)