From b7549f2476730af28910f2a4f1c7fe5123926d7a Mon Sep 17 00:00:00 2001 From: Gorgious56 Date: Tue, 2 Jun 2026 10:37:01 +0200 Subject: [PATCH] Wire array panel buttons to triad lifecycle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two bugs in BIM_PT_array: 1. The "is this layer in edit mode" predicate compared a BoolProperty against an int (props.is_editing == i). Python evaluates False == 0 as True, so layer 0 always rendered the per-layer edit form even when no edit was active — clicking validate/cancel then dispatched against a phantom edit state. Switched to props.editing_item_index == i, which defaults to -1 and matches exactly one layer when an edit is active. 2. The panel's CHECKMARK and CANCEL buttons called bim.edit_array / bim.disable_editing_array, a parallel lifecycle that only cleared editing_item_index. Entering edit mode via the viewport gizmo (bim.enable_editing_array, the triad enter) sets is_editing=True and hides array children; the legacy panel exit unwound neither — so committing or cancelling from the panel left is_editing=True with children hidden, and the viewport gizmo thought the edit was still in progress. Re-bound both panel buttons to the canonical triad operators (bim.finish_editing_array / bim.cancel_editing_array), which _ArrayEditMixin already owns and which the viewport gizmo group already uses. Panel and gizmo now share one exit path. The three now-unreachable operators are deleted with their registration entries: EditArray (bim.edit_array), DisableEditingArray (bim.disable_editing_array), and EnableEditingArrayItem (bim.enable_editing_array_item, never called from any UI). The two test/tool/test_model.py sites that drove bim.edit_array as a commit step are switched to bim.finish_editing_array. External scripts or user keymaps bound to bim.edit_array / bim.disable_editing_array will need to update — the replacements are bim.finish_editing_array and bim.cancel_editing_array, both taking no parameters (the layer is read from props.editing_item_index). Partly generated with the assistance of an AI coding tool. --- .../bonsai/bim/module/model/__init__.py | 3 - src/bonsai/bonsai/bim/module/model/array.py | 102 ------------------ src/bonsai/bonsai/bim/module/model/ui.py | 6 +- src/bonsai/test/tool/test_model.py | 4 +- 4 files changed, 5 insertions(+), 110 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/model/__init__.py b/src/bonsai/bonsai/bim/module/model/__init__.py index ecaa4c9d5f..7ec2346bea 100644 --- a/src/bonsai/bonsai/bim/module/model/__init__.py +++ b/src/bonsai/bonsai/bim/module/model/__init__.py @@ -51,10 +51,7 @@ from . import ( classes = ( array.AddArray, array.CancelEditingArray, - array.DisableEditingArray, - array.EditArray, array.EnableEditingArray, - array.EnableEditingArrayItem, array.FinishEditingArray, array.ApplyArray, array.RegenerateArray, diff --git a/src/bonsai/bonsai/bim/module/model/array.py b/src/bonsai/bonsai/bim/module/model/array.py index 85cc765ea2..c3c53cafbd 100644 --- a/src/bonsai/bonsai/bim/module/model/array.py +++ b/src/bonsai/bonsai/bim/module/model/array.py @@ -157,108 +157,6 @@ class AddArray(bpy.types.Operator, tool.Ifc.Operator): tool.Array.constrain_children_to_parent(element) -class DisableEditingArray(bpy.types.Operator): - bl_idname = "bim.disable_editing_array" - bl_label = "Disable Editing Array" - bl_description = "Cancel editing this array without saving changes" - bl_options = {"REGISTER", "UNDO"} - - def execute(self, context): - obj = context.active_object - assert obj - tool.Model.get_array_props(obj).editing_item_index = -1 - return {"FINISHED"} - - -class EnableEditingArrayItem(bpy.types.Operator): - """Per-item array layer editing: hydrates props from one BBIM_Array layer. - - The element-wide ``bim.enable_editing_array`` (parametric edit lifecycle) coexists with - this operator. They target different state: ``is_editing`` for the edit lifecycle, - ``editing_item_index`` for the per-item panel UI.""" - - bl_idname = "bim.enable_editing_array_item" - bl_label = "Enable Editing Array Item" - bl_description = "Edit this array layer" - bl_options = {"REGISTER", "UNDO"} - item: bpy.props.IntProperty() - - def execute(self, context): - obj = context.active_object - assert obj - element = tool.Ifc.get_entity(obj) - props = tool.Model.get_array_props(obj) - - relating_obj = props.relating_array_object - - if relating_obj: - element = tool.Ifc.get_entity(relating_obj) - parent_globalid = ifcopenshell.util.element.get_pset(element, "BBIM_Array", "Parent") - parent_element = tool.Ifc.get().by_guid(parent_globalid) - data = json.loads(ifcopenshell.util.element.get_pset(parent_element, "BBIM_Array", "Data"))[self.item] - else: - data = json.loads(ifcopenshell.util.element.get_pset(element, "BBIM_Array", "Data"))[self.item] - props.count = data["count"] - si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) - props.x = data["x"] * si_conversion - props.y = data["y"] * si_conversion - props.z = data["z"] * si_conversion - props.use_local_space = data.get("use_local_space", False) - props.method = data.get("method", "OFFSET") - props.per_child_opening = data.get("per_child_opening", data.get("mirror_to_host", True)) - - props.editing_item_index = self.item - return {"FINISHED"} - - -class EditArray(bpy.types.Operator, tool.Ifc.Operator): - bl_idname = "bim.edit_array" - bl_label = "Edit Array" - bl_description = "Save changes to this array layer" - bl_options = {"REGISTER", "UNDO"} - item: bpy.props.IntProperty() - - def _execute(self, context): - obj = context.active_object - element = tool.Ifc.get_entity(obj) - props = tool.Model.get_array_props(obj) - si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) - - pset = ifcopenshell.util.element.get_pset(element, "BBIM_Array") - data = json.loads(pset["Data"]) - data[self.item] = { - "children": data[self.item]["children"], - "count": props.count, - "x": props.x / si_conversion, - "y": props.y / si_conversion, - "z": props.z / si_conversion, - "use_local_space": props.use_local_space, - "method": props.method, - "per_child_opening": props.per_child_opening, - } - - props.editing_item_index = -1 - - try: - parent_element = tool.Ifc.get().by_guid(pset["Parent"]) - parent = tool.Ifc.get_object(parent_element) - except: - return {"FINISHED"} - - tool.Array.remove_constraints(parent_element) - # Conditional wipe-and-rebuild — only when the parent's geometry - # differs from the children's. See ``_parent_geometry_changed`` for - # the bbox-dim heuristic and its known false-negative case. - if _parent_geometry_changed(parent, data): - _wipe_array_children(data) - tool.Model.regenerate_array(parent, data) - tool.Array.set_children_lock_state(element, self.item, True) - tool.Array.constrain_children_to_parent(element) - - # clears the relating_array_object so it doesn't show again next time - props.relating_array_object = None - - class _ArrayEditMixin(ParametricEditMixinBase): """Array edit lifecycle scoped to one layer at a time. diff --git a/src/bonsai/bonsai/bim/module/model/ui.py b/src/bonsai/bonsai/bim/module/model/ui.py index ee76188715..dafee6fa1e 100644 --- a/src/bonsai/bonsai/bim/module/model/ui.py +++ b/src/bonsai/bonsai/bim/module/model/ui.py @@ -238,11 +238,11 @@ class BIM_PT_array(bpy.types.Panel): for i, array in enumerate(ArrayData.data["parameters"]["data_dict"]): box = self.layout.box() - if props.is_editing == i: + if props.editing_item_index == i: row = box.row(align=True) row.prop(props, "count", icon="MOD_ARRAY") - row.operator("bim.edit_array", icon="CHECKMARK", text="").item = i - row.operator("bim.disable_editing_array", icon="CANCEL", text="") + row.operator("bim.finish_editing_array", icon="CHECKMARK", text="") + row.operator("bim.cancel_editing_array", icon="CANCEL", text="") row = box.row(align=True) row.prop(props, "method") row = box.row(align=True) diff --git a/src/bonsai/test/tool/test_model.py b/src/bonsai/test/tool/test_model.py index 30782b8a15..c778b1f59f 100644 --- a/src/bonsai/test/tool/test_model.py +++ b/src/bonsai/test/tool/test_model.py @@ -605,7 +605,7 @@ class TestUsingArrays(NewFile): props.count = 4 props.x = 4 props.sync_children = sync_children - bpy.ops.bim.edit_array(item=0) + bpy.ops.bim.finish_editing_array() if add_second_layer: bpy.ops.bim.add_array() @@ -614,7 +614,7 @@ class TestUsingArrays(NewFile): props.count = 3 props.y = 4 props.sync_children = sync_children - bpy.ops.bim.edit_array(item=1) + bpy.ops.bim.finish_editing_array() def test_remove_array_last_to_first(self): self.setup_array(add_second_layer=True)