Commit Graph
1557 Commits
Author SHA1 Message Date
BFlat d8f180006a Merge pull request #7382 from ncic/pencil-alt-close-straight
Pencil: a closed stroke closes with a straight segment
2026-11-14 13:41:27 +07: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 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
ncic b0772bc2d6 Merge upstream main into pencil-alt-close-straight 2026-11-14 03:16:34 +01: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 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
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
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 ead3cd1ebd Variables: Import Data Sets reads UTF-16 CSV files without a byte-order mark
A CSV file that holds NUL bytes and has no byte-order mark was refused.
It is now read as UTF-16 when at least half of its two-byte units hold
a NUL byte, in the byte order that reads a line break. A file with fewer
NUL bytes (UTF-8 or Windows-1252 text with stray NUL bytes, or UTF-16
text made mostly of characters above U+00FF) is still refused, and so is
a file that reads a line break in both byte orders, has an odd length,
isn't valid UTF-16 in that order or holds a NUL character. Refused files
get the same message as before.
2026-11-13 16:34:43 -08:00
BFlat 92d9604726 Merge pull request #7264 from dotCooCoo/fix/confined-svg-export-script-paths
MCP: SVG export by a confined caller refuses script links outside its read roots
2026-11-14 07:34:26 +07:00
dotCooCoo d30831bd5a Merge main into feat/live-paint-cursor-swatch-preview 2026-11-13 15:54:47 -08:00
dotCooCoo c477db87ba Live Paint: an edit that changes nothing records no undo step
A Live Paint Bucket click or drag over faces that already have the
fill, a stroke on an edge that already has the paint and width, Gap
Options with the options the groups have and no gap to close, and Make
or Merge given one Live Paint group alone now leave the document, the
undo and redo steps and the saved state as they are, and reply as
usual. Such a fill or stroke also leaves the recent colors as they are.

