From c83b4eb69fcc90c95b290a30684f04fd738ef46f Mon Sep 17 00:00:00 2001 From: Ryan Schultz Date: Sun, 31 May 2026 07:41:03 -0500 Subject: [PATCH] Restore pre-aggregate selection on exit; deselect on unsupported profile When override_mode_set_edit encounters an unsupported profile (Couldn't import profile), deselect the object so Tab continues to cycle cleanly. Also restores the selection that existed before entering aggregate mode when finally tabbing out, via save/restore_previous_selection(). --- .../bonsai/bim/module/aggregate/prop.py | 2 ++ .../bonsai/bim/module/geometry/operator.py | 1 + src/bonsai/bonsai/core/aggregate.py | 3 +++ src/bonsai/bonsai/tool/aggregate.py | 21 +++++++++++++++++++ 4 files changed, 27 insertions(+) diff --git a/src/bonsai/bonsai/bim/module/aggregate/prop.py b/src/bonsai/bonsai/bim/module/aggregate/prop.py index 424f2b829f..46123a90c8 100644 --- a/src/bonsai/bonsai/bim/module/aggregate/prop.py +++ b/src/bonsai/bonsai/bim/module/aggregate/prop.py @@ -139,6 +139,7 @@ class BIMAggregateProperties(PropertyGroup): previous_editing_aggregate: PointerProperty(name="Editing Aggregate", type=bpy.types.Object) editing_objects: CollectionProperty(type=Objects) not_editing_objects: CollectionProperty(type=Objects) + previously_selected_objects: CollectionProperty(type=Objects) aggregate_decorator: BoolProperty( name="Display Aggregate", default=False, @@ -155,5 +156,6 @@ class BIMAggregateProperties(PropertyGroup): previous_editing_aggregate: Union[bpy.types.Object, None] editing_objects: bpy.types.bpy_prop_collection_idprop[Objects] not_editing_objects: bpy.types.bpy_prop_collection_idprop[Objects] + previously_selected_objects: bpy.types.bpy_prop_collection_idprop[Objects] aggregate_decorator: bool previous_state: bool diff --git a/src/bonsai/bonsai/bim/module/geometry/operator.py b/src/bonsai/bonsai/bim/module/geometry/operator.py index 6f955ba6bf..0b7748fe72 100644 --- a/src/bonsai/bonsai/bim/module/geometry/operator.py +++ b/src/bonsai/bonsai/bim/module/geometry/operator.py @@ -2366,6 +2366,7 @@ class OverrideModeSetEdit(bpy.types.Operator, tool.Ifc.Operator): {"INFO"}, f"Couldn't import profile, editing it directly is not yet supported. Failing profile: {profile}.", ) + obj.select_set(False) return tool.Ifc.link(item, obj.data) self.enable_edit_mode(context) diff --git a/src/bonsai/bonsai/core/aggregate.py b/src/bonsai/bonsai/core/aggregate.py index 0b6719a180..037f80c6ba 100644 --- a/src/bonsai/bonsai/core/aggregate.py +++ b/src/bonsai/bonsai/core/aggregate.py @@ -93,6 +93,8 @@ def enter_aggregate_mode( aggregator: type[tool.Aggregate], obj: bpy.types.Object, ): + if not aggregator.get_aggregate_props().in_aggregate_mode: + aggregator.save_previous_selection() aggregator.update_previous_aggregate_mode_state() if aggregator.get_higher_aggregate(): aggregator.disable_aggregate_mode() @@ -107,6 +109,7 @@ def exit_aggregate_mode(aggregator: type[tool.Aggregate]): aggregator.enable_aggregate_mode(new_obj) else: aggregator.disable_aggregate_mode() + aggregator.restore_previous_selection() class IncompatibleAggregateError(Exception): diff --git a/src/bonsai/bonsai/tool/aggregate.py b/src/bonsai/bonsai/tool/aggregate.py index 1f7f601862..9106024ad2 100644 --- a/src/bonsai/bonsai/tool/aggregate.py +++ b/src/bonsai/bonsai/tool/aggregate.py @@ -205,6 +205,27 @@ class Aggregate(bonsai.core.tool.Aggregate): props.in_aggregate_mode = True return {"FINISHED"} + @classmethod + def save_previous_selection(cls) -> None: + props = cls.get_aggregate_props() + props.previously_selected_objects.clear() + for obj in bpy.context.selected_objects: + entry = props.previously_selected_objects.add() + entry.obj = obj + + @classmethod + def restore_previous_selection(cls) -> None: + props = cls.get_aggregate_props() + for obj in bpy.context.selected_objects: + obj.select_set(False) + for entry in props.previously_selected_objects: + if entry.obj: + try: + entry.obj.select_set(True) + except Exception: + pass + props.previously_selected_objects.clear() + @classmethod def disable_aggregate_mode(cls): context = bpy.context