Commit Graph
4562 Commits
Author SHA1 Message Date
dotCooCoo f643cddec4 Dimension tool: a reflected aligned dimension has its line on the reflected side
An unlinked aligned dimension that was reflected on its own kept its
offset, which is measured along the left normal of a to b. A reflection
turns that normal to the other side, so a line 30 pt above two level
points stayed 30 pt above them after a flip top to bottom instead of
going below them. The offset now changes sign when the transform
reverses orientation, as a reflection or a scale by a negative factor
does. Other transforms leave it as before, and linked, horizontal and
vertical dimensions keep their own rules.

Docs: docs/dimensions.md.
2026-11-13 19:48:30 -08:00
dotCooCoo ce3445d106 Live Paint: a Cmd double-click or triple-click with the Bucket paints nothing
With Cmd (Ctrl) held, the Bucket's presses go to the selection tool Cmd
lends, but the double-click and triple-click that follow reached the
Bucket and painted. They now paint nothing, as with Alt.
2026-11-13 19:38:18 -08:00
dotCooCoo 497796decc Merge main into fix/more-int-param-wrong-type 2026-11-13 19:24:36 -08:00
dotCooCoo eb9976a825 Merge main into fix/graph-label-paint-recolor 2026-11-13 19:22:11 -08:00
dotCooCoo 9644811965 Merge main into feat/live-paint-bucket-multi-click 2026-11-13 19:18:43 -08:00
dotCooCoo 76c1cd8a96 Merge main into fix/live-paint-expand-drawn-stroke 2026-11-13 19:18:14 -08:00
dotCooCoo 1f6332c0a4 Live Paint: Expand keeps the faces and edges that draw
Expand kept a face only when its topmost fill had paint, and an edge only
when its topmost stroke had paint and a weight. A face or edge drawn by a
lower row under an unpainted top row was removed, and one whose only
painted row was hidden was kept as a visible path.

Expand now keeps a face or edge when it is shown, its opacity is above 0,
and any fill or stroke row is shown, has paint and an opacity above 0 (a
stroke also a weight above 0), with all of its rows. The rows are checked
with the new Appearance::has_drawn_fill and has_drawn_stroke.

Merge carried a face's topmost fill paint by the same topmost-row test.
It now carries every row of each face that draws by this rule, and of
each edge, pins their unplaced gradients to the old outline as
repaint_from does, and leaves the strokes' pen pressure, tilt, bearing
and rotation behind, since the rebuilt parts are other paths.

