Commit Graph
4562 Commits
Author SHA1 Message Date
dotCooCoo 6bcc48690d Merge main into fix/reverse-path-profiles 2026-11-13 23:08:45 -08:00
dotCooCoo e76982bfad Artwork Cleanup: named type on a locked artboard stays out of the text tools
Add a test that Remove Breaks leaves type on a locked artboard as it is
when ids names it, with no undo step. Rewrap the Text tools paragraph
in docs/mcp.md and name the tests in docs/target-app-parity.md.
2026-11-13 23:08:11 -08:00
dotCooCoo 362557147f Merge main into fix/followup-7304 2026-11-13 23:05:53 -08:00
dotCooCoo 7a3ae7489c Merge main into feat/arrange-nest 2026-11-13 22:59:19 -08:00
dotCooCoo b4a7f106ac Merge main into fix/smooth-keeps-closed-start 2026-11-13 22:58:44 -08:00
dotCooCoo 25ff56c0b6 Merge main into fix/live-shape-replay-negative-radius 2026-11-13 22:57:58 -08:00
dotCooCoo 6e765f1848 Merge main into fix/dcs-placement-clip-keeps-file-clip 2026-11-13 22:47:26 -08:00
dotCooCoo ae05540f70 Merge main into feat/cjk-tsume 2026-11-13 22:46:57 -08:00
dotCooCoo cbdd3b4706 Merge main into fix/reflected-dimension-line 2026-11-13 22:46:36 -08:00
BFlat 6beeb9e2a4 Merge pull request #7262 from dotCooCoo/feat/smooth-cursor-without-path
Smooth: the cursor shows Not Allowed when no path is selected to smooth
2026-11-14 13:43:44 +07:00
BFlat 2169e229f6 Merge pull request #7376 from dotCooCoo/fix/int-param-wrong-type
MCP: an integer given as a string or a fraction is refused as the wrong type, not reported as missing
2026-11-14 13:43:27 +07:00
BFlat 18266da1e1 Merge pull request #7328 from dotCooCoo/fix/save-unused-option-notes
Save, Export for Screens: warnings name an option the file doesn't read
2026-11-14 13:42:55 +07:00
BFlat be93e4b3f2 Merge pull request #7377 from dotCooCoo/fix/symbol-expand-reset-bbox
Symbols: Break Link and Expand keep an instance's bounding box
2026-11-14 13:42:23 +07:00
BFlat 4b3df93745 Merge pull request #7371 from dotCooCoo/fix/batch-swatch-default-paint
Swatches: swatch steps in a batch change the paints for new art
2026-11-14 13:42:04 +07:00
BFlat 7fd4564c0c Merge pull request #7390 from dotCooCoo/fix/hyphenation-exceptions-relayout
Type: hyphenated type lays out again when the hyphenation exceptions change
2026-11-14 13:41:57 +07:00
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 ecd4b80af2 Merge pull request #7395 from storytold/fix/warichu-test-text-ops
Tests: warichu PDF check reads only text objects
2026-11-14 13:41:10 +07:00
dotCooCoo 8887806cb2 Undo: no step when Randomize Opacity or a type setting changes nothing
- addon.arrange.randomizeOpacity, type.orientation.vertical and .horizontal,
  type.opticalMarginAlignment, type.systemLayout and type.fractionalWidths
  run through edit_if_changed (the Edit Colors helper) and record an undo step
  only when an opacity, a direction or a setting changes.
- A test for each command; the params text says so, and docs/mcp.md for the
  commands it describes.
2026-11-13 22:40:01 -08:00
dotCooCoo 019f604e91 Artwork Cleanup: text tools act on the locked or hidden type ids name
Remove Breaks, Break Text, Combine Point Text, Join Point Text, Set
Alignment, Keep Position and Reset Text Transform skipped locked and
hidden type even when `ids` named it, or named the group or layer
holding it, while other commands such as text.convertListToText act on
named locked or hidden objects.

- With `ids`, the type they name is taken locked or hidden too (not
  type on a locked artboard); from the selection, only type that can
  be edited, as before.
- Remove Breaks reads a named threaded story with a locked frame as one
  text.
- Objects made from locked or hidden type are not selected.

