Commit Graph
739 Commits
Author SHA1 Message Date
BFlat a1abf13a8a Merge pull request #6852 from dotCooCoo/feat/objects-on-path-select-move-detach
Objects on Path: the Select/Move widget chooses an object and drags it to another place along the path
2026-11-12 22:01:35 +07:00
dotCooCoo a1cbb852b3 Objects on Path: a Select/Move drag takes the place nearest the pointer on a path that turns back
The drag chose its place from the point of the path nearest the pointer, but counted each point as
farther by half its distance along the path from the last one. On an open path that turns back on
itself, the object then stayed at its place while the pointer was over another object's ring 10 pt
away. The drag now uses the point nearest the pointer. Where the path passes as near the pointer
more than once, as where it runs back over itself, the drag follows the part nearest along the path
to where it was.
2026-11-12 05:06:00 -08:00
dotCooCoo 67ebbf0b53 Merge main into feat/warp-images 2026-11-12 04:59:37 -08:00
dotCooCoo 2ee2ac6245 Objects on Path: the Select/Move widget chooses an object and drags it to another place along the path
With one Objects on Path group selected, the Selection and Objects on Path
tools show a ring on each object's attachment point. A click chooses that
object while the group stays selected; dragging a ring along the path moves
its object to the nearest object's place, and the objects between move one
place toward where it was, in one undo step. Hidden and locked objects have
no ring and keep their places. On a closed path the drag goes on round
across the first anchor, and Escape cancels it.

- object.objectsOnPath.selectMember {member} chooses an object.
- object.objectsOnPath.moveMember {member, target, group?} moves an object
  to another object's place; only the order along the path changes.

Docs: docs/mcp.md, docs/target-app-parity.md. Not yet: Detach.
2026-11-12 01:41:55 -08:00
BFlat 27d00baaad Merge pull request #6689 from danngreen/feat/ruler-origin-snap
Rulers: the origin dragged out of the rulers' corner snaps as a drawn point does
2026-11-12 15:12:35 +07:00
dotCooCoo 96ad9344ee Merge main into fix/warp-styles-map 2026-11-11 23:31:05 -08:00
BFlat 48e066f475 Merge pull request #6755 from dotCooCoo/fix/ui-params-wrong-type
Commands: app and control channel params of the wrong type are refused
2026-11-12 14:17:29 +07:00
Dan Green 949553b6ce Rulers: the origin dragged out of the rulers' corner snaps as a drawn point does
The zero point dragged out of the box where the rulers meet snaps as a
Pen or shape tool's point does: with Smart Guides onto the anchors,
centres, edges and paths of the art and the artboards or into line with
them, with Snap to Point onto the anchors and along the ruler guides,
else onto whole pixels or the grid. The guides showing what it snapped
to show during the drag and go when it is released or cancelled
(Escape, focus loss, another document). The origin is still set once,
on release (document.setRulerOrigin, one undo step).

The engine snaps it (Session::ruler_origin_drag, with the tools crate's
rulerguide::OriginDrag over PointSnap::drawn), as it does a guide
dragged out of a ruler.
2026-11-11 22:33:36 -08:00
BFlat 37a392f154 Merge pull request #6621 from makesomethingshit/fix/6373-live-paint-drag
Fix #6373: Live Paint Bucket fills faces crossed by a drag
2026-11-12 13:17:02 +07:00
BFlat 4eb0915795 Merge pull request #6781 from dotCooCoo/feat/diamond-gradient
Gradients: diamond gradients run the stops from the center out to a square
2026-11-12 12:40:46 +07:00
dotCooCoo e83c36785e Commands: pointer events refuse pen values and spaces of the wrong type
ui.pointer and the headless pointer call read a pointer event's pressure,
holdMs, tiltX, tiltY and rotation with a default for any value that was not a
number, and treated any space other than screen as document space. Each event
is now checked before the packet runs: those values must be numbers and space
must be doc or screen, with null keeping the default. docs/mcp.md says so.
2026-11-11 21:04:01 -08:00
makesomethingshit 88894ef27c Merge latest main and retain Live Paint and Eyedropper evidence 2026-11-12 13:48:23 +09:00
makesomethingshit dfa8403ed0 Fix #6373: Keep painting through long Live Paint drags 2026-11-12 13:46:51 +09:00
BFlat aa4657e1ce Merge pull request #6704 from dotCooCoo/fix/shape-tool-handles-scale
Shape tools: a drag on a bounding-box handle scales the selection
2026-11-12 11:43:06 +07:00
makesomethingshit 7a5486d15d Merge upstream main into Live Paint Bucket fix 2026-11-12 13:39:41 +09:00
dotCooCoo 66d21471ae Gradients: diamond gradients run the stops from the center out to a square
A new gradient kind, `diamond`, runs its stops from the center (the
start) out to a square with a corner at the end of the vector; the
aspect stretches the square across the vector into a rhombus. The
Gradient panel's Type row has a Diamond button, the Gradient tool draws
the square with the aspect handle and center ring, and a gradient
fitted to an object covers its box.