Gap Options with Close Gaps With Paths makes a group's faces again only
when it adds a path or what paint stops at changes, so the faces keep
their ids otherwise.
2026-11-13 15:39:04 -08:00
dotCooCoo a8a0316da7 Type: Create Outlines keeps the type object's own fills and strokes
Type > Create Outlines dropped the fills and strokes of the type object
itself (the items around the Appearance panel's Characters row), so the
outlines no longer drew what the type drew. On type without effects of
its own, Object > Expand outlines the type with the same command, so it
lost them before Fill or Stroke could expand them.

- Create Outlines puts those items on paths of the type's whole outline:
  the items below the Characters row on one path under the glyph paths,
  the others on one path over them, in their order. Unplaced gradients
  are fixed to the type's layout box, as the canvas paints them.
- object.expand.info reports the type object's own strokes, pattern
  fills and gradient fills, measuring a gradient on the whole outline.
  It counts them only when the type has an outline: type of only spaces
  reports none of them.
- The stroke flag of object.expand.info counts every stroke Outline
  Stroke outlines, not only the topmost one, for paths as well as type.
  Expand skipped Stroke for a visible stroke under a stroke with no
  paint.

Create Outlines still does not carry over the type object's own effects.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-13 15:39:04 -08:00
dotCooCoo 9594d39bd5 Edit Colors: no undo step when a recolor changes nothing
Invert Colors, the Convert to commands, Saturate, Adjust Color Balance,
the Blend commands and Recolor Artwork recorded an undo step even when
they changed no color, for example Invert Colors with fills and strokes
off, Saturate at 0 or a second Blend Front to Back. The empty step also
cleared the redo steps. paint.invert and paint.complement on whole
objects, Apply as Filter (addon.color.filter) and Apply Nearest Swatch
run the same pass and did the same.

These commands now run on a copy of the document and record the step
only when something changed. Convert to Indexed Color uses the same
helper. Recolor Artwork also compares the documents when it counted no
recolored paint, so rewriting a color group's swatches still records
its step.
2026-11-13 15:29:04 -08:00
BFlat 0b29b2b1f6 Merge pull request #7267 from dotCooCoo/fix/doc-info-values-translated
Document Info: values show in the interface language
2026-11-14 06:27:27 +07:00
BFlat 4a0f4b924e Merge pull request #7305 from dotCooCoo/fix/one-anchor-edit-no-remeasure
Path: anchor edits on a long selected path skip measuring it for the canvas check
2026-11-14 06:27:14 +07:00
BFlat 26de97ee06 Merge pull request #7299 from dotCooCoo/fix/type-commands-thread-lookup
Type: thread checks look up the threads once per command
2026-11-14 06:26:56 +07:00
BFlat be1810e0c9 Merge pull request #7263 from dotCooCoo/feat/smooth-free-end-tangent
Smooth tool: an open path's end turns with the smoothing when a drag reaches it
2026-11-14 06:26:31 +07:00
BFlat 517b725be5 Merge pull request #7089 from dotCooCoo/fix/smooth-fidelity-screen-pixels
Smooth: Fidelity is in screen pixels, so a drag smooths as much at any zoom
2026-11-14 05:42:42 +07:00
BFlat 64c6387b84 Merge pull request #7260 from dotCooCoo/fix/tool-options-refuse-invalid
Live Paint and Shape Builder: tool.setOption refuses invalid options
2026-11-14 05:42:33 +07:00
BFlat 2fe70b2483 Merge pull request #7258 from dotCooCoo/fix/graph-label-appearance-kept
Graphs: Appearance edits on a label are kept for every label of its kind
2026-11-14 05:42:08 +07:00
BFlat c36aaec289 Merge pull request #7296 from dotCooCoo/fix/delete-artboards-one-pass
Artboards: delete several artboards and their guides in one pass
2026-11-14 05:41:59 +07:00
BFlat 1b039350a3 Merge pull request #7297 from dotCooCoo/fix/global-edit-enabled-for-supported-groups
Global Edit: Start Global Edit is offered only for a group it can start on
2026-11-14 05:41:50 +07:00
BFlat 5fd9ef537a Merge pull request #7294 from dotCooCoo/fix/live-shape-unknown-keys
Live Shapes: object.setLiveShape refuses unknown keys and invalid sides or radius
2026-11-14 05:41:41 +07:00
BFlat 7b992a416e Merge pull request #7287 from dotCooCoo/fix/recovery-error-guidance
Data Recovery: a failed copy names the folder in use and how to change it
2026-11-14 05:41:33 +07:00
BFlat 35d7c5d523 Merge pull request #7271 from dotCooCoo/fix/pdf-long-page-warning-names-option
PDF: the long-page warning names the in-points option
2026-11-14 05:40:30 +07:00
BFlat e244a65981 Merge pull request #7293 from dotCooCoo/fix/offset-path-parallel
Offset Path: offsets several selected paths on several threads
2026-11-14 05:40:00 +07:00
dotCooCoo e914d8abdd Merge main into fix/doc-info-values-translated 2026-11-13 14:13:45 -08:00
dotCooCoo 380f03345f Merge main into feat/smooth-free-end-tangent 2026-11-13 14:01:37 -08:00
dotCooCoo e51e67116d Path: anchor edits on a long selected path skip measuring it for the canvas check
The check after each edit that the selected objects stay within the
canvas measured the whole of every selected path. Moving one anchor of
a 10,000-anchor path measured all 9,999 segments. A path or compound
path whose anchors and handles are all finite and inside the canvas
range now passes without being measured, because its curves stay inside
their control points. A path with a point outside that range is still
measured, so the check accepts and refuses the same edits as before.

path.moveAnchor to the point the anchor is already at, and
path.setHandle to the point the handle is already at, now leave the
document as it is and record no undo step.

vectorcraft_geom::path::measured_segments counts the segments that
PathData::bounds measures, and the new engine tests use it.
2026-11-13 13:46:30 -08:00
BFlat e5913e30e1 Merge pull request #7204 from dotCooCoo/fix/trace-overlapping-two-pass
Image Trace: Overlapping fills each shape whole and stacks what it encloses above it
2026-11-14 04:31:56 +07:00
dotCooCoo 5df5acd7f9 Merge main into fix/graph-label-appearance-kept 2026-11-13 13:31:34 -08:00
BFlat 4a039aa63c Merge pull request #7269 from dotCooCoo/fix/free-distort-box-turns
Free Distort: the bounding box turns with the warped art
2026-11-14 04:31:23 +07:00
dotCooCoo d005ff6472 Type: thread checks look up the threads once per command
Dynamic Text, Dynamic Text Presets, Center on Top and Center on
Bottom, and Area Type Options with Block on checked each object for a
thread with its own search of the document's threads. A selection of
many objects in a document with many threads repeated that search for
each object, in the commands' enabled checks as well as when they ran.

The checks now build one lookup from frame to thread for the whole
selection. An object counts as threaded by the first thread that lists
it, as before, so the commands refuse the same frames, list them in the
same order and leave the document and the undo history as they were.
2026-11-13 13:28:42 -08:00
dotCooCoo 58cb261d7c Global Edit: Start Global Edit is offered only for a group it can start on
Select > Start Global Edit was enabled for any plain group, so a group
holding type, an image or nothing was offered in the Select menu and the
Properties panel's Quick Actions, the Control bar showed its Global Edit
Options, and starting then refused it. The enabled check now applies the
same support check as starting to every selected object, a group's
contents included.

The answer is kept per document revision and selected object, so the
Control bar, which asks every frame, walks a group once per change.

Docs: docs/mcp.md, docs/target-app-parity.md (a new line; the existing
Global Edit line no longer says the menu item checks only for a group).
2026-11-13 13:28:13 -08:00
dotCooCoo a2efb2d88b Artboards: delete several artboards and their guides in one pass
Delete Artboards, Delete Empty Artboards and Cut Artboard removed the
chosen artboards one at a time, walking every ruler guide and the layer
tree once per artboard. They now share one helper that removes the
artboards in one walk and their guides in one more, leaving the same
artboards, guides and selected guides as before.

Empty Artboards in Artwork Cleanup had its own copy of the one-pass
removal. It now calls the same helper, and its test reads that helper's
walk counter.
2026-11-13 13:23:42 -08:00
dotCooCoo 4ea2f2e9c6 Merge main into fix/smooth-fidelity-screen-pixels 2026-11-13 13:03:29 -08:00
dotCooCoo ac10c51381 Data Recovery: a failed copy names the folder in use and how to change it
When a recovery copy could not be written, the status bar said only
"Couldn't save recovery data: <error>", and a copy that failed on the
background worker showed as "Saving recovery data for <title> failed:
<error>". Neither said which folder was in use or how to pick another.

The message keeps the error text (and the document's title when one
copy fails), then names the folder copies go to, says whether it is
the default recovery folder or the folder set in Preferences, and
names the setting that picks another folder: Preferences → File
Handling → Data Recovery → Folder (recoveryFolder). The recovery code
writes the same line to the log. The folder is the one in use when the
round started, so a preference changed while a copy runs does not
change the folder the message names.

A copy that fails now reports its own message, so the job's result is
Ok rather than an error, and the job no longer adds "<label> failed:
<error>" over it. A store the host installed (browser storage) has no
folder to name: its failed copy shows "Saving recovery data for
<title> failed: <error>", as a copy on the worker did before, also
when the copy was written without the worker.

- engine: recovery::folder returns the folder in use and whether the
  recoveryFolder preference names it; recovery::store uses it.
- Four @msg rows in each complete-message catalog, and in the bg, bs,
  da and id catalogs, which translate the old message.
- Control replies to a client confined to read roots show a recovery
  folder outside them, and the paths under it, by the folder's name, as
  they already show other paths outside the roots. That covers the
  folder in use and the last eight folders a failure message named.
- docs/target-app-parity.md: a line next to the Data Recovery Folder
  preference.
2026-11-13 12:51:12 -08:00
dotCooCoo 4dc5c4f719 Live Shapes: object.setLiveShape refuses unknown keys and invalid sides or radius
object.setLiveShape was in params::UNCHECKED, so a key it does not read,
such as `path`, ran the command with the key ignored. Its description
names every key it reads, so it now goes through check_keys like other
commands, for MCP, scripts and command.batch steps. Each of `items` takes
`id` and `corners` alone; another key is refused as
`items[0].corner`, with the nearest accepted key. Saved steps still
replay leniently.

A `sides` that is not a whole number from 3 to 1000 (2.5, -1, 2, 1001)
and a negative `radius` are now errors naming the key, and leave the
document and its undo history as they were; a radius of 0 still
removes rounding. The Transform panel's Sides field takes 3 to 1000,
the Corners dialog's radius field stops at 0, and the panels' corner
radius fields send 0 for a negative value typed in.
2026-11-13 12:46:15 -08:00
dotCooCoo 804177bddd Offset Path: work out the offsets of several selected paths on several threads
Offset Path took each selected path in turn, so offsetting many paths, or a
group of many paths, used one CPU. It now reads the selected paths first,
works out their offsets on as many threads as the computer has logical CPUs
(one thread on the web and for a single path), and then makes the new
objects one after another in the selection's order on the editing thread.

The new objects, their ids, their stacking, the selection, the messages and
the undo step are the same as before. When several paths fail, the error is
the one for the first of them in the selection's order, and the paths after
a failure that have not started yet are skipped.
2026-11-13 12:41:24 -08:00
BFlat c9b2119552 Merge pull request #7176 from dotCooCoo/feat/monitor-profile-windows-linux
View: the canvas is drawn through the monitor profile on Windows and X11
2026-11-14 03:24:26 +07:00
BFlat f05cb5e7a4 Merge pull request #7223 from dotCooCoo/fix/inline-graphics-in-symbol-art
Type: inline graphics in symbol, mask and pattern art follow their symbols
2026-11-14 03:24:03 +07:00
BFlat cc0413ee34 Merge pull request #7217 from dotCooCoo/fix/brush-repeated-names-numbered
Brushes: repeated brush names are numbered when a document loads
2026-11-14 03:23:54 +07:00
BFlat 50084b789f Merge pull request #7243 from dotCooCoo/fix/smooth-segment-under-drag
Smooth: a drag along a segment smooths it when its anchors are out of reach
2026-11-14 03:23:45 +07:00
BFlat 9107dad274 Merge pull request #7194 from dotCooCoo/fix/item-3829
Envelopes: a partly transparent image keeps its alpha where its warp pieces overlap
2026-11-14 03:23:28 +07:00
dotCooCoo dd3438cb7f Live Paint Bucket: Cursor Swatch Preview and arrow keys pick swatches
Live Paint Bucket Options gets a Cursor Swatch Preview checkbox (on at
first, saved with the other options). With the Bucket selected, Left and
Right set the active fill, or the stroke when the Stroke proxy is in
front, to the color swatch before or after it in the Swatches panel,
wrapping around at the ends, with the preview on or off. The selected art
keeps its paint. The preview shows the active paint above the pointer
between the swatches before and after it; a color that is no swatch shows
alone until Right picks the first swatch or Left the last, and a paint
that is not a solid color shows no chip. The chips hide during a fill
drag and while Alt samples with the eyedropper. The fill and the stroke
each remember the swatch picked for them, so swatches of the same color
are each reached in turn.

The Bucket and the Shape Builder now take the arrows for swatches only
without Shift, Alt or Cmd/Ctrl, judged by the modifiers held when the key
went down, so modified arrows keep their shortcuts
(Tool::claims_key_with, Session::tool_claims_key_with).

Docs: docs/mcp.md, docs/target-app-parity.md, tool.options params text.
2026-11-13 12:09:16 -08:00
dotCooCoo f42ec13bd2 PDF: the long-page warning names the in-points option
In a PDF without a standard, the warning for a page longer than 14,400 pt
written with a UserUnit above 1 now ends with "turn on Write pages longer
than 200 in at full size in points". The warning already said that apps
ignoring UserUnit show such a page smaller; it now names the Save PDF
option that writes the page at its size in points instead. PDF/A files,
which keep the UserUnit with the option on, and .ai saves, whose options
do not have it, keep the warning as it was.

The longer message has a row in every complete-message catalog. The
params text of document.exportPdf, docs/mcp.md and the evidence line in
docs/target-app-parity.md describe it.
2026-11-13 12:08:49 -08:00
dotCooCoo 291afd8aa6 Free Distort: the bounding box turns with the warped art
object.distort warped the anchors of paths, groups, compound paths and
clip groups but left their bounding-box angle as it was, so a rotated
path kept its old box after a warp and an upright one stayed square to
the page however far the warp tilted it. Text, images and symbol
instances already took the angle of the warp's affine approximation.

- Each path, group, compound path and clip group now takes the angle
  the warp turns its x axis to at its own center before the warp, the
  members of a warped group and the art of a linked opacity mask each
  at their own. An unlinked mask's art keeps its angle. Mirroring keeps
  the nearer angle and a collapsing warp keeps the old one. Reset
  Bounding Box squares the boxes again.
- Each subtree's bounds are measured once while it is warped.
- Corners that equal the corners of the box being warped change
  nothing and add no undo step.

Docs: object.distort params text, docs/mcp.md, docs/target-app-parity.md.
2026-11-13 12:07:21 -08:00