diff --git a/src/blenderbim/blenderbim/bim/helper.py b/src/blenderbim/blenderbim/bim/helper.py index 6703bda0dc..8dc2442216 100644 --- a/src/blenderbim/blenderbim/bim/helper.py +++ b/src/blenderbim/blenderbim/bim/helper.py @@ -40,7 +40,7 @@ def draw_attribute(attribute, layout, copy_operator=None): return if len(attribute.enumerated_values) != 0: layout.label(text=attribute.name) - grid = layout.column_flow(columns=4) + grid = layout.column_flow(columns=3) for e in attribute.enumerated_values: grid.prop( e, diff --git a/src/blenderbim/blenderbim/bim/module/brick/prop.py b/src/blenderbim/blenderbim/bim/module/brick/prop.py index 6e0ba7c814..0d4eec7a6d 100644 --- a/src/blenderbim/blenderbim/bim/module/brick/prop.py +++ b/src/blenderbim/blenderbim/bim/module/brick/prop.py @@ -69,3 +69,9 @@ class BIMBrickProperties(PropertyGroup): libraries: EnumProperty(name="Libraries", items=get_libraries) namespace: EnumProperty(name="Namespace", items=get_namespaces) brick_equipment_class: EnumProperty(name="Brick Equipment Class", items=get_brick_equipment_classes) + + getter_enum = { + "libraries": get_libraries, + "namespace": get_namespaces, + "brick_equipment_class": get_brick_equipment_classes, + } diff --git a/src/blenderbim/blenderbim/bim/module/brick/ui.py b/src/blenderbim/blenderbim/bim/module/brick/ui.py index da3647ab6d..f0b1cedce7 100644 --- a/src/blenderbim/blenderbim/bim/module/brick/ui.py +++ b/src/blenderbim/blenderbim/bim/module/brick/ui.py @@ -18,6 +18,7 @@ import blenderbim.tool as tool from bpy.types import Panel, UIList +from blenderbim.bim.ui import prop_with_search from blenderbim.bim.module.brick.data import BrickschemaData, BrickschemaReferencesData @@ -48,7 +49,8 @@ class BIM_PT_brickschema(Panel): row.operator("bim.close_brick_project", text="", icon="CANCEL") row = self.layout.row(align=True) - row.prop(self.props, "namespace", text="") + prop_with_search(row, self.props, "namespace", text="") + prop_with_search(row, self.props, "brick_equipment_class", text="") row.prop(self.props, "brick_equipment_class", text="") row.operator("bim.add_brick", text="", icon="ADD") @@ -101,7 +103,7 @@ class BIM_PT_ifc_brickschema_references(Panel): return row = self.layout.row(align=True) - row.prop(self.props, "libraries") + prop_with_search(row, self.props, "libraries") row.operator("bim.convert_brick_project", text="", icon="ADD") row = self.layout.row(align=True) diff --git a/src/blenderbim/blenderbim/bim/module/geometry/ui.py b/src/blenderbim/blenderbim/bim/module/geometry/ui.py index 78c8e21414..4ce050ffb9 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/ui.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/ui.py @@ -19,6 +19,7 @@ import bpy from bpy.types import Panel from blenderbim.bim.ifc import IfcStore +from blenderbim.bim.ui import prop_with_search from blenderbim.bim.module.geometry.data import RepresentationsData, DerivedPlacementsData @@ -50,7 +51,7 @@ class BIM_PT_representations(Panel): layout.label(text="No representations found") row = layout.row(align=True) - row.prop(context.scene.BIMRootProperties, "contexts", text="") + prop_with_search(row, context.scene.BIMRootProperties, "contexts", text="") row.operator("bim.add_representation", icon="ADD", text="") for representation in RepresentationsData.data["representations"]: diff --git a/src/blenderbim/blenderbim/bim/module/patch/prop.py b/src/blenderbim/blenderbim/bim/module/patch/prop.py index 27c0e44ab5..0fb0a5f341 100644 --- a/src/blenderbim/blenderbim/bim/module/patch/prop.py +++ b/src/blenderbim/blenderbim/bim/module/patch/prop.py @@ -66,3 +66,7 @@ class BIMPatchProperties(PropertyGroup): ifc_patch_output: StringProperty(default="", name="IFC Patch Output IFC") ifc_patch_args: StringProperty(default="", name="Arguments") ifc_patch_args_attr: CollectionProperty(type=Attribute, name="Arguments") + + getter_enum = { + "ifc_patch_recipes": get_ifcpatch_recipes, + } diff --git a/src/blenderbim/blenderbim/bim/module/patch/ui.py b/src/blenderbim/blenderbim/bim/module/patch/ui.py index 618a5077ca..9d58971d7d 100644 --- a/src/blenderbim/blenderbim/bim/module/patch/ui.py +++ b/src/blenderbim/blenderbim/bim/module/patch/ui.py @@ -16,6 +16,7 @@ # You should have received a copy of the GNU General Public License # along with BlenderBIM Add-on. If not, see . +from blenderbim.bim.ui import prop_with_search import bpy from blenderbim.bim.helper import draw_attributes @@ -37,7 +38,7 @@ class BIM_PT_patch(bpy.types.Panel): scene = context.scene props = scene.BIMPatchProperties row = layout.row() - row.prop(props, "ifc_patch_recipes") + prop_with_search(row, props, "ifc_patch_recipes") row = layout.row(align=True) row.prop(props, "ifc_patch_input") diff --git a/src/blenderbim/blenderbim/bim/module/project/prop.py b/src/blenderbim/blenderbim/bim/module/project/prop.py index 3fe5e5077f..4d38d465fe 100644 --- a/src/blenderbim/blenderbim/bim/module/project/prop.py +++ b/src/blenderbim/blenderbim/bim/module/project/prop.py @@ -167,3 +167,28 @@ class BIMProjectProperties(PropertyGroup): def get_library_element_index(self, lib_element): return next((i for i in range(len(self.library_elements)) if self.library_elements[i] == lib_element)) + + getter_enum = { + "collection_mode": lambda self, context: [ + ("DECOMPOSITION", "Decomposition", "Collections represent aggregates and spatial containers"), + ("SPATIAL_DECOMPOSITION", "Spatial Decomposition", "Collections represent spatial containers"), + ("IFC_CLASS", "IFC Class", "Collections represent IFC class"), + ("NONE", "None", "No collections are created"), + ], + "filter_mode": lambda self, context: [ + ("NONE", "None", "No filtering is performed"), + ("DECOMPOSITION", "Decomposition", "Filter objects by decomposition"), + ("IFC_CLASS", "IFC Class", "Filter objects by class"), + ("IFC_TYPE", "IFC Type", "Filter objects by type"), + ("WHITELIST", "Whitelist", "Filter objects using a custom whitelist query"), + ("BLACKLIST", "Blacklist", "Filter objects using a custom blacklist query"), + ], + "merge_mode": lambda self, context: [ + ("NONE", "None", "No objects are merged"), + ("IFC_CLASS", "IFC Class", "One object per IFC class"), + ("IFC_TYPE", "IFC Type", "One object per IFC construction type"), + ("MATERIAL", "Material", "One object per material"), + ], + "export_schema": get_export_schema, + "template_file": get_template_file, + } diff --git a/src/blenderbim/blenderbim/bim/module/project/ui.py b/src/blenderbim/blenderbim/bim/module/project/ui.py index c8be2f2933..8a0a21f109 100644 --- a/src/blenderbim/blenderbim/bim/module/project/ui.py +++ b/src/blenderbim/blenderbim/bim/module/project/ui.py @@ -17,6 +17,7 @@ # along with BlenderBIM Add-on. If not, see . import os +from blenderbim.bim.ui import prop_with_search from bpy.types import Panel, UIList from blenderbim.bim.ifc import IfcStore from blenderbim.bim.module.project.data import ProjectData @@ -48,10 +49,8 @@ class BIM_PT_project(Panel): def draw_load_ui(self, context): pprops = context.scene.BIMProjectProperties - row = self.layout.row() - row.prop(pprops, "collection_mode") - row = self.layout.row() - row.prop(pprops, "filter_mode") + prop_with_search(self.layout, pprops, "collection_mode") + prop_with_search(self.layout, pprops, "filter_mode") if pprops.filter_mode in ["DECOMPOSITION", "IFC_CLASS", "IFC_TYPE"]: row = self.layout.row(align=True) row.label(text=f"Total: {pprops.total_elements}") @@ -84,8 +83,7 @@ class BIM_PT_project(Panel): row = self.layout.row() row.prop(pprops, "is_coordinating") if pprops.is_coordinating: - row = self.layout.row() - row.prop(pprops, "merge_mode") + prop_with_search(self.layout, pprops, "merge_mode") row = self.layout.row() row.prop(pprops, "deflection_tolerance") row = self.layout.row() @@ -170,8 +168,7 @@ class BIM_PT_project(Panel): def draw_create_project_ui(self, context): props = context.scene.BIMProperties pprops = context.scene.BIMProjectProperties - row = self.layout.row() - row.prop(pprops, "export_schema") + prop_with_search(self.layout, pprops, "export_schema") row = self.layout.row() row.prop(context.scene.unit_settings, "system") row = self.layout.row() @@ -180,8 +177,7 @@ class BIM_PT_project(Panel): row.prop(props, "area_unit", text="Area Unit") row = self.layout.row() row.prop(props, "volume_unit", text="Volume Unit") - row = self.layout.row() - row.prop(pprops, "template_file", text="Template") + prop_with_search(self.layout, pprops, "template_file", text="Template") row = self.layout.row(align=True) row.operator("bim.create_project") diff --git a/src/blenderbim/blenderbim/bim/module/pset/operator.py b/src/blenderbim/blenderbim/bim/module/pset/operator.py index 1829ebee78..72d03570ad 100644 --- a/src/blenderbim/blenderbim/bim/module/pset/operator.py +++ b/src/blenderbim/blenderbim/bim/module/pset/operator.py @@ -412,7 +412,7 @@ class BIM_OT_add_property_to_edit(bpy.types.Operator): bl_idname = "bim.add_property_to_edit" bl_options = {"REGISTER", "UNDO"} option: bpy.props.StringProperty() - index: bpy.props.IntProperty() + index: bpy.props.IntProperty(default=-1) def execute(self, context): if self.index == -1: diff --git a/src/blenderbim/blenderbim/bim/module/pset/prop.py b/src/blenderbim/blenderbim/bim/module/pset/prop.py index 14fedf0f33..9510329013 100644 --- a/src/blenderbim/blenderbim/bim/module/pset/prop.py +++ b/src/blenderbim/blenderbim/bim/module/pset/prop.py @@ -18,7 +18,7 @@ import bpy import blenderbim.bim.schema -from blenderbim.bim.prop import Attribute +from blenderbim.bim.prop import Attribute, StrProperty import ifcopenshell from ifcopenshell.api.pset.data import Data from blenderbim.bim.module.pset.data import AddEditCustomPropertiesData @@ -47,7 +47,7 @@ def purge(): qtonames = {} -def getPsetNames(self, context): +def get_pset_names(self, context): global psetnames obj = context.active_object if not obj.BIMObjectProperties.ifc_definition_id: @@ -122,7 +122,7 @@ def getWorkSchedulePsetNames(self, context): return psetnames[ifc_class] -def getQtoNames(self, context): +def get_qto_names(self, context): global qtonames if "/" in context.active_object.name: ifc_class = context.active_object.name.split("/")[0] @@ -145,22 +145,27 @@ class EnumerationValues(PropertyGroup): int_value: IntProperty(name="Value") float_value: FloatProperty(name="Value") is_selected: BoolProperty(default=False) - - + + class IfcSimpleProperty(Attribute): - #bounded_values: + # bounded_values: enumerated_values: CollectionProperty(type=EnumerationValues) - #list_values: - #reference_values: - #table_values: - - + # list_values: + # reference_values: + # table_values: + + class PsetProperties(PropertyGroup): active_pset_id: IntProperty(name="Active Pset ID") active_pset_name: StringProperty(name="Pset Name") properties: CollectionProperty(name="Properties", type=IfcSimpleProperty) - pset_name: EnumProperty(items=getPsetNames, name="Pset Name") - qto_name: EnumProperty(items=getQtoNames, name="Qto Name") + pset_name: EnumProperty(items=get_pset_names, name="Pset Name") + qto_name: EnumProperty(items=get_qto_names, name="Qto Name") + + getter_enum = { + "qto_name": get_qto_names, + "pset_name": get_pset_names, + } class MaterialPsetProperties(PropertyGroup): @@ -215,13 +220,21 @@ class AddEditProperties(PropertyGroup): primary_measure_type: EnumProperty(items=get_primary_measure_type, name="Primary Measure Type") template_type: EnumProperty( items=[ - ("IfcPropertySingleValue","IfcPropertySingleValue","IfcPropertySingleValue"), - ("IfcPropertyEnumeratedValue","IfcPropertyEnumeratedValue","IfcPropertyEnumeratedValue") + ("IfcPropertySingleValue", "IfcPropertySingleValue", "IfcPropertySingleValue"), + ("IfcPropertyEnumeratedValue", "IfcPropertyEnumeratedValue", "IfcPropertyEnumeratedValue"), ], - name="Template Type" + name="Template Type", ) enum_values: CollectionProperty(name="Enum Values", type=EnumerationValues) + getter_enum = { + "primary_measure_type": get_primary_measure_type, + "template_type": lambda self, context: [ + ("IfcPropertySingleValue", "IfcPropertySingleValue", "IfcPropertySingleValue"), + ("IfcPropertyEnumeratedValue", "IfcPropertyEnumeratedValue", "IfcPropertyEnumeratedValue"), + ], + } + def get_value_name(self): ifc_data_type = IfcStore.get_schema().declaration_by_name(self.primary_measure_type) data_type = ifcopenshell.util.attribute.get_primitive_type(ifc_data_type) diff --git a/src/blenderbim/blenderbim/bim/module/pset/ui.py b/src/blenderbim/blenderbim/bim/module/pset/ui.py index 25adeb2156..ebc421420c 100644 --- a/src/blenderbim/blenderbim/bim/module/pset/ui.py +++ b/src/blenderbim/blenderbim/bim/module/pset/ui.py @@ -18,6 +18,7 @@ from bpy.types import Panel from blenderbim.bim.ifc import IfcStore +from blenderbim.bim.ui import prop_with_search from blenderbim.bim.helper import draw_attribute from blenderbim.bim.module.pset.data import ( ObjectPsetsData, @@ -95,7 +96,7 @@ def draw_psetqto_ui(context, pset_id, pset, props, layout, obj_type): def draw_psetqto_editable_ui(box, props, prop): row = box.row(align=True) - draw_attribute(box, prop, row, copy_operator="bim.copy_property_to_selection") + draw_attribute(prop, row, copy_operator="bim.copy_property_to_selection") if ( "length" in prop.name.lower() or "width" in prop.name.lower() @@ -138,7 +139,7 @@ class BIM_PT_object_psets(Panel): props = context.active_object.PsetProperties row = self.layout.row(align=True) - row.prop(props, "pset_name", text="") + prop_with_search(row, props, "pset_name", text="") op = row.operator("bim.add_pset", icon="ADD", text="") op.obj = context.active_object.name op.obj_type = "Object" @@ -177,7 +178,7 @@ class BIM_PT_object_qtos(Panel): props = context.active_object.PsetProperties row = self.layout.row(align=True) - row.prop(props, "qto_name", text="") + prop_with_search(row, props, "qto_name", text="") op = row.operator("bim.add_qto", icon="ADD", text="") op.obj = context.active_object.name op.obj_type = "Object" @@ -450,12 +451,12 @@ class BIM_PT_add_edit_custom_properties(Panel): row.prop(prop, "property_name", text="") if prop.template_type == "IfcPropertySingleValue": row.prop(prop, prop.get_value_name(), text="") - row.prop(prop, "primary_measure_type", text="") - row.prop(prop, "template_type", text="") + prop_with_search(row, prop, "primary_measure_type", text="") + prop_with_search(row, prop, "template_type", text="") op = row.operator("bim.remove_property_to_edit", icon="X", text="") op.index = index op.option = "AddEditProperties" - + if prop.template_type == "IfcPropertyEnumeratedValue": op = row.operator("bim.add_property_to_edit", icon="ADD", text="Add Enum") op.option = "AddEditProperties" @@ -494,7 +495,7 @@ class BIM_PT_delete_psets(Panel): row = layout.row() op = row.operator("bim.add_property_to_edit", icon="ADD") op.option = "DeletePsets" - + if props: for index, prop in enumerate(props): row = layout.row(align=True) diff --git a/src/blenderbim/blenderbim/bim/module/pset_template/__init__.py b/src/blenderbim/blenderbim/bim/module/pset_template/__init__.py index e4e5591da4..1f822620da 100644 --- a/src/blenderbim/blenderbim/bim/module/pset_template/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/pset_template/__init__.py @@ -20,6 +20,8 @@ import bpy from . import ui, prop, operator classes = ( + operator.RefreshPsetTemplates, + operator.AddPsetFile, operator.SavePsetTemplateFile, operator.AddPsetTemplate, operator.EditPsetTemplate, @@ -30,8 +32,11 @@ classes = ( operator.EnableEditingPsetTemplate, operator.DisableEditingPsetTemplate, operator.EnableEditingPropTemplate, + operator.DeletePropEnum, + operator.AddPropEnum, operator.DisableEditingPropTemplate, prop.PsetTemplate, + prop.EnumerationValues, prop.PropTemplate, prop.BIMPsetTemplateProperties, ui.BIM_PT_pset_template, diff --git a/src/blenderbim/blenderbim/bim/module/pset_template/operator.py b/src/blenderbim/blenderbim/bim/module/pset_template/operator.py index 8699f6d327..9013a6901f 100644 --- a/src/blenderbim/blenderbim/bim/module/pset_template/operator.py +++ b/src/blenderbim/blenderbim/bim/module/pset_template/operator.py @@ -16,16 +16,66 @@ # You should have received a copy of the GNU General Public License # along with BlenderBIM Add-on. If not, see . +import os import bpy import ifcopenshell import ifcopenshell.api import blenderbim.bim.schema import blenderbim.bim.handler -from blenderbim.bim.module.pset_template.prop import updatePsetTemplateFiles, updatePsetTemplates, getPsetTemplates +from blenderbim.bim.module.pset_template.prop import purge as purge_templates, updatePsetTemplates, getPsetTemplates +from blenderbim.bim.module.pset.prop import purge as purge_psets from ifcopenshell.api.pset_template.data import Data from blenderbim.bim.ifc import IfcStore +#This is just a temporary operator until +#@Moult performs some of his refactor-magic ;) - vulevukusej +class RefreshPsetTemplates(bpy.types.Operator): + bl_idname = "bim.refresh_psettemplates" + bl_label = "Refresh the data for PsetTemplates" + bl_options = {"REGISTER", "UNDO"} + + def execute(self, context): + purge_templates() + purge_psets() + return {"FINISHED"} + + +class AddPsetFile(bpy.types.Operator): + bl_idname = "bim.add_pset_file" + bl_label = "Add Pset File" + bl_options = {"REGISTER", "UNDO"} + + def invoke(self, context, event): + return context.window_manager.invoke_props_dialog(self, width=250) + + def draw(self, context): + self.props = context.scene.BIMPsetTemplateProperties + self.layout.prop(self.props, "new_template_filename", text="Filename:") + + def execute(self, context): + template = ifcopenshell.file() + filepath = os.path.join( + context.scene.BIMProperties.data_dir, + "pset", + self.props.new_template_filename + ".ifc", + ) + + template.create_entity( + "IFCPROPERTYSETTEMPLATE", + **{ + "GlobalId": ifcopenshell.guid.new(), + "Name": "Name", + "Description": "Description", + "TemplateType": "PSET_TYPEDRIVENONLY", + "ApplicableEntity": "IfcTypeObject" + } + ) + template.write(filepath) + self.props.new_template_filename = "" + return {"FINISHED"} + + class AddPsetTemplate(bpy.types.Operator): bl_idname = "bim.add_pset_template" bl_label = "Add Pset Template" @@ -41,7 +91,6 @@ class AddPsetTemplate(bpy.types.Operator): return result def _execute(self, context): - props = context.scene.BIMPsetTemplateProperties ifcopenshell.api.run("pset_template.add_pset_template", IfcStore.pset_template_file) Data.load(IfcStore.pset_template_file) updatePsetTemplates(self, context) @@ -139,6 +188,38 @@ class EnableEditingPropTemplate(bpy.types.Operator): props.active_prop_template.name = template["Name"] or "" props.active_prop_template.description = template["Description"] or "" props.active_prop_template.primary_measure_type = template["PrimaryMeasureType"] + props.active_prop_template.template_type = template["TemplateType"] + props.active_prop_template.enum_values.clear() + + if template["Enumerators"]: + props.active_prop_template.enum_values.clear() + data_type = props.active_prop_template.get_value_name() + for e in template["Enumerators"].EnumerationValues: + new = props.active_prop_template.enum_values.add() + setattr(new, data_type, e.wrappedValue) + + return {"FINISHED"} + +class DeletePropEnum(bpy.types.Operator): + bl_idname = "bim.delete_prop_enum" + bl_label = "delete property enumeration" + bl_options = {"REGISTER", "UNDO"} + index: bpy.props.IntProperty() + + def execute(self, context): + active_prop = context.scene.BIMPsetTemplateProperties.active_prop_template + active_prop.enum_values.remove(self.index) + return {"FINISHED"} + +class AddPropEnum(bpy.types.Operator): + bl_idname = "bim.add_prop_enum" + bl_label = "add property enumeration" + bl_options = {"REGISTER", "UNDO"} + index: bpy.props.IntProperty() + + def execute(self, context): + active_prop = context.scene.BIMPsetTemplateProperties.active_prop_template + active_prop.enum_values.add() return {"FINISHED"} @@ -285,6 +366,10 @@ class EditPropTemplate(bpy.types.Operator): def _execute(self, context): props = context.scene.BIMPsetTemplateProperties + if props.active_prop_template.template_type == "P_ENUMERATEDVALUE": + enumerator = self.generate_prop_enum(props) + else: + enumerator = None ifcopenshell.api.run( "pset_template.edit_prop_template", IfcStore.pset_template_file, @@ -294,12 +379,28 @@ class EditPropTemplate(bpy.types.Operator): "Name": props.active_prop_template.name, "Description": props.active_prop_template.description, "PrimaryMeasureType": props.active_prop_template.primary_measure_type, + "TemplateType": props.active_prop_template.template_type, + "Enumerators": enumerator }, } ) Data.load(IfcStore.pset_template_file) bpy.ops.bim.disable_editing_prop_template() return {"FINISHED"} + + #TODO -This will need to go into the + # api code at some point - vulevukusej + def generate_prop_enum(self, props): + self.file = IfcStore.pset_template_file + data_type = props.active_prop_template.get_value_name() + prop = props.active_prop_template + prop_enum = self.file.create_entity( + "IFCPROPERTYENUMERATION", + Name=prop.name, + EnumerationValues=tuple(self.file.create_entity( + prop.primary_measure_type, ev[data_type]) for ev in prop.enum_values) + ) + return prop_enum def rollback(self, data): IfcStore.pset_template_file.undo() diff --git a/src/blenderbim/blenderbim/bim/module/pset_template/prop.py b/src/blenderbim/blenderbim/bim/module/pset_template/prop.py index 0d6a46a94e..4554c229c4 100644 --- a/src/blenderbim/blenderbim/bim/module/pset_template/prop.py +++ b/src/blenderbim/blenderbim/bim/module/pset_template/prop.py @@ -146,11 +146,42 @@ class PsetTemplate(PropertyGroup): applicable_entity: StringProperty(name="Applicable Entity") +class EnumerationValues(PropertyGroup): + string_value: StringProperty(name="Value") + bool_value: BoolProperty(name="Value") + int_value: IntProperty(name="Value") + float_value: FloatProperty(name="Value") + + class PropTemplate(PropertyGroup): global_id: StringProperty(name="Global ID") name: StringProperty(name="Name") description: StringProperty(name="Description") primary_measure_type: EnumProperty(items=get_primary_measure_type, name="Primary Measure Type") + template_type: EnumProperty( + items=[ + ("P_SINGLEVALUE","P_SINGLEVALUE",""), + ("P_ENUMERATEDVALUE","P_ENUMERATEDVALUE","") + ], + name="Template Type" + ) + enum_values: CollectionProperty(type=EnumerationValues) + getter_enum = { + "primary_measure_type": get_primary_measure_type, + } + + + def get_value_name(self): + ifc_data_type = IfcStore.get_schema().declaration_by_name(self.primary_measure_type) + data_type = ifcopenshell.util.attribute.get_primitive_type(ifc_data_type) + if data_type == "string": + return "string_value" + elif data_type == "boolean": + return "bool_value" + elif data_type == "integer": + return "int_value" + elif data_type == "float": + return "float_value" class BIMPsetTemplateProperties(PropertyGroup): @@ -162,3 +193,9 @@ class BIMPsetTemplateProperties(PropertyGroup): active_prop_template_id: IntProperty(name="Active Prop Template Id") active_pset_template: PointerProperty(type=PsetTemplate) active_prop_template: PointerProperty(type=PropTemplate) + new_template_filename: StringProperty("New TemplateFileName") + + getter_enum = { + "pset_template_files": getPsetTemplateFiles, + "pset_templates": getPsetTemplates, + } diff --git a/src/blenderbim/blenderbim/bim/module/pset_template/ui.py b/src/blenderbim/blenderbim/bim/module/pset_template/ui.py index 91f90f82d8..858f856711 100644 --- a/src/blenderbim/blenderbim/bim/module/pset_template/ui.py +++ b/src/blenderbim/blenderbim/bim/module/pset_template/ui.py @@ -19,6 +19,7 @@ import bpy from bpy.types import Panel from blenderbim.bim.ifc import IfcStore +from blenderbim.bim.ui import prop_with_search from blenderbim.bim.module.pset_template.prop import ( getPsetTemplates, ) @@ -37,15 +38,17 @@ class BIM_PT_pset_template(Panel): def draw(self, context): layout = self.layout props = context.scene.BIMPsetTemplateProperties - + row = layout.row(align=True) - row.prop(props, "pset_template_files", text="") + prop_with_search(row, props, "pset_template_files", text="") row.operator("bim.save_pset_template_file", text="", icon="EXPORT") - + row.operator("bim.add_pset_file",icon="ADD",text="") + row.operator("bim.refresh_psettemplates", icon="FILE_REFRESH", text="") + row = layout.row(align=True) if bool(getPsetTemplates(props, context)): - row.prop(props, "pset_templates", text="", icon="COPY_ID") + prop_with_search(row, props, "pset_templates", text="", icon="COPY_ID") else: row.label(text="No Pset Templates", icon="COPY_ID") @@ -73,7 +76,7 @@ class BIM_PT_pset_template(Panel): row.prop(props.active_pset_template, "template_type") row = layout.row() row.prop(props.active_pset_template, "applicable_entity") - else: + else: pset_template = Data.pset_templates[int(props.pset_templates)] for name, value in pset_template.items(): if name == "id" or name == "type" or name == "HasPropertyTemplates": @@ -85,6 +88,9 @@ class BIM_PT_pset_template(Panel): row = layout.row(align=True) row.label(text="Property Templates", icon="COPY_ID") row.operator("bim.add_prop_template", icon="ADD", text="") + + row = layout.row() + row.label(text="Name | Description | PrimaryMeasureType | TemplateType") for prop_template_id in pset_template["HasPropertyTemplates"]: prop_template = Data.prop_templates[prop_template_id] @@ -93,11 +99,33 @@ class BIM_PT_pset_template(Panel): if props.active_prop_template_id and props.active_prop_template_id == prop_template_id: row.prop(props.active_prop_template, "name", text="") row.prop(props.active_prop_template, "description", text="") - row.prop(props.active_prop_template, "primary_measure_type", text="") + prop_with_search(row, props.active_prop_template, "primary_measure_type", text="") + row.prop(props.active_prop_template, "template_type", text="") + + if props.active_prop_template.template_type == "P_ENUMERATEDVALUE": + row = layout.row(align=True) + split = row.split(factor=0.2) + c=split.column() + c.label(text="Enumerations:",) + + c=split.column() + box = c.box() + grid = box.column_flow(columns=4) + value_name = props.active_prop_template.get_value_name() + r = grid.row() + r.operator("bim.add_prop_enum", text="Add Enum") + for k,v in enumerate(props.active_prop_template.enum_values): + r = grid.row(align=True) + r.prop(v, value_name, text="") + op = r.operator("bim.delete_prop_enum", icon="X", text="") + op.index = k + + else: row.label(text=prop_template["Name"]) row.label(text=prop_template["Description"]) row.label(text=prop_template["PrimaryMeasureType"]) + row.label(text=prop_template["TemplateType"]) if props.active_prop_template_id and props.active_prop_template_id == prop_template_id: op = row.operator("bim.edit_prop_template", icon="CHECKMARK", text="") diff --git a/src/blenderbim/blenderbim/bim/module/root/__init__.py b/src/blenderbim/blenderbim/bim/module/root/__init__.py index 00a36e0817..523f3b77cd 100644 --- a/src/blenderbim/blenderbim/bim/module/root/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/root/__init__.py @@ -26,6 +26,7 @@ classes = ( operator.EnableReassignClass, operator.ReassignClass, operator.UnlinkObject, + operator.BIM_OT_enum_property_search, prop.BIMRootProperties, ui.BIM_PT_class, ) diff --git a/src/blenderbim/blenderbim/bim/module/root/operator.py b/src/blenderbim/blenderbim/bim/module/root/operator.py index e64b2e5920..ee57c74f0f 100644 --- a/src/blenderbim/blenderbim/bim/module/root/operator.py +++ b/src/blenderbim/blenderbim/bim/module/root/operator.py @@ -32,6 +32,7 @@ import blenderbim.tool as tool from ifcopenshell.api.void.data import Data as VoidData from blenderbim.bim.ifc import IfcStore from blenderbim.bim.module.root.prop import get_contexts +from blenderbim.bim.prop import StrProperty class Operator: @@ -189,3 +190,27 @@ class CopyClass(bpy.types.Operator, Operator): for obj in objects: core.copy_class(tool.Ifc, tool.Collector, tool.Geometry, tool.Root, obj=obj) blenderbim.bim.handler.purge_module_data() + + +class BIM_OT_enum_property_search(bpy.types.Operator): + bl_idname = "bim.enum_property_search" + bl_label = "Search For Property" + bl_options = {"REGISTER", "UNDO"} + prop_name: bpy.props.StringProperty() + collection: bpy.props.CollectionProperty(type=StrProperty) + + def invoke(self, context, event): + self.data = context.data + getter = self.data.getter_enum.get(self.prop_name, None) + if getter is None: + return {"FINISHED"} + self.collection.clear() + for item in getter(self.data, context): + self.collection.add().name = item[0] + return context.window_manager.invoke_props_dialog(self) + + def execute(self, context): + return {"FINISHED"} + + def draw(self, context): + self.layout.prop_search(self.data, self.prop_name, self, "collection") diff --git a/src/blenderbim/blenderbim/bim/module/root/prop.py b/src/blenderbim/blenderbim/bim/module/root/prop.py index 8b598a2338..8e3fbeca94 100644 --- a/src/blenderbim/blenderbim/bim/module/root/prop.py +++ b/src/blenderbim/blenderbim/bim/module/root/prop.py @@ -21,6 +21,7 @@ import ifcopenshell import ifcopenshell.util.schema from blenderbim.bim.module.root.data import IfcClassData from blenderbim.bim.ifc import IfcStore +from blenderbim.bim.prop import StrProperty from bpy.types import PropertyGroup from bpy.props import ( PointerProperty, @@ -34,11 +35,14 @@ from bpy.props import ( ) types_enum = [] +classes_enum = [] def purge(): global types_enum types_enum = [] + global classes_enum + classes_enum = [] def getIfcPredefinedTypes(self, context): @@ -69,6 +73,10 @@ def refreshPredefinedTypes(self, context): context.scene.BIMRootProperties.ifc_predefined_type = enum[0][0] +def update_class_enum(self, context): + self.ifc_class = self.ifc_class_filter_enum + + def get_ifc_products(self, context): if not IfcClassData.is_loaded: IfcClassData.load() @@ -93,3 +101,10 @@ class BIMRootProperties(PropertyGroup): ifc_class: EnumProperty(items=get_ifc_classes, name="Class", update=refreshPredefinedTypes) ifc_predefined_type: EnumProperty(items=getIfcPredefinedTypes, name="Predefined Type", default=None) ifc_userdefined_type: StringProperty(name="Userdefined Type") + + getter_enum = { + "contexts": get_contexts, + "ifc_product": get_ifc_products, + "ifc_class": get_ifc_classes, + "ifc_predefined_type": getIfcPredefinedTypes, + } diff --git a/src/blenderbim/blenderbim/bim/module/root/ui.py b/src/blenderbim/blenderbim/bim/module/root/ui.py index 369f0b50e8..b6a5f99268 100644 --- a/src/blenderbim/blenderbim/bim/module/root/ui.py +++ b/src/blenderbim/blenderbim/bim/module/root/ui.py @@ -20,6 +20,7 @@ import bpy import blenderbim.bim.module.root.prop as root_prop from bpy.types import Panel from blenderbim.bim.ifc import IfcStore +from blenderbim.bim.ui import prop_with_search from blenderbim.bim.module.root.data import IfcClassData @@ -76,17 +77,14 @@ class BIM_PT_class(Panel): def draw_class_dropdowns(self, context, ifc_predefined_types, is_reassigning_class=False): props = context.scene.BIMRootProperties + layout = self.layout if not is_reassigning_class: - row = self.layout.row() - row.prop(props, "ifc_product") - row = self.layout.row() - row.prop(props, "ifc_class") + prop_with_search(layout, props, "ifc_product") + prop_with_search(layout, props, "ifc_class") if ifc_predefined_types: - row = self.layout.row() - row.prop(props, "ifc_predefined_type") - if ifc_predefined_types == "USERDEFINED": - row = self.layout.row() - row.prop(props, "ifc_userdefined_type") + prop_with_search(layout, props, "ifc_predefined_type") + if props.ifc_predefined_type == "USERDEFINED": + row = layout.row() + row.prop(props, "ifc_userdefined_type") if not is_reassigning_class: - row = self.layout.row() - row.prop(context.scene.BIMRootProperties, "contexts") + prop_with_search(layout, props, "contexts") diff --git a/src/blenderbim/blenderbim/bim/module/unit/prop.py b/src/blenderbim/blenderbim/bim/module/unit/prop.py index 22ef9c7a0e..f631ac1b69 100644 --- a/src/blenderbim/blenderbim/bim/module/unit/prop.py +++ b/src/blenderbim/blenderbim/bim/module/unit/prop.py @@ -68,3 +68,9 @@ class BIMUnitProperties(PropertyGroup): conversion_unit_types: EnumProperty(items=get_conversion_unit_types, name="Conversion Unit Types") named_unit_types: EnumProperty(items=get_named_unit_types, name="Named Unit Types") unit_attributes: CollectionProperty(name="Unit Attributes", type=Attribute) + + getter_enum = { + "unit_classes": get_unit_classes, + "conversion_unit_types": get_conversion_unit_types, + "named_unit_types": get_named_unit_types, + } diff --git a/src/blenderbim/blenderbim/bim/module/unit/ui.py b/src/blenderbim/blenderbim/bim/module/unit/ui.py index a6d13447f5..183ed5cbe7 100644 --- a/src/blenderbim/blenderbim/bim/module/unit/ui.py +++ b/src/blenderbim/blenderbim/bim/module/unit/ui.py @@ -19,6 +19,7 @@ import blenderbim.bim.helper from bpy.types import Panel, UIList from blenderbim.bim.ifc import IfcStore +from blenderbim.bim.ui import prop_with_search from blenderbim.bim.module.unit.data import UnitsData @@ -53,22 +54,22 @@ class BIM_PT_units(Panel): return row = self.layout.row(align=True) - row.prop(self.props, "unit_classes", text="") + prop_with_search(row, self.props, "unit_classes", text="") if self.props.unit_classes == "IfcMonetaryUnit": row.operator("bim.add_monetary_unit", text="", icon="ADD") elif self.props.unit_classes in ("IfcConversionBasedUnit", "IfcConversionBasedUnitWithOffset"): - row.prop(self.props, "conversion_unit_types", text="") + prop_with_search(row, self.props, "conversion_unit_types", text="") op = row.operator("bim.add_conversion_based_unit", text="", icon="ADD") op.name = self.props.conversion_unit_types elif self.props.unit_classes == "IfcDerivedUnit": pass # TODO elif self.props.unit_classes == "IfcSIUnit": - row.prop(self.props, "named_unit_types", text="") + prop_with_search(row, self.props, "named_unit_types", text="") op = row.operator("bim.add_si_unit", text="", icon="ADD") op.unit_type = self.props.named_unit_types elif self.props.unit_classes == "IfcContextDependentUnit": - row.prop(self.props, "named_unit_types", text="") + prop_with_search(row, self.props, "named_unit_types", text="") op = row.operator("bim.add_context_dependent_unit", text="", icon="ADD") op.name = "THINGAMAJIG" op.unit_type = self.props.named_unit_types diff --git a/src/blenderbim/blenderbim/bim/ui.py b/src/blenderbim/blenderbim/bim/ui.py index 2457cd99bf..e04e05d5be 100644 --- a/src/blenderbim/blenderbim/bim/ui.py +++ b/src/blenderbim/blenderbim/bim/ui.py @@ -170,6 +170,15 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences): row.operator("bim.configure_visibility") +def prop_with_search(layout, data, prop_name, **kwargs): # Kwargs are layout.prop arguments (text, icon, etc.) + row = layout.row(align=True) + # Magick courtesy of https://blender.stackexchange.com/a/203443/86891 + row.context_pointer_set(name="data", data=data) + row.prop(data, prop_name, **kwargs) + op = row.operator("bim.enum_property_search", text="", icon="VIEWZOOM") + op.prop_name = prop_name + + def ifc_units(self, context): scene = context.scene props = scene.BIMProperties diff --git a/src/ifcopenshell-python/ifcopenshell/api/pset/edit_pset.py b/src/ifcopenshell-python/ifcopenshell/api/pset/edit_pset.py index d6b234071d..28c307756c 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/pset/edit_pset.py +++ b/src/ifcopenshell-python/ifcopenshell/api/pset/edit_pset.py @@ -102,9 +102,11 @@ class Usecase: if value is None: continue if isinstance(value, ifcopenshell.entity_instance): - nominal_value = value if value.is_a(True) == "IFC4.IfcPropertyEnumeratedValue": properties.append(value) + continue + else: + nominal_value = value #TODO-The following "elif" is temporary code, will need to refactor at some point - vulevukusej elif isinstance(value, list): for pset_template in self.settings["pset_template"].HasPropertyTemplates: @@ -122,17 +124,18 @@ class Usecase: EnumerationReference=prop_enum ) properties.append(prop_enum_value) + continue else: primary_measure_type = self.get_primary_measure_type(name, new_value=value) value = self.cast_value_to_primary_measure_type(value, primary_measure_type) nominal_value = self.file.create_entity(primary_measure_type, value) - properties.append( - self.file.create_entity( - "IfcPropertySingleValue", - **{"Name": name, "NominalValue": nominal_value}, - ) + properties.append( + self.file.create_entity( + "IfcPropertySingleValue", + **{"Name": name, "NominalValue": nominal_value}, ) + ) return properties def extend_pset_with_new_properties(self, new_properties): diff --git a/src/ifcopenshell-python/ifcopenshell/api/pset_template/add_prop_template.py b/src/ifcopenshell-python/ifcopenshell/api/pset_template/add_prop_template.py index 3c3d9cc334..10061e2ec3 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/pset_template/add_prop_template.py +++ b/src/ifcopenshell-python/ifcopenshell/api/pset_template/add_prop_template.py @@ -35,6 +35,7 @@ class Usecase: "PrimaryMeasureType": "IfcLabel", "TemplateType": "P_SINGLEVALUE", "AccessState": "READWRITE", + "Enumerators": None } ) has_property_templates = list(self.settings["pset_template"].HasPropertyTemplates or []) diff --git a/src/ifcopenshell-python/ifcopenshell/api/pset_template/data.py b/src/ifcopenshell-python/ifcopenshell/api/pset_template/data.py index 2a1adda379..71b255cc41 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/pset_template/data.py +++ b/src/ifcopenshell-python/ifcopenshell/api/pset_template/data.py @@ -49,5 +49,7 @@ class Data: "Name": data["Name"], "Description": data["Description"], "PrimaryMeasureType": data["PrimaryMeasureType"], + "TemplateType": data["TemplateType"], + "Enumerators": data["Enumerators"] } cls.is_loaded = True