Docs: livePaint.expand params text, docs/mcp.md, and a line in
docs/target-app-parity.md, which also drops a repeated Live Paint
Selection marquee line.
2026-11-13 19:17:21 -08:00
Dylan M. Taylor 1e4e3534f5 Merge pull request #7398 from storytold/feat/craft-libs-migration
Migrate CAD (DXF), EPS/PostScript, and SVG to craft-libs (#778)
2026-11-13 22:14:10 -05:00
dotCooCoo bc2caaaa37 Live Paint: a triple-click matches the first fill of a face clicked again
A triple-click whose clicks land on a face, another face, then the first
face again matched the fill the first click gave that face. It now
matches the fill the face had before the first click that painted it, as
the tool's doc comment and docs/mcp.md say.

- With Space held for the view tools, the Live Paint Bucket outlines no
  face or edge, as a press there paints nothing.
- A scoped livePaint.fill or livePaint.strokeEdge where every face or
  edge reached already has the paint records no undo step; a test covers
  it, and one where only some faces need the paint.
- An MCP test drives the bucket through ui.pointer with mods.space.
- The tool's doc comment and the progress line state the rule.
2026-11-13 19:10:40 -08:00
dotCooCoo f383ce1475 Merge main into fix/knockout-groups-flat-masks 2026-11-13 19:09:32 -08:00
dotCooCoo b992531dcf Merge main into fix/more-int-param-wrong-type 2026-11-13 19:09:14 -08:00
dotCooCoo 941b5fcb14 Merge main into fix/colored-light-seams 2026-11-13 19:08:25 -08:00
dotCooCoo 531fad0532 MCP: path, type, panel, library, style and ruler indices refuse a wrong-type value
A required index given as something other than a whole number of 0 or
more, such as "3", 2.5, -1 or true, was reported as missing: `anchor` of
path.setHandle, path.moveAnchor and text.setPathHandle, `segment` of
path.insertAnchor, and `to` of artboard.reorder, library.moveGroup and
graphicStyle.move. Each now refuses it with "`anchor` must be a whole
number", naming the key; left out or null, it is still missing.

An optional `subpath` of path.appendAnchor, path.close and path.reverse
given that way was read as left out, so the command extended, closed or
reversed the default subpath (path.reverse reversed every subpath). The
`artboard` of the ruler origin commands answered "index out of range"
for such a value and for null. Both now refuse such a value with the
same message and change nothing. A null `artboard` is artboard 0, as one
left out is; a whole number past the artboards is still out of range.
2026-11-13 19:08:16 -08:00
bflatastic 3da4c4ba13 Tests: warichu PDF check reads only text objects
warichu_is_a_character_attribute_set_saved_and_exported looked for Tj or
TJ anywhere in the exported PDF. The file ID in the trailer and the XMP is
a base64 hash that changes each second and now and then spells one of
them, so the test failed on main twice (bf3cf422e, 446bf59bc) while
export outlines warichu type every time. It now counts text-object lines
only, as the colour font PDF test already does.
2026-11-14 10:06:23 +07:00
dotCooCoo 2b64456e5c Smooth tool: keep corners where the path turns by more than 57.5°
The Smooth tool refit every anchor in the smoothed stretch with a corner
angle of 179°, so a drag across a corner rounded it off. An anchor is now
kept as a corner when the path turns there by more than 57.5° (an
interior angle under 122.5°) at the anchor itself, over the Smooth
radius and over twice the radius on either side. On a closed path the
distances are no more than an eighth of its length. The stretch is cut
at each corner, each part is refit on its own, and the corner keeps its
position. The threshold is the same on every pass and has no setting.

A jag or bump smaller than the radius is not kept: the path does not
turn by that much over twice the radius. A whole closed path with
corners keeps its start anchor when the refit keeps an anchor there. A
drag that changes nothing adds no anchors and no undo step.

Docs: params text for path.smoothRegion, docs/mcp.md,
docs/target-app-parity.md.
2026-11-13 19:01:56 -08:00
dotCooCoo 1dc8b72bbf Type: hyphenated type lays out again when the hyphenation exceptions change
Changing Preferences › Hyphenation › Exceptions bumped each open
document's revision, but the caches of laid-out type outside the text
crate were keyed on the font generation alone. The renderer kept the
glyph geometry, raster-effect pixels, live-effect and envelope art,
pattern tiles and placed symbol art of unchanged type objects, so
hyphenated area type kept its old line breaks on the canvas. The
hit-test art of blends and envelopes, the Fit to Artwork Bounds answer,
the layout caches of the Type and Touch Type tools and the out port's
overflow mark were keyed the same way.

vectorcraft_text::layout_inputs() returns a number that changes with
the fonts and with the hyphenation exceptions. Every one of those
caches now keys on it instead of FontDb::generation(), and envelope ink
uses it in place of the private envelope_ink_inputs(). The hit-test key
hashes it together with the plug-in revision.

Tests: a renderer that drew hyphenated area type, alone, with a drop
shadow, in a group with a Transform effect, in a symbol instance and in
an envelope, draws it as a new renderer does after the exceptions
change; the out port of selected area type shows the overflow that the
new exceptions cause. The render test helpers that run a step again
when the fonts change during it now also run it again when the
exceptions change.
2026-11-13 18:56:48 -08:00
dotCooCoo a234216ea3 Cutting Tools: Nest Shapes packs the selected objects onto a sheet or roll
Object › Plug-ins › Cutting Tools › Nest Shapes… (`addon.cutting.nest`)
moves the selected objects close together onto a sheet or a roll of
material. The sheet starts at an artboard's top-left corner and is the
artboard's size or a set width and height; a roll is a set width with
no end. A margin (18 pt by default) is kept inside the sheet's edges and
a spacing (9 pt) between objects.

Objects are packed by their bounding boxes, with their strokes and
effects (the reach of shadows, glows and blurs included) or by their
geometry: the tallest first, each where its bottom edge is highest and
then furthest left. With Rotate, an object may turn 90° clockwise where
that puts its bottom edge higher or where only the turned object fits;
a turned object is measured after the turn. A path of a pixel-aligned
compound path is not turned. Objects that do not fit go in a column to
the right of the sheet, in stacking order. Objects on the pixel grid
move by whole points and take 1 pt more room, so they stay on the grid
and keep the margin and spacing. A path of a compound path selected on
its own moves alone. Objects without bounds, such as an empty group,
are not moved and are listed in the result.

The command is one undo step, and its result gives the objects placed,
put aside, turned and skipped and the length of material used. The
dialog has Preview.

The new Nest Shapes and Roll catalog rows are in every catalog.

Docs: docs/mcp.md (Cutting Tools add-on), docs/target-app-parity.md and
ROADMAP.
2026-11-13 18:40:14 -08:00
dotCooCoo ffd9579ccb Merge main into fix/mcp-docs-stack-file 2026-11-13 18:37:26 -08:00
dotCooCoo 0104aaeb9d Docs: script stack frames and $.fileName name the file of the code
docs/mcp.md's line and stack row said $.stack shows at most 64 lines
and uses [global] only for the script's own code. It keeps the
innermost 64 frames after a leading line "…" when some are left out,
and [global] names any code outside a function, including code that
an included file, $.evalFile or eval runs. The row now also says how
a frame's file compares with $.fileName in each case: the same file
for code from a file, the run's name where $.fileName is empty for a
script given as source, [eval] where $.fileName is the file being run,
and [unknown] at line 0 where $.fileName is empty.

The engineName row now gives the #targetengine name, and the
script.run params text, the script module doc and the Scripts evidence
line say $.fileName is the file of the code that reads it rather than
the file being run.
2026-11-13 18:36:47 -08:00
BFlat 446bf59bc2 Merge pull request #7265 from dotCooCoo/feat/live-paint-cursor-swatch-preview
Live Paint Bucket: Cursor Swatch Preview and arrow keys pick swatches
2026-11-14 09:33:39 +07:00
BFlat 02dd94e9b8 Merge pull request #7347 from dotCooCoo/fix/corner-set-member-keys
Path Precision Tools: Corner commands refuse unknown item keys
2026-11-14 09:33:31 +07:00
BFlat e026414c70 Merge pull request #7348 from dotCooCoo/fix/csv-utf16-no-bom
Variables: Import Data Sets reads UTF-16 CSV files without a byte-order mark
2026-11-14 09:33:23 +07:00
BFlat caa56c2739 Merge pull request #7334 from dotCooCoo/fix/wrap-offset-length-field
Text Wrap: Offset is a distance in the document's units
2026-11-14 09:33:15 +07:00
dotCooCoo 20fc6a0225 Symbols: Break Link and Expand keep an instance's bounding box
After Reset Bounding Box on a turned symbol instance, Break Link to
Symbol and Object > Expand gave the art a box turned with the instance's
transform again. The art's boxes now turn with the instance's own box,
so they stand square when the instance's box did, and the angles the
art has inside the symbol are kept relative to it. The group that an
instance's opacity, blending mode or opacity mask adds around the art
takes the instance's box angle instead of standing square to the page.

A reflected instance can hold a box 180 degrees from the box its
transform gives in one step; the art now takes the instance's box
there too, the same rectangle with its handles where the instance had
them.

Compound shapes and Pathfinder receive an instance's art through the
same rule.

The clip groups and clip paths that 9-slice guides make for gradient
and pattern art take the angle of the cell that places them, and the
outer group keeps the object's angle turned by the instance, instead
of standing square to the page. This also changes the result for an
instance that was never reset: a 20 degree sliced instance gave clip
groups at 0 degrees and now gives them at 20.

Docs: params text, docs/mcp.md, docs/target-app-parity.md.
2026-11-13 18:26:00 -08:00
ncic 5a55fdce0e Merge upstream main into pencil-cursors
# Conflicts:
#	docs/mcp.md
#	docs/target-app-parity.md
2026-11-14 03:17:11 +01:00
ncic b0772bc2d6 Merge upstream main into pencil-alt-close-straight 2026-11-14 03:16:34 +01:00
dotCooCoo 33319b2c4d Merge main into feat/live-paint-bucket-multi-click 2026-11-13 18:04:02 -08:00
dotCooCoo c8bdb6ee06 Merge main into fix/int-param-wrong-type 2026-11-13 18:03:25 -08:00
dotCooCoo 78ce56d021 MCP: an integer given as a string or a fraction is refused as the wrong type, not reported as missing
A command that needs a whole number of 0 or more, such as `index` of
`appearance.setItem`, `anchor` of `path.removeAnchor` and
`addon.pen.removePoint`, `sourceDocument` of `edit.dropSelection`, `index`
of `document.activate` and `to` of `document.move`, answered "missing
integer `index`" (or "missing index") both when the key was left out and
when it was given as a value that is not a whole number of 0 or more, such
as "3", 2.5, -1 or true. A value that is given but is not one is now
refused with "`index` must be a whole number", the message object ids
already use. A key left out or given as null is still missing, and an
optional index such as `subpath` keeps its default. Neither error changes
the document or records an undo step.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-13 18:02:42 -08:00
dotCooCoo b3fae432b6 Merge main into fix/batch-swatch-default-paint 2026-11-13 17:54:08 -08:00
dotCooCoo 73fd610324 Swatches: swatch steps in a batch change the paints for new art
A swatch delete, Swatch Options edit, merge, Edit Color Group, Spot
Colors options change or Default Swatches replace run as a
command.batch step left the fill and stroke new art takes linked to the
old or deleted swatch, because the defaults were skipped whenever an
interaction was open. A batch step now rewrites them as the command run
on its own does; a live Swatch Options preview still leaves them alone,
and a failed batch or a canceled batch preview puts them back.

The same commands now also rewrite the fills and strokes of the
appearance new art takes, and record the change with their undo step,
so Undo and Redo put the paints for new art back with the swatches.
2026-11-13 17:54:07 -08:00
dotCooCoo 4dd3809f84 Live Paint: triple-click test checks the face the planar map makes
The test for a triple-click whose first click makes the group now also
builds the planar map from the same two paths and checks that the face
at the click takes its fill from the square. The doc comment of the
double-click flood names the three points it checks along each edge
segment.
2026-11-13 17:43:37 -08:00
BFlat c1efdbdaae Merge pull request #7255 from dotCooCoo/fix/folder-prefs-out-of-recorded-steps
Actions: keep folder preferences out of saved sets and confined replies
2026-11-14 08:40:15 +07:00
BFlat 5ccb284e34 Merge pull request #7335 from dotCooCoo/fix/live-paint-noop-undo
Live Paint: an edit that changes nothing records no undo step
2026-11-14 08:40:06 +07:00
BFlat bf3cf422e2 Merge pull request #7311 from dotCooCoo/fix/ai-graphs-keep-data
PDF/.ai import: graphs keep their data and settings when their records read whole
2026-11-14 08:39:57 +07:00
BFlat 12117a48f9 Merge pull request #7324 from dotCooCoo/fix/edit-colors-no-change-undo
Edit Colors: no undo step when a recolor changes nothing
2026-11-14 08:39:40 +07:00
BFlat c028cf6ab1 Merge pull request #7332 from dotCooCoo/fix/type-outlines-keep-appearance
Type: Create Outlines keeps the type object's own fills and strokes
2026-11-14 08:38:56 +07:00
BFlat 043e008194 Merge pull request #7196 from dotCooCoo/fix/item-4459
Brushes: strokes draw with the first of two brushes with one name
2026-11-14 08:38:40 +07:00
dotCooCoo f74fe81292 Live Paint: the swatch preview follows the release point; nudges read the key press's modifiers
- After a fill drag, the Live Paint Bucket stores the release point, so the
  cursor swatch preview shows there instead of where the pointer last moved
  before the press.
- Arrow nudges and Alt+arrow type spacing read Shift and Alt from the key
  press, as the tool keys do, so a modifier released within the same frame
  still makes a 10 pt nudge, a copy, or a spacing step.
- tool.setOption accepts cursorSwatchPreview for the Live Paint Bucket and
  refuses a value that is not true or false.
2026-11-13 17:19:33 -08:00
dotCooCoo 815c772a46 Image Trace: presets trace at Paths 50 with new Corners and Noise
Every built-in preset other than Auto Color and Flat Logo now traces at
Paths 50. Corners is 100 in Technical Drawing, 75 in Default, Black and
White Logo, Line Art and Outline, and 50 in the others. Noise is 1 px in
Technical Drawing, 5 in High Fidelity Photo, 10 in Low Fidelity Photo, 15
in 3 Colors, 6 Colors, 16 Colors and Shades of Gray, 20 in Sketched Art,
Line Art and Outline, 25 in Default and Black and White Logo, and 90 in
Silhouettes. Palettes, color counts and the other options are unchanged.

This changes the output of every preset but Default, Auto Color and Flat
Logo. The traces take fewer anchors (High Fidelity Photo 5,494 to 3,136
and Black and White Logo 27 to 14 in crates/trace/tests/quality), and
outlines on flat art lie further from the true edge (16 Colors 0.100 to
0.123 px off on average).

Docs: docs/image-trace-adjustments.md, docs/image-trace-quality.md,
docs/target-app-parity.md.
2026-11-13 17:13:52 -08:00
ncic b48688cb1c Pencil: a closed stroke closes with a straight segment
A closed freehand stroke is fitted as the open stroke would be and closed by a
straight segment from its end back to its start. Fitted as one loop, the
closing segment curved on past both ends and back, like a hat's brim.
2026-11-14 02:10:48 +01:00
dotCooCoo 52aec70e19 Live Paint: double-click floods along split edges, triple-click on new art skips open paths
- A face outline segment that runs along several edge segments (the
  face has no corner where a crossing line splits the edge) now joins
  the face to every edge segment it runs along, not only the one under
  its middle, so a double-click flood no longer stops there.
- The first click of a triple-click on selected paths, which makes the
  Live Paint group, takes the fill to match from the paths' closed
  subpaths only, as the group's faces do; an open path in front no
  longer gives the wrong fill.
2026-11-13 17:05:06 -08:00
dotCooCoo 78e7227358 Merge main into fix/graph-series-gradient-per-mark 2026-11-13 17:01:05 -08:00
dotCooCoo 269ca40954 Merge main into fix/colored-light-seams 2026-11-13 17:00:43 -08:00
dotCooCoo 2ee29aefc6 Merge main into fix/knockout-groups-flat-masks 2026-11-13 16:59:50 -08:00
dotCooCoo 45be5112e9 Merge main into fix/save-unused-option-notes 2026-11-13 16:56:43 -08:00
Dylan M. Taylor e4035a75db DXF import: read the drawing with craft_dxf::model
craft_dxf::parse_recovering reads the tags (ASCII and binary, any code
page), model::Document::read the sections, tables, blocks, layouts and
entity followers, and Entity::read each entity. The pair parser, the
records, the header, layer, block and layout readers and the colour
palette are gone; what stays is the mapping onto VectorCraft art.

Binary DXF files now open instead of being refused. A damaged binary
file says so.
2026-11-14 00:56:01 +00:00
dotCooCoo 87b4a8053b Merge main into fix/graph-series-group-opacity 2026-11-13 16:49:51 -08:00
dotCooCoo ab44332804 Merge main into feat/smooth-cursor-without-path 2026-11-13 16:43:32 -08:00
dotCooCoo adc60bfb16 Merge main into feat/rotated-box-scale-reflect 2026-11-13 16:42:07 -08:00