Docs: docs/mcp.md (Text tools), docs/target-app-parity.md.
2026-11-13 22:38:38 -08:00
dotCooCoo 9685e1e312 Merge main into fix/mcp-docs-stack-file 2026-11-13 22:33:56 -08:00
dotCooCoo 1d5c30d753 Merge main into fix/colored-light-seams 2026-11-13 22:31:14 -08:00
dotCooCoo 5a4020a6c0 Graphs: graphic styles leave a design's art in a series unlinked
graphicStyle.new linked the object it was made from, the art of a column
or marker design in a graph series included, and graphicStyle.redefine
gave the new look to every object still linked to the style. Redefining
the style from another object then restyled that art, which the graph
draws again from the design.

- graphicStyle.new makes a style from the art without linking it.
- graphicStyle.redefine leaves the art's look as it was and unlinks it,
  as an edited object is, whether the art is a linked object (as in a
  document saved before this change) or the source.

Docs: docs/mcp.md, the params text of graphicStyle.new and
graphicStyle.redefine.
2026-11-13 22:27:58 -08:00
dotCooCoo 70da63f5b0 Merge main into fix/polygon-sides-refused 2026-11-13 22:23:24 -08:00
dotCooCoo 2a4185d6ca Merge main into fix/graph-series-gradient-per-mark 2026-11-13 22:15:43 -08:00
dotCooCoo bc6c48367e Merge main into fix/knockout-groups-flat-masks 2026-11-13 22:15:33 -08:00
dotCooCoo 5d89b37040 Paste: graphs bring and follow the styles and swatches their labels keep
A graph keeps paints for its series and labels, and character and
paragraph style names for its labels, which each redraw gives the
marks and labels. Copy did not follow them, so a graph pasted into
another document left those swatches and styles behind, and a paste
that renamed them left the graph pointing at the old names.

Copy now collects them and paste relinks them, as it does for type.
Paste without Formatting drops the labels' style names, so it still
leaves text styles behind.
2026-11-13 22:10:18 -08:00
dotCooCoo d3e520b14b Effects: raster effects on a symbol instance's fill or stroke are drawn
A raster effect (Drop Shadow, Outer Glow, Gaussian Blur and the other
effects that paint pixels) on a symbol instance's topmost fill now draws
on each filled shape of the symbol's art, and one on its topmost stroke
draws on each stroked shape, after any geometry effects listed before
it. The same rules as for geometry effects apply: only a visible fill or
stroke with an opacity above 0 counts, a group's own fills and strokes
in the art take the effect, and an instance inside the art passes it on.

The canvas, Use Preview Bounds and the drawn bounds, SVG and PDF export
draw it, and Object > Expand Appearance is enabled for such an instance:
a shadow or glow becomes an image under the instance, and a blur,
feather or inner glow replaces it with the image, in one undo step.

Existing documents with a raster effect on a symbol instance's fill or
stroke draw differently: before, the effect drew nothing.
2026-11-13 21:53:15 -08:00
dotCooCoo 1494e2c230 Type: Tsume narrows the space around each character's ink
Character panel > Tsume, shown with Show East Asian Options, takes away a
percentage of the blank space on each side of a character's ink, inside
its own width, in horizontal type. The value is from 0 to 100, 0 by
default. 50 halves that space and 100 sets the ink against the
characters before and after it; the glyph keeps its shape. A character
without ink, such as a space, keeps its width, and a ligature or a
letter with its marks takes the value of its first character. The
font's pair kerning, tracking, manual kerning and Insert Aki are added
after it, and justification keeps it. Vertical type keeps its spacing.

- text.setFormat and text.setRangeStyle take `tsume`; a value that is
  not a number or is outside 0 to 100 is refused, naming the key.
  Character styles carry it, and a file holding a value outside the
  range opens with the nearer end.
- The Character panel's Tsume field has 0, 25, 50, 75 and 100 in its
  menu, and Reset Panel sets it to 0. Character Style Options shows it
  in Advanced Character Formats.
- Live SVG text places each character Tsume moves, and type on a path
  with Tsume is written as outlines.

