From b4da342f0e001f8e1a9a2d443c3f8021ca69173f Mon Sep 17 00:00:00 2001 From: Karim Jerbi Date: Sat, 15 Aug 2026 14:42:08 +0100 Subject: [PATCH] refactor(ribbon): derive the Block Palette button highlight from app state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ribbon kept its own \show_block_palette\ copy that the app had to manually sync at every mutation point (the BLOCKPALETTE command and the dock Close handler). Drop the copy and thread the app's authoritative \show_block_palette\ into \Ribbon::view\ at render time, so the button highlight can't drift from the panel's true visibility — those two handlers are now mutate-points only and the ribbon view is the single place that reads the state back. --- src/app/commands/blocks.rs | 1 - src/app/update/dialog.rs | 1 - src/app/view/mod.rs | 1 + src/ui/ribbon/mod.rs | 36 ++++++++++++++++++++++++++---------- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/app/commands/blocks.rs b/src/app/commands/blocks.rs index 2d0e94e5c..6cf2394ae 100644 --- a/src/app/commands/blocks.rs +++ b/src/app/commands/blocks.rs @@ -486,7 +486,6 @@ impl OpenCADStudio { // BLOCKPALETTE / BLOCKSPALETTE — toggle the docked Insert Block panel. "BLOCKPALETTE" | "BLOCKSPALETTE" => { self.show_block_palette ^= true; - self.ribbon.set_block_palette(self.show_block_palette); if self.show_block_palette { // Always open expanded so the panel is immediately usable; // the user can still collapse it via the pin (Auto) button. diff --git a/src/app/update/dialog.rs b/src/app/update/dialog.rs index 318957ea1..10795046f 100644 --- a/src/app/update/dialog.rs +++ b/src/app/update/dialog.rs @@ -597,7 +597,6 @@ pub(super) fn on_ribbon_tool_click(&mut self, tool_id: String, event: ModuleEven match id { PanelId::BlockPalette => { self.show_block_palette = false; - self.ribbon.set_block_palette(false); self.block_palette.placing = None; } PanelId::Properties => { diff --git a/src/app/view/mod.rs b/src/app/view/mod.rs index daab2d005..b9c70975b 100644 --- a/src/app/view/mod.rs +++ b/src/app/view/mod.rs @@ -1742,6 +1742,7 @@ impl OpenCADStudio { self.tabs[self.active_tab].is_start, self.tabs[self.active_tab].history.undo_stack.len(), self.tabs[self.active_tab].history.redo_stack.len(), + self.show_block_palette, )); } if self.show_file_tabs { diff --git a/src/ui/ribbon/mod.rs b/src/ui/ribbon/mod.rs index 1d187f5e7..6a385b0da 100644 --- a/src/ui/ribbon/mod.rs +++ b/src/ui/ribbon/mod.rs @@ -50,9 +50,6 @@ pub struct Ribbon { pub show_ucs_icon: bool, /// Properties panel (PROPERTIES) visibility — drives the Properties button highlight. pub show_properties: bool, - /// Block Palette panel (BLOCKPALETTE) visibility — drives the Block Palette - /// button highlight. - pub show_block_palette: bool, /// File tabs (FILETAB) visibility — drives the File Tabs button highlight. pub show_file_tabs: bool, /// Layout tabs (LAYOUTTAB) visibility — drives the Layout Tabs button highlight. @@ -161,7 +158,6 @@ impl Ribbon { show_viewcube: true, show_ucs_icon: true, show_properties: true, - show_block_palette: false, show_file_tabs: true, show_layout_tabs: true, open_dropdown: None, @@ -315,9 +311,6 @@ impl Ribbon { pub fn set_properties(&mut self, on: bool) { self.show_properties = on; } - pub fn set_block_palette(&mut self, on: bool) { - self.show_block_palette = on; - } pub fn set_file_tabs(&mut self, on: bool) { self.show_file_tabs = on; } @@ -325,14 +318,17 @@ impl Ribbon { self.show_layout_tabs = on; } /// Snapshot of every ribbon toggle's live state, for the render path. - fn toggle_state(&self) -> widgets::ToggleState { + /// The Block Palette highlight is threaded in from the app's authoritative + /// `show_block_palette` rather than a ribbon copy, so it can't drift from + /// the panel's true visibility. + fn toggle_state(&self, show_block_palette: bool) -> widgets::ToggleState { use widgets::ToggleState; ToggleState { ortho_mode: self.ortho_mode, show_viewcube: self.show_viewcube, show_ucs_icon: self.show_ucs_icon, show_properties: self.show_properties, - show_block_palette: self.show_block_palette, + show_block_palette, show_file_tabs: self.show_file_tabs, show_layout_tabs: self.show_layout_tabs, } @@ -406,6 +402,7 @@ impl Ribbon { is_start: bool, undo_count: usize, redo_count: usize, + show_block_palette: bool, ) -> Element<'_, Message> { // ── Quick-access file commands + undo/redo, one merged flow ──────── let lead = iced::widget::Row::with_children(vec![ @@ -586,7 +583,7 @@ impl Ribbon { let panels: Vec> = groups .iter() .map(|g| { - let ts = self.toggle_state(); + let ts = self.toggle_state(show_block_palette); Panel { id: g.title.to_string(), full: render_group( @@ -1563,3 +1560,22 @@ impl Default for Ribbon { Self::new() } } + +#[cfg(test)] +mod tests { + use super::widgets::is_active_tool; + use super::Ribbon; + + #[test] + fn block_palette_highlight_follows_the_app_state_passed_to_the_view() { + // The Block Palette button highlight is derived from the app's + // authoritative `show_block_palette`, threaded into the view at render + // time: the ribbon keeps no second copy that a BLOCKPALETTE / close + // handler must remember to keep in sync. + let ribbon = Ribbon::default(); + let on = ribbon.toggle_state(true); + assert!(is_active_tool("BLOCKPALETTE", &None, &on)); + let off = ribbon.toggle_state(false); + assert!(!is_active_tool("BLOCKPALETTE", &None, &off)); + } +}