From 7a87e08a02368591b4b4572a988cc8a1839dd214 Mon Sep 17 00:00:00 2001 From: Marcel Date: Tue, 8 Sep 2026 20:33:24 +0200 Subject: [PATCH 1/2] Add collapsible Properties-panel sections --- src/app/mod.rs | 7 +++++++ src/app/properties.rs | 5 +++++ src/app/update/mod.rs | 14 +++++++++++++ src/app/update/mod.rs:5116:57 | 0 src/ui/properties.rs | 39 +++++++++++++++++++++++++++++++---- 5 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 src/app/update/mod.rs:5116:57 diff --git a/src/app/mod.rs b/src/app/mod.rs index c9dbd3cbf..4cdc35a9f 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -385,6 +385,10 @@ pub(super) struct OpenCADStudio { /// though the three factors are currently equal — the user unchecked the /// "Uniform scale" box for them (#427). Keyed by entity handle. props_asym_scale: std::collections::HashSet, + /// Collapsed Properties-panel section titles. This belongs to the app, + /// rather than an individual document tab, so the same view preference is + /// used by every currently open drawing/project. + collapsed_property_sections: rustc_hash::FxHashSet, /// Which Start-page section is shown when the page is too narrow for all /// three side by side and falls back to a tab bar. start_section: StartSection, @@ -2555,6 +2559,8 @@ pub enum Message { /// Toggle a collapsed coordinate group ("Position", "Scale", …) open or /// closed in the Properties panel, keyed `section:base`. PropGroupToggle(String), + /// Toggle an entire Properties-panel section, keyed by its title. + PropSectionToggle(String), /// Toggle the editable-dropdown (block Name) option list open/closed. PropEditChoiceToggle, /// User is typing in a block-attribute value field (live buffer update), @@ -3304,6 +3310,7 @@ impl OpenCADStudio { discussions: Vec::new(), discussions_loading: false, props_asym_scale: std::collections::HashSet::new(), + collapsed_property_sections: rustc_hash::FxHashSet::default(), start_section: StartSection::default(), start_action_w: std::sync::Arc::new(std::sync::atomic::AtomicU32::new(0)), history_content: iced::widget::text_editor::Content::new(), diff --git a/src/app/properties.rs b/src/app/properties.rs index ad055f125..4ec650fcc 100644 --- a/src/app/properties.rs +++ b/src/app/properties.rs @@ -47,6 +47,10 @@ impl OpenCADStudio { // Expanded coordinate groups persist across rebuilds AND selection // changes — it's a per-user view preference, not per-entity state. let expanded_groups = std::mem::take(&mut self.tabs[i].properties.expanded_groups); + // Section state belongs to the app, not a drawing tab, so the user's + // collapsed sections carry across every currently open drawing/project. + // The empty app-level default keeps a first-run palette fully expanded. + let collapsed_sections = self.collapsed_property_sections.clone(); // Which entities the previous panel was built for — an uncommitted // edit buffer only survives a rebuild for the *same* selection. let prev_handles = std::mem::take(&mut self.tabs[i].properties.source_handles); @@ -2236,6 +2240,7 @@ impl OpenCADStudio { None }; panel.expanded_groups = expanded_groups; + panel.collapsed_sections = collapsed_sections; panel.source_handles = new_handles; panel.prop_vertex = prop_vertex; panel.prop_vertex_indicator_active = prop_vertex_indicator_active; diff --git a/src/app/update/mod.rs b/src/app/update/mod.rs index 5aff46f09..a76158d93 100644 --- a/src/app/update/mod.rs +++ b/src/app/update/mod.rs @@ -5104,6 +5104,20 @@ impl OpenCADStudio { Task::none() } + Message::PropSectionToggle(title) => { + let sections = &mut self.collapsed_property_sections; + if !sections.remove(&title) { + sections.insert(title); + } + // Keep already-built panels in other open documents in sync, + // rather than waiting for each one to rebuild on selection. + let sections = self.collapsed_property_sections.clone(); + for tab in &mut self.tabs { + tab.properties.collapsed_sections = sections.clone(); + } + Task::none() + } + Message::PropEditChoiceToggle => { let panel = &mut self.tabs[self.active_tab].properties; panel.edit_choice_open = !panel.edit_choice_open; diff --git a/src/app/update/mod.rs:5116:57 b/src/app/update/mod.rs:5116:57 new file mode 100644 index 000000000..e69de29bb diff --git a/src/ui/properties.rs b/src/ui/properties.rs index fb0660c52..7bbf8329b 100644 --- a/src/ui/properties.rs +++ b/src/ui/properties.rs @@ -447,6 +447,10 @@ pub struct PropertiesPanel { /// carried across panel rebuilds so the state survives edits and selection /// changes. pub expanded_groups: HashSet, + /// Property sections the user collapsed. This is a rendered copy of the + /// app-wide preference, allowing every open document panel to share it. + /// Empty by default, meaning every section is initially shown. + pub collapsed_sections: HashSet, /// Whether the editable-dropdown (block Name) option list is open. pub edit_choice_open: bool, /// Field key of the value row currently being edited, or `None`. Marked when @@ -485,6 +489,7 @@ impl Default for PropertiesPanel { prop_vertex: 0, prop_vertex_indicator_active: false, expanded_groups: HashSet::default(), + collapsed_sections: HashSet::default(), edit_choice_open: false, active_field: None, field_key_by_id: HashMap::default(), @@ -710,8 +715,32 @@ impl PropertiesPanel { // ── Section renderer ────────────────────────────────────────────────── fn render_section<'a>(&'a self, section: &'a PropSection) -> Element<'a, Message> { - // Section header - let hdr = container(text(§ion.title).size(10)) + let collapsed = self.collapsed_sections.contains(§ion.title); + let toggle = button(if collapsed { + crate::ui::icons::themed_arrow_right(10.0) + } else { + crate::ui::icons::themed_arrow_down(10.0) + }) + .on_press(Message::PropSectionToggle(section.title.clone())) + .style(button::text) + .padding([0, 3]); + + // The arrow intentionally sits at the far end of the header. The rest + // of the header responds to a double-click, leaving a single click on + // the arrow as the precise, discoverable toggle target. + let title = mouse_area( + container(text(§ion.title).size(10)) + .width(Length::Fill) + .padding([3, 8]), + ) + .on_double_click(Message::PropSectionToggle(section.title.clone())); + let hdr = container( + row![ + title, + toggle, + ] + .align_y(iced::Center), + ) .style(|theme: &Theme| { let palette = theme.palette(); container::Style { @@ -724,10 +753,12 @@ impl PropertiesPanel { ..Default::default() } }) - .width(Length::Fill) - .padding([3, 8]); + .width(Length::Fill); let mut col = column![hdr].spacing(0); + if collapsed { + return col.into(); + } // Consecutive " X / Y [/ Z]" text rows collapse // into one clickable summary row; clicking expands the components. From d22f4fdbe7e5a928f41866b2873fb10a4e8b7ba6 Mon Sep 17 00:00:00 2001 From: Marcel Date: Tue, 8 Sep 2026 20:52:01 +0200 Subject: [PATCH 2/2] Remove accidental file --- src/app/update/mod.rs:5116:57 | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/app/update/mod.rs:5116:57 diff --git a/src/app/update/mod.rs:5116:57 b/src/app/update/mod.rs:5116:57 deleted file mode 100644 index e69de29bb..000000000