From 112ce48350093f115a6bab8ceaaa9dd81437ca5c Mon Sep 17 00:00:00 2001 From: Gorgious56 Date: Tue, 24 Aug 2021 13:58:52 +0200 Subject: [PATCH] Improve groups and systems interface (#1688) * Enable Batch adding/removing objects from groups Might hang up Blender for a few secs with a big number of object on execution * Enable Batch adding/removing objects from systems Might hang up Blender for a few secs with a big number of object on execution * Add Group Panel in object properties + Transfer adding object(s) to group into the object properties * Add Systems Panel in object properties + Transfer adding object(s) to system into the object properties * Simplify group & systems operators * Disabling Editing of groups/systems also disables individual edition --- .../blenderbim/bim/module/group/__init__.py | 3 + .../blenderbim/bim/module/group/operator.py | 55 ++++++++----- .../blenderbim/bim/module/group/prop.py | 1 + .../blenderbim/bim/module/group/ui.py | 81 ++++++++++++++----- .../blenderbim/bim/module/system/__init__.py | 3 + .../blenderbim/bim/module/system/operator.py | 61 +++++++++----- .../blenderbim/bim/module/system/prop.py | 1 + .../blenderbim/bim/module/system/ui.py | 81 ++++++++++++++----- 8 files changed, 206 insertions(+), 80 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/group/__init__.py b/src/blenderbim/blenderbim/bim/module/group/__init__.py index 4cf5131a2f..0bea604778 100644 --- a/src/blenderbim/blenderbim/bim/module/group/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/group/__init__.py @@ -26,6 +26,7 @@ classes = ( operator.AddGroup, operator.EditGroup, operator.RemoveGroup, + operator.ToggleAssigningGroup, operator.AssignGroup, operator.UnassignGroup, operator.EnableEditingGroup, @@ -34,7 +35,9 @@ classes = ( prop.Group, prop.BIMGroupProperties, ui.BIM_PT_groups, + ui.BIM_PT_object_groups, ui.BIM_UL_groups, + ui.BIM_UL_object_groups, ) diff --git a/src/blenderbim/blenderbim/bim/module/group/operator.py b/src/blenderbim/blenderbim/bim/module/group/operator.py index 0cd773791f..0485249733 100644 --- a/src/blenderbim/blenderbim/bim/module/group/operator.py +++ b/src/blenderbim/blenderbim/bim/module/group/operator.py @@ -48,6 +48,7 @@ class DisableGroupEditingUI(bpy.types.Operator): def execute(self, context): context.scene.BIMGroupProperties.is_editing = False + context.scene.BIMGroupProperties.active_group_id = 0 return {"FINISHED"} @@ -145,6 +146,16 @@ class DisableEditingGroup(bpy.types.Operator): return {"FINISHED"} +class ToggleAssigningGroup(bpy.types.Operator): + bl_idname = "bim.toggle_assigning_group" + bl_label = "Toggle Assigning Group" + bl_options = {"REGISTER", "UNDO"} + + def execute(self, context): + context.scene.BIMGroupProperties.is_adding = not context.scene.BIMGroupProperties.is_adding + return {"FINISHED"} + + class AssignGroup(bpy.types.Operator): bl_idname = "bim.assign_group" bl_label = "Assign Group" @@ -156,17 +167,20 @@ class AssignGroup(bpy.types.Operator): return IfcStore.execute_ifc_operator(self, context) def _execute(self, context): - product = bpy.data.objects.get(self.product) if self.product else context.active_object self.file = IfcStore.get_file() - ifcopenshell.api.run( - "group.assign_group", - self.file, - **{ - "product": self.file.by_id(product.BIMObjectProperties.ifc_definition_id), - "group": self.file.by_id(self.group), - } - ) - Data.load(IfcStore.get_file()) + products = [bpy.data.objects.get(self.product)] if self.product else context.selected_objects + for product in products: + if not product.BIMObjectProperties.ifc_definition_id: + continue + ifcopenshell.api.run( + "group.assign_group", + self.file, + **{ + "product": self.file.by_id(product.BIMObjectProperties.ifc_definition_id), + "group": self.file.by_id(self.group), + } + ) + Data.load(self.file) return {"FINISHED"} @@ -181,16 +195,19 @@ class UnassignGroup(bpy.types.Operator): return IfcStore.execute_ifc_operator(self, context) def _execute(self, context): - product = bpy.data.objects.get(self.product) if self.product else context.active_object self.file = IfcStore.get_file() - ifcopenshell.api.run( - "group.unassign_group", - self.file, - **{ - "product": self.file.by_id(product.BIMObjectProperties.ifc_definition_id), - "group": self.file.by_id(self.group), - } - ) + products = [bpy.data.objects.get(self.product)] if self.product else context.selected_objects + for product in products: + if not product.BIMObjectProperties.ifc_definition_id: + continue + ifcopenshell.api.run( + "group.unassign_group", + self.file, + **{ + "product": self.file.by_id(product.BIMObjectProperties.ifc_definition_id), + "group": self.file.by_id(self.group), + } + ) Data.load(IfcStore.get_file()) return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/group/prop.py b/src/blenderbim/blenderbim/bim/module/group/prop.py index 05decfb78d..590d2efd85 100644 --- a/src/blenderbim/blenderbim/bim/module/group/prop.py +++ b/src/blenderbim/blenderbim/bim/module/group/prop.py @@ -40,6 +40,7 @@ class Group(PropertyGroup): class BIMGroupProperties(PropertyGroup): group_attributes: CollectionProperty(name="Group Attributes", type=Attribute) is_editing: BoolProperty(name="Is Editing", default=False) + is_adding: BoolProperty(name="Is Adding", default=False) groups: CollectionProperty(name="Groups", type=Group) active_group_index: IntProperty(name="Active Group Index") active_group_id: IntProperty(name="Active Group Id") diff --git a/src/blenderbim/blenderbim/bim/module/group/ui.py b/src/blenderbim/blenderbim/bim/module/group/ui.py index 479a4c787a..4142ab0db2 100644 --- a/src/blenderbim/blenderbim/bim/module/group/ui.py +++ b/src/blenderbim/blenderbim/bim/module/group/ui.py @@ -68,37 +68,78 @@ class BIM_PT_groups(Panel): row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") +class BIM_PT_object_groups(Panel): + bl_label = "IFC Groups" + bl_idname = "BIM_PT_object_groups" + bl_options = {"DEFAULT_CLOSED"} + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "object" + + @classmethod + def poll(cls, context): + return IfcStore.get_file() and context.active_object.BIMObjectProperties.ifc_definition_id + + def draw(self, context): + if not Data.is_loaded: + Data.load(IfcStore.get_file()) + self.props = context.scene.BIMGroupProperties + row = self.layout.row(align=True) + if self.props.is_adding: + row.label(text="Adding Groups", icon="OUTLINER") + row.operator("bim.toggle_assigning_group", text="", icon="CANCEL") + self.layout.template_list( + "BIM_UL_object_groups", + "", + self.props, + "groups", + self.props, + "active_group_index", + ) + else: + row.label(text=f"{len(Data.groups)} Groups in IFC Project", icon="OUTLINER") + row.operator("bim.toggle_assigning_group", text="", icon="ADD") + + groups_object = Data.products.get(context.active_object.BIMObjectProperties.ifc_definition_id, []) + for group_id in groups_object: + row = self.layout.row(align=True) + row.label(text=Data.groups[group_id].get("Name", "Unnamed")) + op = row.operator("bim.unassign_group", text="", icon="X") + op.group = group_id + + if not groups_object: + self.layout.label(text="No Group associated with Active Object") + class BIM_UL_groups(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname): if item: row = layout.row(align=True) row.label(text=item.name) - - if context.active_object: - oprops = context.active_object.BIMObjectProperties - if ( - oprops.ifc_definition_id in Data.products - and item.ifc_definition_id in Data.products[oprops.ifc_definition_id] - ): - op = row.operator("bim.unassign_group", text="", icon="KEYFRAME_HLT", emboss=False) - op.group = item.ifc_definition_id - else: - op = row.operator("bim.assign_group", text="", icon="KEYFRAME", emboss=False) - op.group = item.ifc_definition_id - - if context.scene.BIMGroupProperties.active_group_id == item.ifc_definition_id: + group_id = item.ifc_definition_id + if context.scene.BIMGroupProperties.active_group_id == group_id: op = row.operator("bim.select_group_products", text="", icon="RESTRICT_SELECT_OFF") - op.group = item.ifc_definition_id + op.group = group_id row.operator("bim.edit_group", text="", icon="CHECKMARK") row.operator("bim.disable_editing_group", text="", icon="CANCEL") elif context.scene.BIMGroupProperties.active_group_id: op = row.operator("bim.select_group_products", text="", icon="RESTRICT_SELECT_OFF") - op.group = item.ifc_definition_id - row.operator("bim.remove_group", text="", icon="X").group = item.ifc_definition_id + op.group = group_id + op = row.operator("bim.remove_group", text="", icon="X") + op.group = group_id else: op = row.operator("bim.select_group_products", text="", icon="RESTRICT_SELECT_OFF") - op.group = item.ifc_definition_id + op.group = group_id op = row.operator("bim.enable_editing_group", text="", icon="GREASEPENCIL") - op.group = item.ifc_definition_id - row.operator("bim.remove_group", text="", icon="X").group = item.ifc_definition_id + op.group = group_id + op = row.operator("bim.remove_group", text="", icon="X") + op.group = group_id + + +class BIM_UL_object_groups(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname): + if item: + row = layout.row(align=True) + row.label(text=item.name) + op = row.operator("bim.assign_group", text="", icon="ADD") + op.group = item.ifc_definition_id diff --git a/src/blenderbim/blenderbim/bim/module/system/__init__.py b/src/blenderbim/blenderbim/bim/module/system/__init__.py index c5652828e0..47c1210569 100644 --- a/src/blenderbim/blenderbim/bim/module/system/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/system/__init__.py @@ -26,6 +26,7 @@ classes = ( operator.AddSystem, operator.EditSystem, operator.RemoveSystem, + operator.ToggleAssigningSystem, operator.AssignSystem, operator.UnassignSystem, operator.EnableEditingSystem, @@ -34,7 +35,9 @@ classes = ( prop.System, prop.BIMSystemProperties, ui.BIM_PT_systems, + ui.BIM_PT_object_systems, ui.BIM_UL_systems, + ui.BIM_UL_object_systems, ) diff --git a/src/blenderbim/blenderbim/bim/module/system/operator.py b/src/blenderbim/blenderbim/bim/module/system/operator.py index 51597aa7c0..23ce075299 100644 --- a/src/blenderbim/blenderbim/bim/module/system/operator.py +++ b/src/blenderbim/blenderbim/bim/module/system/operator.py @@ -48,6 +48,7 @@ class DisableSystemEditingUI(bpy.types.Operator): def execute(self, context): context.scene.BIMSystemProperties.is_editing = False + context.scene.BIMSystemProperties.active_system_id = 0 return {"FINISHED"} @@ -145,6 +146,16 @@ class DisableEditingSystem(bpy.types.Operator): return {"FINISHED"} +class ToggleAssigningSystem(bpy.types.Operator): + bl_idname = "bim.toggle_assigning_system" + bl_label = "Toggle Assigning System" + bl_options = {"REGISTER", "UNDO"} + + def execute(self, context): + context.scene.BIMSystemProperties.is_adding = not context.scene.BIMSystemProperties.is_adding + return {"FINISHED"} + + class AssignSystem(bpy.types.Operator): bl_idname = "bim.assign_system" bl_label = "Assign System" @@ -156,17 +167,20 @@ class AssignSystem(bpy.types.Operator): return IfcStore.execute_ifc_operator(self, context) def _execute(self, context): - product = bpy.data.objects.get(self.product) if self.product else context.active_object self.file = IfcStore.get_file() - ifcopenshell.api.run( - "system.assign_system", - self.file, - **{ - "product": self.file.by_id(product.BIMObjectProperties.ifc_definition_id), - "system": self.file.by_id(self.system), - } - ) - Data.load(IfcStore.get_file()) + products = [bpy.data.objects.get(self.product)] if self.product else context.selected_objects + for product in products: + if not product.BIMObjectProperties.ifc_definition_id: + continue + ifcopenshell.api.run( + "system.assign_system", + self.file, + **{ + "product": self.file.by_id(product.BIMObjectProperties.ifc_definition_id), + "system": self.file.by_id(self.system), + } + ) + Data.load(self.file) return {"FINISHED"} @@ -181,17 +195,23 @@ class UnassignSystem(bpy.types.Operator): return IfcStore.execute_ifc_operator(self, context) def _execute(self, context): - product = bpy.data.objects.get(self.product) if self.product else context.active_object self.file = IfcStore.get_file() - ifcopenshell.api.run( - "system.unassign_system", - self.file, - **{ - "product": self.file.by_id(product.BIMObjectProperties.ifc_definition_id), - "system": self.file.by_id(self.system), - } - ) - Data.load(IfcStore.get_file()) + products = [bpy.data.objects.get(self.product)] if self.product else context.selected_objects + for product in products: + props = product.BIMObjectProperties + if not props.ifc_definition_id: + continue + if not (props.ifc_definition_id in Data.products and self.system in Data.products[props.ifc_definition_id]): + continue + ifcopenshell.api.run( + "system.unassign_system", + self.file, + **{ + "product": self.file.by_id(product.BIMObjectProperties.ifc_definition_id), + "system": self.file.by_id(self.system), + } + ) + Data.load(self.file) return {"FINISHED"} @@ -202,7 +222,6 @@ class SelectSystemProducts(bpy.types.Operator): system: bpy.props.IntProperty() def execute(self, context): - self.file = IfcStore.get_file() for obj in context.visible_objects: obj.select_set(False) if not obj.BIMObjectProperties.ifc_definition_id: diff --git a/src/blenderbim/blenderbim/bim/module/system/prop.py b/src/blenderbim/blenderbim/bim/module/system/prop.py index f792ac8597..328b56882f 100644 --- a/src/blenderbim/blenderbim/bim/module/system/prop.py +++ b/src/blenderbim/blenderbim/bim/module/system/prop.py @@ -40,6 +40,7 @@ class System(PropertyGroup): class BIMSystemProperties(PropertyGroup): system_attributes: CollectionProperty(name="System Attributes", type=Attribute) is_editing: BoolProperty(name="Is Editing", default=False) + is_adding: BoolProperty(name="Is Adding", default=False) systems: CollectionProperty(name="Systems", type=System) active_system_index: IntProperty(name="Active System Index") active_system_id: IntProperty(name="Active System Id") diff --git a/src/blenderbim/blenderbim/bim/module/system/ui.py b/src/blenderbim/blenderbim/bim/module/system/ui.py index 516e382a90..e63267ca2a 100644 --- a/src/blenderbim/blenderbim/bim/module/system/ui.py +++ b/src/blenderbim/blenderbim/bim/module/system/ui.py @@ -68,37 +68,78 @@ class BIM_PT_systems(Panel): row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="") +class BIM_PT_object_systems(Panel): + bl_label = "IFC Systems" + bl_idname = "BIM_PT_object_systems" + bl_options = {"DEFAULT_CLOSED"} + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "object" + + @classmethod + def poll(cls, context): + return IfcStore.get_file() and context.active_object.BIMObjectProperties.ifc_definition_id + + def draw(self, context): + if not Data.is_loaded: + Data.load(IfcStore.get_file()) + self.props = context.scene.BIMSystemProperties + row = self.layout.row(align=True) + if self.props.is_adding: + row.label(text="Adding Systems", icon="OUTLINER") + row.operator("bim.toggle_assigning_system", text="", icon="CANCEL") + self.layout.template_list( + "BIM_UL_object_systems", + "", + self.props, + "systems", + self.props, + "active_system_index", + ) + else: + row.label(text=f"{len(Data.systems)} Systems in IFC Project", icon="OUTLINER") + row.operator("bim.toggle_assigning_system", text="", icon="ADD") + + systems_object = Data.products.get(context.active_object.BIMObjectProperties.ifc_definition_id, []) + for system_id in systems_object: + row = self.layout.row(align=True) + row.label(text=Data.systems[system_id].get("Name", "Unnamed")) + op = row.operator("bim.unassign_system", text="", icon="X") + op.system = system_id + + if not systems_object: + self.layout.label(text="No System associated with Active Object") + class BIM_UL_systems(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname): if item: row = layout.row(align=True) row.label(text=item.name) - - if context.active_object: - oprops = context.active_object.BIMObjectProperties - if ( - oprops.ifc_definition_id in Data.products - and item.ifc_definition_id in Data.products[oprops.ifc_definition_id] - ): - op = row.operator("bim.unassign_system", text="", icon="KEYFRAME_HLT", emboss=False) - op.system = item.ifc_definition_id - else: - op = row.operator("bim.assign_system", text="", icon="KEYFRAME", emboss=False) - op.system = item.ifc_definition_id - - if context.scene.BIMSystemProperties.active_system_id == item.ifc_definition_id: + system_id = item.ifc_definition_id + if context.scene.BIMSystemProperties.active_system_id == system_id: op = row.operator("bim.select_system_products", text="", icon="RESTRICT_SELECT_OFF") - op.system = item.ifc_definition_id + op.system = system_id row.operator("bim.edit_system", text="", icon="CHECKMARK") row.operator("bim.disable_editing_system", text="", icon="CANCEL") elif context.scene.BIMSystemProperties.active_system_id: op = row.operator("bim.select_system_products", text="", icon="RESTRICT_SELECT_OFF") - op.system = item.ifc_definition_id - row.operator("bim.remove_system", text="", icon="X").system = item.ifc_definition_id + op.system = system_id + op = row.operator("bim.remove_system", text="", icon="X") + op.system = system_id else: op = row.operator("bim.select_system_products", text="", icon="RESTRICT_SELECT_OFF") - op.system = item.ifc_definition_id + op.system = system_id op = row.operator("bim.enable_editing_system", text="", icon="GREASEPENCIL") - op.system = item.ifc_definition_id - row.operator("bim.remove_system", text="", icon="X").system = item.ifc_definition_id + op.system = system_id + op = row.operator("bim.remove_system", text="", icon="X") + op.system = system_id + + +class BIM_UL_object_systems(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname): + if item: + row = layout.row(align=True) + row.label(text=item.name) + op = row.operator("bim.assign_system", text="", icon="ADD") + op.system = item.ifc_definition_id