From db2234acefcb500580f424e32c19add5ebe6d1a6 Mon Sep 17 00:00:00 2001 From: falken10vdl Date: Fri, 31 Oct 2025 14:27:45 +0100 Subject: [PATCH 1/4] Add Extras in addon preferences to conditionally add functionality. One extra added form commit from sjb007 --- .../bonsai/bim/module/spatial/__init__.py | 1 + .../bonsai/bim/module/spatial/operator.py | 46 +++++++++++++++++++ src/bonsai/bonsai/bim/module/spatial/ui.py | 17 +++++++ src/bonsai/bonsai/bim/ui.py | 27 +++++++++++ 4 files changed, 91 insertions(+) diff --git a/src/bonsai/bonsai/bim/module/spatial/__init__.py b/src/bonsai/bonsai/bim/module/spatial/__init__.py index 810766c552..6c62218532 100644 --- a/src/bonsai/bonsai/bim/module/spatial/__init__.py +++ b/src/bonsai/bonsai/bim/module/spatial/__init__.py @@ -38,6 +38,7 @@ classes = ( operator.SelectDecomposedElements, operator.SelectProduct, operator.SelectSimilarContainer, + operator.SetContainerVisibility, operator.SetDefaultContainer, operator.SetElementVisibility, operator.ToggleContainerElement, diff --git a/src/bonsai/bonsai/bim/module/spatial/operator.py b/src/bonsai/bonsai/bim/module/spatial/operator.py index 965be5c270..bffe88bff7 100644 --- a/src/bonsai/bonsai/bim/module/spatial/operator.py +++ b/src/bonsai/bonsai/bim/module/spatial/operator.py @@ -507,6 +507,52 @@ class SetDefaultContainer(bpy.types.Operator): core.set_orientation_slot(tool.Spatial, container=tool.Ifc.get().by_id(self.container)) return {"FINISHED"} +class SetContainerVisibility(bpy.types.Operator): + bl_idname = "bim.set_container_visibility" + bl_label = "Set Container Visibility" + bl_options = {"REGISTER", "UNDO"} + container: bpy.props.IntProperty() + should_include_children: bpy.props.BoolProperty(name="Should Include Children", default=True, options={"SKIP_SAVE"}) + mode: bpy.props.StringProperty(name="Mode") + + @classmethod + def description(cls, context, operator): + if operator.mode == "HIDE": + return "Hides the selected container and all children.\n" + "ALT+CLICK to ignore children" + elif operator.mode == "SHOW": + return "Shows the selected container and all children.\n" + "ALT+CLICK to ignore children" + return "Isolate the selected container and all children.\n" + "ALT+CLICK to ignore children" + + def invoke(self, context, event): + if event.type == "LEFTMOUSE" and event.alt: + self.should_include_children = False + return self.execute(context) + + def execute(self, context): + if self.mode == "ISOLATE": + if tool.Ifc.get_schema() == "IFC2X3": + containers = tool.Ifc.get().by_type("IfcSpatialStructureElement") + elif tool.Ifc.get_schema() != "IFC2X3": + containers = set(tool.Ifc.get().by_type("IfcSpatialElement")) + containers -= set(tool.Ifc.get().by_type("IfcSpatialZone")) + for container in containers: + if obj := tool.Ifc.get_object(container): + if collection := obj.BIMObjectProperties.collection: + collection.hide_viewport = True + should_hide = False + else: + should_hide = self.mode == "HIDE" + + container = tool.Ifc.get().by_id(self.container) + queue = [container] + while queue: + container = queue.pop() + if obj := tool.Ifc.get_object(container): + if collection := obj.BIMObjectProperties.collection: + collection.hide_viewport = should_hide + if self.should_include_children: + queue.extend(ifcopenshell.util.element.get_parts(container)) + return {"FINISHED"} class SetElementVisibility(bpy.types.Operator): bl_idname = "bim.set_element_visibility" diff --git a/src/bonsai/bonsai/bim/module/spatial/ui.py b/src/bonsai/bonsai/bim/module/spatial/ui.py index ffb7773ac2..e3fbfb8cf2 100644 --- a/src/bonsai/bonsai/bim/module/spatial/ui.py +++ b/src/bonsai/bonsai/bim/module/spatial/ui.py @@ -132,6 +132,23 @@ class BIM_PT_spatial_decomposition(Panel): op = col.operator("bim.set_default_container", icon="OUTLINER_COLLECTION", text="Set Default") op.container = ifc_definition_id + # Only show container visibility operators if the preference is enabled + from bonsai.bim.ui import BIM_ADDON_preferences + addon = BIM_ADDON_preferences.get_addon_instance() + if addon and getattr(addon, "preferences", None): + prefs = addon.preferences + value = getattr(prefs, "container_hide_show_isolate", None) + if value: + op = row.operator("bim.set_container_visibility", icon="FULLSCREEN_EXIT", text="") + op.mode = "ISOLATE" + op.container = ifc_definition_id + op = row.operator("bim.set_container_visibility", icon="HIDE_OFF", text="") + op.mode = "SHOW" + op.container = ifc_definition_id + op = row.operator("bim.set_container_visibility", icon="HIDE_ON", text="") + op.mode = "HIDE" + op.container = ifc_definition_id + # The only operator that's enabled for IfcProject. col = row.column(align=True) col.operator("bim.select_container", icon="OBJECT_DATA", text="").container = ifc_definition_id diff --git a/src/bonsai/bonsai/bim/ui.py b/src/bonsai/bonsai/bim/ui.py index 49b408ba70..de4f57a14b 100644 --- a/src/bonsai/bonsai/bim/ui.py +++ b/src/bonsai/bonsai/bim/ui.py @@ -678,6 +678,32 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences): description="Default parameters for BIM elements", ) + addon_instance = None + @classmethod + def set_addon_instance(cls): + import bpy + instance = None + for key in bpy.context.preferences.addons.keys(): + if ".bonsai" in key: + instance = bpy.context.preferences.addons.get(key) + break + cls.addon_instance = instance + + @classmethod + def get_addon_instance(cls): + if cls.addon_instance is None: + cls.set_addon_instance() + return cls.addon_instance + + def draw_extras_settings(self, layout: bpy.types.UILayout, context: bpy.types.Context) -> None: + layout.prop(self, "container_hide_show_isolate") + + container_hide_show_isolate: BoolProperty( + name="Container hide/show/isolate", + description="Enable container hide/show/isolate feature in the UI", + default=False, + ) + if TYPE_CHECKING: svg2pdf_command: str svg2dxf_command: str @@ -738,6 +764,7 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences): bonsai.bim.helper.draw_expandable_panel(self.layout, context, "Directories", self.draw_directories) bonsai.bim.helper.draw_expandable_panel(self.layout, context, "Drawing", self.draw_drawing_settings) bonsai.bim.helper.draw_expandable_panel(self.layout, context, "Other", self.draw_other_settings) + bonsai.bim.helper.draw_expandable_panel(self.layout, context, "Extras", self.draw_extras_settings) def draw_commands(self, layout: bpy.types.UILayout, context: bpy.types.Context) -> None: layout.prop(self, "svg2pdf_command") From 9f6e92eefd46066f46dfa7d78d2d31180627ad4b Mon Sep 17 00:00:00 2001 From: falken10vdl Date: Sun, 7 Dec 2025 23:11:29 +0100 Subject: [PATCH 2/4] black --- src/bonsai/bonsai/bim/module/spatial/operator.py | 2 ++ src/bonsai/bonsai/bim/module/spatial/ui.py | 1 + src/bonsai/bonsai/bim/ui.py | 2 ++ 3 files changed, 5 insertions(+) diff --git a/src/bonsai/bonsai/bim/module/spatial/operator.py b/src/bonsai/bonsai/bim/module/spatial/operator.py index bffe88bff7..e79cfc7d47 100644 --- a/src/bonsai/bonsai/bim/module/spatial/operator.py +++ b/src/bonsai/bonsai/bim/module/spatial/operator.py @@ -507,6 +507,7 @@ class SetDefaultContainer(bpy.types.Operator): core.set_orientation_slot(tool.Spatial, container=tool.Ifc.get().by_id(self.container)) return {"FINISHED"} + class SetContainerVisibility(bpy.types.Operator): bl_idname = "bim.set_container_visibility" bl_label = "Set Container Visibility" @@ -554,6 +555,7 @@ class SetContainerVisibility(bpy.types.Operator): queue.extend(ifcopenshell.util.element.get_parts(container)) return {"FINISHED"} + class SetElementVisibility(bpy.types.Operator): bl_idname = "bim.set_element_visibility" bl_label = "Set Element Visibility" diff --git a/src/bonsai/bonsai/bim/module/spatial/ui.py b/src/bonsai/bonsai/bim/module/spatial/ui.py index e3fbfb8cf2..f7716b867c 100644 --- a/src/bonsai/bonsai/bim/module/spatial/ui.py +++ b/src/bonsai/bonsai/bim/module/spatial/ui.py @@ -134,6 +134,7 @@ class BIM_PT_spatial_decomposition(Panel): # Only show container visibility operators if the preference is enabled from bonsai.bim.ui import BIM_ADDON_preferences + addon = BIM_ADDON_preferences.get_addon_instance() if addon and getattr(addon, "preferences", None): prefs = addon.preferences diff --git a/src/bonsai/bonsai/bim/ui.py b/src/bonsai/bonsai/bim/ui.py index de4f57a14b..acc88cfa9f 100644 --- a/src/bonsai/bonsai/bim/ui.py +++ b/src/bonsai/bonsai/bim/ui.py @@ -679,9 +679,11 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences): ) addon_instance = None + @classmethod def set_addon_instance(cls): import bpy + instance = None for key in bpy.context.preferences.addons.keys(): if ".bonsai" in key: From c4da1dda4d812a9d649f688efdba9b6d8a6bc7c2 Mon Sep 17 00:00:00 2001 From: falken10vdl Date: Mon, 8 Dec 2025 09:25:49 +0100 Subject: [PATCH 3/4] Refactor addon preferences to make it cleaner as per developer's feedback --- src/bonsai/bonsai/bim/module/spatial/ui.py | 27 ++++++--------- src/bonsai/bonsai/bim/ui.py | 38 ++++++---------------- 2 files changed, 20 insertions(+), 45 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/spatial/ui.py b/src/bonsai/bonsai/bim/module/spatial/ui.py index f7716b867c..acc604f992 100644 --- a/src/bonsai/bonsai/bim/module/spatial/ui.py +++ b/src/bonsai/bonsai/bim/module/spatial/ui.py @@ -132,23 +132,16 @@ class BIM_PT_spatial_decomposition(Panel): op = col.operator("bim.set_default_container", icon="OUTLINER_COLLECTION", text="Set Default") op.container = ifc_definition_id - # Only show container visibility operators if the preference is enabled - from bonsai.bim.ui import BIM_ADDON_preferences - - addon = BIM_ADDON_preferences.get_addon_instance() - if addon and getattr(addon, "preferences", None): - prefs = addon.preferences - value = getattr(prefs, "container_hide_show_isolate", None) - if value: - op = row.operator("bim.set_container_visibility", icon="FULLSCREEN_EXIT", text="") - op.mode = "ISOLATE" - op.container = ifc_definition_id - op = row.operator("bim.set_container_visibility", icon="HIDE_OFF", text="") - op.mode = "SHOW" - op.container = ifc_definition_id - op = row.operator("bim.set_container_visibility", icon="HIDE_ON", text="") - op.mode = "HIDE" - op.container = ifc_definition_id + if tool.Blender.get_addon_preferences().container_hide_show_isolate: + op = row.operator("bim.set_container_visibility", icon="FULLSCREEN_EXIT", text="") + op.mode = "ISOLATE" + op.container = ifc_definition_id + op = row.operator("bim.set_container_visibility", icon="HIDE_OFF", text="") + op.mode = "SHOW" + op.container = ifc_definition_id + op = row.operator("bim.set_container_visibility", icon="HIDE_ON", text="") + op.mode = "HIDE" + op.container = ifc_definition_id # The only operator that's enabled for IfcProject. col = row.column(align=True) diff --git a/src/bonsai/bonsai/bim/ui.py b/src/bonsai/bonsai/bim/ui.py index acc88cfa9f..82b154a46e 100644 --- a/src/bonsai/bonsai/bim/ui.py +++ b/src/bonsai/bonsai/bim/ui.py @@ -678,34 +678,6 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences): description="Default parameters for BIM elements", ) - addon_instance = None - - @classmethod - def set_addon_instance(cls): - import bpy - - instance = None - for key in bpy.context.preferences.addons.keys(): - if ".bonsai" in key: - instance = bpy.context.preferences.addons.get(key) - break - cls.addon_instance = instance - - @classmethod - def get_addon_instance(cls): - if cls.addon_instance is None: - cls.set_addon_instance() - return cls.addon_instance - - def draw_extras_settings(self, layout: bpy.types.UILayout, context: bpy.types.Context) -> None: - layout.prop(self, "container_hide_show_isolate") - - container_hide_show_isolate: BoolProperty( - name="Container hide/show/isolate", - description="Enable container hide/show/isolate feature in the UI", - default=False, - ) - if TYPE_CHECKING: svg2pdf_command: str svg2dxf_command: str @@ -921,6 +893,16 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences): layout.prop(self, "bsdd_load_test_dictionaries") + def draw_extras_settings(self, layout: bpy.types.UILayout, context: bpy.types.Context) -> None: + layout.prop(self, "container_hide_show_isolate") + + container_hide_show_isolate: BoolProperty( + name="Container hide/show/isolate", + description="Enable container hide/show/isolate feature in the UI", + default=False, + ) + + # Scene panel groups class BIM_PT_tabs(Panel): bl_label = "Bonsai" From 75881aab242fe3432da034bffbaac48b0db749cc Mon Sep 17 00:00:00 2001 From: falken10vdl Date: Mon, 8 Dec 2025 09:35:08 +0100 Subject: [PATCH 4/4] place new code after the current preferences one to follow the order. Added to type checking --- src/bonsai/bonsai/bim/ui.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/bonsai/bonsai/bim/ui.py b/src/bonsai/bonsai/bim/ui.py index 82b154a46e..b7ed2180c1 100644 --- a/src/bonsai/bonsai/bim/ui.py +++ b/src/bonsai/bonsai/bim/ui.py @@ -678,6 +678,12 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences): description="Default parameters for BIM elements", ) + container_hide_show_isolate: BoolProperty( + name="Container hide/show/isolate", + description="Enable container hide/show/isolate feature in the UI", + default=False, + ) + if TYPE_CHECKING: svg2pdf_command: str svg2dxf_command: str @@ -713,6 +719,7 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences): pset_dir: str doc: DocPreferences default_parameters: DefaultParameters + container_hide_show_isolate: bool def draw(self, context: bpy.types.Context) -> None: layout = self.layout @@ -892,16 +899,9 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences): layout.prop(self, "bsdd_load_inactive_dictionaries") layout.prop(self, "bsdd_load_test_dictionaries") - def draw_extras_settings(self, layout: bpy.types.UILayout, context: bpy.types.Context) -> None: layout.prop(self, "container_hide_show_isolate") - container_hide_show_isolate: BoolProperty( - name="Container hide/show/isolate", - description="Enable container hide/show/isolate feature in the UI", - default=False, - ) - # Scene panel groups class BIM_PT_tabs(Panel):