mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-20 23:36:20 +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
|
return False
|
||||||
if not tool.Blender.are_viewport_gizmos_enabled():
|
if not tool.Blender.are_viewport_gizmos_enabled():
|
||||||
return False
|
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:
|
if cls.gizmo_pref_name:
|
||||||
prefs = tool.Blender.get_addon_preferences()
|
prefs = tool.Blender.get_addon_preferences()
|
||||||
feature_prefs = getattr(prefs.gizmos, cls.gizmo_pref_name, None)
|
feature_prefs = getattr(prefs.gizmos, cls.gizmo_pref_name, None)
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ import bonsai.core.root
|
|||||||
import bonsai.core.spatial
|
import bonsai.core.spatial
|
||||||
import bonsai.tool as tool
|
import bonsai.tool as tool
|
||||||
from bonsai.bim.ifc import IfcStore
|
from bonsai.bim.ifc import IfcStore
|
||||||
|
from bonsai.bim.module.model import preview_base
|
||||||
from bonsai.bim.module.model.decorator import ProfileDecorator
|
from bonsai.bim.module.model.decorator import ProfileDecorator
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@@ -2228,6 +2229,8 @@ class OverrideEscape(bpy.types.Operator):
|
|||||||
bpy.ops.bim.hide_all_openings()
|
bpy.ops.bim.hide_all_openings()
|
||||||
elif tool.Aggregate.get_aggregate_props().in_aggregate_mode:
|
elif tool.Aggregate.get_aggregate_props().in_aggregate_mode:
|
||||||
bpy.ops.bim.disable_aggregate_mode()
|
bpy.ops.bim.disable_aggregate_mode()
|
||||||
|
elif preview_base.try_cancel_active_preview(context):
|
||||||
|
pass
|
||||||
elif active_object := context.active_object:
|
elif active_object := context.active_object:
|
||||||
if tool.Blender.Modifier.try_canceling_editing_modifier_parameters_or_path(active_object):
|
if tool.Blender.Modifier.try_canceling_editing_modifier_parameters_or_path(active_object):
|
||||||
pass
|
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)
|
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 --------------------------------------------------
|
# --- Lazy closure factories --------------------------------------------------
|
||||||
#
|
#
|
||||||
# Used by preview gizmo groups when wiring ``BIM_GT_gizmo_dimension``'s
|
# 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.
|
_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:
|
def regenerate_wall_mesh_from_props(obj: bpy.types.Object) -> None:
|
||||||
"""Rebuild ``obj.data`` as a preview box from ``BIMWallProperties`` without touching IFC.
|
"""Rebuild ``obj.data`` as a preview box from ``BIMWallProperties`` without touching IFC.
|
||||||
|
|
||||||
@@ -3336,8 +3349,7 @@ class GizmoWallAddOpening(bpy.types.GizmoGroup, _WallGeomCachedBillboardingMixin
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context: bpy.types.Context) -> bool:
|
def poll(cls, context: bpy.types.Context) -> bool:
|
||||||
prefs = tool.Blender.get_addon_preferences()
|
if not _wall_gizmo_poll_gate(context):
|
||||||
if not prefs.gizmos.draw_gizmos_in_3d_viewport:
|
|
||||||
return False
|
return False
|
||||||
selected = tool.Blender.get_selected_objects()
|
selected = tool.Blender.get_selected_objects()
|
||||||
if len(selected) != 2:
|
if len(selected) != 2:
|
||||||
@@ -3405,8 +3417,7 @@ class GizmoWallExtendVertically(bpy.types.GizmoGroup, _WallGeomCachedBillboardin
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context: bpy.types.Context) -> bool:
|
def poll(cls, context: bpy.types.Context) -> bool:
|
||||||
prefs = tool.Blender.get_addon_preferences()
|
if not _wall_gizmo_poll_gate(context):
|
||||||
if not prefs.gizmos.draw_gizmos_in_3d_viewport:
|
|
||||||
return False
|
return False
|
||||||
selected = tool.Blender.get_selected_objects()
|
selected = tool.Blender.get_selected_objects()
|
||||||
if len(selected) != 2:
|
if len(selected) != 2:
|
||||||
@@ -3493,8 +3504,7 @@ class GizmoWallJoinIntersection(bpy.types.GizmoGroup, _WallGeomCachedBillboardin
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context: bpy.types.Context) -> bool:
|
def poll(cls, context: bpy.types.Context) -> bool:
|
||||||
prefs = tool.Blender.get_addon_preferences()
|
if not _wall_gizmo_poll_gate(context):
|
||||||
if not prefs.gizmos.draw_gizmos_in_3d_viewport:
|
|
||||||
return False
|
return False
|
||||||
selected = tool.Blender.get_selected_objects()
|
selected = tool.Blender.get_selected_objects()
|
||||||
if len(selected) != 2:
|
if len(selected) != 2:
|
||||||
@@ -3664,7 +3674,7 @@ class GizmoWallUnjoinSingle(bpy.types.GizmoGroup, _WallGeomCachedBillboardingMix
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context: bpy.types.Context) -> bool:
|
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
|
return False
|
||||||
active = tool.Blender.get_active_object(is_selected=True)
|
active = tool.Blender.get_active_object(is_selected=True)
|
||||||
if active is None:
|
if active is None:
|
||||||
@@ -4032,9 +4042,7 @@ class GizmoWallFilletReedit(bpy.types.GizmoGroup, _WallGeomCachedBillboardingMix
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context: bpy.types.Context) -> bool:
|
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
|
|
||||||
if _wall_fillet_preview_active(context):
|
|
||||||
return False
|
return False
|
||||||
active = tool.Blender.get_active_object(is_selected=True)
|
active = tool.Blender.get_active_object(is_selected=True)
|
||||||
if active is None:
|
if active is None:
|
||||||
|
|||||||
Reference in New Issue
Block a user