From 32e00f6d491c0285b3d11edf948aef398e3567c5 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Thu, 3 Nov 2022 23:36:04 +1100 Subject: [PATCH] Refactor material UI to not depend on IOS API data class --- .../blenderbim/bim/module/material/data.py | 140 ++++++++++++- .../bim/module/material/operator.py | 90 ++------ .../blenderbim/bim/module/material/ui.py | 193 +++++------------- src/blenderbim/pytest.ini | 1 + 4 files changed, 202 insertions(+), 222 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/material/data.py b/src/blenderbim/blenderbim/bim/module/material/data.py index 9cb372bc9a..e8238f1016 100644 --- a/src/blenderbim/blenderbim/bim/module/material/data.py +++ b/src/blenderbim/blenderbim/bim/module/material/data.py @@ -69,9 +69,7 @@ class MaterialsData: version = tool.Ifc.get_schema() if version == "IFC2X3": material_types = ["IfcMaterial", "IfcMaterialLayerSet", "IfcMaterialList"] - return [ - (m, m, ifcopenshell.util.doc.get_entity_doc(version, m).get("description", "")) for m in material_types - ] + return [(m, m, ifcopenshell.util.doc.get_entity_doc(version, m).get("description", "")) for m in material_types] @classmethod def profiles(cls): @@ -84,12 +82,140 @@ class ObjectMaterialData: @classmethod def load(cls): - cls.data = { - "materials": cls.materials(), - "type_material": cls.type_material(), - } + cls.data["material_class"] = cls.material_class() + cls.data["material_id"] = cls.material_id() + cls.data["material_name"] = cls.material_name() + cls.data["set"] = cls.set() + cls.data["set_usage"] = cls.set_usage() + cls.data["set_items"] = cls.set_items() + cls.data["set_item_name"] = cls.set_item_name() + cls.data["total_thickness"] = cls.total_thickness() + cls.data["materials"] = cls.materials() + cls.data["type_material"] = cls.type_material() cls.is_loaded = True + @classmethod + def material_class(cls): + element = tool.Ifc.get_entity(bpy.context.active_object) + cls.material = ifcopenshell.util.element.get_material(element) + if cls.material: + return cls.material.is_a() + + @classmethod + def material_id(cls): + if cls.material: + return cls.material.id() + return 0 + + @classmethod + def set(cls): + mset = None + if cls.material: + mset = cls.material + if cls.material.is_a("IfcMaterialLayerSetUsage"): + mset = cls.material.ForLayerSet + elif cls.material.is_a("IfcMaterialProfileSetUsage"): + mset = cls.material.ForProfileSet + return { + "id": mset.id(), + "name": getattr(mset, "LayerSetName", getattr(mset, "Name", None)) or "Unnamed", + "description": getattr(mset, "Description", None), + } + + @classmethod + def set_usage(cls): + # TODO: complain to buildingSMART + cardinal_point_map = { + 1: "bottom left", + 2: "bottom centre", + 3: "bottom right", + 4: "mid-depth left", + 5: "mid-depth centre", + 6: "mid-depth right", + 7: "top left", + 8: "top centre", + 9: "top right", + 10: "geometric centroid", + 11: "bottom in line with the geometric centroid", + 12: "left in line with the geometric centroid", + 13: "right in line with the geometric centroid", + 14: "top in line with the geometric centroid", + 15: "shear centre", + 16: "bottom in line with the shear centre", + 17: "left in line with the shear centre", + 18: "right in line with the shear centre", + 19: "top in line with the shear centre", + } + results = {} + if cls.material: + if cls.material.is_a("IfcMaterialProfileSetUsage"): + if cls.material.CardinalPoint: + results["cardinal_point"] = cardinal_point_map[cls.material.CardinalPoint] + return results + + @classmethod + def set_items(cls): + results = [] + if cls.material: + items = [] + if cls.material.is_a("IfcMaterialLayerSetUsage"): + items = cls.material.ForLayerSet.MaterialLayers + elif cls.material.is_a("IfcMaterialProfileSetUsage"): + items = cls.material.ForProfileSet.MaterialProfiles + elif cls.material.is_a("IfcMaterialLayerSet"): + items = cls.material.MaterialLayers + elif cls.material.is_a("IfcMaterialProfileSet"): + items = cls.material.MaterialProfiles + elif cls.material.is_a("IfcMaterialConstituentSet"): + items = cls.material.MaterialConstituents + + icon = "LAYER_ACTIVE" + if "Layer" in cls.material.is_a(): + icon = "ALIGN_CENTER" + elif "Profile" in cls.material.is_a(): + icon = "ITALIC" + elif "Constituent" in cls.material.is_a(): + icon = "POINTCLOUD_DATA" + + for item in items or []: + data = {"id": item.id(), "name": item.Name or "Unnamed", "icon": icon} + if item.is_a("IfcMaterialLayer"): + data["name"] += f" ({item.LayerThickness})" + if not item.is_a("IfcMaterialList"): + data["material"] = item.Material.Name or "Unnamed" + results.append(data) + return results + + @classmethod + def total_thickness(cls): + if cls.material: + layers = [] + if cls.material.is_a("IfcMaterialLayerSetUsage"): + layers = cls.material.ForLayerSet.MaterialLayers + elif cls.material.is_a("IfcMaterialLayerSet"): + layers = cls.material.MaterialLayers + return sum([l.LayerThickness for l in layers or []]) + + @classmethod + def set_item_name(cls): + results = [] + if cls.material: + if "Constituent" in cls.material.is_a(): + return "constituent" + elif "Layer" in cls.material.is_a(): + return "layer" + elif "Profile" in cls.material.is_a(): + return "profile" + elif "List" in cls.material.is_a(): + return "list_item" + + @classmethod + def material_name(cls): + element = tool.Ifc.get_entity(bpy.context.active_object) + material = ifcopenshell.util.element.get_material(element) + if material: + return getattr(material, "Name", None) or "Unnamed" + @classmethod def materials(cls): return sorted( diff --git a/src/blenderbim/blenderbim/bim/module/material/operator.py b/src/blenderbim/blenderbim/bim/module/material/operator.py index 2b1cfb20d9..324e1a0931 100644 --- a/src/blenderbim/blenderbim/bim/module/material/operator.py +++ b/src/blenderbim/blenderbim/bim/module/material/operator.py @@ -58,7 +58,7 @@ class SelectByMaterial(bpy.types.Operator, tool.Ifc.Operator): core.select_by_material(tool.Material, material=tool.Ifc.get().by_id(self.material)) -class AssignParameterizedProfile(bpy.types.Operator): +class AssignParameterizedProfile(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.assign_parameterized_profile" bl_label = "Assign Parameterized Profile" bl_options = {"REGISTER", "UNDO"} @@ -66,9 +66,6 @@ class AssignParameterizedProfile(bpy.types.Operator): material_profile: bpy.props.IntProperty() obj: bpy.props.StringProperty() - def execute(self, context): - return IfcStore.execute_ifc_operator(self, context) - def _execute(self, context): obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object self.file = IfcStore.get_file() @@ -84,7 +81,6 @@ class AssignParameterizedProfile(bpy.types.Operator): ) Data.load_profiles() bpy.ops.bim.enable_editing_material_set_item(obj=obj.name, material_set_item=self.material_profile) - return {"FINISHED"} class AddMaterial(bpy.types.Operator, tool.Ifc.Operator): @@ -143,16 +139,13 @@ class UnlinkMaterial(bpy.types.Operator, tool.Ifc.Operator): core.unlink_material(tool.Ifc, obj=context.active_object.active_material) -class AssignMaterial(bpy.types.Operator): +class AssignMaterial(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.assign_material" bl_label = "Assign Material" bl_options = {"REGISTER", "UNDO"} obj: bpy.props.StringProperty() material_type: bpy.props.StringProperty() - def execute(self, context): - return IfcStore.execute_ifc_operator(self, context) - def _execute(self, context): obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object material_type = self.material_type or obj.BIMObjectMaterialProperties.material_type @@ -169,18 +162,14 @@ class AssignMaterial(bpy.types.Operator): ) Data.load(IfcStore.get_file()) Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id) - return {"FINISHED"} -class UnassignMaterial(bpy.types.Operator): +class UnassignMaterial(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.unassign_material" bl_label = "Unassign Material" bl_options = {"REGISTER", "UNDO"} obj: bpy.props.StringProperty() - def execute(self, context): - return IfcStore.execute_ifc_operator(self, context) - def _execute(self, context): obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object self.file = IfcStore.get_file() @@ -190,19 +179,15 @@ class UnassignMaterial(bpy.types.Operator): **{"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)}, ) Data.purge() - return {"FINISHED"} -class AddConstituent(bpy.types.Operator): +class AddConstituent(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.add_constituent" bl_label = "Add Constituent" bl_options = {"REGISTER", "UNDO"} obj: bpy.props.StringProperty() constituent_set: bpy.props.IntProperty() - def execute(self, context): - return IfcStore.execute_ifc_operator(self, context) - def _execute(self, context): obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object self.file = IfcStore.get_file() @@ -215,19 +200,15 @@ class AddConstituent(bpy.types.Operator): }, ) Data.load_constituents() - return {"FINISHED"} -class RemoveConstituent(bpy.types.Operator): +class RemoveConstituent(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.remove_constituent" bl_label = "Remove Constituent" bl_options = {"REGISTER", "UNDO"} obj: bpy.props.StringProperty() constituent: bpy.props.IntProperty() - def execute(self, context): - return IfcStore.execute_ifc_operator(self, context) - def _execute(self, context): obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object self.file = IfcStore.get_file() @@ -235,19 +216,15 @@ class RemoveConstituent(bpy.types.Operator): "material.remove_constituent", self.file, **{"constituent": self.file.by_id(self.constituent)} ) Data.load_constituents() - return {"FINISHED"} -class AddProfile(bpy.types.Operator): +class AddProfile(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.add_profile" bl_label = "Add Profile" bl_options = {"REGISTER", "UNDO"} obj: bpy.props.StringProperty() profile_set: bpy.props.IntProperty() - def execute(self, context): - return IfcStore.execute_ifc_operator(self, context) - def _execute(self, context): obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object self.file = IfcStore.get_file() @@ -259,37 +236,29 @@ class AddProfile(bpy.types.Operator): profile=self.file.by_id(int(context.scene.BIMMaterialProperties.profiles)), ) Data.load_profiles() - return {"FINISHED"} -class RemoveProfile(bpy.types.Operator): +class RemoveProfile(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.remove_profile" bl_label = "Remove Profile" bl_options = {"REGISTER", "UNDO"} obj: bpy.props.StringProperty() profile: bpy.props.IntProperty() - def execute(self, context): - return IfcStore.execute_ifc_operator(self, context) - def _execute(self, context): obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object self.file = IfcStore.get_file() ifcopenshell.api.run("material.remove_profile", self.file, **{"profile": self.file.by_id(self.profile)}) Data.load_profiles() - return {"FINISHED"} -class AddLayer(bpy.types.Operator): +class AddLayer(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.add_layer" bl_label = "Add Layer" bl_options = {"REGISTER", "UNDO"} obj: bpy.props.StringProperty() layer_set: bpy.props.IntProperty() - def execute(self, context): - return IfcStore.execute_ifc_operator(self, context) - def _execute(self, context): obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object self.file = IfcStore.get_file() @@ -302,10 +271,9 @@ class AddLayer(bpy.types.Operator): }, ) Data.load_layers() - return {"FINISHED"} -class ReorderMaterialSetItem(bpy.types.Operator): +class ReorderMaterialSetItem(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.reorder_material_set_item" bl_label = "Reorder Material Set Item" bl_options = {"REGISTER", "UNDO"} @@ -314,9 +282,6 @@ class ReorderMaterialSetItem(bpy.types.Operator): new_index: bpy.props.IntProperty() material_set: bpy.props.IntProperty() - def execute(self, context): - return IfcStore.execute_ifc_operator(self, context) - def _execute(self, context): obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object self.file = IfcStore.get_file() @@ -338,37 +303,29 @@ class ReorderMaterialSetItem(bpy.types.Operator): Data.load_profiles() elif material_set.is_a("IfcMaterialList"): Data.load_lists() - return {"FINISHED"} -class RemoveLayer(bpy.types.Operator): +class RemoveLayer(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.remove_layer" bl_label = "Remove Layer" bl_options = {"REGISTER", "UNDO"} obj: bpy.props.StringProperty() layer: bpy.props.IntProperty() - def execute(self, context): - return IfcStore.execute_ifc_operator(self, context) - def _execute(self, context): obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object self.file = IfcStore.get_file() ifcopenshell.api.run("material.remove_layer", self.file, **{"layer": self.file.by_id(self.layer)}) Data.load_layers() - return {"FINISHED"} -class AddListItem(bpy.types.Operator): +class AddListItem(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.add_list_item" bl_label = "Add List Item" bl_options = {"REGISTER", "UNDO"} obj: bpy.props.StringProperty() list_item_set: bpy.props.IntProperty() - def execute(self, context): - return IfcStore.execute_ifc_operator(self, context) - def _execute(self, context): obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object self.file = IfcStore.get_file() @@ -381,10 +338,9 @@ class AddListItem(bpy.types.Operator): }, ) Data.load_lists() - return {"FINISHED"} -class RemoveListItem(bpy.types.Operator): +class RemoveListItem(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.remove_list_item" bl_label = "Remove List Item" bl_options = {"REGISTER", "UNDO"} @@ -393,9 +349,6 @@ class RemoveListItem(bpy.types.Operator): list_item: bpy.props.IntProperty() list_item_index: bpy.props.IntProperty() - def execute(self, context): - return IfcStore.execute_ifc_operator(self, context) - def _execute(self, context): obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object self.file = IfcStore.get_file() @@ -408,7 +361,6 @@ class RemoveListItem(bpy.types.Operator): }, ) Data.load_lists() - return {"FINISHED"} class EnableEditingAssignedMaterial(bpy.types.Operator): @@ -504,7 +456,7 @@ class DisableEditingAssignedMaterial(bpy.types.Operator): return {"FINISHED"} -class EditAssignedMaterial(bpy.types.Operator): +class EditAssignedMaterial(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.edit_assigned_material" bl_label = "Edit Assigned Material" bl_options = {"REGISTER", "UNDO"} @@ -512,9 +464,6 @@ class EditAssignedMaterial(bpy.types.Operator): material_set: bpy.props.IntProperty() material_set_usage: bpy.props.IntProperty() - def execute(self, context): - return IfcStore.execute_ifc_operator(self, context) - def _execute(self, context): self.file = IfcStore.get_file() obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object @@ -567,7 +516,6 @@ class EditAssignedMaterial(bpy.types.Operator): elif material_set.is_a("IfcMaterialProfileSet"): Data.load_profiles() bpy.ops.bim.disable_editing_assigned_material(obj=obj.name) - return {"FINISHED"} class EnableEditingMaterialSetItem(bpy.types.Operator): @@ -642,16 +590,13 @@ class DisableEditingMaterialSetItem(bpy.types.Operator): return {"FINISHED"} -class EditMaterialSetItem(bpy.types.Operator): +class EditMaterialSetItem(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.edit_material_set_item" bl_label = "Edit Material Set Item" bl_options = {"REGISTER", "UNDO"} obj: bpy.props.StringProperty() material_set_item: bpy.props.IntProperty() - def execute(self, context): - return IfcStore.execute_ifc_operator(self, context) - def _execute(self, context): obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object self.file = IfcStore.get_file() @@ -701,17 +646,13 @@ class EditMaterialSetItem(bpy.types.Operator): pass bpy.ops.bim.disable_editing_material_set_item(obj=obj.name) - return {"FINISHED"} -class CopyMaterial(bpy.types.Operator): +class CopyMaterial(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.copy_material" bl_label = "Copy Material" bl_options = {"REGISTER", "UNDO"} - def execute(self, context): - return IfcStore.execute_ifc_operator(self, context) - def _execute(self, context): self.file = IfcStore.get_file() material = ifcopenshell.util.element.get_material( @@ -732,7 +673,6 @@ class CopyMaterial(bpy.types.Operator): ) Data.load(self.file, obj.BIMObjectProperties.ifc_definition_id) self.set_default_material(obj, material) - return {"FINISHED"} def set_default_material(self, obj, material): object_material_ids = [ diff --git a/src/blenderbim/blenderbim/bim/module/material/ui.py b/src/blenderbim/blenderbim/bim/module/material/ui.py index 78f5999084..5790903ce7 100644 --- a/src/blenderbim/blenderbim/bim/module/material/ui.py +++ b/src/blenderbim/blenderbim/bim/module/material/ui.py @@ -132,7 +132,6 @@ class BIM_PT_object_material(Panel): Data.load(IfcStore.get_file()) if self.oprops.ifc_definition_id not in Data.products: Data.load(IfcStore.get_file(), self.oprops.ifc_definition_id) - self.product_data = Data.products[self.oprops.ifc_definition_id] if not ObjectMaterialData.data["materials"]: row = self.layout.row(align=True) @@ -144,46 +143,7 @@ class BIM_PT_object_material(Panel): row = self.layout.row(align=True) row.label(text="Inherited Material: " + ObjectMaterialData.data["type_material"], icon="FILE_PARENT") - if self.product_data: - if self.product_data["type"] == "IfcMaterialConstituentSet": - self.material_set_id = self.product_data["id"] - self.material_set_data = Data.constituent_sets[self.material_set_id] - self.set_items = self.material_set_data["MaterialConstituents"] or [] - self.set_data = Data.constituents - self.set_item_name = "constituent" - elif self.product_data["type"] == "IfcMaterialLayerSet": - self.material_set_id = self.product_data["id"] - self.material_set_data = Data.layer_sets[self.material_set_id] - self.set_items = self.material_set_data["MaterialLayers"] or [] - self.set_data = Data.layers - self.set_item_name = "layer" - elif self.product_data["type"] == "IfcMaterialLayerSetUsage": - self.material_set_usage = Data.layer_set_usages[self.product_data["id"]] - self.material_set_id = self.material_set_usage["ForLayerSet"] - self.material_set_data = Data.layer_sets[self.material_set_id] - self.set_items = self.material_set_data["MaterialLayers"] or [] - self.set_data = Data.layers - self.set_item_name = "layer" - elif self.product_data["type"] == "IfcMaterialProfileSet": - self.material_set_id = self.product_data["id"] - self.material_set_data = Data.profile_sets[self.material_set_id] - self.set_items = self.material_set_data["MaterialProfiles"] or [] - self.set_data = Data.profiles - self.set_item_name = "profile" - elif self.product_data["type"] == "IfcMaterialProfileSetUsage": - self.material_set_usage = Data.profile_set_usages[self.product_data["id"]] - self.material_set_id = self.material_set_usage["ForProfileSet"] - self.material_set_data = Data.profile_sets[self.material_set_id] - self.set_items = self.material_set_data["MaterialProfiles"] or [] - self.set_data = Data.profiles - self.set_item_name = "profile" - elif self.product_data["type"] == "IfcMaterialList": - self.material_set_id = self.product_data["id"] - self.material_set_data = Data.lists[self.material_set_id] - self.set_items = self.material_set_data["Materials"] or [] - self.set_item_name = "list_item" - else: - self.material_set_id = 0 + if ObjectMaterialData.data["material_class"]: return self.draw_material_ui() row = self.layout.row(align=True) @@ -194,21 +154,21 @@ class BIM_PT_object_material(Panel): def draw_material_ui(self): row = self.layout.row(align=True) - row.label(text=self.product_data["type"]) + row.label(text=ObjectMaterialData.data["material_class"]) if self.props.is_editing: op = row.operator("bim.edit_assigned_material", icon="CHECKMARK", text="") - op.material_set = self.material_set_id - if "Usage" in self.product_data["type"]: - op.material_set_usage = self.product_data["id"] + op.material_set = ObjectMaterialData.data["set"]["id"] + if "Usage" in ObjectMaterialData.data["material_class"]: + op.material_set_usage = ObjectMaterialData.data["material_id"] row.operator("bim.disable_editing_assigned_material", icon="CANCEL", text="") else: - if self.product_data["type"] == "IfcMaterial": + if ObjectMaterialData.data["material_class"] == "IfcMaterial": row.operator("bim.copy_material", icon="COPYDOWN", text="") row.operator("bim.enable_editing_assigned_material", icon="GREASEPENCIL", text="") row.operator("bim.unassign_material", icon="X", text="") - if self.product_data["type"] == "IfcMaterial": + if ObjectMaterialData.data["material_class"] == "IfcMaterial": self.draw_single_ui() else: self.draw_set_ui() @@ -222,10 +182,9 @@ class BIM_PT_object_material(Panel): prop_with_search(self.layout, self.props, "material", text="") def draw_read_only_single_ui(self): - material = Data.materials[self.product_data["id"]] row = self.layout.row(align=True) row.label(text="Name") - row.label(text=material["Name"]) + row.label(text=ObjectMaterialData.data["material_name"]) def draw_set_ui(self): if self.props.is_editing: @@ -237,29 +196,26 @@ class BIM_PT_object_material(Panel): blenderbim.bim.helper.draw_attributes(self.props.material_set_usage_attributes, self.layout) row = self.layout.row(align=True) - if self.set_item_name == "profile": + if ObjectMaterialData.data["set_item_name"] == "profile": row.prop(self.mprops, "profiles", icon="ITALIC", text="") prop_with_search(row, self.props, "material", icon="MATERIAL", text="") - op = row.operator(f"bim.add_{self.set_item_name}", icon="ADD", text="") - setattr(op, f"{self.set_item_name}_set", self.material_set_id) + op = row.operator(f"bim.add_{ObjectMaterialData.data['set_item_name']}", icon="ADD", text="") + setattr(op, f"{ObjectMaterialData.data['set_item_name']}_set", ObjectMaterialData.data["set"]["id"]) - total_items = len(self.set_items) - for index, set_item_id in enumerate(self.set_items): - if self.props.active_material_set_item_id == set_item_id: - self.draw_editable_set_item_ui(set_item_id) + total_items = len(ObjectMaterialData.data["set_items"]) + for index, set_item in enumerate(ObjectMaterialData.data["set_items"]): + if self.props.active_material_set_item_id == set_item["id"]: + self.draw_editable_set_item_ui(set_item) else: self.draw_read_only_set_item_ui( - set_item_id, index, is_first=index == 0, is_last=index == total_items - 1 + set_item, index, is_first=index == 0, is_last=index == total_items - 1 ) - def draw_editable_set_item_ui(self, set_item_id): - item = self.set_data[set_item_id] - material = Data.materials[item["Material"]] - + def draw_editable_set_item_ui(self, set_item): box = self.layout.box() row = box.row(align=True) op = row.operator("bim.edit_material_set_item", icon="CHECKMARK", text="Save Changes") - op.material_set_item = set_item_id + op.material_set_item = set_item["id"] row.operator("bim.disable_editing_material_set_item", icon="CANCEL", text="") draw_attributes(self.props.material_set_item_attributes, box) @@ -267,114 +223,71 @@ class BIM_PT_object_material(Panel): row = box.row() row.prop(self.props, "material_set_item_material", icon="MATERIAL", text="Material") - if self.set_item_name == "profile": + if ObjectMaterialData.data["set_item_name"] == "profile": row = box.row() row.prop(self.mprops, "profiles", icon="ITALIC", text="Profile") - def draw_read_only_set_item_ui(self, set_item_id, index, is_first=False, is_last=False): - if self.product_data["type"] == "IfcMaterialList": - item = Data.materials[set_item_id] + def draw_read_only_set_item_ui(self, set_item, index, is_first=False, is_last=False): + if ObjectMaterialData.data["material_class"] == "IfcMaterialList": row = self.layout.row(align=True) - row.label(text="IfcMaterial", icon="ALIGN_CENTER") - row.label(text=item["Name"], icon="MATERIAL") + row.label(text="IfcMaterial", icon="LAYER_ACTIVE") + row.label(text=set_item["name"], icon="MATERIAL") else: - item = self.set_data[set_item_id] row = self.layout.row(align=True) - item_name = item.get("Name", "Unnamed") or "Unnamed" - thickness = item.get("LayerThickness") - if thickness: - item_name += f" ({thickness})" - row.label(text=item_name, icon="ALIGN_CENTER") - row.label(text=Data.materials[item["Material"]]["Name"], icon="MATERIAL") + row.label(text=set_item["name"], icon=set_item["icon"]) + row.label(text=set_item["material"], icon="MATERIAL") if not is_first: op = row.operator(f"bim.reorder_material_set_item", icon="TRIA_UP", text="") op.old_index = index op.new_index = index - 1 - setattr(op, "material_set", self.material_set_id) + setattr(op, "material_set", ObjectMaterialData.data["set"]["id"]) if not is_last: op = row.operator(f"bim.reorder_material_set_item", icon="TRIA_DOWN", text="") op.old_index = index op.new_index = index + 1 - setattr(op, "material_set", self.material_set_id) - if not self.props.active_material_set_item_id and self.product_data["type"] != "IfcMaterialList": + setattr(op, "material_set", ObjectMaterialData.data["set"]["id"]) + if not self.props.active_material_set_item_id and ObjectMaterialData.data["material_class"] != "IfcMaterialList": + if "Profile" in ObjectMaterialData.data["material_class"]: + op = row.operator("bim.enable_editing_material_set_item", icon="ITALIC", text="") + op.material_set_item = set_item["id"] op = row.operator("bim.enable_editing_material_set_item", icon="GREASEPENCIL", text="") - op.material_set_item = set_item_id - op = row.operator(f"bim.remove_{self.set_item_name}", icon="X", text="") - if self.product_data["type"] == "IfcMaterialList": - setattr(op, "list_item_set", self.material_set_id) - setattr(op, self.set_item_name, item["id"]) - if hasattr(op, f"{self.set_item_name}_index"): - setattr(op, f"{self.set_item_name}_index", index) + op.material_set_item = set_item["id"] + op = row.operator(f"bim.remove_{ObjectMaterialData.data['set_item_name']}", icon="X", text="") + if ObjectMaterialData.data["material_class"] == "IfcMaterialList": + setattr(op, "list_item_set", ObjectMaterialData.data["set"]["id"]) + setattr(op, ObjectMaterialData.data["set_item_name"], set_item["id"]) + if hasattr(op, f"{ObjectMaterialData.data['set_item_name']}_index"): + setattr(op, f"{ObjectMaterialData.data['set_item_name']}_index", index) def draw_read_only_set_ui(self): - if ( - self.product_data["type"] == "IfcMaterialLayerSetUsage" - or self.product_data["type"] == "IfcMaterialLayerSet" - ): - name_attr = "LayerSetName" - else: - name_attr = "Name" row = self.layout.row(align=True) - row.label(text=name_attr) - row.label(text=self.material_set_data.get(name_attr, "Unnamed") or "Unnamed") - if hasattr(self.material_set_data, "Description") and self.material_set_data["Description"]: + row.label(text="Name") + row.label(text=ObjectMaterialData.data["set"]["name"]) + if ObjectMaterialData.data["set"]["description"]: row = self.layout.row(align=True) row.label(text="Description") - row.label(text=str(self.material_set_data["Description"])) + row.label(text=ObjectMaterialData.data["set"]["description"]) - if self.product_data["type"] == "IfcMaterialProfileSetUsage": - # TODO: complain to buildingSMART - cardinal_point_map = { - 1: "bottom left", - 2: "bottom centre", - 3: "bottom right", - 4: "mid-depth left", - 5: "mid-depth centre", - 6: "mid-depth right", - 7: "top left", - 8: "top centre", - 9: "top right", - 10: "geometric centroid", - 11: "bottom in line with the geometric centroid", - 12: "left in line with the geometric centroid", - 13: "right in line with the geometric centroid", - 14: "top in line with the geometric centroid", - 15: "shear centre", - 16: "bottom in line with the shear centre", - 17: "left in line with the shear centre", - 18: "right in line with the shear centre", - 19: "top in line with the shear centre", - } - if self.material_set_usage["CardinalPoint"]: + if ObjectMaterialData.data["material_class"] == "IfcMaterialProfileSetUsage": + if ObjectMaterialData.data["set_usage"].get("cardinal_point"): row = self.layout.row(align=True) row.label(text="CardinalPoint") - row.label(text=cardinal_point_map[self.material_set_usage["CardinalPoint"]]) - if self.material_set_usage["ReferenceExtent"]: - row = self.layout.row(align=True) - row.label(text="ReferenceExtent") - row.label(text=str(self.material_set_usage["ReferenceExtent"])) + row.label(text=ObjectMaterialData.data["set_usage"]["cardinal_point"]) - total_thickness = 0 - for item_id in self.set_items: - if self.product_data["type"] == "IfcMaterialList": + for set_item in ObjectMaterialData.data["set_items"]: + if ObjectMaterialData.data["material_class"] == "IfcMaterialList": row = self.layout.row(align=True) - row.label(text="IfcMaterial", icon="ALIGN_CENTER") - row.label(text=Data.materials[item_id]["Name"], icon="MATERIAL") + row.label(text="IfcMaterial", icon="LAYER_ACTIVE") + row.label(text=set_item["name"], icon="MATERIAL") else: - item = self.set_data[item_id] row = self.layout.row(align=True) - item_name = item.get("Name", "Unnamed") or "Unnamed" - thickness = item.get("LayerThickness") - if thickness: - item_name += f" ({thickness:.3f})" - total_thickness += thickness - row.label(text=item_name, icon="ALIGN_CENTER") - row.label(text=Data.materials[item["Material"]]["Name"], icon="MATERIAL") + row.label(text=set_item["name"], icon=set_item["icon"]) + row.label(text=set_item["material"], icon="MATERIAL") - if total_thickness: + if ObjectMaterialData.data["total_thickness"]: row = self.layout.row(align=True) - row.label(text=f"Total Thickness: {total_thickness:.3f}") + row.label(text=f"Total Thickness: {ObjectMaterialData.data['total_thickness']:.3f}") class BIM_UL_materials(UIList): diff --git a/src/blenderbim/pytest.ini b/src/blenderbim/pytest.ini index dc9d7f02f6..4b4d9ae52c 100644 --- a/src/blenderbim/pytest.ini +++ b/src/blenderbim/pytest.ini @@ -23,6 +23,7 @@ markers = pset pset_template qto + resource root search sequence