diff --git a/src/ifcblenderexport/blenderbim/bim/__init__.py b/src/ifcblenderexport/blenderbim/bim/__init__.py index b9edfe5a65..ba4ab10571 100644 --- a/src/ifcblenderexport/blenderbim/bim/__init__.py +++ b/src/ifcblenderexport/blenderbim/bim/__init__.py @@ -14,6 +14,7 @@ if bpy is not None: import blenderbim.bim.module.geometry as module_geometry import blenderbim.bim.module.model as module_model import blenderbim.bim.module.project as module_project + import blenderbim.bim.module.pset as module_pset import blenderbim.bim.module.spatial as module_spatial import blenderbim.bim.module.style as module_style import blenderbim.bim.module.type as module_type @@ -52,8 +53,6 @@ if bpy is not None: operator.SelectSweptSolidInnerCurves, operator.AssignSweptSolidExtrusion, operator.SelectSweptSolidExtrusion, - operator.AddPset, - operator.RemovePset, operator.AddQto, operator.RemoveQto, operator.AddMaterialPset, @@ -286,7 +285,6 @@ if bpy is not None: ui.BIM_PT_material, ui.BIM_PT_presentation_layer_data, ui.BIM_PT_object_material, - ui.BIM_PT_object_psets, ui.BIM_PT_object_qto, ui.BIM_PT_classification_references, ui.BIM_PT_documents, @@ -320,6 +318,7 @@ if bpy is not None: classes.extend(module_geometry.classes) classes.extend(module_model.classes) classes.extend(module_project.classes) + classes.extend(module_pset.classes) classes.extend(module_spatial.classes) classes.extend(module_style.classes) classes.extend(module_type.classes) @@ -364,6 +363,7 @@ if bpy is not None: module_geometry.register() module_model.register() module_project.register() + module_pset.register() module_spatial.register() module_style.register() module_type.register() @@ -393,6 +393,7 @@ if bpy is not None: module_type.unregister() module_style.unregister() module_spatial.unregister() + module_pset.unregister() module_project.unregister() module_model.unregister() module_geometry.unregister() diff --git a/src/ifcblenderexport/blenderbim/bim/import_ifc.py b/src/ifcblenderexport/blenderbim/bim/import_ifc.py index b21be24c48..c9b3ca684f 100644 --- a/src/ifcblenderexport/blenderbim/bim/import_ifc.py +++ b/src/ifcblenderexport/blenderbim/bim/import_ifc.py @@ -849,7 +849,6 @@ class IfcImporter: self.material_creator.create(element, obj, mesh) self.add_element_classifications(element, obj) self.add_element_document_relations(element, obj) - self.add_type_product_psets(element, obj) self.type_collection.objects.link(obj) self.type_products[element.GlobalId] = obj @@ -1364,18 +1363,9 @@ class IfcImporter: for definition in element.IsDefinedBy: if not definition.is_a("IfcRelDefinesByProperties"): continue - if definition.RelatingPropertyDefinition.is_a("IfcPropertySet"): - self.add_pset(definition.RelatingPropertyDefinition, obj.BIMObjectProperties) - elif definition.RelatingPropertyDefinition.is_a("IfcElementQuantity"): + if definition.RelatingPropertyDefinition.is_a("IfcElementQuantity"): self.add_qto(definition.RelatingPropertyDefinition, obj) - def add_type_product_psets(self, element, obj): - if not hasattr(element, "HasPropertySets") or not element.HasPropertySets: - return - for definition in element.HasPropertySets: - if definition.is_a("IfcPropertySet"): - self.add_pset(definition, obj.BIMObjectProperties) - def add_pset(self, pset, props): new_pset = props.psets.add() new_pset.name = pset.Name diff --git a/src/ifcblenderexport/blenderbim/bim/module/attribute/data.py b/src/ifcblenderexport/blenderbim/bim/module/attribute/data.py index b02874563c..4a90c6c5cc 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/attribute/data.py +++ b/src/ifcblenderexport/blenderbim/bim/module/attribute/data.py @@ -12,7 +12,6 @@ class Data: return product = file.by_id(product_id) cls.products[product_id] = [] - attributes = product.get_info() declaration = IfcStore.get_schema().declaration_by_name(product.is_a()) for attribute in declaration.all_attributes(): data_type = str(attribute.type_of_attribute()) diff --git a/src/ifcblenderexport/blenderbim/bim/module/attribute/operator.py b/src/ifcblenderexport/blenderbim/bim/module/attribute/operator.py index 4a3df216dd..d696bb775b 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/attribute/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/module/attribute/operator.py @@ -76,11 +76,10 @@ class EditAttributes(bpy.types.Operator): attributes[attribute["name"]] = blender_attribute.float_value elif attribute["type"] == "enum": attributes[attribute["name"]] = blender_attribute.enum_value - usecase = edit_attributes.Usecase(self.file, { + edit_attributes.Usecase(self.file, { "product": self.file.by_id(props.ifc_definition_id), "attributes": attributes - }) - usecase.execute() + }).execute() Data.load(props.ifc_definition_id) bpy.ops.bim.disable_editing_attributes() return {"FINISHED"} diff --git a/src/ifcblenderexport/blenderbim/bim/module/attribute/ui.py b/src/ifcblenderexport/blenderbim/bim/module/attribute/ui.py index 1454159966..8b47150d7a 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/attribute/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/module/attribute/ui.py @@ -20,9 +20,6 @@ class BIM_PT_attributes(Panel): if props.ifc_definition_id not in Data.products: Data.load(props.ifc_definition_id) - props = context.active_object.BIMObjectProperties - - if props.is_editing_attributes: row = self.layout.row(align=True) row.operator("bim.edit_attributes", icon="CHECKMARK", text="Save Attributes") diff --git a/src/ifcblenderexport/blenderbim/bim/module/pset/__init__.py b/src/ifcblenderexport/blenderbim/bim/module/pset/__init__.py new file mode 100644 index 0000000000..31724d5e7b --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/pset/__init__.py @@ -0,0 +1,20 @@ +import bpy +from . import ui, operator + +classes = ( + operator.TogglePsetExpansion, + operator.EnablePsetEditing, + operator.DisablePsetEditing, + operator.EditPset, + operator.RemovePset, + operator.AddPset, + ui.BIM_PT_object_psets, +) + + +def register(): + pass + + +def unregister(): + pass diff --git a/src/ifcblenderexport/blenderbim/bim/module/pset/add_pset.py b/src/ifcblenderexport/blenderbim/bim/module/pset/add_pset.py new file mode 100644 index 0000000000..14301e3d1a --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/pset/add_pset.py @@ -0,0 +1,41 @@ +import ifcopenshell +import blenderbim.bim.schema # TODO: refactor + + +class Usecase: + def __init__(self, file, settings=None): + self.file = file + self.settings = {"product": None, "Name": None} + for key, value in settings.items(): + self.settings[key] = value + + def execute(self): + if self.settings["product"].is_a("IfcObject"): + pset = self.file.create_entity( + "IfcPropertySet", **{"GlobalId": ifcopenshell.guid.new(), "Name": self.settings["Name"]} + ) + self.file.create_entity( + "IfcRelDefinesByProperties", + **{ + "GlobalId": ifcopenshell.guid.new(), + # TODO: owner history + "RelatedObjects": [self.settings["product"]], + "RelatingPropertyDefinition": pset, + } + ) + elif self.settings["product"].is_a("IfcTypeObject"): + pset = self.file.create_entity( + "IfcPropertySet", **{"GlobalId": ifcopenshell.guid.new(), "Name": self.settings["Name"]} + ) + has_property_sets = list(self.settings["product"].HasPropertySets) + has_property_sets.append(pset) + self.settings["product"].HasPropertySets = has_property_sets + elif self.settings["product"].is_a("IfcMaterialDefinition"): + pset = self.file.create_entity( + "IfcPropertySet", + **{ + "GlobalId": ifcopenshell.guid.new(), + "Name": self.settings["Name"], + "Material": self.settings["product"], + } + ) diff --git a/src/ifcblenderexport/blenderbim/bim/module/pset/data.py b/src/ifcblenderexport/blenderbim/bim/module/pset/data.py new file mode 100644 index 0000000000..d936db0e50 --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/pset/data.py @@ -0,0 +1,129 @@ +import ifcopenshell +import blenderbim.bim.schema # TODO: refactor elsewhere +from blenderbim.bim.ifc import IfcStore + + +class Data: + products = {} + psets = {} + + @classmethod + def load(cls, product_id): + file = IfcStore.get_file() + if not file: + return + product = file.by_id(product_id) + cls.products[product_id] = set() + if product.is_a("IfcElementType"): + cls.add_type_product_psets(product, product_id) + else: + cls.add_product_psets(product, product_id) + + @classmethod + def add_type_product_psets(cls, product, product_id): + if not hasattr(product, "HasPropertySets") or not product.HasPropertySets: + return # TODO + for definition in product.HasPropertySets: + if definition.is_a("IfcPropertySet"): + cls.add_pset(definition, product_id) + + @classmethod + def add_product_psets(cls, product, product_id): + if not hasattr(product, "IsDefinedBy") or not product.IsDefinedBy: + return + for definition in product.IsDefinedBy: + if not definition.is_a("IfcRelDefinesByProperties"): + continue + if definition.RelatingPropertyDefinition.is_a("IfcPropertySet"): + cls.add_pset(definition.RelatingPropertyDefinition, product_id) + + @classmethod + def add_pset(cls, pset, product_id): + new_pset = { + "Name": pset.Name, + "is_expanded": True, + "Properties": [] + } + cls.products[product_id].add(int(pset.id())) + cls.psets[int(pset.id())] = new_pset + pset_template = blenderbim.bim.schema.ifc.psetqto.get_by_name(pset.Name) + if pset_template: + for prop_template in pset_template.HasPropertyTemplates: + if not prop_template.is_a("IfcSimplePropertyTemplate"): + continue # Other types not yet supported + enum_items = [] + if prop_template.TemplateType == "P_SINGLEVALUE": + data_type = str(IfcStore.get_schema().declaration_by_name(prop_template.PrimaryMeasureType)) + elif prop_template.TemplateType == "P_ENUMERATEDVALUE": + data_type = "enum" + enum_items = [v.wrappedValue for v in prop_template.Enumerators.EnumerationValues] + else: + continue # Other types not yet supported + if "" in data_type: + data_type = "string" + elif "" in data_type: + data_type = "float" + elif "" in data_type: + data_type = "integer" + elif "" in data_type: + data_type = "boolean" + elif " 0: + props.properties.remove(0) + + props.active_pset_name = Data.psets[self.pset_id]["Name"] + for prop in Data.psets[self.pset_id]["Properties"]: + new = props.properties.add() + new.name = prop["Name"] + new.is_null = prop["is_null"] + if prop["type"] == "string": + new.string_value = prop["value"] or "" + elif prop["type"] == "integer": + new.int_value = prop["value"] or 0 + elif prop["type"] == "float": + new.float_value = prop["value"] or 0. + elif prop["type"] == "boolean": + new.bool_value = prop["value"] or False + elif prop["type"] == "enum": + new.enum_items = json.dumps(prop["enum_items"]) + if prop["value"]: + new.enum_value = prop["value"] + + props.active_pset_id = self.pset_id + return {"FINISHED"} + + +class DisablePsetEditing(bpy.types.Operator): + bl_idname = "bim.disable_pset_editing" + bl_label = "Disable Pset Editing" + + def execute(self, context): + obj = bpy.context.active_object + props = obj.BIMObjectProperties + props.active_pset_id = 0 + return {"FINISHED"} + + +class EditPset(bpy.types.Operator): + bl_idname = "bim.edit_pset" + bl_label = "Edit Pset" + + def execute(self, context): + self.file = IfcStore.get_file() + obj = bpy.context.active_object + props = obj.BIMObjectProperties + properties = {} + for prop in Data.psets[props.active_pset_id]["Properties"]: + blender_prop = props.properties.get(prop["Name"]) + if not blender_prop: + continue + if blender_prop.is_null: + properties[prop["Name"]] = None + elif prop["type"] == "string": + properties[prop["Name"]] = blender_prop.string_value + elif prop["type"] == "boolean": + properties[prop["Name"]] = blender_prop.bool_value + elif prop["type"] == "integer": + properties[prop["Name"]] = blender_prop.int_value + elif prop["type"] == "float": + properties[prop["Name"]] = blender_prop.float_value + elif prop["type"] == "enum": + properties[prop["Name"]] = blender_prop.enum_value + edit_pset.Usecase(self.file, { + "pset": self.file.by_id(props.active_pset_id), + "Name": props.active_pset_name, + "Properties": properties + }).execute() + Data.load(props.ifc_definition_id) + bpy.ops.bim.disable_pset_editing() + return {"FINISHED"} + + +class RemovePset(bpy.types.Operator): + bl_idname = "bim.remove_pset" + bl_label = "Remove Pset" + pset_id: bpy.props.IntProperty() + + def execute(self, context): + self.file = IfcStore.get_file() + obj = bpy.context.active_object + props = obj.BIMObjectProperties + remove_pset.Usecase(self.file, { + "product": self.file.by_id(props.ifc_definition_id), + "pset": self.file.by_id(self.pset_id), + }).execute() + Data.load(props.ifc_definition_id) + return {"FINISHED"} + + +class AddPset(bpy.types.Operator): + bl_idname = "bim.add_pset" + bl_label = "Add Pset" + + def execute(self, context): + self.file = IfcStore.get_file() + obj = bpy.context.active_object + props = obj.BIMObjectProperties + add_pset.Usecase(self.file, { + "product": self.file.by_id(props.ifc_definition_id), + "Name": props.pset_name, + }).execute() + Data.load(props.ifc_definition_id) + return {"FINISHED"} diff --git a/src/ifcblenderexport/blenderbim/bim/module/pset/remove_pset.py b/src/ifcblenderexport/blenderbim/bim/module/pset/remove_pset.py new file mode 100644 index 0000000000..3ccdf6d0ef --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/pset/remove_pset.py @@ -0,0 +1,27 @@ +import blenderbim.bim.schema # TODO: refactor + + +class Usecase: + def __init__(self, file, settings=None): + self.file = file + self.settings = {"product": None, "pset": None} + for key, value in settings.items(): + self.settings[key] = value + + def execute(self): + to_purge = [] + should_remove_pset = True + for inverse in self.file.get_inverse(self.settings["pset"]): + if inverse.is_a("IfcRelDefinesByProperties"): + if not inverse.RelatedObjects or len(inverse.RelatedObjects) == 1: + to_purge.append(inverse) + else: + related_objects = list(inverse.RelatedObjects) + related_objects.remove(self.settings["product"]) + inverse.RelatedObjects = related_objects + should_remove_pset = False + if should_remove_pset: + self.file.remove(self.settings["pset"]) + for element in to_purge: + self.file.remove(element) + # TODO: implement deep purging diff --git a/src/ifcblenderexport/blenderbim/bim/module/pset/ui.py b/src/ifcblenderexport/blenderbim/bim/module/pset/ui.py new file mode 100644 index 0000000000..6aac43b0b0 --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/pset/ui.py @@ -0,0 +1,74 @@ +from bpy.types import Panel +from blenderbim.bim.module.pset.data import Data + + +class BIM_PT_object_psets(Panel): + bl_label = "IFC Object Property Sets" + bl_idname = "BIM_PT_object_psets" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "object" + + @classmethod + def poll(cls, context): + return context.active_object is not None and hasattr(context.active_object, "BIMObjectProperties") + + def draw(self, context): + props = context.active_object.BIMObjectProperties + if not props.ifc_definition_id: + return + if props.ifc_definition_id not in Data.products: + Data.load(props.ifc_definition_id) + row = self.layout.row(align=True) + row.prop(props, "pset_name", text="") + row.operator("bim.add_pset", icon="ADD", text="") + + self.draw_psets_ui(props, Data.products[props.ifc_definition_id]) + + # TODO reimplement. See #1222. + #if props.relating_type and props.relating_type.BIMObjectProperties.psets: + # self.layout.label(text="Inherited Psets:") + # self.draw_psets_ui(props.relating_type.BIMObjectProperties, enabled=False) + + def draw_psets_ui(self, props, pset_ids): + for pset_id in pset_ids: + pset = Data.psets[pset_id] + box = self.layout.box() + row = box.row(align=True) + icon = "TRIA_DOWN" if pset["is_expanded"] else "TRIA_RIGHT" + row.operator("bim.toggle_pset_expansion", icon=icon, text="", emboss=False).pset_id = pset_id + if not props.active_pset_id: + row.label(text=pset["Name"], icon="COPY_ID") + row.operator("bim.enable_pset_editing", icon="GREASEPENCIL", text="").pset_id = pset_id + row.operator("bim.remove_pset", icon="X", text="").pset_id = pset_id + elif props.active_pset_id != pset_id: + row.label(text=pset["Name"], icon="COPY_ID") + row.operator("bim.remove_pset", icon="X", text="").pset_id = pset_id + elif props.active_pset_id == pset_id: + row.prop(props, "active_pset_name", icon="COPY_ID", text="") + row.operator("bim.edit_pset", icon="CHECKMARK", text="") + row.operator("bim.disable_pset_editing", icon="X", text="") + if pset["is_expanded"]: + if props.active_pset_id == pset_id: + for prop in pset["Properties"]: + row = box.row(align=True) + blender_prop = props.properties.get(prop["Name"]) + if prop["type"] == "string": + row.prop(blender_prop, "string_value", text=prop["Name"]) + elif prop["type"] == "integer": + row.prop(blender_prop, "int_value", text=prop["Name"]) + elif prop["type"] == "float": + row.prop(blender_prop, "float_value", text=prop["Name"]) + elif prop["type"] == "boolean": + row.prop(blender_prop, "bool_value", text=prop["Name"]) + elif prop["type"] == "enum": + row.prop(blender_prop, "enum_value", text=prop["Name"]) + row.prop(blender_prop, "is_null", icon="RADIOBUT_OFF" if blender_prop.is_null else "RADIOBUT_ON", text="") + else: + for prop in pset["Properties"]: + if prop["value"] is None or prop["value"] == "": + continue + row = box.row(align=True) + row.scale_y = 0.8 + row.label(text=prop["Name"]) + row.label(text=str(prop["value"])) diff --git a/src/ifcblenderexport/blenderbim/bim/operator.py b/src/ifcblenderexport/blenderbim/bim/operator.py index b1ea842083..7525ee06a6 100644 --- a/src/ifcblenderexport/blenderbim/bim/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/operator.py @@ -484,45 +484,6 @@ class AddQto(bpy.types.Operator): return {"FINISHED"} -class AddPset(bpy.types.Operator): - bl_idname = "bim.add_pset" - bl_label = "Add Pset" - - def execute(self, context): - name = bpy.context.active_object.BIMObjectProperties.pset_name - pset_template = schema.ifc.psetqto.get_by_name(name) - if not pset_template: - return {"FINISHED"} - for obj in bpy.context.selected_objects: - if "/" not in obj.name or obj.BIMObjectProperties.psets.find(name) != -1: - continue - applicable_psets = schema.ifc.psetqto.get_applicable_names(obj.name.split("/")[0], pset_only=True) - if name not in applicable_psets: - continue - pset = obj.BIMObjectProperties.psets.add() - pset.name = name - for prop_name in (p.Name for p in pset_template.HasPropertyTemplates): - prop = pset.properties.add() - prop.name = prop_name - return {"FINISHED"} - - -class RemovePset(bpy.types.Operator): - bl_idname = "bim.remove_pset" - bl_label = "Remove Pset" - pset_index: bpy.props.IntProperty() - - def execute(self, context): - name = bpy.context.active_object.BIMObjectProperties.psets[self.pset_index].name - for obj in bpy.context.selected_objects: - if "/" not in obj.name: - continue - index = obj.BIMObjectProperties.psets.find(name) - if index != -1: - obj.BIMObjectProperties.psets.remove(index) - return {"FINISHED"} - - class RemoveQto(bpy.types.Operator): bl_idname = "bim.remove_qto" bl_label = "Remove Qto" diff --git a/src/ifcblenderexport/blenderbim/bim/prop.py b/src/ifcblenderexport/blenderbim/bim/prop.py index de0ba731f3..ebe645b45e 100644 --- a/src/ifcblenderexport/blenderbim/bim/prop.py +++ b/src/ifcblenderexport/blenderbim/bim/prop.py @@ -40,7 +40,7 @@ psettemplatefiles_enum = [] propertysettemplates_enum = [] classification_enum = [] attributes_enum = [] -psetnames_enum = [] +psetnames = {} qtonames_enum = [] materialattributes_enum = [] materialtypes_enum = [] @@ -435,12 +435,14 @@ def refreshReferences(self, context): def getPsetNames(self, context): - global psetnames_enum - psetnames_enum.clear() - if "/" in context.active_object.name and context.active_object.name.split("/")[0] in schema.ifc.elements: - pset_names = schema.ifc.psetqto.get_applicable_names(context.active_object.name.split("/")[0], pset_only=True) - psetnames_enum.extend([(p, p, "") for p in pset_names]) - return psetnames_enum + global psetnames + if "/" in context.active_object.name: + ifc_class = context.active_object.name.split("/")[0] + if ifc_class not in psetnames: + psets = schema.ifc.psetqto.get_applicable(ifc_class, pset_only=True) + psetnames[ifc_class] = [(p.Name, p.Name, "") for p in psets] + return psetnames[ifc_class] + return [] def getMaterialPsetNames(self, context): @@ -1483,6 +1485,9 @@ class BIMObjectProperties(PropertyGroup): is_editing_type: BoolProperty(name="Is Editing Type") relating_type: PointerProperty(name="Type Product", type=bpy.types.Object) relating_structure: PointerProperty(name="Spatial Container", type=bpy.types.Object) + active_pset_id: IntProperty(name="Active Pset ID") + active_pset_name: StringProperty(name="Pset Name") + properties: CollectionProperty(name="Properties", type=Attribute) psets: CollectionProperty(name="Psets", type=PsetQto) qtos: CollectionProperty(name="Qtos", type=PsetQto) document_references: CollectionProperty(name="Document References", type=DocumentReference) diff --git a/src/ifcblenderexport/blenderbim/bim/schema.py b/src/ifcblenderexport/blenderbim/bim/schema.py index 314f784922..f11bffd3c2 100644 --- a/src/ifcblenderexport/blenderbim/bim/schema.py +++ b/src/ifcblenderexport/blenderbim/bim/schema.py @@ -29,6 +29,7 @@ class IfcSchema: self.property_files = [] property_paths = self.data_dir.joinpath("pset").glob("*.ifc") + # TODO: add IFC2X3 PsetQto template support self.psetqto = ifcopenshell.util.pset.PsetQto("IFC4") for path in property_paths: self.psetqto.templates.append(ifcopenshell.open(path)) diff --git a/src/ifcblenderexport/blenderbim/bim/ui.py b/src/ifcblenderexport/blenderbim/bim/ui.py index 8cf73cdeb2..9a885c2e02 100644 --- a/src/ifcblenderexport/blenderbim/bim/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/ui.py @@ -143,73 +143,6 @@ class BIM_PT_object_material(Panel): row.prop(attribute, "string_value", text="") -class BIM_PT_object_psets(Panel): - bl_label = "IFC Object Property Sets" - bl_idname = "BIM_PT_object_psets" - bl_space_type = "PROPERTIES" - bl_region_type = "WINDOW" - bl_context = "object" - - @classmethod - def poll(cls, context): - return context.active_object is not None and hasattr(context.active_object, "BIMObjectProperties") - - def draw(self, context): - if context.active_object is None: - return - layout = self.layout - props = context.active_object.BIMObjectProperties - row = layout.row(align=True) - row.prop(props, "pset_name", text="") - row.operator("bim.add_pset") - - self.draw_psets_ui(props) - - if props.relating_type and props.relating_type.BIMObjectProperties.psets: - layout.label(text="Inherited Psets:") - self.draw_psets_ui(props.relating_type.BIMObjectProperties, enabled=False) - - def draw_psets_ui(self, props, enabled=True): - for index, pset in enumerate(props.psets): - box = self.layout.box() - row = box.row(align=True) - row.prop( - pset, - "is_expanded", - icon="TRIA_DOWN" if pset.is_expanded else "TRIA_RIGHT", - icon_only=True, - emboss=False, - ) - row2 = row.row(align=True) - row2.enabled = enabled - row2.prop(pset, "name", text="", icon="COPY_ID", emboss=pset.is_editable) - - if enabled: - row.prop(pset, "is_editable", icon="CHECKMARK" if pset.is_editable else "GREASEPENCIL", icon_only=True) - row.operator("bim.remove_pset", icon="X", text="").pset_index = index - if not pset.is_expanded: - continue - if pset.is_editable: - for prop in pset.properties: - row = box.row(align=True) - row.enabled = enabled - row.prop(prop, "name", text="") - row.prop(prop, "string_value", text="") - if not enabled: - continue - op = row.operator("bim.copy_property_to_selection", icon="COPYDOWN", text="") - op.pset_name = pset.name - op.prop_name = prop.name - op.prop_value = prop.string_value - else: - col = box.column(align=True) - for prop in pset.properties: - if not prop.string_value: - continue - col.enabled = enabled - col.prop(prop, "string_value", text=prop.name) - - class BIM_PT_object_qto(Panel): bl_label = "IFC Object Quantity Sets" bl_idname = "BIM_PT_object_qto"