mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 02:02:22 +00:00
Hide sister gizmos during preview + ESC cancels + DRY wall polls
Three live-session regressions surfaced after the fillet feature landed. Sister gizmos competed with the active preview: * preview_base.any_preview_active(context): new helper iterates the PREVIEW_CANCEL_OPS registry and returns True if any preview is open. Future previews registered there automatically gate sister gizmos. * BaseParametricGizmoGroup.poll (gizmos.py): short-circuits on any_preview_active so every parametric gizmo (door/window/stair/ roof/railing/wall edition) hides during ANY preview. * The 4 wall gizmo groups with explicit polls (GizmoWallAddOpening, GizmoWallExtendVertically, GizmoWallJoinIntersection, GizmoWallUnjoinSingle) + GizmoWallFilletReedit gain the same gate. DRY: extract _wall_gizmo_poll_gate(context): * 5 wall gizmo polls each duplicated the 2 pre-flight checks (viewport-gizmos enabled + no preview active). The helper centralises them — each poll becomes a single short-circuit line followed by its per-feature selection inspection. ESC cancels the active preview: * try_cancel_active_preview already existed in preview_base since PR3 but had no caller. Hooked into OverrideEscape.execute (geometry/ operator.py) as a new elif branch — same keymap that already cancels pen gizmo edit mode + item mode + edit mode + aggregate mode. Order in the branch chain matters: try preview cancel before falling back to try_canceling_editing_modifier_parameters_or_path so the in- flight preview wins over a stale modifier-edit cancel attempt. Generated with the assistance of an AI coding tool.
This commit is contained in:
@@ -5283,6 +5283,14 @@ class BaseParametricGizmoGroup:
|
||||
return False
|
||||
if not tool.Blender.are_viewport_gizmos_enabled():
|
||||
return False
|
||||
# Hide every parametric gizmo while any preview is open — the preview
|
||||
# is the only interactive surface in that mode, sister gizmos would
|
||||
# compete for screen space and let the user trigger mutations that
|
||||
# would race the preview's in-progress draft.
|
||||
from bonsai.bim.module.model import preview_base
|
||||
|
||||
if preview_base.any_preview_active(context):
|
||||
return False
|
||||
if cls.gizmo_pref_name:
|
||||
prefs = tool.Blender.get_addon_preferences()
|
||||
feature_prefs = getattr(prefs.gizmos, cls.gizmo_pref_name, None)
|
||||
|
||||
@@ -60,6 +60,7 @@ import bonsai.core.root
|
||||
import bonsai.core.spatial
|
||||
import bonsai.tool as tool
|
||||
from bonsai.bim.ifc import IfcStore
|
||||
from bonsai.bim.module.model import preview_base
|
||||
from bonsai.bim.module.model.decorator import ProfileDecorator
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -2228,6 +2229,8 @@ class OverrideEscape(bpy.types.Operator):
|
||||
bpy.ops.bim.hide_all_openings()
|
||||
elif tool.Aggregate.get_aggregate_props().in_aggregate_mode:
|
||||
bpy.ops.bim.disable_aggregate_mode()
|
||||
elif preview_base.try_cancel_active_preview(context):
|
||||
pass
|
||||
elif active_object := context.active_object:
|
||||
if tool.Blender.Modifier.try_canceling_editing_modifier_parameters_or_path(active_object):
|
||||
pass
|
||||
|
||||
@@ -74,6 +74,17 @@ def is_preview_active(context: bpy.types.Context, attr: str) -> bool:
|
||||
return bool(props is not None and props.is_active)
|
||||
|
||||
|
||||
def any_preview_active(context: bpy.types.Context) -> bool:
|
||||
"""``True`` if any registered preview is currently open. Sister gizmo
|
||||
polls call this to hide themselves uniformly during ANY preview, so a
|
||||
new preview registered in ``PREVIEW_CANCEL_OPS`` automatically gates
|
||||
every parametric gizmo without each one growing a specific check."""
|
||||
for attr, _op_name in PREVIEW_CANCEL_OPS:
|
||||
if is_preview_active(context, attr):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
# --- Lazy closure factories --------------------------------------------------
|
||||
#
|
||||
# Used by preview gizmo groups when wiring ``BIM_GT_gizmo_dimension``'s
|
||||
|
||||
@@ -67,6 +67,19 @@ _FILLET_DEFAULT_LEG_FRACTION = 0.25 # Quarter of the shorter available leg —
|
||||
_FILLET_MIN_RADIUS_M = 0.001 # Lower bound — anything smaller renders as a single pixel at common viewport scales.
|
||||
|
||||
|
||||
def _wall_gizmo_poll_gate(context: bpy.types.Context) -> bool:
|
||||
"""Common pre-flight gate every wall gizmo group's ``poll`` runs first:
|
||||
viewport gizmos are enabled AND no preview is active. Centralises the
|
||||
two checks every wall gizmo group otherwise duplicates inline; returning
|
||||
``False`` here short-circuits the caller's poll before any per-feature
|
||||
selection inspection runs."""
|
||||
if not tool.Blender.are_viewport_gizmos_enabled():
|
||||
return False
|
||||
if preview_base.any_preview_active(context):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def regenerate_wall_mesh_from_props(obj: bpy.types.Object) -> None:
|
||||
"""Rebuild ``obj.data`` as a preview box from ``BIMWallProperties`` without touching IFC.
|
||||
|
||||
@@ -3336,8 +3349,7 @@ class GizmoWallAddOpening(bpy.types.GizmoGroup, _WallGeomCachedBillboardingMixin
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context: bpy.types.Context) -> bool:
|
||||
prefs = tool.Blender.get_addon_preferences()
|
||||
if not prefs.gizmos.draw_gizmos_in_3d_viewport:
|
||||
if not _wall_gizmo_poll_gate(context):
|
||||
return False
|
||||
selected = tool.Blender.get_selected_objects()
|
||||
if len(selected) != 2:
|
||||
@@ -3405,8 +3417,7 @@ class GizmoWallExtendVertically(bpy.types.GizmoGroup, _WallGeomCachedBillboardin
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context: bpy.types.Context) -> bool:
|
||||
prefs = tool.Blender.get_addon_preferences()
|
||||
if not prefs.gizmos.draw_gizmos_in_3d_viewport:
|
||||
if not _wall_gizmo_poll_gate(context):
|
||||
return False
|
||||
selected = tool.Blender.get_selected_objects()
|
||||
if len(selected) != 2:
|
||||
@@ -3493,8 +3504,7 @@ class GizmoWallJoinIntersection(bpy.types.GizmoGroup, _WallGeomCachedBillboardin
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context: bpy.types.Context) -> bool:
|
||||
prefs = tool.Blender.get_addon_preferences()
|
||||
if not prefs.gizmos.draw_gizmos_in_3d_viewport:
|
||||
if not _wall_gizmo_poll_gate(context):
|
||||
return False
|
||||
selected = tool.Blender.get_selected_objects()
|
||||
if len(selected) != 2:
|
||||
@@ -3664,7 +3674,7 @@ class GizmoWallUnjoinSingle(bpy.types.GizmoGroup, _WallGeomCachedBillboardingMix
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context: bpy.types.Context) -> bool:
|
||||
if not tool.Blender.are_viewport_gizmos_enabled():
|
||||
if not _wall_gizmo_poll_gate(context):
|
||||
return False
|
||||
active = tool.Blender.get_active_object(is_selected=True)
|
||||
if active is None:
|
||||
@@ -4032,9 +4042,7 @@ class GizmoWallFilletReedit(bpy.types.GizmoGroup, _WallGeomCachedBillboardingMix
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context: bpy.types.Context) -> bool:
|
||||
if not tool.Blender.are_viewport_gizmos_enabled():
|
||||
return False
|
||||
if _wall_fillet_preview_active(context):
|
||||
if not _wall_gizmo_poll_gate(context):
|
||||
return False
|
||||
active = tool.Blender.get_active_object(is_selected=True)
|
||||
if active is None:
|
||||
|
||||
Reference in New Issue
Block a user