diff --git a/src/bonsai/bonsai/bim/module/spatial/__init__.py b/src/bonsai/bonsai/bim/module/spatial/__init__.py index 99d9bae24c..bef4f21e46 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.SelectSimilarContainer, operator.SetContainerVisibility, operator.SetDefaultContainer, + operator.ToggleContainerElement, prop.Element, prop.BIMObjectSpatialProperties, prop.BIMContainer, diff --git a/src/bonsai/bonsai/bim/module/spatial/operator.py b/src/bonsai/bonsai/bim/module/spatial/operator.py index 9ba7831940..aeaf6033fe 100644 --- a/src/bonsai/bonsai/bim/module/spatial/operator.py +++ b/src/bonsai/bonsai/bim/module/spatial/operator.py @@ -243,6 +243,17 @@ class DeleteContainer(bpy.types.Operator, tool.Ifc.Operator): core.delete_container(tool.Ifc, tool.Spatial, tool.Geometry, container=tool.Ifc.get().by_id(self.container)) +class ToggleContainerElement(bpy.types.Operator): + bl_idname = "bim.toggle_container_element" + bl_label = "Toggle Container Element" + bl_options = {"REGISTER", "UNDO"} + ifc_class: bpy.props.StringProperty() + + def execute(self, context): + core.toggle_container_element(tool.Spatial, ifc_class=self.ifc_class) + return {"FINISHED"} + + class SelectDecomposedElements(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.select_decomposed_elements" bl_label = "Select Children" diff --git a/src/bonsai/bonsai/bim/module/spatial/prop.py b/src/bonsai/bonsai/bim/module/spatial/prop.py index 12384f08c2..4f04f1bb48 100644 --- a/src/bonsai/bonsai/bim/module/spatial/prop.py +++ b/src/bonsai/bonsai/bim/module/spatial/prop.py @@ -112,6 +112,7 @@ class Element(PropertyGroup): is_type: BoolProperty(name="Is Type", default=False) ifc_definition_id: IntProperty(name="IFC Definition ID") total: IntProperty(name="Total") + is_expanded: BoolProperty(name="Is Expanded", default=False) class BIMSpatialDecompositionProperties(PropertyGroup): @@ -122,6 +123,7 @@ class BIMSpatialDecompositionProperties(PropertyGroup): active_container_index: IntProperty(name="Active Container Index", update=update_active_container_index) element_filter: StringProperty(name="Element Filter", default="", options={"TEXTEDIT_UPDATE"}) elements: CollectionProperty(name="Elements", type=Element) + contracted_classes: StringProperty(name="Contracted Classes", default="[]") active_element_index: IntProperty(name="Active Element Index") total_elements: IntProperty(name="Total Elements") subelement_class: bpy.props.EnumProperty(items=get_subelement_class, name="Subelement Class") diff --git a/src/bonsai/bonsai/bim/module/spatial/ui.py b/src/bonsai/bonsai/bim/module/spatial/ui.py index a7d3e0a51a..da35223b33 100644 --- a/src/bonsai/bonsai/bim/module/spatial/ui.py +++ b/src/bonsai/bonsai/bim/module/spatial/ui.py @@ -262,7 +262,8 @@ class BIM_UL_elements(UIList): if item: row = layout.row(align=True) if item.is_class: - row.label(text="", icon="DISCLOSURE_TRI_DOWN") + icon_id = "DISCLOSURE_TRI_DOWN" if item.is_expanded else "DISCLOSURE_TRI_RIGHT" + row.operator("bim.toggle_container_element", text="", emboss=False, icon=icon_id).ifc_class = item.name row.label(text=item.name) col = row.column() col.alignment = "RIGHT" diff --git a/src/bonsai/bonsai/core/spatial.py b/src/bonsai/bonsai/core/spatial.py index 4bad423e30..1bf19d386e 100644 --- a/src/bonsai/bonsai/core/spatial.py +++ b/src/bonsai/bonsai/core/spatial.py @@ -141,6 +141,11 @@ def delete_container( spatial.import_spatial_decomposition() +def toggle_container_element(spatial: tool.Spatial, ifc_class: str) -> None: + spatial.toggle_container_element(ifc_class) + spatial.load_contained_elements() + + def select_decomposed_elements( spatial: tool.Spatial, container: ifcopenshell.entity_instance, diff --git a/src/bonsai/bonsai/tool/spatial.py b/src/bonsai/bonsai/tool/spatial.py index 499508e9bd..d8e6410dfe 100644 --- a/src/bonsai/bonsai/tool/spatial.py +++ b/src/bonsai/bonsai/tool/spatial.py @@ -221,22 +221,27 @@ class Spatial(bonsai.core.tool.Spatial): results.setdefault(ifc_class, {}).setdefault(ifc_definition_id, {"total": 0, "type_name": type_name}) results[ifc_class][ifc_definition_id]["total"] += 1 + contracted_classes = json.loads(props.contracted_classes) total_elements = 0 for ifc_class in sorted(results.keys()): new = props.elements.add() new.name = ifc_class new.is_class = True + class_is_expanded = ifc_class not in contracted_classes + new.is_expanded = class_is_expanded total = 0 for ifc_definition_id in sorted( results[ifc_class].keys(), key=lambda x: results[ifc_class][x]["type_name"] ): - new2 = props.elements.add() - new2.is_type = True - new2.name = results[ifc_class][ifc_definition_id]["type_name"] - new2.ifc_class = ifc_class - new2.total = results[ifc_class][ifc_definition_id]["total"] - new2.ifc_definition_id = ifc_definition_id - total += new2.total + total2 = results[ifc_class][ifc_definition_id]["total"] + if class_is_expanded: + new2 = props.elements.add() + new2.is_type = True + new2.name = results[ifc_class][ifc_definition_id]["type_name"] + new2.ifc_class = ifc_class + new2.total = total2 + new2.ifc_definition_id = ifc_definition_id + total += total2 new.total = total total_elements += total @@ -336,6 +341,16 @@ class Spatial(bonsai.core.tool.Spatial): contracted_containers.remove(container.id()) props.contracted_containers = json.dumps(contracted_containers) + @classmethod + def toggle_container_element(cls, ifc_class: str) -> None: + props = bpy.context.scene.BIMSpatialDecompositionProperties + contracted_classes: list[str] = json.loads(props.contracted_classes) + if ifc_class in contracted_classes: + contracted_classes.remove(ifc_class) + else: + contracted_classes.append(ifc_class) + props.contracted_classes = json.dumps(contracted_classes) + # HERE STARTS SPATIAL TOOL @classmethod