Hide MEP gizmos on non-parametric elements

MEP elements imported as tessellation / brep (no IfcExtrudedAreaSolid
or IfcSweptDiskSolid in their body representation) can't be
parametrically edited — the gizmos offer affordances the geometry
kernel has no path to honour. tool.System.has_parametric_body
inspects the Model/Body/MODEL_VIEW representation and returns True
only when at least one item resolves to one of the two
profile-sweep primitives.

The gate is wired into:
- GizmoMEPActions.is_eligible_object (the action icon group)
- _active_is_flow_segment / _active_is_bend_fitting visibility
  predicates the icon row consults per-icon
- GizmoPipeSegmentEdition / GizmoDuctSegmentEdition is_element_type

tool.Parametric.is_pipe_segment / is_duct_segment stay IFC-class-only
so their truth-table contract test keeps reading a single concern.

Generated with the assistance of an AI coding tool.
This commit is contained in:
Gorgious56
2026-06-10 13:00:01 +02:00
parent 6c9cfccc43
commit 4d24cef0c9
4 changed files with 39 additions and 14 deletions
@@ -214,7 +214,9 @@ def test_active_is_flow_segment_handles_unbound_object():
def test_active_is_flow_segment_classifies_segment_vs_fitting():
"""Only IfcFlowSegment lights the lock-icon row; IfcFlowFitting (the
bend's own class) does not."""
bend's own class) does not. The parametric-body gate is mocked True
here — its dedicated truth-table is in test_mep_actions_visibility
sibling tests."""
from bonsai.bim.module.model.mep import _active_is_flow_segment
segment_elem = Mock()
@@ -223,10 +225,11 @@ def test_active_is_flow_segment_classifies_segment_vs_fitting():
fitting_elem.is_a = lambda c: c == "IfcFlowFitting"
plain = Mock()
with patch("bonsai.bim.module.model.mep.tool.Ifc.get_entity", return_value=segment_elem):
assert _active_is_flow_segment(plain) is True
with patch("bonsai.bim.module.model.mep.tool.Ifc.get_entity", return_value=fitting_elem):
assert _active_is_flow_segment(plain) is False
with patch("bonsai.bim.module.model.mep.tool.System.has_parametric_body", return_value=True):
with patch("bonsai.bim.module.model.mep.tool.Ifc.get_entity", return_value=segment_elem):
assert _active_is_flow_segment(plain) is True
with patch("bonsai.bim.module.model.mep.tool.Ifc.get_entity", return_value=fitting_elem):
assert _active_is_flow_segment(plain) is False
def test_active_mep_has_connected_neighbor_returns_false_on_no_entity():
@@ -170,11 +170,12 @@ def test_gizmo_group_class_wiring(gizmo_cls_name, bl_idname, is_element_predicat
cls = getattr(mep, gizmo_cls_name)
assert cls.bl_idname == bl_idname
# The element_type predicate must delegate to the matching tool.Parametric.is_*.
predicate = getattr(tool.Parametric, is_element_predicate)
fake_element = Mock()
fake_element.is_a.return_value = True
with patch.object(tool.Parametric, is_element_predicate, side_effect=predicate) as p:
with patch.object(tool.Parametric, is_element_predicate, side_effect=predicate) as p, patch.object(
tool.System, "has_parametric_body", return_value=True
):
cls.is_element_type(fake_element)
assert p.called, f"{gizmo_cls_name}.is_element_type did not delegate to Parametric.{is_element_predicate}"