Docs: docs/mcp.md (Tsume, Character Style Options fields),
docs/target-app-parity.md.
2026-11-13 21:50:05 -08:00
dotCooCoo b39bfbed4f Export Selection: the picked format's options dialog follows the save panel
document.exportSelection run with no params or {} (a shortcut, or an
automation call) wrote the picked file straight away with each format's
defaults: a PDF used the default preset, so Save PDF's options, such as
writing long pages in points, could not be chosen. It now takes Export
As's route after the save panel: Save PDF without its Artboards
section, SVG Options without its artboards, the raster options, EPS
Options, DXF Options, Text Export Options with Selection Only on, or an
exporter plug-in's parameters. OK writes the selection alone, cropped
to it, with the chosen options. While a dialog is open the call returns
null, and OK returns what file.exportAs returns, without format or
bounds.
With a path or any option it still writes straight away.

- file.exportAs takes exportSelection: true and then writes the
  document that document.exportSelection writes
  (fileio::selection_doc), without artboard choices. The options
  dialogs and the replace-file questions pass it on.
- Nothing selected stops before the save panel.
- SVG Options opened by Export Selection leaves the remembered Use
  Artboards as it was.
- Exports through file.exportAs (Export As and the options dialogs)
  apply Appearance of Black's rich black, as document.export does.

Docs: docs/mcp.md, docs/control-protocol.md, docs/target-app-parity.md.
2026-11-13 21:44:06 -08:00
dotCooCoo a173ba75d2 Docs: script.run params text puts a space before $.includePath
The $.fileName clause in the script.run params text ended without a space before $.includePath.
2026-11-13 21:36:00 -08:00
dotCooCoo 81b79ae67d Swatches: a gradient stop unlinked from its spot swatch also drops its plates
A gradient stop that loses its link to a spot swatch kept the process
plates it printed with that ink, so it carried a DeviceN mix with no
ink. Paint::map_links, which deleting a swatch, recoloring and color
adjustments go through, now clears a stop's plates whenever it leaves
the stop without a link, as GradientStop::set_color(color, None)
already does. Library gradients and library character styles linked
to a swatch the document lacks unlink their stops the same way.

Docs: docs/target-app-parity.md.
2026-11-13 21:30:14 -08:00
dotCooCoo a903feb870 Dimension tool: no construction guides through a first point off the anchors
With Smart Guides on, the Dimension tool's second point snapped onto the
construction guides through the first point (Smart Guides › Construction
Guides), so a click beside a segment straight below a first point that
was not on an anchor stayed on the vertical guide instead of landing on
the segment.

The second point now has no construction guides through a first point
that is not on an anchor. After a first point picked on an anchor, the
construction guides through it still apply. The second point still snaps
to anchors, centers and alignment lines, and with Snap to Perpendicular
or Snap to Tangent on it lands where the line from the first point meets
a segment square or grazes a curve.

Docs: docs/dimensions.md, docs/target-app-parity.md.
2026-11-13 21:26:04 -08:00
dotCooCoo 090293db4e Image Trace: preset docs name the enhanced versions and older figures
The preset paragraphs say that the enhanced versions use the same Paths,
Corners and Noise, and that Corners 50 applies to the other eight
presets. The quality notes add the staircase and anchor rises in Line
Art, Outline, 3 Colors, Sketched Art and Silhouettes, and say which
figures were measured at the earlier values. The anchor-limit comments
name the same settings in both places.
2026-11-13 21:22:12 -08:00
dotCooCoo 541059faf2 Path: path.setHandle to the handle's own point leaves a smooth anchor unchanged
path.setHandle checked for a no-op by running the handle edit on a copy
and comparing the whole anchor. On a smooth anchor the edit recomputes
the other handle, so when that handle was not exactly in line, or the
recomputed value rounded differently, a request for the handle's own
point realigned the other handle and recorded an undo step.

The check now compares the requested point with the handle itself, and
still lets independent turn a smooth anchor into a corner.
2026-11-13 21:21:11 -08:00
dotCooCoo c5e2e9210a Sort Objects: an opacity sort that gives marks their own opacities changes nothing
With apply "opacity", Sort Objects compared each object's opacity with the
value it gets as a percentage, within 1e-6. An evenly stepped value can
differ from a mark's percentage by more than that while it rounds to the
same stored opacity: marks at 30%, 65% and 100% sorted by x with
distribute on keep their opacities, yet the 65% mark counted as changed.
The sort then made an undo step and replaced the opacity the graph stores
for the series (30%) with 65%.