- Model and canvas: the level is |x| + |y| in the square's frame; a
  square with no area (no vector, an aspect of 0, numbers out of range)
  paints the last stop. The canvas draws it as pixels, out to a
  stroke's miters, caps and arrowheads. Transforms keep the vector and
  take the mapped size across it as the aspect.
- Commands: `paint.setFill`, `paint.editGradient` and
  `paint.setGradientGeom` take `kind: "diamond"`; a negative aspect or
  a focal point is an error. A conic or diamond gradient that a plug-in
  returns with a focal point loses the focal point.
- Gradient tool: dragging the aspect handle of a radial or diamond
  gradient whose file gave it a negative aspect now sets a positive
  aspect; only a conic's negative aspect mirrors it.
- Export: PDF, SVG, EPS and legacy .ai write four linear gradients, one
  for each quarter of the square, clipped to the shape (PDF as axial
  shadings). PDF and SVG write an image for translucent stops, a
  dithered fill or a flat square, and for the Perceptual method unless
  PDF writes the stops as spot color shadings. SVG writes a diamond on
  type characters as a radial gradient through the corners, and so
  does CSS. A swatch library saved as CSS gets four corner layers, a
  value for the `background` property (a circle when the swatch is
  turned by an angle that is not a multiple of 90 degrees). The .ai
  editing data holds a radial gradient through the corners. The
  document exports give a warning.
- SVG export: a stroke drawn as an image, as conic wedges or as diamond
  quarters now covers the miters, caps and arrowheads that reach past
  its paint box.
- PDF import reads a function-based shading whose color is the same
  along each square about the origin of its space as a diamond.
- Object > Expand gives nested squares or a mesh of rings.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-11 20:27:48 -08:00
dotCooCoo e609b26a95 Warp: bend each style as one Bézier patch, and keep saved warps' look
Each of the fifteen Warp styles now bends the bounds as one Bézier patch.
The style sets the patch's control points from the bend and the size of
the bounds, the horizontal distortion scales each column of control
points about its middle, and the vertical distortion scales each row.
The Warp effects and warp envelopes share the map (`WarpNet`). Content
with no width or no height takes the middle of the patch along that
side.

A warp carries the map it draws with as `version`. New warps, the
built-in graphic styles' Warps and warps opened from .ai files get 1.
Warps in .vectorcraft documents saved before the version existed read
as 0 and keep the earlier map, so those documents keep their look.
Edits keep a warp's version, and Warp Options editing several objects
keeps each one's own. effect.apply, effect.setParams and the warp
envelope commands take `version` 0 or 1 (`1.0` counts as 1) and refuse
any other value. An .ai file holds a warp's settings and not its
version, so a version 0 warp saved to .ai opens again with version 1.
The .ai writer compares a style's settings without the version, so
saved warps still export as editable effects.

