The Edit Colors commands read `fill`, `stroke`, `includeImages` and
`includePatterns` with a reader that fell back to the default for any
value that is not true or false, so `edit.colors.toGrayscale
{"fill": "false"}` converted the fills it was asked to leave alone.
These keys, and `convert` and `mode` in `edit.colors.adjustBalance`,
are now read with `switch_or` and `text_param`, and a wrong type is an
error that changes nothing. The same applies to `addon.color.filter`,
which shares the scope.
`edit.colors.overprintBlack` now refuses a `remove`, `fill`, `stroke`,
`includeCmyBlacks` or `includeSpotBlacks` that is not true or false
and a `percentage` that is not a number. `color.harmony` refuses a
`rule` or `variation` that is not a string; a `variation` such as 5
was dropped before.
A null still counts as a key left out. docs/mcp.md describes the
errors.
With the Artboard tool selecting several artboards, Paste in Place, Paste
in Front and Paste in Back put a copy of the copied art on each, where it
was on the artboard it was copied from, in one undo step. The three
commands take `artboards: [index...]`; the app passes the Artboard tool's
selection there, and without it the engine uses that selection while the
tool is chosen and records it in the journal. Art copied from no artboard
keeps its place on the first artboard and its offset to it on the others.
Copied artboards still paste once, where they were.
An `artboard` or `artboards` value that is not an artboard index of the
document, a repeated index or an empty list is now an error, and nothing
is pasted. An out-of-range `artboard` used to paste the art where it was.
A batch keeps the `artboards` a paste step names, and a paste step that
names neither pastes on the Artboard tool's selection while that tool is
chosen with several artboards selected.
Help page: https://helpx.adobe.com/illustrator/desktop/create-manage-artboards/organize-manage-artboards/cut-copy-and-paste-artboards.html
select.object.notAlignedToPixelGrid selects the paths (not guides) and
compound paths whose pixel-aligned property is off, whatever their
coordinates, and returns {count}. It looks into groups but not into
compound paths, which take the property as one object, and leaves out
hidden, locked and template art and, in isolation mode, everything
outside the isolated object. It replaces the selection, clears it when
nothing matches, and records no undo step.
The menu item goes under Select › Object with rows in every complete
catalog, and plug-ins may call the command like the other Select ›
Object filters. Docs: docs/mcp.md, docs/target-app-parity.md.
graph.setType read `axisMin: "10"` as a cleared bound, so the axis went
back to the calculated range, and it ignored a string or number given for
a true/false option, a string for a number and a number for a text option.
graph.setData and graph.create ignored a `csv` that is not a string and
`series`, `categories` or `rows` that are not lists, and read a string in
`rows` as a blank cell.
The three commands now refuse such a value with an error naming the key,
and leave the graph and the undo history as they were. A null is still
read as a key left out, and a null axis bound still goes back to the
calculated value. A negative tick count is refused too.
The Control bar's panel menu lists the bar's groups of options above
Dock to Top and Dock to Bottom, each checked while it is on. A click
turns that group off or on, and a group that is off stays out of the
bar even while its tool or object is selected. A group that is off
takes no room, so the groups after it fit a narrower window. The menu
scrolls in a window too short for all its items.
- window.control.options {group, visible?} sets or toggles a group and
returns {group, visible}; an unknown group or a non-boolean visible
is an error and changes nothing.
- The groups are off only by choice: every group starts on. The choice
is kept with the preferences and with each workspace; files saved
without it show every group, and unknown ids are dropped on read.
- The Artboard tool's bar follows the Artboard Options and Transform
groups; with Image Options off, an image shows neither its controls
nor Fill and Stroke.
- New labels have rows in every complete catalog.
Docs: docs/mcp.md, docs/target-app-parity.md.
Double-clicking a paragraph style, or Paragraph Style Options... in the
Paragraph Styles panel menu, opens Paragraph Style Options
(`ui.paraStyleOptions`) instead of the rename dialog. Its sections are
General (name and stored attributes), Basic Paragraph Formats (Alignment,
indents, space before and after), Composition (composer, Roman Hanging
Punctuation), Hyphenation and Justification. OK runs the new
`paraStyle.edit {name, to, attrs}`, which replaces the name and attributes
in one undo step; paragraphs that use the style keep their local
overrides. Fields left as they were keep the style's values, empty fields
leave an attribute unset, Preview can be canceled, and each section's
Reset Panel (`ui.paraStyleOptions.resetPanel`) clears only its own
attributes. New Paragraph Style shows the same sections, filled in from
the selected paragraph or the interface language's paragraph defaults.
`paraStyle.new`, `paraStyle.setAttrs` and `paraStyle.edit` now reject a
changed indent or space outside -1296 to 1296 pt, Hyphenation counts and
zone outside their ranges, Justification values outside their ranges or
out of Minimum/Desired/Maximum order, and tab positions outside 0 to
100000 pt. A value the style already holds is kept.
Docs: docs/mcp.md, docs/target-app-parity.md.
The Symbols panel menu gains Sort by Name, which puts the document's
symbols in name order, ignoring case, as one undo step
(`symbol.sortByName`). Symbols whose names differ only in case keep their
order, the current symbol stays current, and no undo step is added when
the symbols are already in order.
The menu's Thumbnail View and List View become Thumbnail View, Small List
View (18-point rows, 14-point thumbnails) and Large List View (the former
List View's 26-point rows and 22-point thumbnails), as in the Graphic
Styles panel. Clicking, double-clicking and dragging a symbol work the
same in every view.
Docs: docs/mcp.md, docs/target-app-parity.md.
file.package, file.place, file.place.queue, file.place.info,
document.serialize, document.export, document.exportSelection and
document.exportForOffice read their switches, strings and numbers with
helpers that fell back to the default for a value of the wrong type.
file.package {"copyFonts": "false"} copied the fonts, and
document.exportForOffice {"path": 5} returned the bytes instead of
writing a file. Each such value is now an error naming the key, and
nothing is placed or written. Null still means the key was left out.
swatch.library.list, brush.libraries, symbol.libraries and
graphicStyle.libraries returned every library's file path and the user
library folder to a client confined by --automation-read-root, including
paths outside its read roots. They now return null for those paths, and a
library loaded from a file outside the roots is listed as
loaded/<file name>, numbered (2), (3) when names repeat. That id finds the
library in the other library commands, and their replies show it too.
- The naming moves from control.rs into
swatchlib::concealed_library_ids, which numbers the session's loaded
libraries first, so ui.inspect, ui.docking and the library commands show
a library under the same id.
- swatch.library.copyToUser refuses a library whose file is outside the
read roots without naming the file; it and the library saves with
`user: true` leave out `path` when the user library folder is outside
the read roots.
Docs: docs/mcp.md (read roots), docs/target-app-parity.md.
A missing file below a folder link whose target does not exist got
"does not exist", while one below a link to an existing outside folder
was refused, so a script could tell whether the folder a link leads to
exists. A missing path is now refused when the nearest entry above it
that exists is a link that leads to nothing.
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>
When plugin.remove could not remove the grant and then could not rename
the plug-in's settings folder back from <folder>.removed, the failure was
only logged: the plug-in got empty settings, and the next removal deleted
the .removed folder with the settings in it.
- The error now names the .removed folder, the plug-in folder and the
reason, and the plug-in gets no storage until the settings are back.
- The next load, install or plugin.remove of the plug-in renames a kept
folder back while the plug-in has no folder of its own. When it has one,
that folder is used and the kept one stays until plugin.remove deletes
both. A removal while a kept .removed folder exists renames the plug-in
folder to <folder>.removing.
- Before deleting a renamed folder, the store writes an empty
<folder>.removed.delete file and removes it once the folder is gone, so
what a failed deletion leaves is not moved back. When that file can't
be written, nothing is deleted.
- A .removed folder without a .delete file, including one an earlier
version left, counts as kept settings: a new install of the id needs
replace: true, and plugin.remove of the id deletes it.
The word gap is now the Desired word spacing the layout uses for area type
with Block on (TextObject::layout_justification), with Minimum and Maximum
moved out to it when it lies outside them. The paragraphs keep their own
Justification values, so a wide gap no longer leaves a 1,000 % Maximum
behind, and turning Block off brings back the paragraph's own Desired
value. The SVG writer reads the same values.
- The Contextual Task Bar offers Dynamic Text for area type outside a
thread, beside Convert To Point Type.
- type.dynamicText with wordGap or lineGap and no area type in the
selection is an error instead of being ignored.
- Docs: docs/mcp.md, params text, docs/target-app-parity.md.
With the Selection tool on several frames of one threaded story, the
Tabs panel listed the paragraphs to change in the order the frames were
selected, and listed each frame's paragraphs separately. A marker drag
over mixed indents then ran its per-paragraph steps out of story order,
so a step that made text reflow could move a later step's paragraph,
and a paragraph that runs on from one frame into the next got two
steps. After Type tool Select All the split paragraph also got two.
The panel now lists each paragraph of a story once, in story order,
by its last piece with text in a selected frame. With the Selection
tool only the paragraphs with text in a selected frame change, so a
frame selected alone that starts or ends inside a paragraph sets it.
Docs: docs/target-app-parity.md.
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.
The gradients category was titled Gradient Swatches and listed every
gradient swatch, used or not. It is now Gradient Objects: one row per
object filled or stroked with a gradient, named as the object is, with
the gradients it uses (a linked swatch by name, else Linear gradient,
Radial gradient or Freeform gradient). document.info adds
gradientObjects and gradientNames, and Selection Only, Save and the
Package report use the same rows.
Gradient objects follow the rules Pattern Objects uses for paint that
draws: hidden fills and strokes, strokes with no width, guides, compound
path members' own paint, image paint without a shape and type that draws
nothing are left out, and type whose characters carry a gradient is
included. objects.gradients now counts the listed objects, so it no
longer counts hidden or zero-width gradient paint and no longer misses
type whose characters use a gradient.
The duplicate Document Info Save line in docs/target-app-parity.md is
removed.
A `File` or `Folder` for a missing path got "does not exist" even when
the path led outside the script's folder, through a folder link or, on a
file system where case matters, through a folder whose name differs from
the script's folder only in case, while an existing file there was
refused. A missing path is now refused unless the nearest folder above
it that exists lies inside a granted folder.
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.
The Batch dialog showed File Name for every destination when Play was
Data Sets, though only Destination Folder writes a file named from it.
The row now shows after Destination Folder for Data Sets with a folder
destination, and the dialog sends datasetFileNaming only then. The
chosen value stays in the dialog while another destination is picked.
action.batch and its default for an omitted datasetFileNaming are
unchanged.
Type > Dynamic Text (type.dynamicText) now also works on area type as
Block. Each line as typed (each paragraph, and each forced line break in
one) is set to the frame's width, less the inset, the column gutters and
the paragraph's indents, by changing its font size only. Lines are not
broken again. The first character's size moves in 0.1 pt steps within
0.1 to 1,296 pt, and the line's other characters keep their proportions.
The sizes are written into the characters and fitted again after every
edit to the text or the frame, in the same undo step.
- Word Gap (0 to 1,000 % of a word space, default 100) sets every
paragraph's Desired word spacing; Line Gap (-1,296 to 1,296 pt,
default 0) is added to each character's size for its leading. Both are
VectorCraft's own ranges and defaults, saved in the area options only
when they differ from the defaults.
- Area Type Options gains a Block fit (text.areaOptions fit "block",
with wordGap and lineGap), and the Properties panel's Paragraph section
shows a Dynamic Text checkbox with Word Gap and Line Gap rows.
- Block replaces Auto Size and Shrink Text to Fit. Off keeps the sizes.
Threaded area type is refused, as for type on a path.
- Empty lines keep their size, a frame with no width changes nothing,
vertical type fits each line to the frame's height, and right-to-left
lines and list markers are fitted like other lines. A refit runs at
most four extra layouts.
Docs: docs/mcp.md, docs/target-app-parity.md.
With Envelope Options > Distort Appearance on, VectorCraft turned the strokes
of type in an envelope into filled outlines and bent them with the art, so a
stroke got thinner where the grid squeezes the type and thicker where it
stretches it. The drawn art of users' .ai files keeps those strokes as stroked
paths at the type's own weights, and the ring they paint is as wide wherever
the grid squeezes or stretches the type. An envelope of stroked type in such a
grid therefore didn't draw as its drawn art and kept it instead of opening live.
Type's strokes (its characters' and those on its own appearance) now paint
along the bent glyph outlines at their own weight, with Distort Appearance on
or off, also in an envelope inside an envelope:
- doc: `map_node` maps the groups that hold type's glyph outlines with
`Hooks::type_appearance` in place of `Hooks::appearance`, for type in the
envelope's contents and for type that a live object in them (an inner
envelope) outlined (`Warper::type_outlines`). Such a group's opacity mask
is mapped with the ordinary hooks, so it bends as other art does. Groups
marked as type's outlines in the contents themselves (art an earlier Expand
made) stay plain art.
- effects: `bake_type_appearance`, `bake_appearance` with strokes kept as
strokes: geometry effects on type's fills and strokes still bake in and bend.
- doc: `max_outset` counts type's character strokes as type's own visual
bounds do (`char_stroke_outset`). It left them out, though they already
painted past an envelope's grid where the glyphs reach its edge; this also
grows the visual bounds of blends and repeats of stroked type and the reach
of symbol art holding it.
Paths' strokes, geometry effects, opacity masks, linear gradients and pattern
fills bend as before. The canvas, hit testing, effect bounds, Expand, every
export and the .ai save take the evaluation from the same hooks. Expand of an
envelope of stroked type gives the bent outlines with the strokes on them.
This changes how VectorCraft's own envelopes of stroked type draw.
Tests: envelope_distort::type_strokes_paint_at_their_own_weight_in_a_squeezed_envelope,
a_stroke_on_types_appearance_paints_at_its_own_weight_in_a_squeezed_envelope,
type_strokes_paint_at_their_own_weight_in_an_envelope_inside_an_envelope,
a_paths_stroke_still_bends_in_a_squeezed_envelope,
an_opacity_mask_on_type_bends_as_other_art,
the_visual_bounds_of_an_envelope_hold_its_types_strokes,
the_visual_bounds_of_a_repeat_of_stroked_type_grow_by_half_the_stroke,
expanding_an_envelope_of_stroked_type_keeps_the_stroke_at_its_weight,
bake::tests::type_pieces_bake_their_geometry_effects_and_keep_their_strokes and
tests_native::an_envelope_of_stroked_type_whose_drawn_art_strokes_the_bent_outlines_at_the_weight_opens_live.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An error a finally block passed on unchanged was reported at the end of
that block, in script.run's report and in the Script Console, because the
block's end raised the error again at a new site. The interpreter now keeps
the site of the exception each finally block runs for, keyed by the stack
slot that holds it, and the block's end throws the exception on from that
site. This holds through nested finally blocks, called functions, resumed
runs and marked host errors. An error the finally block throws is reported
at that throw, and one its return, break or continue discards is not
reported.
Type › Dynamic Text (`type.dynamicText`, also on the Contextual Task Bar
for type on a path) scales the text by one factor so it fills the span
between its start and end brackets, and the layout fits it again after
each edit to the text, the path or a bracket. The first character's
size moves in 0.1 pt steps within 0.1 to 1,296 pt. Turning it off, or
threading the type, keeps the sizes it was drawn at.
- The model saves `dynamicText` only when on.
- SVG, the legacy .ai writer and the .ai editing data write the drawn
sizes through `vectorcraft_text::drawn`; the editing data warns that
the setting is not written.
- Shrink Text to Fit and Dynamic Text step the size the Character panel
shows when a size measures the cap height, x-height or ICF box.
Docs: docs/mcp.md, docs/type-parity.md, docs/target-app-parity.md.
Part of #4134.