The sort now compares each object's stored opacity with the opacity it is
given, as stored, both to skip a run that changes nothing and to pick the
marks whose opacity the graph keeps.
2026-11-13 21:16:20 -08:00
dotCooCoo 39dc6c365b Type: Convert to Text and Remove Breaks on a selected story include its locked and hidden frames
After Select All in a frame of threaded text, Convert to Text skipped
the story's locked and hidden frames, even when `ids` named them, and
left a paragraph whose text started in one as a list. Remove Line
Breaks and Remove Paragraph Breaks also kept the breaks in those frames.
A selected story is one text, as it already is for Apply Bullets and
Apply Numbers and the Character and Paragraph panels, so both commands
now change every frame of the story, as one undo step.

- text.convertListToText converts every list paragraph of the story,
  locked and hidden frames included; `ids` naming a locked or hidden
  frame converts its paragraphs too. A call that changes nothing adds
  no undo step.
- addon.cleanup.removeBreaks removes the breaks in every frame of the
  selected story.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-13 21:11:10 -08:00
dotCooCoo df951caea4 Docs: $.fileName names the file being run in code eval or Function compiled
The script module docs, the script.run params text and the evidence line now
say that $.fileName in code that eval or Function compiled gives the file
being run, and the params text says that the empty name applies to code
compiled from a script given as text.
2026-11-13 21:09:02 -08:00
dotCooCoo 7abd11d19d Plug-ins: windows and processes take turns on the Plug-ins folder
Two windows or processes using one Plug-ins folder could interleave their
writes: an install from one could leave its module with the other's grant,
a grant written for one plug-in could drop one written for another, and
plug-in settings and cache changes could lose each other's keys or pass the
cache caps together.

Each change to the folder now runs in one turn on disabled.lock, the file
the disabled list was already locked with:

- plugin.install takes the turn before it reads the stored grants and holds
  it through the module, grant, put-back and disabled-list writes;
  plugin.remove holds it through grant removal and storage deletion.
- Grant writes, the disabled list, loading the folder, and the plug-ins'
  settings and cache changes read and write in a turn.
- When disabled.lock can't be locked, plugin.install and plugin.remove fail
  and change nothing, plugin.setEnabled keeps its change in the process, and
  loading the folder writes nothing to it.

Docs: docs/plugins.md, docs/mcp.md, the plugin.install and plugin.remove
params text, docs/target-app-parity.md.
2026-11-13 21:07:28 -08:00
dotCooCoo cf250db2e8 Paths: Reverse Path Direction turns the stroke's width profile and pen records with the path
Reverse Path Direction reversed the anchors but left the stroke's width
profile, pressure, tilt, bearing and rotation running the old way, so a
tapered or pressure-drawn stroke changed shape. They now turn with the
path through the blend code's stroke reorientation (the width profile's
sides swap), and the stroke draws as before. A path whose subpaths do
not all turn alike keeps its stroke as it was, as blends do. Arrowheads
stay at the path's start and end.
2026-11-13 21:05:44 -08:00
dotCooCoo 5750843d73 Links: placed images in stored brush art get Links rows
Linked images and placed documents in the art of the stored brushes (a
scatter or art brush's art, a pattern brush's tiles) are listed in the
Links panel after the other stored art, one row per linked or placed
object in each brush tile, with the brush as owner
(`{kind: brush, name, index, tile?}`). Check Links, the missing and
modified files reported on open, the link watch, Find in Folder, Relink
(including Relink All Instances), Update, Embed, Placement Options, Link
Info and Go To act on them, and their tooltip names the brush.

- vectorcraft-doc: `Document::mounted_art` holds art kept outside the
  document's trees while a command looks it up by id; the stored-art
  lookups, link visitors and `art_roots` include it, and
  `number_mounted_art` gives its objects ids of their own.
- vectorcraft-brush: `stored_art::StoredArt` mounts the art of the
  brushes that hold images or placed documents and writes back only the
  entries whose art changed. Entries that do not read as a brush are left
  as stored. `brush::store` keeps ids of their own in that art, so a row
  keeps its id between commands.
- vectorcraft-engine: the links commands, opening a document, saving a
  placed document's source, output of linked files and placed documents,
  color masks after Update or Relink, and Package relinking go through
  the mounted art.

