Several transitions between the same pair of states: make transition onto a state that is already connected in that direction adds another transition, which gets its own name right away (Transition 2, Transition 3, skipping names that already leave the state), so two unnamed transitions between one pair never exist; renaming is refused when another transition between the same pair in the same direction already carries the name, the empty name included, while equal names to other targets are only warned about as before; the behavior graph keeps Already connected; self transitions may repeat too, each further loop drawn as a ring around the previous one with the preview showing the next ring, and transition labels that would cover another one slide along their own edge until they are free (pure function freeLabelSpot); test hook transitionLabelAt also returns width and height, e2e 26e6 (#162)
game-maker / gate (push) Successful in 1m58s
game-maker / suite (push) Successful in 6m50s

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5 committed 2026-09-19 16:30:52 +02:00
1 parent 010b6a7f6c
commit 25ec7879a0
9 files changed
+402 -34

No files matched your search

+10 -4
View File
@@ -1105,7 +1105,10 @@ export class GraphCanvas extends Widget {
const a = drag && this.anchorPoint(drag.from);
const home = drag && target?.nodeId === drag.from.nodeId ? this.views.get(target.nodeId) : undefined;
if (home?.def.transitionEdges === true) {
const loop = selfLoop(home);
const ring = asset.graph.edges.filter(
(e) => e.from.node === home.node.id && e.to.node === home.node.id,
).length;
const loop = selfLoop(home, ring);
loopPath(this.tempEdge, loop);
this.tempEdge.stroke({ width: 2, color: c.textMuted, alpha: 0.9 });
arrowHead(this.tempEdge, loop.c2, loop.end, c.textMuted);
@@ -1200,10 +1203,13 @@ export class GraphCanvas extends Widget {
return this.edgeLayer.drawnTransitionLabels().find((l) => l.edgeId === edgeId)?.text ?? null;
}
/** Where that name is drawn, its top-left corner on screen – null when nothing is drawn. */
transitionLabelAt(edgeId: string): { x: number; y: number } | null {
/** Where that name's plate is drawn on screen, top-left corner and size – null when nothing is drawn. */
transitionLabelAt(edgeId: string): { x: number; y: number; w: number; h: number } | null {
const label = this.edgeLayer.drawnTransitionLabels().find((l) => l.edgeId === edgeId);
return label ? globalPoint(this.edgeLayer, label) : null;
if (!label) return null;
const corner = globalPoint(this.edgeLayer, label);
const far = globalPoint(this.edgeLayer, { x: label.x + label.w, y: label.y + label.h });
return { ...corner, w: far.x - corner.x, h: far.y - corner.y };
}
/** Whether a pin can be grabbed on this node at all – false for a state, whose ports are hidden. */