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")