Brush art rows follow the general Links rule as VectorCraft's own
application of it.
2026-11-13 20:51:54 -08:00
dotCooCoo 5b24c0a55e Actions: Batch errors name the step by its place in the commands sent
action.batch drops Open steps before it plays each file or data set, and
returned the per-file error of command.batch unchanged, so `batch step N`
counted from 0 within the filtered steps. A failed step is now named
``action step N (`id`) failed: reason``, N being its place in the
`commands` the caller sent, from 1, with skipped Open steps counted.
The batch's own open, data set choice and destination steps keep their
unnumbered errors, and command.batch messages are unchanged.

A prefs.import step, which command.batch refuses when it reaches that
step, rolling the batch back, is now refused before any file opens
instead of failing each file or data set the batch plays.

Docs: action.batch params text, docs/mcp.md, docs/target-app-parity.md.
2026-11-13 20:47:50 -08:00
dotCooCoo 0263b4af13 Merge main into fix/smooth-keeps-closed-start 2026-11-13 20:38:29 -08:00
dotCooCoo 395ddae55a Merge main into fix/file-folder-param-classification 2026-11-13 20:30:48 -08:00
dotCooCoo f9b1c2504f Smooth tool: measure twice the reach along a curve that leaves without a handle
Near an anchor whose handle does not reach out, the curve starts more slowly than its control polygon, so the finely cut stretch could end before twice the reach and the turn there was measured along a long chord. The stretches past it are now cut as finely until the pieces reach three times the reach. docs/mcp.md says the one-eighth cap applies to a closed path the drag reaches all the way round.
2026-11-13 20:28:08 -08:00
dotCooCoo 6027126a1f Merge main into feat/trace-preset-defaults 2026-11-13 20:19:30 -08:00
dotCooCoo 155c2f722b Place: Placement Options clip a DCS image inside its file's clipping path
When links.update or links.relink re-read a DCS file and Placement
Options also clipped the image (Fill with Clip, or an aspect change
that overflows), the placement rectangle replaced the file's clipping
path, so plate art outside that path showed and printed.

The file's clip group now stays around the image and the placement's
clip goes in a clip group around it. The clip group holding just the
file's group takes that clip, as one holding just an image does today,
else a new one does, so later updates reuse the same two groups. A
file that loses its clipping path leaves its group as a plain group
inside the placement's clip. The same applies in symbols, graph
designs, patterns and opacity masks.
2026-11-13 20:18:35 -08:00
dotCooCoo 9b2e21f6ca Live Paint: Merge keeps the visibility, opacity and blending of the parts it carries
Merge copied a face's or edge's appearance to the part it rebuilds in its
place, but not its visibility, opacity or blending mode. A half-transparent
face drawn by its stroke became opaque, and a hidden edge was shown again.
2026-11-13 20:14:37 -08:00
dotCooCoo 00de304ab0 Live Shapes: saved object.setLiveShape steps with a negative radius or out-of-range sides replay again
Since #7294, object.setLiveShape refuses a negative `radius` and a
`sides` that is not a whole number from 3 to 1000. Session::replay
applied the same checks, so a journal entry or action step recorded
before that change with such a value stopped with a parameter error.

On replay, a negative radius now counts as 0, which is how it drew
before. A whole side count below 3 or above 1000 is brought into that
range, and a fractional or negative one is ignored. Direct calls still
refuse these values.
2026-11-13 20:12:05 -08:00
dotCooCoo 877eb84f6d Graphs: an unchanged paint write keeps a series' kept gradient
A paint write that leaves a series mark's gradient as the graph drew it
now keeps the series' stored gradient and its unit-box flag in two more
cases:

- a mark with no width or no height, such as a column for a value of 0,
  where the stored gradient was replaced by the mark's gradient in
  document coordinates and no mark took it on the next redraw;
- a gradient kept in document coordinates (a file saved before the unit
  box), which a stroke weight written as it was moved to the unit box,
  so the next redraw placed it on each mark's own box.
2026-11-13 20:09:25 -08:00
dotCooCoo 1a01d591f3 Shapes: addon.shapes params text parses, and configure keeps omitted values
The ranges in the addon.shapes params text are in parentheses, so each
description reads as a params object. The configure description and
docs/mcp.md say that an omitted or null value keeps each shape's setting;
the defaults apply to the drawing commands only.
2026-11-13 19:56:50 -08:00