Docs: docs/mcp.md (Envelopes), docs/effects-parity.md (Warp),
docs/target-app-parity.md.
2026-11-11 19:40:01 -08:00
BFlat e9960c71a7 Merge pull request #6703 from dotCooCoo/feat/objects-on-path-move-all
Objects on Path: the Move All widget slides every attached object along the path
2026-11-12 09:13:09 +07:00
BFlat d1a9c5a49c Merge pull request #6728 from dotCooCoo/feat/conic-gradient
Gradients: conic gradients sweep the stops once around the center
2026-11-12 09:09:08 +07:00
dotCooCoo 7c90c6e93d Shape tools: a press scales only on the drawn handle square
A shape tool now takes a press as a bounding-box handle's only on the
drawn handle square, kept square to the screen: 3 screen points from the
handle's centre along each axis at the default Anchor Size, a half point
more or less per step. A press just beside a handle draws a new shape.

drawing_gestures_snap_to_smart_guides started its second rectangle on the
first rectangle's corner handle, which stays selected; it now deselects
first.
2026-11-11 17:57:08 -08:00
dotCooCooandGert Pellin 1b744eae52 Gradients: conic gradients sweep the stops once around the center
A fourth gradient kind, conic (also accepted as `angle` or `conical`),
sweeps the stops once around the center (the gradient's start),
clockwise on the page from the vector, with a seam where the last stop
meets the first. A negative aspect mirrors the sweep, and reflecting an
object turns its sweep the other way, also for a conic without a
vector or with a flat extent.

- Gradient panel: a Conic button in the Type row; the Aspect Ratio
  field works for conic gradients and keeps a mirrored sweep mirrored.
- Gradient tool: the extent ellipse, aspect handle and center ring of a
  radial gradient, without a focal point.
- Rendering, swatch chips, transforms, warps, plug-in round trips, and
  Object > Expand into wedges or a mesh of columns around the center.
- Commands: a negative `aspect` is an error for linear and radial
  gradients, and so is a `focal` point for a conic gradient.
- PDF export writes a function-based shading whose calculator function
  turns the angle into the ramp, and PDF import reads a function-based
  shading that turns around the origin of its space back as a conic
  gradient, also when that origin lies outside the painted area. A
  PDF/A file, or a conic with more than 97 stops, gets an image
  instead.
- SVG export writes 360 solid wedges clipped to the shape for opaque
  stops and an image otherwise, and a linear gradient on characters.
- CSS export writes `conic-gradient(from ...)`, with the stops mirrored
  for a mirrored sweep.
- EPS and legacy .ai export write 360 solid wedges; the .ai editing data
  holds a linear gradient along the vector with the same stops.
- .af files: conical gradients open as conic gradients.
- An export that writes the gradient in another form gives a warning.

Supersedes #2326 and includes switch87's code from it.

Co-authored-by: Gert Pellin <gert@pellin.be>
2026-11-11 15:51:11 -08:00
dotCooCoo e6add18663 Fix #6634: Pen closing drag no longer gives the first anchor symmetric handles
Closing a path by dragging on its first anchor made that anchor smooth
with symmetric handles, so the first segment bent along with the closing
one. The drag now sets the first anchor's incoming handle to the mirror
of the pointer. Its outgoing handle stays where it is on a corner, so
the first segment keeps its shape, and on a smooth anchor it turns to
stay in line at its own length. Alt makes the anchor a corner and leaves
the outgoing handle where it was when Alt went down. A click on the
first anchor closes the path with the incoming handle retracted and the
anchor a corner, so the closing segment comes in straight.

The Smart Pen's closing drag follows the same rule.

path.close's `in` now places the handle as path.setHandle does, and a
new `out` param places the outgoing handle and makes the anchor a
corner.
2026-11-11 15:33:09 -08:00
dotCooCoo b576a4e39a Shape tools: a drag on a bounding-box handle scales the selection
Since #5839 the Rectangle, Rounded Rectangle, Ellipse, Polygon and Star
tools draw the selection's bounding box with its eight handles, but a
press on a handle drew a new shape from it. A shape just drawn could not
be resized without switching to the Selection tool.

A press on a handle now scales the selection as the Selection tool's
handles do: the same cursors, snapping, Shift and Alt, Use Preview
Bounds, area type frames and Backtick for patterns. The box stays on
show at the changing bounds during the drag. With the bounding box
hidden, a press there still draws.

Docs: docs/target-app-parity.md.
2026-11-11 15:07:21 -08:00
dotCooCoo 634b9c7ff8 Objects on Path: the Move All widget slides every attached object along the path
With one Objects on Path group selected whose objects have room to move,
the Selection and Objects on Path tools show a diamond below the first
object. Dragging it moves every object along the path together, keeping
the distances between them (object.objectsOnPath.options with start),
in one undo step; Escape cancels it, and the first object's distance
along the path shows next to the pointer.

On an open path the widget shows only when the distance from the first
object to the last is shorter than the path, and the objects stop at its
ends; on a closed path they go on round across the first anchor. Where
Auto or a Space value the open path is too short for sets the distance,
the drag also sets spacing to the distance as drawn.
2026-11-11 14:55:46 -08:00
dotCooCoo 5ac7d97d85 Guides: ruler guides are document objects on their layers
Ruler guides were a list kept beside the layers. Each guide is now an
object of its layer or sublayer, always directly in it and above the
layer's art. These behave as on main:

- Guides draw on screen only. Exports (SVG, PDF, PNG, PSD), Fit All,
  Select All, the art bounds, clicks and marquees, and a layer's
  Pathfinder and Transform effects leave them out. The Layers panel
  lists them as guide rows of their layer, the highest guide.list
  index first.
- Deleting a layer deletes its guides, and merging layers keeps their
  guides in the merged layer.
- The guide commands number guides as guide.list does, in the order
  they were made.

New: each guide takes an id from the document's object ids. An object
command given a guide's id fails with an error, and node.move cannot
put a guide into a group or out of its layers. A guide made while an
opacity mask, a symbol or a pattern is edited moves to the top
visible, unlocked layer when editing ends.

File format: native files still save the guides in the document's
guides list, in every file version, so older builds read them. Each
entry may now also carry the guide's id, name, locked and hidden
flags; older builds ignore those fields. Opening a file puts each
saved guide on its layer (on the top visible, unlocked layer when the
file names none or a layer it does not have), and each saved guide
counts against the object limit for opening a file. A ruler guide node
that a file holds below a layer's art moves up to the layer's guides,
and one anywhere else (in a group or another object, beside the
layers, or in a symbol) is removed. Ruler guides read from an .ai file
become guide objects on the layer they were on, numbered in the order
the file lists them.
2026-11-11 09:52:28 -08:00
makesomethingshit 2fd5076842 Fix #6373: Live Paint Bucket fills faces crossed by a drag 2026-11-12 01:42:41 +09:00
HassanKhan fd43a1901d Merge remote-tracking branch 'upstream/main' into fix-6437-outline-select-behind
# Conflicts:
#	docs/ui-parity.md
2026-11-11 19:01:30 +05:00
BFlat 8c05cbbe72 Merge pull request #4338 from SofiaAFigueredo/fix/4312-move-edges-snap-to-ruler-guides
Fix #4312: a Shift move lands the selection's edges and centre on ruler guides
2026-11-11 20:45:06 +07:00
HassanKhan ad75391187 Merge remote-tracking branch 'upstream/main' into fix-6437-outline-select-behind
# Conflicts:
#	docs/ui-parity.md
2026-11-11 18:08:24 +05:00
SofiaAFigueredoandClaude Sonnet 5.5 337a2e02f5 Fix #4312: a Shift move lands the selection's edges and centre on ruler guides
main lines a moved selection's edges and centre up with ruler guides
(snap_moved_to_rulers, #5746) but not when Shift keeps the move to its line. The
bounds now slide along that line onto a ruler guide the same way
(snap_moved_along_to_rulers), when nothing else lined up and the grabbed point is
not on a guide, within twice the Snap to Point distance along the line.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-11 09:51:18 -03:00
BFlat 3af2b09d9c Merge pull request #6587 from SofiaAFigueredo/fix/4343-blob-brush-round-tips-preview
Blob Brush: a round tip's preview is the outline of the area, round at both ends (#4343)
2026-11-11 19:44:14 +07:00
SofiaAFigueredoandClaude Sonnet 5.5 478bc4d408 Blob Brush: a round tip's preview is the outline of the area, round at both ends (#4343)
While painting, a round Blob Brush showed a line as wide as the brush, which ends
square, though the stroke it adds is round at both ends. Only an angled or flattened
tip showed the outline of the area. The Blob Brush now shows that outline whatever
its roundness (blob_area, which path.blob's stroke matches).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-11 08:57:09 -03:00
dotCooCoo 4cde1aaa1f Pen: Escape after the path is deselected ends something else
The Pen and the Smart Pen reported a path being drawn to Escape for as
long as they remembered the path, even after Deselect or Undo left it
unselected. That Escape then ended nothing, and isolation mode or a
rotated view needed a second press. Both tools now report the path only
while they would go on drawing it, as the Curvature tool does.

Follows #6405
2026-11-11 03:44:25 -08:00
HassanKhan a87d996e1d Outline view: a click on a path's outline selects it through an image or a gradient mesh in front (#6437)
In Outline view an image was still hit anywhere inside its box and a
gradient mesh inside its fill, though Outline draws only the image's
frame and the mesh lines. A path behind them could not be picked there.
Now an image is hit on its frame (unless Show Images in Outline Mode
draws its pixels) and a mesh on its edge and mesh lines. Preview is
unchanged.
2026-11-11 16:38:59 +05:00
BFlat df7a185cb2 Merge pull request #6534 from dotCooCoo/fix/reshape-earlier-steps
Reshape: a step recorded without focal points plays by the earlier rule
2026-11-11 14:48:26 +07:00
BFlat fe346e53be Merge pull request #6527 from dotCooCoo/fix/dimension-follow-both-ends
Dimension tool: both ends of a dimension follow the art it measures
2026-11-11 14:03:40 +07:00
dotCooCoo 4110f8c24e Reshape: a step recorded without focal points plays by the earlier rule
Before the Reshape tool had focal points it sent path.reshape without
focal or radius, and the command stretched an open path from the grabbed
point to its ends whatever the selection, and moved the anchors of a
closed path within half the diagonal of its bounding box with a
falloff. Such a step, in a saved action or a script, now moved a closed
path whole. A step without focal (or with focal null) and without
radius now plays by that earlier rule. The Reshape tool always sends
focal, an empty list included, so its drags keep the focal-point rule.
2026-11-10 22:30:19 -08:00
BFlat 0695db3ec0 Merge pull request #6519 from dotCooCoo/feat/reshape-focal-points
Reshape: a click sets a focal point and a drag moves every focal point
2026-11-11 12:53:37 +07:00
dotCooCoo ef6d14dc22 Dimension tool: both ends of a dimension follow the art it measures
A linear dimension clicked from an anchor to a point that is not an
anchor (a point on a segment, or a point a Smart Guide gave) followed
the art at the anchor end only, so scaling the art turned it into a
long slanted dimension.

- A point on a segment is stored by its curve parameter on that
  segment, and stays on it when the segment's anchors or handles are
  edited.
- Any other point is stored against anchors (and, for a path whose
  anchors lie on one line, handles) of the path under it, or of the
  path at the other end, and moves, scales, turns and reflects with
  that path. Beside a path whose anchors and handles all lie on one
  line, such as a straight line, it keeps its distance along and
  across the path: a reflection moves it as a half turn does, and a
  scale that is not uniform moves it as a uniform scale does.
- When linked art is reflected, a linear dimension's line goes to the
  reflected side, except for art whose anchors and handles lie on one
  line.
- Deleting the art, changing its anchor count or whether it is closed,
  turning an angle's arm into a curve, or making a measured circle or
  arc no longer circular leaves the dimension where it was, no longer
  linked, instead of removing it. Undo links it again.

Docs: docs/dimensions.md, docs/target-app-parity.md.
2026-11-10 21:25:59 -08:00
dotCooCoo bd39674469 Reshape: a click sets a focal point and a drag moves every focal point
A click with the Reshape tool on an anchor of a selected path makes it
the focal point, and a click on a segment adds an anchor there that
becomes the focal point. Shift-click adds an anchor or a point on a
segment to the focal points, or removes an anchor that is one already.
Each focal point shows a filled anchor square in a larger hollow one.
A drag from a focal point moves all of them; a drag from another point
moves that point alone, and Shift only keeps the drag's angle.

path.reshape takes the other focal points as focal: [[subpath,
anchor]...]. Anchors that are not direct-selected stay in place, and so
do the ends of an open path unless they are focal points. A selected
anchor between two focal points moves by the whole drag, and one
between a focal point and an anchor that stays takes u² (3 - 2u) of
the drag, as before. A closed subpath with every anchor selected moves
whole: a Reshape drag on a fully selected closed path, and path.reshape
without radius on a closed path selected whole or not selected, move
the whole path instead of a local area. With radius, only the grabbed
point's subpath changes, with the falloff as before.

- An anchor added on a segment of a partly selected path is selected,
  and the selected anchors and segments after it keep their points.
- A focal pair that names no anchor is refused ("`focal` names [0, 7],
  which is not an anchor of the path"), and so is focal with radius.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-10 20:18:23 -08:00
dotCooCoo beef32b8a3 Artboards: an artboard's guide label colors its own guides
Each artboard can carry a guide label: one of the layer colors or a
custom RGB. Guides that belong to an artboard draw in its label color,
and guides without an artboard, or on an artboard without a label, keep
the guide color from the preferences. Selected guides still draw in the
selection color.

- Artboard Options has a Guide Label row (None, the layer colors with
  swatches, or Custom with a color swatch).
- artboard.new and artboard.setProps take guideLabel: null, a layer
  color's name, or #rrggbb. Any other value is an error. The inspect
  summary lists guideLabel when one is set.
- The native format saves the label and skips it when unset; a preset
  index outside the layer colors reads as no label.
- artboard.setProps no longer adds an undo step when nothing changes.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-10 19:37:17 -08:00
BFlat af66951c41 Merge pull request #6496 from dotCooCoo/feat/ruler-artboard-guides
Guides: an option makes Cmd/Ctrl ruler drags artboard guides
2026-11-11 09:04:35 +07:00
BFlat 69d36e961d Merge pull request #6494 from dotCooCoo/feat/dimension-horizontal-vertical
Dimension tool: linear dimensions measure horizontally, vertically or aligned
2026-11-11 08:50:56 +07:00
BFlat 4302b7bde4 Merge pull request #6492 from dotCooCoo/fix/reshape-stretches-whole-path
Reshape: a drag stretches an open path from the dragged point to its two ends
2026-11-11 08:31:45 +07:00
dotCooCoo ed17e8fc17 Dimension tool: linear dimensions measure horizontally, vertically or aligned
A linear dimension between two clicked points, or dragged out from a
segment, always measured the straight distance between its points and
drew its line parallel to them, so two points at different heights gave
only a slanted dimension. The linear dimensions help describes aligned,
horizontal and vertical linear dimensions: after the second click,
clicking again gives an aligned one and moving the pointer gives a
horizontal or vertical one.
https://helpx.adobe.com/illustrator/desktop/measure-and-align/plot-and-measure/plot-linear-dimensions-of-objects.html

While a linear dimension is being placed, the pointer's position sets
whether it is aligned, horizontal or vertical. The rule is VectorCraft's
own. With the pointer beside the two points (the nearest point of the
line through them lies between them) or on that line, the dimension is
aligned. Past either point, the line through the points and the
perpendicular through that point bound a quarter on each side of the
line. The quarter that holds the direction straight up or down gives
the horizontal distance, and the quarter that holds the direction
straight left or right gives the vertical distance. A click within
reach of the second point, or of where the pointer was for the second
click, places it aligned. Points on one horizontal or vertical line
give an aligned dimension. The dimension stays linked to the anchors it
measures.

- Dimension recipes carry an orientation (aligned by default; files
  without it open as before). The line runs along the axis, and each
  extension line runs from its point to it.
- dimension.create and dimension.update take orientation: aligned,
  horizontal or vertical, for linear dimensions only. Any other value
  is an error. A new orientation keeps the line on the side of the
  points it was on, and an update that changes nothing records no
  undo step.
- A horizontal or vertical dimension keeps its orientation when it or
  the art it measures turns, and shows 0 when its points come into line
  across its axis. A line that lay outside the points stays outside
  them after a turn.
- The hint bar names the two-click placement.

Docs: docs/dimensions.md, the Evidence list in docs/target-app-parity.md.
2026-11-10 16:54:35 -08:00
dotCooCoo a2d13cd6a8 Merge main into feat/ruler-artboard-guides 2026-11-10 16:27:09 -08:00
dotCooCoo 91509f1776 Guides: an option makes Cmd/Ctrl ruler drags artboard guides
Preferences > Guides & Grid gets Artboard Guides with Cmd/Ctrl + Ruler
Drag (cmdRulerDragArtboardGuides), off by default. With it on, Cmd/Ctrl
held when a drag leaves a ruler makes a guide of the active artboard,
with any tool but the Artboard tool; with the Artboard tool it makes a
canvas guide instead. The key is read when the drag starts, so letting
it go during the drag keeps the kind of guide. Such a guide shows and is
made only where it lies within the active artboard; released elsewhere,
it makes no guide and no undo step. A ruler click still makes no guide.

This is VectorCraft's own option. The documented way to limit a guide
to one artboard, dragging it out with the Artboard tool, is unchanged.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-10 16:26:14 -08:00
dotCooCoo 1d41174876 Reshape: a drag stretches an open path from the dragged point to its two ends
A Reshape drag on an open path moved only the anchors within half the
diagonal of the path's bounding box, measured along the path. On a
zigzag, a wave or a spiral that is one or two anchors, so dragging an
end moved the end and left the rest of the path where it was (#2723).

path.reshape now stretches an open path from the grabbed point to both
ends. The end anchors stay in place. Each anchor between an end and the
grabbed point takes u² (3 - 2u) of the drag, where u is its distance
from that end along the control polygon divided by the grabbed point's
distance from that end. A handle takes the share on the tangent line of
that curve at its anchor, so the handles of a smooth anchor stay in
line with it. A handle that is long beside the span takes a share below
0 or above 1.

This changes the default for every caller that leaves radius out on an
open path. A closed path still moves the anchors within half the
diagonal of its bounding box, and a call that gives radius uses that
radius on open and closed paths.

- A negative radius is refused ("`radius` must be 0 or more"). It gave
  anchors beyond the radius a share above 1.
- A drag of no length on an anchor no longer records an undo step.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-10 16:11:52 -08:00
dotCooCoo 7eb1006abb Scissors: a cut leaves one of the two new end points selected
After a Scissors cut (`path.split`) the whole path stayed selected: both
pieces of an open path, or the opened path of a closed one. A Direct
Selection drag from the cut then moved every anchor, so an ellipse cut
at an anchor could not be pulled open by dragging its end.

- `path.split` selects the first anchor of the piece after the cut and
  nothing else, as `path.cutAtAnchors` does: anchor 0 of an opened
  closed subpath, of the new path when an open path becomes two, or of
  the subpath added to a path of several subpaths.
- A Direct Selection press on anchors of a selected path that lie on top
  of each other takes the selected one. It took the first in path order,
  which in a path of several subpaths was the unselected end.

Docs: docs/mcp.md, docs/target-app-parity.md, the `path.split` params
text.
2026-11-10 15:04:50 -08:00
ruchirguitar 74ae6fdd05 #3565: Direct Selection shows and drags type on a path's direction handles
Direct Selection showed and dragged the anchors of type on a path's path
(#3980) but not their direction handles: handle_anchors read only a
path's own data, and the canvas draws only a path's handles.

- text.setPathHandle moves a handle of type on a path's path, in
  document space, as path.setHandle moves a path's; the brackets keep
  their fractions and the text reflows. One undo step.
- Direct Selection draws the handles of selected type on a path and
  drags them with it (Alt: one side, Shift: 45 degree steps).
2026-11-10 19:35:29 +05:30