From 9724447dd03c5e4ef9900ce85a0d7acac83379cb Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Tue, 13 Oct 2026 15:53:55 +0300 Subject: [PATCH] feat(ribbon): contextual Block Editor tab while editing a block Opening the block editor brings up a Block Editor ribbon tab with Edit / Save / Discard, Attribute Definition, and the geometric, dimensional and parameter tools that drive parametric blocks. The tab is only listed while a block editor session is open, and leaving the session returns to the tab that was active before. Refs #509 Co-Authored-By: Claude Opus 5.5 --- locales/ar-SA/opencadstudio.ftl | 1 + locales/bg-BG/opencadstudio.ftl | 1 + locales/cs-CZ/opencadstudio.ftl | 1 + locales/de-DE/opencadstudio.ftl | 1 + locales/el-GR/opencadstudio.ftl | 1 + locales/en-US/opencadstudio.ftl | 1 + locales/es-ES/opencadstudio.ftl | 1 + locales/fi-FI/opencadstudio.ftl | 1 + locales/fr-FR/opencadstudio.ftl | 1 + locales/hi-IN/opencadstudio.ftl | 1 + locales/hu-HU/opencadstudio.ftl | 1 + locales/it-IT/opencadstudio.ftl | 1 + locales/ja-JP/opencadstudio.ftl | 1 + locales/ko-KR/opencadstudio.ftl | 1 + locales/lo-LA/opencadstudio.ftl | 1 + locales/nl-NL/opencadstudio.ftl | 1 + locales/pl-PL/opencadstudio.ftl | 1 + locales/pt-BR/opencadstudio.ftl | 1 + locales/ru-RU/opencadstudio.ftl | 1 + locales/tr-TR/opencadstudio.ftl | 1 + locales/zh-CN/opencadstudio.ftl | 1 + locales/zh-TW/opencadstudio.ftl | 1 + src/app/update/mod.rs | 5 +++ src/i18n.rs | 1 + src/modules/block_editor/mod.rs | 66 +++++++++++++++++++++++++++++++++ src/modules/mod.rs | 1 + src/modules/registry.rs | 1 + src/ui/ribbon/mod.rs | 32 +++++++++++++++- 28 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 src/modules/block_editor/mod.rs diff --git a/locales/ar-SA/opencadstudio.ftl b/locales/ar-SA/opencadstudio.ftl index 4a312724e..7185cb3ee 100644 --- a/locales/ar-SA/opencadstudio.ftl +++ b/locales/ar-SA/opencadstudio.ftl @@ -29,6 +29,7 @@ action = .plugins = الإضافات ribbon-tab = + .block-editor = محرر الكتل .draw = رسم .parametric = بارامتري .annotate = تعليقات توضيحية diff --git a/locales/bg-BG/opencadstudio.ftl b/locales/bg-BG/opencadstudio.ftl index 2e6b8fca2..f4e42fc76 100644 --- a/locales/bg-BG/opencadstudio.ftl +++ b/locales/bg-BG/opencadstudio.ftl @@ -29,6 +29,7 @@ action = .plugins = Приставки ribbon-tab = + .block-editor = Редактор на блокове .draw = Чертане .parametric = Параметричен .annotate = Анотиране diff --git a/locales/cs-CZ/opencadstudio.ftl b/locales/cs-CZ/opencadstudio.ftl index 11cd48cef..7b519210e 100644 --- a/locales/cs-CZ/opencadstudio.ftl +++ b/locales/cs-CZ/opencadstudio.ftl @@ -29,6 +29,7 @@ action = .plugins = Zásuvné moduly ribbon-tab = + .block-editor = Editor bloků .draw = Kreslení .parametric = Parametrické .annotate = Poznámky diff --git a/locales/de-DE/opencadstudio.ftl b/locales/de-DE/opencadstudio.ftl index 5772847aa..0acdc8b7d 100644 --- a/locales/de-DE/opencadstudio.ftl +++ b/locales/de-DE/opencadstudio.ftl @@ -29,6 +29,7 @@ action = .plugins = Plug-ins ribbon-tab = + .block-editor = Blockeditor .draw = Zeichnen .parametric = Parametrisch .annotate = Beschriften diff --git a/locales/el-GR/opencadstudio.ftl b/locales/el-GR/opencadstudio.ftl index ce1bf9e2b..f2837327e 100644 --- a/locales/el-GR/opencadstudio.ftl +++ b/locales/el-GR/opencadstudio.ftl @@ -29,6 +29,7 @@ action = .plugins = Πρόσθετα ribbon-tab = + .block-editor = Επεξεργαστής μπλοκ .draw = Σχεδίαση .parametric = Παραμετρικό .annotate = Επισημείωση diff --git a/locales/en-US/opencadstudio.ftl b/locales/en-US/opencadstudio.ftl index a0ffaed80..8879adf32 100644 --- a/locales/en-US/opencadstudio.ftl +++ b/locales/en-US/opencadstudio.ftl @@ -29,6 +29,7 @@ action = .plugins = Plugins ribbon-tab = + .block-editor = Block Editor .draw = Draw .parametric = Parametric .annotate = Annotate diff --git a/locales/es-ES/opencadstudio.ftl b/locales/es-ES/opencadstudio.ftl index 3a5ae2136..0646c6190 100644 --- a/locales/es-ES/opencadstudio.ftl +++ b/locales/es-ES/opencadstudio.ftl @@ -29,6 +29,7 @@ action = .plugins = Complementos ribbon-tab = + .block-editor = Editor de bloques .draw = Dibujo .parametric = Paramétrico .annotate = Anotar diff --git a/locales/fi-FI/opencadstudio.ftl b/locales/fi-FI/opencadstudio.ftl index ed06fed02..6252cbe50 100644 --- a/locales/fi-FI/opencadstudio.ftl +++ b/locales/fi-FI/opencadstudio.ftl @@ -29,6 +29,7 @@ action = .plugins = Liitännäiset ribbon-tab = + .block-editor = Lohkoeditori .draw = Piirrä .parametric = Parametrinen .annotate = Merkinnät diff --git a/locales/fr-FR/opencadstudio.ftl b/locales/fr-FR/opencadstudio.ftl index 4696460de..235debc62 100644 --- a/locales/fr-FR/opencadstudio.ftl +++ b/locales/fr-FR/opencadstudio.ftl @@ -29,6 +29,7 @@ action = .plugins = Extensions ribbon-tab = + .block-editor = Éditeur de blocs .draw = Dessin .parametric = Paramétrique .annotate = Annoter diff --git a/locales/hi-IN/opencadstudio.ftl b/locales/hi-IN/opencadstudio.ftl index 73a8dc9d3..8a5227f08 100644 --- a/locales/hi-IN/opencadstudio.ftl +++ b/locales/hi-IN/opencadstudio.ftl @@ -29,6 +29,7 @@ action = .plugins = प्लग-इन ribbon-tab = + .block-editor = ब्लॉक संपादक .draw = ड्रॉ .parametric = पैरामीट्रिक .annotate = एनोटेट diff --git a/locales/hu-HU/opencadstudio.ftl b/locales/hu-HU/opencadstudio.ftl index ac9df005c..784bae332 100644 --- a/locales/hu-HU/opencadstudio.ftl +++ b/locales/hu-HU/opencadstudio.ftl @@ -29,6 +29,7 @@ action = .plugins = Bővítmények ribbon-tab = + .block-editor = Blokkszerkesztő .draw = Rajz .parametric = Parametrikus .annotate = Feliratozás diff --git a/locales/it-IT/opencadstudio.ftl b/locales/it-IT/opencadstudio.ftl index 39113b508..83e178234 100644 --- a/locales/it-IT/opencadstudio.ftl +++ b/locales/it-IT/opencadstudio.ftl @@ -29,6 +29,7 @@ action = .plugins = Plugin ribbon-tab = + .block-editor = Editor blocchi .draw = Disegno .parametric = Parametrico .annotate = Annotazione diff --git a/locales/ja-JP/opencadstudio.ftl b/locales/ja-JP/opencadstudio.ftl index c5e439c29..4cd6bfc04 100644 --- a/locales/ja-JP/opencadstudio.ftl +++ b/locales/ja-JP/opencadstudio.ftl @@ -29,6 +29,7 @@ action = .plugins = プラグイン ribbon-tab = + .block-editor = ブロック エディタ .draw = 作図 .parametric = パラメトリック .annotate = 注釈 diff --git a/locales/ko-KR/opencadstudio.ftl b/locales/ko-KR/opencadstudio.ftl index 4e004adf7..aacc80b7e 100644 --- a/locales/ko-KR/opencadstudio.ftl +++ b/locales/ko-KR/opencadstudio.ftl @@ -29,6 +29,7 @@ action = .plugins = 플러그인 ribbon-tab = + .block-editor = 블록 편집기 .draw = 그리기 .parametric = 파라메트릭 .annotate = 주석 diff --git a/locales/lo-LA/opencadstudio.ftl b/locales/lo-LA/opencadstudio.ftl index 071c889c5..b6f25c0c6 100644 --- a/locales/lo-LA/opencadstudio.ftl +++ b/locales/lo-LA/opencadstudio.ftl @@ -29,6 +29,7 @@ action = .plugins = ປລັກອິນ ribbon-tab = + .block-editor = ຕົວແກ້ໄຂບລັອກ .draw = ແຕ້ມ .parametric = ພາຣາມີຕຣິກ .annotate = ຄຳອະທິບາຍ diff --git a/locales/nl-NL/opencadstudio.ftl b/locales/nl-NL/opencadstudio.ftl index 0594c5359..71c7cb298 100644 --- a/locales/nl-NL/opencadstudio.ftl +++ b/locales/nl-NL/opencadstudio.ftl @@ -29,6 +29,7 @@ action = .plugins = Plug-ins ribbon-tab = + .block-editor = Blokeditor .draw = Tekenen .parametric = Parametrisch .annotate = Annoteren diff --git a/locales/pl-PL/opencadstudio.ftl b/locales/pl-PL/opencadstudio.ftl index e4a9650a4..9cce07e5d 100644 --- a/locales/pl-PL/opencadstudio.ftl +++ b/locales/pl-PL/opencadstudio.ftl @@ -29,6 +29,7 @@ action = .plugins = Wtyczki ribbon-tab = + .block-editor = Edytor bloków .draw = Rysowanie .parametric = Parametryczne .annotate = Opisy diff --git a/locales/pt-BR/opencadstudio.ftl b/locales/pt-BR/opencadstudio.ftl index 287747095..03ed5c74b 100644 --- a/locales/pt-BR/opencadstudio.ftl +++ b/locales/pt-BR/opencadstudio.ftl @@ -29,6 +29,7 @@ action = .plugins = Plugins ribbon-tab = + .block-editor = Editor de blocos .draw = Desenhar .parametric = Paramétrico .annotate = Anotar diff --git a/locales/ru-RU/opencadstudio.ftl b/locales/ru-RU/opencadstudio.ftl index e83bc70f5..f86a8bdf2 100644 --- a/locales/ru-RU/opencadstudio.ftl +++ b/locales/ru-RU/opencadstudio.ftl @@ -29,6 +29,7 @@ action = .plugins = Модули ribbon-tab = + .block-editor = Редактор блоков .draw = Начертить .parametric = Параметрический .annotate = Аннотации diff --git a/locales/tr-TR/opencadstudio.ftl b/locales/tr-TR/opencadstudio.ftl index 984042390..c2e968dba 100644 --- a/locales/tr-TR/opencadstudio.ftl +++ b/locales/tr-TR/opencadstudio.ftl @@ -29,6 +29,7 @@ action = .plugins = Eklentiler ribbon-tab = + .block-editor = Blok Düzenleyici .draw = Çizim .parametric = Parametrik .annotate = Açıklama diff --git a/locales/zh-CN/opencadstudio.ftl b/locales/zh-CN/opencadstudio.ftl index b43507ca0..11c90021c 100644 --- a/locales/zh-CN/opencadstudio.ftl +++ b/locales/zh-CN/opencadstudio.ftl @@ -29,6 +29,7 @@ action = .plugins = 插件 ribbon-tab = + .block-editor = 块编辑器 .draw = 绘制 .parametric = 参数化 .annotate = 注释 diff --git a/locales/zh-TW/opencadstudio.ftl b/locales/zh-TW/opencadstudio.ftl index 3a6877afb..e51fe693a 100644 --- a/locales/zh-TW/opencadstudio.ftl +++ b/locales/zh-TW/opencadstudio.ftl @@ -29,6 +29,7 @@ action = .plugins = 外掛程式 ribbon-tab = + .block-editor = 圖塊編輯器 .draw = 繪製 .parametric = 參數化 .annotate = 註解 diff --git a/src/app/update/mod.rs b/src/app/update/mod.rs index 862364e38..256fb5e71 100644 --- a/src/app/update/mod.rs +++ b/src/app/update/mod.rs @@ -339,6 +339,11 @@ impl OpenCADStudio { self.sync_underlay_tab(); } self.sync_frame_dropdown(); + let block_editing = self + .tabs + .get(self.active_tab) + .is_some_and(|tab| tab.active_block_edit.is_some()); + self.ribbon.set_block_editing(block_editing); task } diff --git a/src/i18n.rs b/src/i18n.rs index d2ac1e73b..38bea8676 100644 --- a/src/i18n.rs +++ b/src/i18n.rs @@ -365,6 +365,7 @@ pub fn ribbon_module_title(id: &str, fallback: &str) -> String { "layout" => crate::tr!("ribbon-tab", "layout"), "manage" => crate::tr!("ribbon-tab", "manage"), "view" => crate::tr!("ribbon-tab", "view"), + "block_editor" => crate::tr!("ribbon-tab", "block-editor"), _ => fallback.to_string(), } } diff --git a/src/modules/block_editor/mod.rs b/src/modules/block_editor/mod.rs new file mode 100644 index 000000000..705507002 --- /dev/null +++ b/src/modules/block_editor/mod.rs @@ -0,0 +1,66 @@ +//! Contextual "Block Editor" ribbon tab, shown only while a BEDIT session is +//! open: saving or discarding the block, attribute definitions, and the +//! constraint tools that drive parametric blocks. + +use crate::modules::parametric::ParametricModule; +use crate::modules::{CadModule, IconKind, ModuleEvent, RibbonGroup, RibbonItem, ToolDef}; + +pub struct BlockEditorModule; + +impl CadModule for BlockEditorModule { + fn id(&self) -> &'static str { + "block_editor" + } + + fn title(&self) -> &'static str { + "Block Editor" + } + + fn ribbon_groups(&self) -> &[RibbonGroup] { + static GROUPS: std::sync::OnceLock> = std::sync::OnceLock::new(); + GROUPS.get_or_init(|| { + let command = |id: &'static str, label: &'static str, icon: &'static [u8]| { + RibbonItem::LargeTool(ToolDef { + id, + label, + icon: IconKind::Svg(icon), + event: ModuleEvent::Command(id.to_string()), + }) + }; + let mut groups = vec![ + RibbonGroup { + title: "Open and Save", + tools: vec![ + command( + "BEDIT", + "Edit Block", + include_bytes!("../../../assets/icons/edit_block.svg"), + ), + command( + "BEDIT_SAVE", + "Save Block", + include_bytes!("../../../assets/icons/mt_ok.svg"), + ), + command( + "BEDIT_DISCARD", + "Discard Block Edit", + include_bytes!("../../../assets/icons/mt_cancel.svg"), + ), + ], + }, + RibbonGroup { + title: "Attributes", + tools: vec![command( + "ATTDEF", + "Attribute Definition", + include_bytes!("../../../assets/icons/attdef.svg"), + )], + }, + ]; + // Parametric blocks are driven by the same constraints and + // parameters as the Parametric tab. + groups.extend(ParametricModule.ribbon_groups().iter().cloned()); + groups + }) + } +} diff --git a/src/modules/mod.rs b/src/modules/mod.rs index abd8529ae..d3b7c9715 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -25,6 +25,7 @@ pub use ocs_plugin_api::ribbon::{ // ── Module declarations ─────────────────────────────────────────────────── pub mod annotate; +pub mod block_editor; pub mod draw; pub mod insert; pub mod layout; diff --git a/src/modules/registry.rs b/src/modules/registry.rs index 14e7a3d31..26899beca 100644 --- a/src/modules/registry.rs +++ b/src/modules/registry.rs @@ -23,6 +23,7 @@ pub fn all_modules() -> Vec> { Box::new(super::view::ViewModule), Box::new(super::manage::ManageModule), Box::new(super::layout::LayoutModule), + Box::new(super::block_editor::BlockEditorModule), ] } diff --git a/src/ui/ribbon/mod.rs b/src/ui/ribbon/mod.rs index 149f4e9a1..c4274b7e6 100644 --- a/src/ui/ribbon/mod.rs +++ b/src/ui/ribbon/mod.rs @@ -117,6 +117,9 @@ pub struct Ribbon { xref_ctx: bool, /// Only point clouds are selected: whether the first shows its crops. point_cloud_ctx: Option, + /// A block editor session is open: the tab that was active before the + /// Block Editor tab took over. + block_editing: Option, /// XDWGFADECTL as the Reference slide-out shows it (negative = off). pub xref_fade: i32, } @@ -219,6 +222,7 @@ impl Ribbon { underlay_ctx: None, xref_ctx: false, point_cloud_ctx: None, + block_editing: None, xref_fade: 50, } } @@ -293,6 +297,28 @@ impl Ribbon { self.available_linetypes = items; } + /// Show the Block Editor tab while a block is being edited, and return to + /// the previous tab when the editing ends. + pub fn set_block_editing(&mut self, editing: bool) { + let Some(index) = self.modules.iter().position(|module| module.id() == "block_editor") + else { + return; + }; + match (editing, self.block_editing) { + (true, None) => { + self.block_editing = Some(self.active); + self.active = index; + } + (false, Some(previous)) => { + self.block_editing = None; + if self.active == index { + self.active = previous.min(self.modules.len().saturating_sub(1)); + } + } + _ => {} + } + } + pub fn select(&mut self, index: usize) { if index < self.modules.len() { self.active = index; @@ -550,12 +576,14 @@ impl Ribbon { |mut acc, (i, module)| { // The Layout module no longer has a ribbon tab — its paper-space // tools live in the right-edge side toolbar (see ui::side_toolbar). - if module.id() == "layout" { + if module.id() == "layout" + || (module.id() == "block_editor" && self.block_editing.is_none()) + { return acc; } let is_active = i == self.active; - let is_contextual = module.id() == "layout"; + let is_contextual = matches!(module.id(), "layout" | "block_editor"); let holds_tool = holding_tab == Some(i); let btn = container( button(