From 4d7588e1e0f482e9982fd073de74fb69ac2a5f33 Mon Sep 17 00:00:00 2001 From: sLuCHa <142535358+sLuCHaa@users.noreply.github.com> Date: Wed, 8 Jul 2026 18:57:11 +0200 Subject: [PATCH] perf(properties): count-only panel for very large selections Rebuilding the Properties panel aggregated shared/varying values across the whole selection: O(n) per property row, plus an O(n^2) group filter (group.handles.contains is a linear scan per selected entity). Selecting or pasting tens of thousands of objects stalled the rebuild for seconds. Above a cap, show a lightweight ' objects selected' panel instead of the per-entity aggregation; bulk layer/colour/lineweight edits still go through the ribbon. --- src/app/properties.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/app/properties.rs b/src/app/properties.rs index 3171f733..eb8bd93b 100644 --- a/src/app/properties.rs +++ b/src/app/properties.rs @@ -5,6 +5,11 @@ use crate::scene::view::dispatch; use crate::ui; use acadrust::{EntityType, Handle}; +/// Above this many selected objects the Properties panel skips per-entity +/// property aggregation (which is O(n) per row, plus an O(n²) group filter) and +/// shows a count-only summary instead. Bulk edits still go through the ribbon. +const MAX_PROP_AGGREGATE: usize = 2_000; + impl OpenCADStudio { /// Rebuild the PropertiesPanel from the current entity selection. /// Preserves UI state (open pickers, edit buffer) across refreshes. @@ -416,6 +421,23 @@ impl OpenCADStudio { ..Default::default() } } + // Property aggregation is O(n) per row plus an O(n²) group filter + // (`group.handles.contains` scans per entity), stalling the rebuild + // for seconds at tens of thousands of objects. Above the cap show a + // count-only panel; bulk edits still go through the ribbon. + n if n > MAX_PROP_AGGREGATE => ui::PropertiesPanel { + title: format!("{} objects selected", n), + layer_combo: iced::widget::combo_box::State::new(layer_names.clone()), + linetype_combo: iced::widget::combo_box::State::new(linetype_items.clone()), + lineweight_combo: iced::widget::combo_box::State::new( + ui::properties::lw_options(), + ), + hatch_pattern_combo: iced::widget::combo_box::State::new( + crate::scene::model::hatch_patterns::names(), + ), + linetype_items, + ..Default::default() + }, _ => { let groups = build_selection_groups(&selected); let active_group = selected_group