Fix #6030. Consolidate group management into single UI and allow for bulk assign / unassign.

This commit is contained in:
Dion Moult
2025-01-25 14:01:56 +11:00
parent 5fbb496818
commit a2a4da596f
5 changed files with 48 additions and 110 deletions
@@ -38,7 +38,6 @@ classes = (
ui.BIM_PT_groups,
ui.BIM_PT_object_groups,
ui.BIM_UL_groups,
ui.BIM_UL_object_groups,
)
+1 -5
View File
@@ -48,13 +48,9 @@ class ObjectGroupsData:
@classmethod
def load(cls):
cls.data = {"total_groups": cls.total_groups(), "groups": cls.groups()}
cls.data = {"groups": cls.groups()}
cls.is_loaded = True
@classmethod
def total_groups(cls):
return len(tool.Ifc.get().by_type("IfcGroup", include_subtypes=False))
@classmethod
def groups(cls):
element = tool.Ifc.get_entity(bpy.context.active_object)
+26 -30
View File
@@ -164,52 +164,48 @@ class AssignGroup(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.assign_group"
bl_label = "Assign Group"
bl_options = {"REGISTER", "UNDO"}
product: bpy.props.StringProperty()
group: bpy.props.IntProperty()
bl_description = "Assign the selected objects to the selected group\nALT + CLICK to unassign."
group: bpy.props.IntProperty(options={"SKIP_SAVE"})
is_assigning: bpy.props.BoolProperty(default=True, options={"SKIP_SAVE"})
def invoke(self, context, event):
self.is_assigning = not event.alt
return self.execute(context)
def _execute(self, context):
self.file = 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,
products=[self.file.by_id(product.BIMObjectProperties.ifc_definition_id)],
group=self.file.by_id(self.group),
)
return {"FINISHED"}
if not self.is_assigning:
return bpy.ops.bim.unassign_group(group=self.group)
products = [
tool.Ifc.get_entity(o)
for o in tool.Blender.get_selected_objects(include_active=False)
if tool.Ifc.get_entity(o)
]
ifcopenshell.api.group.assign_group(tool.Ifc.get(), products=products, group=tool.Ifc.get().by_id(self.group))
class UnassignGroup(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.unassign_group"
bl_label = "Unassign Group"
bl_options = {"REGISTER", "UNDO"}
product: bpy.props.StringProperty()
group: bpy.props.IntProperty()
bl_description = "Unassign the selected objects from the selected group"
group: bpy.props.IntProperty(options={"SKIP_SAVE"})
def _execute(self, context):
self.file = 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.unassign_group",
self.file,
**{
"products": [self.file.by_id(product.BIMObjectProperties.ifc_definition_id)],
"group": self.file.by_id(self.group),
}
)
return {"FINISHED"}
products = [
tool.Ifc.get_entity(o)
for o in tool.Blender.get_selected_objects(include_active=False)
if tool.Ifc.get_entity(o)
]
if not products:
return
ifcopenshell.api.group.unassign_group(tool.Ifc.get(), products=products, group=tool.Ifc.get().by_id(self.group))
class SelectGroupProducts(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.select_group_products"
bl_label = "Select Group Products"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Select objects assigned to the selected group"
group: bpy.props.IntProperty()
def _execute(self, context):
@@ -55,3 +55,8 @@ class BIMGroupProperties(PropertyGroup):
groups: CollectionProperty(name="Groups", type=Group)
active_group_index: IntProperty(name="Active Group Index", update=update_active_group_index)
active_group_id: IntProperty(name="Active Group Id")
@property
def active_group(self):
if self.active_group_index < len(self.groups):
return self.groups[self.active_group_index]
+16 -74
View File
@@ -49,21 +49,25 @@ class BIM_PT_groups(Panel):
else:
row.operator("bim.load_groups", text="", icon="GREASEPENCIL")
if self.props.is_editing:
self.layout.template_list(
"BIM_UL_groups",
"",
self.props,
"groups",
self.props,
"active_group_index",
)
if not self.props.is_editing:
return
if (group := self.props.active_group) and (group_id := group.ifc_definition_id):
row = self.layout.row(align=True)
row.alignment = "RIGHT"
row.operator("bim.select_group_products", text="", icon="RESTRICT_SELECT_OFF").group = group_id
row.operator("bim.assign_group", text="", icon="FOLDER_REDIRECT").group = group_id
row.operator("bim.enable_editing_group", text="", icon="GREASEPENCIL").group = group_id
row.operator("bim.add_group", text="", icon="ADD").group = group_id
row.operator("bim.remove_group", text="", icon="X").group = group_id
if self.props.active_group_id:
self.draw_editable_ui(context)
draw_attributes(self.props.group_attributes, self.layout)
row = self.layout.row(align=True)
row.operator("bim.edit_group", text="Save Group", icon="CHECKMARK")
row.operator("bim.disable_editing_group", text="", icon="CANCEL")
def draw_editable_ui(self, context: bpy.types.Context) -> None:
draw_attributes(self.props.group_attributes, self.layout)
self.layout.template_list("BIM_UL_groups", "", self.props, "groups", self.props, "active_group_index")
class BIM_PT_object_groups(Panel):
@@ -86,21 +90,6 @@ class BIM_PT_object_groups(Panel):
if not ObjectGroupsData.is_loaded:
ObjectGroupsData.load()
self.props = context.scene.BIMGroupProperties
row = self.layout.row(align=True)
if self.props.is_editing:
row.label(text="Adding Groups", icon="OUTLINER")
row.operator("bim.disable_group_editing_ui", text="", icon="CANCEL")
self.layout.template_list(
"BIM_UL_object_groups",
"",
self.props,
"groups",
self.props,
"active_group_index",
)
else:
row.label(text=f"{ObjectGroupsData.data['total_groups']} Groups in IFC Project", icon="OUTLINER")
row.operator("bim.load_groups", text="", icon="GREASEPENCIL")
for group in ObjectGroupsData.data["groups"]:
row = self.layout.row(align=True)
@@ -126,51 +115,4 @@ class BIM_UL_groups(UIList):
op.ifc_definition_id = item.ifc_definition_id
op.index = index
op.option = "Collapse" if item.is_expanded else "Expand"
else:
row.label(text="", icon="BLANK1")
row.label(text=item.name)
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 = 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 = group_id
op = row.operator("bim.add_group", text="", icon="ADD")
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 = group_id
op = row.operator("bim.enable_editing_group", text="", icon="GREASEPENCIL")
op.group = group_id
op = row.operator("bim.add_group", text="", icon="ADD")
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, index):
if item:
row = layout.row(align=True)
for i in range(0, item.tree_depth):
row.label(text="", icon="BLANK1")
if item.has_children:
op = row.operator(
"bim.toggle_group", icon="TRIA_DOWN" if item.is_expanded else "TRIA_RIGHT", text="", emboss=False
)
op.ifc_definition_id = item.ifc_definition_id
op.index = index
op.option = "Collapse" if item.is_expanded else "Expand"
else:
row.label(text="", icon="BLANK1")
row.label(text=item.name)
op = row.operator("bim.remove_group", text="", icon="X")
op.group = item.ifc_definition_id
op = row.operator("bim.assign_group", text="", icon="ADD")
op.group = item.ifc_definition_id