Promote idle-row icons into the slot system

The toggle_openings icon lived outside the IconSlot layout — each
host (wall, roof) declared an ad-hoc setup_pen_row_toggle_openings_icon
+ update_pen_row_toggle_openings_icon pair, and GizmoArrayEdition
queried a hardcoded _FEATURE_IDLE_MAX_X dict to position past it.
On an arrayed wall the dict was shadowed: find_for_element returns
"array" before "wall" in EDIT_TYPES order, the wall reservation was
never consulted, and the first per-layer ARRAY icon (local X=0.37)
landed 13cm from the wall's toggle_openings (X=0.50) — visually on
top of each other.

Promote idle-row icons into the slot system instead of patching the
dict:

* IconSlot gains an Optional visible_when predicate for state-driven
  visibility (toggle_openings only when the host carries openings).
* BaseParametricGizmoGroup gains idle_slots: ClassVar[tuple[IconSlot]]
  + _idle_slot_x_positions() + _idle_row_right_edge() helpers; the
  setup + idle-branch positioning loops mirror the existing
  feature_slots path.
* Wall and roof declare toggle_openings as an idle_slot and drop
  their ad-hoc setup/update calls.
* GizmoArrayEdition's _resolve_feature_idle_max_x walks
  BaseParametricGizmoGroup.REGISTRY and takes the max
  _idle_row_right_edge() across peers whose poll passes — no more
  hardcoded dict, no more find_for_element-order shadowing.
* setup_pen_row_toggle_openings_icon + update_pen_row_toggle_openings_icon
  helpers deleted from drawing/gizmos.py.
* 3 forward-compat AST guards pin the new contract.

Also bundles an unrelated array-test fix: TestUsingArrays in
test/tool/test_model.py was asserting against bpy.context.selected_objects
which is a fragile signal after remove_array / apply_array. A new
_array_objects() helper filters bpy.data.objects via the BIM_Array
pset's IfcActuator type instead.

Layout on an arrayed wall after the fix:
  pen        X = 0.00
  toggle     X = 0.50 (idle_slot 0)
  array[0]   X = 0.87 (one ICON_ARRAY_GAP past idle row)
  array[1]   X = 1.27
All separated by the standard inter-icon spacing.

Generated with the assistance of an AI coding tool.
This commit is contained in:
Gorgious56
2026-06-06 18:22:27 +02:00
committed by Thomas Krijnen
parent b873db11db
commit 99d758a330
6 changed files with 360 additions and 112 deletions
+7 -3
View File
@@ -588,6 +588,10 @@ class TestGenerateStair2DProfile(NewFile):
class TestUsingArrays(NewFile):
@staticmethod
def _array_objects() -> list[bpy.types.Object]:
return [o for o in bpy.data.objects if (e := tool.Ifc.get_entity(o)) and e.is_a("IfcActuator")]
def setup_array(self, add_second_layer=False, sync_children=False):
tool.Project.get_project_props().template_file = "0"
bpy.ops.bim.create_project()
@@ -619,9 +623,9 @@ class TestUsingArrays(NewFile):
def test_remove_array_last_to_first(self):
self.setup_array(add_second_layer=True)
bpy.ops.bim.remove_array(item=1)
assert len(bpy.context.selected_objects) == 4
assert len(self._array_objects()) == 4
bpy.ops.bim.remove_array(item=0)
assert len(bpy.context.selected_objects) == 1
assert len(self._array_objects()) == 1
def test_remove_array_first_to_last(self):
self.setup_array(add_second_layer=True)
@@ -647,7 +651,7 @@ class TestUsingArrays(NewFile):
bpy.ops.bim.apply_array() # apply second layer
bpy.ops.bim.apply_array() # apply first layer
objs = bpy.context.selected_objects
objs = self._array_objects()
assert len(objs) == 12
# check BBIM_Array psets are removed