diff --git a/src/bonsai/bonsai/bim/module/material/__init__.py b/src/bonsai/bonsai/bim/module/material/__init__.py index 294486bb65..c7f7756bc9 100644 --- a/src/bonsai/bonsai/bim/module/material/__init__.py +++ b/src/bonsai/bonsai/bim/module/material/__init__.py @@ -57,6 +57,7 @@ classes = ( operator.RemoveProfile, operator.ReorderMaterialSetItem, operator.SelectByMaterial, + operator.SelectMaterialInMaterialsUI, operator.UnassignMaterial, operator.UnassignMaterialStyle, prop.Material, diff --git a/src/bonsai/bonsai/bim/module/material/operator.py b/src/bonsai/bonsai/bim/module/material/operator.py index 8dd1663c09..ab757b3665 100644 --- a/src/bonsai/bonsai/bim/module/material/operator.py +++ b/src/bonsai/bonsai/bim/module/material/operator.py @@ -30,6 +30,7 @@ import bonsai.core.material as core import bonsai.bim.module.model.profile as model_profile from bonsai.bim.module.material.prop import purge as material_prop_purge from bonsai.bim.ifc import IfcStore +from typing import Any, Union class LoadMaterials(bpy.types.Operator): @@ -854,3 +855,36 @@ class UnassignMaterialStyle(bpy.types.Operator, tool.Ifc.Operator): ) core.load_materials(tool.Material, props.material_type) tool.Material.update_elements_using_material(material) + + +class SelectMaterialInMaterialsUI(bpy.types.Operator): + bl_idname = "bim.material_ui_select" + bl_label = "Select Material In Materials UI" + bl_options = {"REGISTER", "UNDO"} + material_id: bpy.props.IntProperty() + + def execute(self, context): + props = bpy.context.scene.BIMMaterialProperties + ifc_file = tool.Ifc.get() + material = ifc_file.by_id(self.material_id) + core.load_materials(tool.Material, material.is_a()) + + def get_material_item() -> Union[tuple[int, bpy.types.PropertyGroup], None]: + return next( + ((i, m) for i, m in enumerate(props.materials) if m.ifc_definition_id == self.material_id), None + ) + + material_item = get_material_item() + + # Material category is contracted, won't occur for non-IfcMaterials. + if material_item is None: + material_category = tool.Material.get_material_category(material) + bpy.ops.bim.expand_material_category(category=material_category) + material_item = get_material_item() + assert material_item + + item_index, _ = material_item + props.active_material_index = item_index + + self.report({"INFO"}, f"Material '{material.Name}' is selected in Materials UI.") + return {"FINISHED"} diff --git a/src/bonsai/bonsai/bim/module/material/ui.py b/src/bonsai/bonsai/bim/module/material/ui.py index 3b474010f1..686c5473d3 100644 --- a/src/bonsai/bonsai/bim/module/material/ui.py +++ b/src/bonsai/bonsai/bim/module/material/ui.py @@ -186,6 +186,8 @@ class BIM_PT_object_material(Panel): op.material_set_usage = ObjectMaterialData.data["material_id"] row.operator("bim.disable_editing_assigned_material", icon="CANCEL", text="") else: + op = row.operator("bim.material_ui_select", icon="ZOOM_SELECTED", text="") + op.material_id = ObjectMaterialData.data["material_id"] row.operator("bim.enable_editing_assigned_material", icon="GREASEPENCIL", text="") row.operator("bim.unassign_material", icon="X", text="") diff --git a/src/bonsai/bonsai/tool/material.py b/src/bonsai/bonsai/tool/material.py index c69bb49ea7..c7d207f995 100644 --- a/src/bonsai/bonsai/tool/material.py +++ b/src/bonsai/bonsai/tool/material.py @@ -73,6 +73,11 @@ class Material(bonsai.core.tool.Material): return props.materials[props.active_material_index] return None + @classmethod + def get_material_category(cls, material: ifcopenshell.entity_instance) -> str: + # IfcMaterial has Category since IFC4. + return getattr(material, "Category", None) or "Uncategorised" + @classmethod def import_material_definitions(cls, material_type: str) -> None: props = bpy.context.scene.BIMMaterialProperties @@ -99,8 +104,7 @@ class Material(bonsai.core.tool.Material): for m in materials: # IfcMaterial has Category since IFC4. - category = getattr(m, "Category", None) - category = category or "Uncategorised" + category = cls.get_material_category(m) categories[category].append(m) for category, mats in categories.items():