From 81bacb5899c73b91e9c6d2d64a0b079e245da268 Mon Sep 17 00:00:00 2001 From: Gorgious56 Date: Wed, 3 Jun 2026 16:07:13 +0200 Subject: [PATCH] Use menu pick gizmo for door / window / stair type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The door / window / stair edit-row's type-cycle icon advanced one type per click (CycleDoorType / CycleWindowType / CycleStairType bound to cycle_type_operator). DoorType has 8 IFC variants, WindowType 9, StairType 3 — so cycling past the target was the norm. Threshold rule for cycle-vs-menu: cycle is appropriate for exactly 2 values (advance-one-per-click stays predictable). Three or more values warrants a popup menu. Door / window / stair all qualify; roof (RoofGenerationMethod has 2 values) keeps cycle. Wall has no type cycle. Array is unaffected. Swap to the popup-menu pattern (PickTypeMixin already on HEAD at bim/parametric_lifecycle.py:442): clicking the icon opens a menu listing all type_literal values; selecting one applies it in a single undo step. The hamburger icon (VIEW3D_GT_menu) is wired into BaseParametricGizmoGroup.setup_editing_gizmos whenever pick_type_operator is set (mutually exclusive with cycle_type_operator). Matches gizmos-8088's pattern exactly. Per-feature shape: * door.py: PickDoorType replaces CycleDoorType. GizmoDoorEdition.cycle_type_operator → pick_type_operator. * window.py: PickWindowType replaces CycleWindowType. Same swap. * stair.py: PickStairType replaces CycleStairType (no tool.Ifc.Operator inheritance — stair-type changes BIMStairProperties only, no IFC mutation). Same swap. * bim/module/model/__init__.py: registration entries renamed Cycle* → Pick*. * bim/module/drawing/gizmos.py: drop the CycleTypeMixin / PickTypeMixin / TypeAccessorBase shim re-export — its own docstring already noted "PR5 cleanup drops these" and the three callers (door / window / stair Cycle*Type) it served are gone. Roof's CycleTypeMixin import was already direct from bim.parametric_lifecycle. Also update GizmoMenu docstring to reflect the 2-vs-3+ threshold. Generated with the assistance of an AI coding tool. --- src/bonsai/bonsai/bim/module/drawing/gizmos.py | 13 ++----------- src/bonsai/bonsai/bim/module/model/__init__.py | 6 +++--- src/bonsai/bonsai/bim/module/model/door.py | 14 +++++++------- src/bonsai/bonsai/bim/module/model/stair.py | 14 +++++++------- src/bonsai/bonsai/bim/module/model/window.py | 14 +++++++------- 5 files changed, 26 insertions(+), 35 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/drawing/gizmos.py b/src/bonsai/bonsai/bim/module/drawing/gizmos.py index 3999edbc9f..64cde8789f 100644 --- a/src/bonsai/bonsai/bim/module/drawing/gizmos.py +++ b/src/bonsai/bonsai/bim/module/drawing/gizmos.py @@ -105,16 +105,6 @@ from mathutils.kdtree import KDTree import bonsai.tool as tool from bonsai.bim.module.drawing.shaders import ExtrusionGuidesShader -# Backward-compat re-exports — these mixins moved to bim.parametric_lifecycle -# in the gizmos.py framework refactor. PR4 callers (CycleDoorType / CycleWindowType -# / CycleStairType) still spell gizmo.CycleTypeMixin; the re-export keeps the -# old access path alive until PR4 rewrites the import. PR5 cleanup drops these. -from bonsai.bim.parametric_lifecycle import ( # noqa: F401, E402 - CycleTypeMixin, - PickTypeMixin, - TypeAccessorBase, -) - SNAP_POINT_SIZE = 10.0 SNAP_POINT_COLOR = (1.0, 0.5, 0.0, 1.0) SNAP_MAX_RADIUS = 50.0 @@ -4225,7 +4215,8 @@ def _generate_menu_tris() -> tuple[tuple[float, float, float], ...]: class GizmoMenu(StaticTrisGizmoMixin, bpy.types.Gizmo): """Hamburger-stack menu icon — 'open a picker to choose from many options'. - For enums with 5+ values; use ``GizmoCycle`` for 2-4.""" + For enums with 3+ values; use ``GizmoCycle`` for exactly 2 (where the + advance-one-per-click semantic stays predictable).""" bl_idname = "VIEW3D_GT_menu" diff --git a/src/bonsai/bonsai/bim/module/model/__init__.py b/src/bonsai/bonsai/bim/module/model/__init__.py index 549472417e..b3c24c9610 100644 --- a/src/bonsai/bonsai/bim/module/model/__init__.py +++ b/src/bonsai/bonsai/bim/module/model/__init__.py @@ -212,7 +212,7 @@ classes = ( stair.AdjustStairTreads, stair.SetStairTreads, stair.InputStairTreads, - stair.CycleStairType, + stair.PickStairType, stair.GizmoStairEdition, sverchok_modifier.CreateNewSverchokGraph, sverchok_modifier.UpdateDataFromSverchok, @@ -225,7 +225,7 @@ classes = ( window.FinishEditingWindow, window.EnableEditingWindow, window.RemoveWindow, - window.CycleWindowType, + window.PickWindowType, window.GizmoWindowEdition, door.BIM_OT_add_door, door.AddDoor, @@ -234,7 +234,7 @@ classes = ( door.EnableEditingDoor, door.RemoveDoor, door.ToggleDoorSwing, - door.CycleDoorType, + door.PickDoorType, door.GizmoDoorEdition, railing.BIM_OT_add_railing, railing.CopyRailingParameters, diff --git a/src/bonsai/bonsai/bim/module/model/door.py b/src/bonsai/bonsai/bim/module/model/door.py index cce861be5f..ba27524007 100644 --- a/src/bonsai/bonsai/bim/module/model/door.py +++ b/src/bonsai/bonsai/bim/module/model/door.py @@ -39,7 +39,7 @@ from bonsai.bim.module.drawing import gizmos as gizmo from bonsai.bim.module.drawing.gizmos import DimensionGizmoConfig from bonsai.bim.module.model.wall_offset_gizmos import WALL_OFFSET_GIZMO_CONFIGS from bonsai.bim.module.model.window import create_bm_box, create_bm_window -from bonsai.bim.parametric_lifecycle import FeatureModifierEditMixin +from bonsai.bim.parametric_lifecycle import FeatureModifierEditMixin, PickTypeMixin if TYPE_CHECKING: from bonsai.bim.module.model.prop import BIMDoorProperties @@ -706,11 +706,11 @@ class ToggleDoorSwing(bpy.types.Operator, tool.Ifc.Operator): return {"FINISHED"} -class CycleDoorType(bpy.types.Operator, tool.Ifc.Operator, gizmo.CycleTypeMixin): - """Cycle through available door types. Shift+click to cycle in reverse.""" +class PickDoorType(bpy.types.Operator, tool.Ifc.Operator, PickTypeMixin): + """Pick a door type from a popup menu.""" - bl_idname = "bim.cycle_door_type" - bl_label = "Cycle Door Type" + bl_idname = "bim.pick_door_type" + bl_label = "Pick Door Type" bl_options = {"REGISTER", "UNDO"} element_checker = tool.Parametric.is_door @@ -719,7 +719,7 @@ class CycleDoorType(bpy.types.Operator, tool.Ifc.Operator, gizmo.CycleTypeMixin) type_attr = "door_type" def _execute(self, context: bpy.types.Context) -> set[str]: - return self._cycle_type(context) + return self._pick_type(context) class GizmoDoorEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup): @@ -732,7 +732,7 @@ class GizmoDoorEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup): enable_editing_operator = "bim.enable_editing_door" finish_editing_operator = "bim.finish_editing_door" cancel_editing_operator = "bim.cancel_editing_door" - cycle_type_operator = "bim.cycle_door_type" + pick_type_operator = "bim.pick_door_type" # Declarative dimension gizmo configuration with visibility and position # matrix_position lambdas replace the get_dimension_matrix_* methods diff --git a/src/bonsai/bonsai/bim/module/model/stair.py b/src/bonsai/bonsai/bim/module/model/stair.py index a7972e9630..70295d6e72 100644 --- a/src/bonsai/bonsai/bim/module/model/stair.py +++ b/src/bonsai/bonsai/bim/module/model/stair.py @@ -37,7 +37,7 @@ from bonsai.bim.module.drawing.gizmos import ( DimensionGizmoConfig, IconSlot, ) -from bonsai.bim.parametric_lifecycle import IntegerInputDialogMixin +from bonsai.bim.parametric_lifecycle import IntegerInputDialogMixin, PickTypeMixin from bonsai.tool.numeric_input import ( IntegerInputState, run_integer_input_modal, @@ -443,11 +443,11 @@ class SetStairTreads(bpy.types.Operator): return f"Number of Treads: {input_str}_{validity} | Enter to confirm, Esc to cancel" -class CycleStairType(bpy.types.Operator, gizmo.CycleTypeMixin): - """Cycle through stair types. Shift+click to cycle in reverse.""" +class PickStairType(bpy.types.Operator, PickTypeMixin): + """Pick a stair type from a popup menu.""" - bl_idname = "bim.cycle_stair_type" - bl_label = "Cycle Stair Type" + bl_idname = "bim.pick_stair_type" + bl_label = "Pick Stair Type" bl_options = {"REGISTER", "UNDO"} props_getter = tool.Model.get_stair_props @@ -456,7 +456,7 @@ class CycleStairType(bpy.types.Operator, gizmo.CycleTypeMixin): skip_element_check = True def execute(self, context: bpy.types.Context) -> set[str]: - return self._cycle_type(context) + return self._pick_type(context) # Tread run accessors - callbacks that delegate to BIMStairProperties methods @@ -522,7 +522,7 @@ class GizmoStairEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup): enable_editing_operator = "bim.enable_editing_stair" finish_editing_operator = "bim.finish_editing_stair" cancel_editing_operator = "bim.cancel_editing_stair" - cycle_type_operator = "bim.cycle_stair_type" + pick_type_operator = "bim.pick_stair_type" def get_icon_y_extent(self, props: "BIMStairProperties") -> tuple[float, float]: """Get Y extents for stair icon positioning. diff --git a/src/bonsai/bonsai/bim/module/model/window.py b/src/bonsai/bonsai/bim/module/model/window.py index 39fbdfeda8..5b470fc8e5 100644 --- a/src/bonsai/bonsai/bim/module/model/window.py +++ b/src/bonsai/bonsai/bim/module/model/window.py @@ -40,7 +40,7 @@ import bonsai.tool as tool from bonsai.bim.module.drawing import gizmos as gizmo from bonsai.bim.module.drawing.gizmos import DimensionGizmoConfig from bonsai.bim.module.model.wall_offset_gizmos import WALL_OFFSET_GIZMO_CONFIGS -from bonsai.bim.parametric_lifecycle import FeatureModifierEditMixin +from bonsai.bim.parametric_lifecycle import FeatureModifierEditMixin, PickTypeMixin if TYPE_CHECKING: from bonsai.bim.module.model.prop import BIMWindowProperties @@ -552,11 +552,11 @@ class RemoveWindow(bpy.types.Operator, tool.Ifc.Operator): return {"FINISHED"} -class CycleWindowType(bpy.types.Operator, tool.Ifc.Operator, gizmo.CycleTypeMixin): - """Cycle through available window types. Shift+click to cycle in reverse.""" +class PickWindowType(bpy.types.Operator, tool.Ifc.Operator, PickTypeMixin): + """Pick a window type from a popup menu.""" - bl_idname = "bim.cycle_window_type" - bl_label = "Cycle Window Type" + bl_idname = "bim.pick_window_type" + bl_label = "Pick Window Type" bl_options = {"REGISTER", "UNDO"} element_checker = tool.Parametric.is_window @@ -565,7 +565,7 @@ class CycleWindowType(bpy.types.Operator, tool.Ifc.Operator, gizmo.CycleTypeMixi type_attr = "window_type" def _execute(self, context: bpy.types.Context) -> set[str]: - return self._cycle_type(context) + return self._pick_type(context) # Frame accessor factory - creates callbacks that delegate to BIMWindowProperties methods @@ -603,7 +603,7 @@ class GizmoWindowEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup): enable_editing_operator = "bim.enable_editing_window" finish_editing_operator = "bim.finish_editing_window" cancel_editing_operator = "bim.cancel_editing_window" - cycle_type_operator = "bim.cycle_window_type" + pick_type_operator = "bim.pick_window_type" # matrix_position lambdas replace the get_dimension_matrix_* methods dimension_gizmo_props = [