M4: vector edit transform box and point snapping (#64)

- Transform box around 2+ selected points (Move tool): corners/edges scale
  them (Shift keeps proportions, Alt from the centre), just outside a corner
  rotates them (Shift: 15° steps, the box turns with them), dragging inside
  moves them; one undo step each. Corners win over points, points over edges,
  edges over segments.
- Commands: vector.edit.bounds, vector.edit.resize, vector.edit.rotate,
  vector.edit.transform; object.flipH/V and the 90°/180° rotations act on the
  selected points while editing (unless ids are given).
- Design panel in edit mode: W/H for the selected points next to X/Y (the
  layer's dimensions are hidden while points are selected).
- Point snapping for dragged points and handles and both pens: points and
  segment midpoints of this and other vectors, the usual layer targets and
  the pixel grid, with guides and a marker on the point landed on; Ctrl/Cmd
  turns object snapping off. Snap code generalised in snap.rs (Targets spans).
- Fix: handle/bend drags read positions in the gesture snapshot's coordinates,
  so handles no longer lag when the preview re-fits the vector.
- Shared resize math (tools::resized_box) and handle hit-testing for layer
  and point boxes; canvas draws both boxes through one helper.
- Tests in vectoredit/transform_tests.rs (incl. junk sweep for the
  edit-aware commands).

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
BFlat
2026-10-10 10:44:12 +07:00
committed by GitHub
co-authored by Claude Opus 5.5
parent 5f54fecca2
commit 8dff0089e5
16 changed files with 1245 additions and 238 deletions
+10
View File
@@ -146,6 +146,16 @@ from the pen's open end; clicking a point connects or branches), `vector.edit.pe
`vector.edit.cornerRadius`, `vector.edit.end`. Point indices refer to `network.vertices` in
`vector.edit.state`; local coordinates are the layer's own.
The selected points' transform box: `vector.edit.bounds` (`{x, y, width, height, corners,
points}`: the box in the vector's axes, `x`/`y` in the parent's coordinates like the Position
fields), `vector.edit.resize {width?, height?, center?}` (keeps the top-left unless `center`),
`vector.edit.rotate {angle, cx?, cy?}` (degrees counter-clockwise about the box centre or a page
pivot), `vector.edit.transform {matrix: [a, b, c, d, e, f], vertices?}` (any page-space affine).
While points are selected, `object.flipH` / `object.flipV` and the 90°/180° rotations act on them.
On the canvas (`pointer`), dragging points, handles and pen clicks snap to other points and segment
midpoints (this vector's and other vectors'), the usual layer targets and the pixel grid; `cmd`
held while dragging turns the object snapping off.
Variable width strokes: `stroke.widthProfile {ids?, preset?: uniform|wedge|taper|eye|rounded|pinch,
points?: [[t, scale], ...]}` (also `node.set {widthProfile}`; `t` runs 0–1 along each subpath by
length, `scale` multiplies the stroke weight, widths in between are interpolated smoothly; no
+1 -1
View File
@@ -1,6 +1,6 @@
# Parity report
Generated by `cargo xtask parity`: FigCraft commands registered for the incumbent's main menu and toolbar (389 commands in the engine).
Generated by `cargo xtask parity`: FigCraft commands registered for the incumbent's main menu and toolbar (393 commands in the engine).
**197 / 202 menu items (97.5%)**