From 3aa5ddb07064f6a14f520476cff14c6882f1d6cc Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Tue, 7 Oct 2025 12:27:38 +1100 Subject: [PATCH] Implement auto element selection for tasks in work schedule. Also add manual selection (instead of going into ICOM panel for speed) --- .../bonsai/bim/module/sequence/__init__.py | 1 + .../bonsai/bim/module/sequence/operator.py | 11 +++++++ src/bonsai/bonsai/bim/module/sequence/prop.py | 11 +++++-- src/bonsai/bonsai/bim/module/sequence/ui.py | 32 +++++++++++-------- src/bonsai/bonsai/tool/sequence.py | 9 ++++++ src/bonsai/bonsai/tool/spatial.py | 1 - 6 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/sequence/__init__.py b/src/bonsai/bonsai/bim/module/sequence/__init__.py index 40a7e1fb3a..3262b64527 100644 --- a/src/bonsai/bonsai/bim/module/sequence/__init__.py +++ b/src/bonsai/bonsai/bim/module/sequence/__init__.py @@ -105,6 +105,7 @@ classes = ( operator.RemoveWorkTime, operator.ReorderTask, operator.SaveAnimationColorScheme, + operator.SelectTaskElements, operator.SelectTaskRelatedInputs, operator.SelectTaskRelatedProducts, operator.SelectUnassignedWorkScheduleProducts, diff --git a/src/bonsai/bonsai/bim/module/sequence/operator.py b/src/bonsai/bonsai/bim/module/sequence/operator.py index 1dacf6efb7..c07b9a0496 100644 --- a/src/bonsai/bonsai/bim/module/sequence/operator.py +++ b/src/bonsai/bonsai/bim/module/sequence/operator.py @@ -1281,6 +1281,17 @@ class DisableEditingSequence(bpy.types.Operator): return {"FINISHED"} +class SelectTaskElements(bpy.types.Operator, tool.Ifc.Operator): + bl_idname = "bim.select_task_elements" + bl_label = "Select All Task Elements" + bl_options = {"REGISTER", "UNDO"} + task: bpy.props.IntProperty() + + def _execute(self, context): + core.select_task_inputs(tool.Sequence, tool.Spatial, task=tool.Ifc.get().by_id(self.task)) + core.select_task_outputs(tool.Sequence, tool.Spatial, task=tool.Ifc.get().by_id(self.task)) + + class SelectTaskRelatedProducts(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.select_task_related_products" bl_label = "Select All Output Products" diff --git a/src/bonsai/bonsai/bim/module/sequence/prop.py b/src/bonsai/bonsai/bim/module/sequence/prop.py index 86b5a1966d..1e5671e65c 100644 --- a/src/bonsai/bonsai/bim/module/sequence/prop.py +++ b/src/bonsai/bonsai/bim/module/sequence/prop.py @@ -75,6 +75,8 @@ def update_active_task_index(self, context): bonsai.bim.module.pset.data.refresh() if self.editing_task_type == "SEQUENCE": tool.Sequence.load_task_properties() + if self.should_auto_select: + tool.Sequence.select_active_task_elements(task) def update_active_task_outputs(self, context): @@ -518,9 +520,9 @@ class BIMWorkScheduleProperties(PropertyGroup): active_task_input_index: IntProperty(name="Active Task Input Index") task_outputs: CollectionProperty(name="Task Outputs", type=TaskProduct) active_task_output_index: IntProperty(name="Active Task Output Index") - show_nested_outputs: BoolProperty(name="Show Nested Tasks", default=False, update=update_active_task_outputs) - show_nested_resources: BoolProperty(name="Show Nested Tasks", default=False, update=update_active_task_resources) - show_nested_inputs: BoolProperty(name="Show Nested Tasks", default=False, update=update_active_task_inputs) + show_nested_outputs: BoolProperty(name="Show Nested Task Elements", default=False, update=update_active_task_outputs) + show_nested_resources: BoolProperty(name="Show Nested Task Elements", default=False, update=update_active_task_resources) + show_nested_inputs: BoolProperty(name="Show Nested Task Elements", default=False, update=update_active_task_inputs) product_input_tasks: CollectionProperty(name="Product Task Inputs", type=TaskProduct) product_output_tasks: CollectionProperty(name="Product Task Outputs", type=TaskProduct) active_product_output_task_index: IntProperty(name="Active Product Output Task Index") @@ -531,6 +533,9 @@ class BIMWorkScheduleProperties(PropertyGroup): filter_by_active_schedule: BoolProperty( name="Filter By Active Schedule", default=False, update=update_filter_by_active_schedule ) + should_auto_select: BoolProperty( + name="Auto Select", description="Auto select elements when task is selected", default=False + ) if TYPE_CHECKING: work_schedule_predefined_types: str diff --git a/src/bonsai/bonsai/bim/module/sequence/ui.py b/src/bonsai/bonsai/bim/module/sequence/ui.py index dc31471af3..c16545171f 100644 --- a/src/bonsai/bonsai/bim/module/sequence/ui.py +++ b/src/bonsai/bonsai/bim/module/sequence/ui.py @@ -290,13 +290,21 @@ class BIM_PT_work_schedules(Panel): row2 = self.layout.row(align=True) row2.alignment = "RIGHT" - row2.prop(self.props, "enable_reorder", text="", icon="SORTALPHA") - row2.operator("bim.enable_editing_task_sequence", text="", icon="TRACKING") - row2.operator("bim.enable_editing_task_time", text="", icon="TIME").task = ifc_definition_id - row2.operator("bim.enable_editing_task_calendar", text="", icon="VIEW_ORTHO").task = ( + col = row2.column() + row_ = col.row(align=True) + op = row_.operator("bim.select_task_elements", icon="RESTRICT_SELECT_OFF", text="Select Elements") + op.task = task.ifc_definition_id + row_.prop(self.props, "should_auto_select", icon="OBJECT_HIDDEN", text="") + + col = row2.column() + row_ = col.row(align=True) + row_.prop(self.props, "enable_reorder", text="", icon="SORTALPHA") + row_.operator("bim.enable_editing_task_sequence", text="", icon="TRACKING") + row_.operator("bim.enable_editing_task_time", text="", icon="TIME").task = ifc_definition_id + row_.operator("bim.enable_editing_task_calendar", text="", icon="VIEW_ORTHO").task = ( ifc_definition_id ) - row2.operator("bim.enable_editing_task_attributes", text="", icon="GREASEPENCIL").task = ( + row_.operator("bim.enable_editing_task_attributes", text="", icon="GREASEPENCIL").task = ( ifc_definition_id ) row.operator("bim.add_task", text="Add", icon="ADD").task = ifc_definition_id @@ -716,11 +724,10 @@ class BIM_PT_task_icom(Panel): input_id = self.props.task_inputs[self.props.active_task_input_index].ifc_definition_id op.related_object = input_id - op = row2.operator("bim.select_task_related_inputs", icon="RESTRICT_SELECT_OFF", text="Select") + op = row2.operator("bim.select_task_related_inputs", icon="RESTRICT_SELECT_OFF", text="") op.task = task.ifc_definition_id + row2.prop(self.props, "show_nested_inputs", icon="OUTLINER", text="") - row2 = col.row() - row2.prop(self.props, "show_nested_inputs", text="Show Nested") row2 = col.row() row2.template_list("BIM_UL_task_inputs", "", self.props, "task_inputs", self.props, "active_task_input_index") @@ -744,8 +751,7 @@ class BIM_PT_task_icom(Panel): op.related_object_type = "RESOURCE" op.resource = self.props.task_resources[self.props.active_task_resource_index].ifc_definition_id - row2 = col.row() - row2.prop(self.props, "show_nested_resources", text="Show Nested") + row2.prop(self.props, "show_nested_resources", icon="OUTLINER", text="") row2 = col.row() row2.template_list( @@ -773,10 +779,10 @@ class BIM_PT_task_icom(Panel): output_id = self.props.task_outputs[self.props.active_task_output_index].ifc_definition_id op.relating_product = output_id - op = row2.operator("bim.select_task_related_products", icon="RESTRICT_SELECT_OFF", text="Select") + op = row2.operator("bim.select_task_related_products", icon="RESTRICT_SELECT_OFF", text="") op.task = task.ifc_definition_id - row2 = col.row() - row2.prop(self.props, "show_nested_outputs", text="Show Nested") + row2.prop(self.props, "show_nested_outputs", icon="OUTLINER", text="") + row2 = col.row() row2.template_list( "BIM_UL_task_outputs", "", self.props, "task_outputs", self.props, "active_task_output_index" diff --git a/src/bonsai/bonsai/tool/sequence.py b/src/bonsai/bonsai/tool/sequence.py index 96fbb487a5..815c456f27 100644 --- a/src/bonsai/bonsai/tool/sequence.py +++ b/src/bonsai/bonsai/tool/sequence.py @@ -1789,6 +1789,15 @@ class Sequence(bonsai.core.tool.Sequence): cls.load_task_outputs(outputs) cls.load_task_resources(task) + @classmethod + def select_active_task_elements(cls, task): + if not task: + return + bpy.ops.object.select_all(action="DESELECT") + for element in set(cls.get_task_inputs(task) + cls.get_task_outputs(task)): + if obj := tool.Ifc.get_object(element): + obj.select_set(True) + @classmethod def refresh_task_resources(cls): task = cls.get_highlighted_task() diff --git a/src/bonsai/bonsai/tool/spatial.py b/src/bonsai/bonsai/tool/spatial.py index a9d7c170ef..ec0835b0a9 100644 --- a/src/bonsai/bonsai/tool/spatial.py +++ b/src/bonsai/bonsai/tool/spatial.py @@ -175,7 +175,6 @@ class Spatial(bonsai.core.tool.Spatial): @classmethod def select_products(cls, products: Iterable[ifcopenshell.entity_instance], unhide: bool = False) -> None: - bpy.ops.object.select_all(action="DESELECT") for product in products: obj = tool.Ifc.get_object(product) if obj and bpy.context.view_layer.objects.get(obj.name):