fix(editor): draft line reaches cursor + ports react on hover

Two operator-visible fixes from the 0.5.2 review:

(1) Draft line stopped short of the cursor. EdgePainter
shortens every segment endpoint by portRadius to dock at
port-dot perimeters — but the DRAFT segment's `to` is the
cursor itself, not a port. Result: while dragging a
connection, the live line ended 6 px short of where the
operator's mouse actually was. Felt like the cable
wouldn't reach.

EdgeSegment gains `shortenFrom` / `shortenTo` flags
(default true). The draft segment passes `shortenTo:
false`, so the line tip tracks the cursor exactly. From-
side stays shortened because the FROM is still a real
port dot.

(2) Ports had no hover affordance — mouse-over was
invisible. Operators couldn't tell ahead of time that a
port was interactive.

Adds `_hoveredPort` state on the canvas, updated via the
existing MouseRegion's onEnter / onExit. Port dot now has
three focus levels:

  resting → 12 px, 1.8 px border, no glow
  hover   → 15 px, 2.2 px border, soft accent glow
  drop-target (drag is over it) → 18 px, 2.5 px border,
            stronger glow

The hover state pre-shadows the drop-target state —
operators see "yes, this port is grabbable / droppable"
before they commit to dragging. When the drag does start,
the drop-target halo is the same family of treatment,
just stronger, so the visual progression reads as one
continuous interaction.

Signed-off-by: flemming-it <sf@flemming.it>
This commit is contained in:
flemming-it 2026-06-01 17:13:14 +02:00
parent 9afb51a4b5
commit 5c59f3a554
3 changed files with 59 additions and 19 deletions

View file

@ -22,12 +22,22 @@ class EdgeSegment {
final EdgeSide fromSide;
final EdgeSide toSide;
final EdgeAccent accent;
/// When false, the bezier endpoint is NOT shortened by
/// `portRadius` on the corresponding side. Used by the
/// draft-drag segment so the line actually reaches the
/// cursor instead of stopping a port-radius short of it
/// (the cursor is a mouse position, not a port socket).
final bool shortenFrom;
final bool shortenTo;
const EdgeSegment({
required this.from,
required this.to,
required this.fromSide,
required this.toSide,
this.accent = EdgeAccent.normal,
this.shortenFrom = true,
this.shortenTo = true,
});
}
@ -75,15 +85,14 @@ class EdgePainter extends CustomPainter {
// a left-side port has its outer perimeter to the left
// of its centre, so we move the endpoint LEFT by
// radius; right-side port goes the other way.
final shortenedFrom = Offset(
seg.from.dx +
(seg.fromSide == EdgeSide.right ? portRadius : -portRadius),
seg.from.dy,
);
final shortenedTo = Offset(
seg.to.dx + (seg.toSide == EdgeSide.right ? portRadius : -portRadius),
seg.to.dy,
);
final fromShift = seg.shortenFrom
? (seg.fromSide == EdgeSide.right ? portRadius : -portRadius)
: 0.0;
final toShift = seg.shortenTo
? (seg.toSide == EdgeSide.right ? portRadius : -portRadius)
: 0.0;
final shortenedFrom = Offset(seg.from.dx + fromShift, seg.from.dy);
final shortenedTo = Offset(seg.to.dx + toShift, seg.to.dy);
canvas.drawPath(_bezier(shortenedFrom, shortenedTo), paint);
}
}