Keep a side-aware element's rule in step with a gesture that moved or resized it (TYP-731).
⚠️ An anchored element's x is the RULE's output: resolve_page_anchors() puts it back against
the edge it names on every structural change. So a drag that moves the element without moving
the rule is undone the next time a page is added, deleted or reordered — the element snapping
back, which reads as the drag having been ignored rather than as the rule doing its job.
Re-measuring the offset here is what makes a drag mean "and this is the new distance". Called
from the four gestures that change an element's own geometry — move and resize, single and
multiple — at two moments each:
on every mousemove, before update_ui(). The parameter bar is rebuilt from the STORED
offset, so without this the distance field sits frozen at its old value for the whole gesture
while the element visibly moves away from it. Cheap: a subtraction and one field write, no
undo, inside the step the gesture already opened.
on mouseup, before set_redo(), so the final offset belongs to the same undo step as the
move that caused it.
A resize counts for the same reason a move does: the gap is measured to the element's nearer
edge, and a resize can move that edge without moving the element's origin at all.
Elements with no anchor cost one field read, so there is nothing to gate on at the call sites.
Keep a side-aware element's rule in step with a gesture that moved or resized it (TYP-731).
⚠️ An anchored element's x is the RULE's output:
resolve_page_anchors()puts it back against the edge it names on every structural change. So a drag that moves the element without moving the rule is undone the next time a page is added, deleted or reordered — the element snapping back, which reads as the drag having been ignored rather than as the rule doing its job.Re-measuring the offset here is what makes a drag mean "and this is the new distance". Called from the four gestures that change an element's own geometry — move and resize, single and multiple — at two moments each:
update_ui(). The parameter bar is rebuilt from the STORED offset, so without this the distance field sits frozen at its old value for the whole gesture while the element visibly moves away from it. Cheap: a subtraction and one field write, no undo, inside the step the gesture already opened.set_redo(), so the final offset belongs to the same undo step as the move that caused it.A resize counts for the same reason a move does: the gap is measured to the element's nearer edge, and a resize can move that edge without moving the element's origin at all.
Elements with no anchor cost one field read, so there is nothing to gate on at the call sites.