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..e79cfc7d47 100644 --- a/src/bonsai/bonsai/bim/module/spatial/operator.py +++ b/src/bonsai/bonsai/bim/module/spatial/operator.py @@ -508,6 +508,54 @@ class SetDefaultContainer(bpy.types.Operator): 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" 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 ffb7773ac2..acc604f992 100644 --- a/src/bonsai/bonsai/bim/module/spatial/ui.py +++ b/src/bonsai/bonsai/bim/module/spatial/ui.py @@ -132,6 +132,17 @@ class BIM_PT_spatial_decomposition(Panel): op = col.operator("bim.set_default_container", icon="OUTLINER_COLLECTION", text="Set Default") 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) 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..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 @@ -738,6 +745,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") @@ -891,6 +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") + # Scene panel groups class BIM_PT_tabs(Panel):