Skip to content

Microflow layout: elements overlap where the measurer and the builder disagree — nested decisions, named merges, wide CASE #1158

Description

@tgolembiewski

mxcli version: main at 643271e8 (Mendix 11.12.1, MPR v2, macOS)

Summary

Running the layout examples added in #1157 (mdl-examples/doctype-tests/02c-complex-layout-examples.mdl) through exec and reading the coordinates back with describe: 15 pairs of elements overlap, in 3 of the 6 flows. mx check reports 0 errors either way, so nothing automatic sees it.

Repro

./bin/mxcli exec mdl-examples/doctype-tests/02c-complex-layout-examples.mdl -p App.mpr
./bin/mxcli -p App.mpr -c "DESCRIBE MICROFLOW CxLayout.CX_SYNC_FactoryTelemetry"

Three shapes, each an example from that file:

Where Coordinates on 643271e8 Problem
CX_SYNC_FactoryTelemetry, after merge rejoin2 merge (850, 200), next activity (930, 200) 80 px apart: the merge's right edge and the activity's left edge are the same line
CX_ACT_HandleAuthCode, end of a case branch set $Success (2855, 200), the split's merge (2885, 200) 30 px apart — the activity covers the merge
CX_SYNC_FactoryTelemetry, nested decisions set $Outcome (2365, 300), the outer else at (2475, 350) the two lanes are 50 px apart where an activity is 60 tall

Cause

Three fixed-size disagreements between what measureStatements predicts and where the builder places things. Every merge, every following statement and every branch lane is positioned from the first and drawn by the second, so a few pixels of disagreement is an overlap, not a cosmetic difference.

  1. A split is measured to its branch, not to the merge that closes it. measureIfStatement and measureEnumSplitStatement return SplitWidth + HorizontalSpacing/2 + branchWidth + MergeSize, which is 25 px short of the distance from the split's left edge to the merge's right edge.
  2. The advance past a merge treats it as an activity's width. fb.posX = mergeX + HorizontalSpacing/2 (enum split) and fb.posX += fb.spacing/2 (addMergeStatement) move half a pitch from the merge's centre; a merge is MergeSize = 40 wide against an activity's 120, so the gap comes out 0. addIfStatement uses mergeX + MergeSize + HorizontalSpacing/2 and is right.
  3. A branch lane is placed half the branch's measured height below the line. That holds only for content centred on its line. A branch containing a nested if hangs entirely below its own: measured 160 tall, it occupies 30 above the line and 130 below, so the next lane lands 50 px inside it.

All three predate the layout work in #1155 — they were covered by slack in the spacing that #1155 removed, which is why they surface now.

Fix

I have a branch that removes all three, geometry only:

  • measure a split from its left edge to the merge's right edge;
  • clear the merge, then leave the ordinary gap, in the two places that did not;
  • place a lane below what the branch above actually occupies — it is already built by then, the same approach separateRows already uses for wrapped rows.

Result on the same file: 15 overlapping pairs → 0. The three describe reports afterwards are each one activity printed twice at the same coordinates by the shared-tail traversal (see the note at the end), not two elements on the canvas. mx check 0 errors, make test and the integration suite pass.

Two new tests hold the invariant rather than the pixel values: one asks the measurer and the builder the same question about the same run and compares, the other asserts directly that no two elements of a built flow overlap, over eight shapes. Each of the three fixes was reverted in turn to confirm the tests fail with the symptom above.

Happy to open the PR.

Separate observation, not part of this

describeexec of CX_SYNC_FactoryTelemetry does not round-trip: the shared tail after merge shared4 is printed twice, the labels are renumbered (join finish comes back as join shared3), and the re-executed model fails mx check with [error] [CE0773] "Value must be of type Boolean." at Sequence flow. Reproduced identically on the v0.23.0 release binary, so it is not from the layout work. I can file it separately if useful.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions