The menu items that a pick or a shortcut reads are read once. Rows that
show a name that is user data (a custom toolbar under Window › Toolbars,
a script under File › Scripts, a recent file, a saved selection) are now
left out of them, as rows that list a plug-in already are, so a pick of
Show Toolbar no longer runs with the name of a toolbar that existed when
the items were read.
While a menu item is dimmed and the engine gives no reason (a UI
command, or an Appearance command with nothing targeted), a pick or a
shortcut now opens no dialog and shows "command `<id>` is not available
right now". The message has a row in every catalog that has the
engine's longer "not available right now" message.
Review feedback: with no tolerance, pen or trackpad jitter turned a tap
into a drag and the value was no longer selected. A release within 1 pt
of the press is a tap; anything further keeps the caret.
Regression test: a_tap_with_a_pixel_of_jitter_still_selects_all_on_release.
A shortcut given to Set Corners… (`addon.pathtools.cornerSet`) ran nothing,
on a single key or a chord. The keymap is built from the list in Edit ›
Keyboard Shortcuts, and that list left the command out. An engine command
without a menu path of its own was listed only when it had a default key,
or when it was an undoable command, not an alias, whose params doc ends
each field with `?`. A UI command was listed only when it had a default
key or a params doc of `{}` or `{path…}`, or was Rename. Set Corners…
needs a radius, so it was left out. The same rules left out other
commands that items of the menu bar run:
- View › Perspective Grid's Lock Grid, Lock Station Point, Show Rulers and
Snap to Grid, and Object › Perspective's Attach to Active Plane, Move
Plane to Match Object and Edit Text.
- Edit › Edit Custom Dictionary…, a query.
- UI commands: Recolor Artwork…, the Edit menu's four preset dialogs,
Apply SVG Filter…, Export As…, Export Selection…, Edit Original, Apply
Bullets, Apply Numbers, the four library saves, and the Window menu's
New Toolbar…, Double Column, Keep Tools Beside the Canvas, New
Workspace…, Float in Window and Consolidate All Windows.
Such a command is now listed when an item of the menu bar runs it as a key
press would: with no params, or with the one set of params all its items
give. `needs_a_value` already used this check, and it moves into
`a_menu_bar_item_runs` so that both use it. The command is listed in the
group named by the first part of its id, next to the commands of its
family that were listed before (Set Corners… under Addon with Corner
Tool, the grid toggles under Perspective).
File › Export Selection… was the row of `document.exportSelection`, which
no item of the menu bar runs. That row now runs `file.exportSelection`, as
the menu item does, and `document.exportSelection` is listed as Document ›
Export Selection…. A shortcut already given to it keeps running it. The
Window menu's Learn item gets no row, because the Learn panel's row
already has its name.
Tests: on F and on a chord, Set Corners…, Edit Custom Dictionary…, Recolor
Artwork…, the four preset dialogs and Apply SVG Filter… open the dialog a
click on their menu item opens. Snap to Grid turns off and on from F, and
Export Selection… on F opens Export for Screens. Every command the menu
bar runs this way is listed, none of them shares its group and label with
another entry, and a shortcut on four of them is kept through a saved
set's export and import. The other Object › Plug-ins dialogs, Select by
Link Status… and Composite Fonts… already opened from a shortcut and are
checked the same way.
A compressed arrowheads file is refused when the data after its document, the preview included, unpacks to more than 64 MB, so the whole stream is read and its checksum checked. Other files are read as before.
Under --automation-read-root, an error about a file or folder the client
did not give now names it whole only when it is inside the read roots.
Outside them it names the file or folder by its file name, or as "a file
or folder outside the read roots" when it has none, and keeps the roots
and the reason. A path the client gives stays whole.
This covers a save without a path (the document's own file and the files
written beside it, also inside action.batch, and the refusal to write
over a file read with losses), file.revert, script.listInstalled,
plugin.reload without a path and plugin.list's folder report, and
links.relink with copy (the document's folder, its error when the
document's path has no folder, and the copies in the reply). Export for
Screens' refusal for an export preset's folder uses the same helper.
The canvas kept the art of an image whose own fill or stroke follows the
outline of its pixels for as long as the image object stayed the same. When
the document's pixels for the image changed under the same key (Update Link
replacing a preview with the linked file's pixels), the stroke kept the old
outline while hit testing and Use Preview Bounds used the new one. The
renderer now keys that art by the document's pixels for the image too.
- vectorcraft-effects: `follows_image_pixels` names such images.
- vectorcraft-render: `reads_outside` counts them, and the resources key
hashes the address of the document's pixels for them; their walk is not
kept between frames.
- A test places an off-center opaque area in a smaller copy of the pixels
under a turned and reflected placement.
- Docs: the Outline Object params text names every case that keeps the frame
and the 50% cutoff as VectorCraft's own; docs/mcp.md's `effect.apply` entry
for Outline Object, how long an outline is kept and the 16-bit RGBA limit;
docs/target-app-parity.md's evidence lines.
A client confined by --automation-read-root saw paths outside its read
roots that the person or an earlier request had put in the session:
- plugin.list: the plug-in folder last loaded and its failed files;
plugin.list and plugin.info: a plug-in's source file; plugin.list,
plugin.safeMode and plugin.setEnabled: the file of a plug-in turned
off for the next launch.
- file.recovery.list and file.recovery.restore: a document's original
file; file.recovery.list and file.recovery.save: the recovery folder.
- ui.inspect's scriptReport: the files a run wrote and the included
file a failed run stopped in.
A folder outside the read roots is now null, and a file outside them is
named by its file name. plugin.setEnabled {file} takes that name. The
restored documents keep their files, and unconfined clients and the
app's own UI see the same replies as before.
object.objectsOnPath.selectMember and object.objectsOnPath.moveMember
change only the document and its selection, as the other Objects on
Path commands do, so both join the commands a plug-in may call when its
manifest lists them.
docs/mcp.md lists the four easingType values. It and the
object.blend.setEasing params text say that a blend made without a
spine takes easingType and ramp once Replace Spine has given it one,
which the set_easing test now checks.
Each built-in category (Mobile, Web, Print, Film & Video, Art &
Illustration, Branding, Social) has a New Document profile, a native
document in the New Document Profiles folder next to the preferences.
file.new copies the profile's swatches, graphic styles, brushes, symbols,
patterns, character and paragraph styles, rulers, Document Setup options,
assigned color profiles and print settings into the new document. The
preset's size, units, artboards, bleed, background, color mode and
resolution still apply, and the profile's art and layers are not copied.
- file.newProfiles lists the profiles, file.newProfiles.edit opens one
as a document (writing the shipped profile first), and
file.newProfiles.reset deletes its file. file.new takes `profile`.
- Saved and Recent presets keep the profile of the preset they came from.
- A profile that cannot be read, is larger than 64 MiB or is not a native
document leaves the defaults, and file.new reports it in profileError.
- New Document has a Manage Profiles pop-up with Edit and Reset.
Docs: docs/mcp.md, docs/target-app-parity.md.
The dialog sent the Count instead of a Spacing that was not above 0, so a Spacing below 0 ran with the Count. Now only a Spacing of 0, or none, leaves the Count in use, and any other Spacing goes to the command, which refuses one below 0.
- Expanding a layer removed its ruler guides with its members. The guides
of the layer and of its sublayers now stay on the layer, after the edges.
- Geometry effects after a 3D effect reshaped all the faces as one path, so
Offset Path merged faces that touch. Each effect now reshapes each face on
its own, about the bounds of all the faces, within one shared budget of
anchors, as it reshapes the drawn surface.
Docs: docs/mcp.md.
A four-component JPEG whose EXIF orientation turns or flips it went
through the image decoder, which reads CMYK JPEGs as RGB, and was
stored as an RGB PNG without its inks. It is now stored the way a
turned CMYK TIFF is: its inks, 8 bits each, turned and written as a
CMYK TIFF with the turned resolution.
- vectorcraft_doc::cmyk::turned_cmyk turns the inks of a CMYK JPEG or
TIFF, next to stored_cmyk_tiff; tiff_inks is private again.
- raster_image swaps the resolution axes inline, as its HEIF branch
does.
- The links comment and the docs/target-app-parity.md line on EXIF
orientation now describe the turned CMYK TIFF.
With Background Export on, an Export for Screens call that gives only an
`exportPreset` whose preset keeps a folder ran at once on the UI thread,
because the background route looked at the call's own `folder` only. It
now takes the preset's folder as well and writes in the background with
the progress dialog and Cancel, as an export into a folder it names.
When that folder is outside an MCP client's read roots, the prepared
export carries the folder's shown name, so the reply written later lists
the files relative to the folder with no ZIP `path`, a refused write names
the folder by its name, and the status bar does the same, as for an
export made at once.
The status of a preset-only export made at once named an empty folder
("Exported 1 file to "); it now names the preset's folder.
- `Session::screen_export_folder` returns the folder an export writes
into and its shown name when the reply leaves it out.
- `ScreenExport::write` applies the read-root rule decided when the
export was prepared.
- docs/mcp.md and docs/target-app-parity.md describe the change.
A text on a path that many <use> elements show was laid out along the
whole path once per <use>, and the path was found in the file and parsed
again each time, while the 1 MiB limit on texts built for <use> elements
counted only the text's nodes and characters. A file with a short text on
a very long path and many <use> elements of it could keep the importer
busy far past that limit.
- The elements of the path a <textPath> follows now count toward the
limit. Past it, the remaining <use> elements show the text with its own
properties, and the warning names text paths as well as text.
- The path of each <textPath> is found and parsed once and shared by
every <use> that shows its text.
Files within the limit import as before.
A custom arrowhead takes a clipping path's own fills and strokes only where the clipping path paints them on the canvas. A group used as the clipping path paints nothing, so its members' fills no longer widen the head past the clipped art.
effect.expandAsWireframes returned "draws no faces" for an object with
Revolve (Classic). It now takes the faces of Revolve (Classic) with that
effect's own options, and Rotate (Classic) is expanded as Rotate is: every
fill and stroke turned as one plane.
Docs: docs/mcp.md, docs/three-d.md.
The Dynamic Text: Block entry says the Contextual Task Bar offers the
item for point type too, and that turning it on makes point type area
type with Block on. The Dynamic Text entry no longer says point type in
the selection is left as it is.
`the_menu_bar_is_inert_while_a_file_dialog_is_open` excused a missing
menu row when the composite font or plug-in it named was gone at the
time of the check. A test running alongside can remove such a font and
define it again between the menu read and the check, and the test then
failed. It now runs inside `undisturbed`, as the file's other tests that
compare menu reads do. When the shortcut, plug-in or font generation
changes during a run, the test runs again on a new app. Every row from
before the dialog must then be back as it was.
The plug-in host's manifest, module and run errors, the errors about an
importer's, exporter's or effect's output and the approval error had no
@msg row in most complete-message catalogs, and the reasons its error
helpers put inside them (bad(), wrong(), out_err(), in_range(), unit(),
read_packed()) were never scanned, so the status bar showed them in
English or mixed two languages.
- Every complete-message catalog gets the rows in a "Plug-in host
messages" section, and the Hindi rows for these messages are fixed.
- The message scan reads the plug-in host's error helpers, and
objects.rs writes its two duplicate-id errors as whole strings.
- message() leaves a captured JSON object or array as written.
- Templates that start with text match before templates that start
with a placeholder, so a wrapping message uses its own row.
A pick in Search Commands ran its command with no params, while the
menu bar item gives the command params and opens a dialog for them.
Clean Up, Create Gradient Mesh, Smart Punctuation, Release Type on a
Path and Deep Ungroup ran at once with their default values, Find and
Replace reported "missing `find`", and Print Ink Fixes reported that it
needs a value. A pick now runs what a click on the menu item runs, so
these open their dialogs and nothing changes until the dialog is
confirmed.
While the menu item is dimmed (Remove Background or Object Mosaic with
no image selected, Find and Replace with no document open), a pick and
a shortcut open no dialog, and the status line says why the command
can't run. Before this, a shortcut of such a command opened its dialog,
and confirming it failed. Both routes use one helper,
shortcut_editor::menu_target_now.
The menu items that helper reads are read once. Items that list an
installed plug-in (File › Open With importers, Object › Plug-ins
filters) are now left out of them, so a plug-in installed or removed
later does not leave an item there that the menu no longer shows.
The element a <use> shows inherits from the <use> rather than from where it
is defined (SVG 2, https://www.w3.org/TR/SVG2/struct.html#UseElement). A
text shown by a <use> now takes the font, size, weight, fill, stroke and
other text properties the <use> or its parents set, in clip paths too,
while the text's own properties still win. Uses with the same parent and
properties share one text. A <use> inside the text it shows is ignored for
inheritance, and texts built for <use> elements stop at 1 MiB of text with
a warning.
A run whose script fails to compile defines no code, so its source map
is not kept and the places of earlier runs stay within the engine's
budget. docs/mcp.md and the progress line say so, and the progress line
names the errors that are reported without a line and column.
Object › Plug-ins › Image Tools gains Color Mask… (`addon.image.colorMask`),
Remove Color Mask and Apply Color Mask. Color Mask hides colors of the
selected images without changing their pixels. It matches colors as Remove
Background does: the edge color, the corner color or picked colors, with
Contiguous, Match, Tolerance and Softness. The mask is kept with the image
object and saved with the document: its settings, and a PNG of the image's
pixels with the hidden colors made clear, at the source's depth with its
color profile and resolution. It is a VectorCraft addition.
- The canvas (clip groups and white-shape opacity masks included),
printing and separations, PDF (soft masks of CMYK images included), SVG,
EPS, the raster formats, the legacy .ai and .ai editing data, EMF/WMF,
DXF and the flattener draw the masked pixels. A linked image stays
linked, and an output that would refer to its file writes the masked
pixels instead.
- Copy and paste, placing a document and placed documents carry the masked
pixels with the image, under the names they are given there.
- The dialog opens on the selected image's mask settings, with a Preview.
Without settings, the command returns them and changes nothing.
- Setting, removing and applying a mask are each one undo step, and no
step is added when nothing changes. Apply makes the masked pixels the
image's own and embeds a linked image. A mask that hides nothing is only
taken off, and the image keeps its pixels and its link.
- When an image's own pixels are replaced (Update Link, Relink, Crop
Image, a recolor, a linked file read again on open), its mask is made
again for the new pixels, in every art tree and in opacity-mask art.
Crop Image cuts the image's own pixels. When the new pixels can't be
masked, the mask keeps its settings and hides nothing.
- Objects in `ids` that are not images, CMYK images, linked images that
show their preview, images past the decode allowance, masks that would
hide every pixel, and grayscale images colorized with a process color
are refused. The Eyedropper, Object Mosaic, Create Gradient Mesh, Crop
Image's trim and Image Trace read the image's own pixels.
- An image is selected by a click anywhere in its frame, as before.
Remove Background now also refuses a grayscale image colorized with a
process color. Its result has an alpha channel, and a process color is
refused on a grayscale image with transparency.
Docs: docs/mcp.md (Image Tools add-on › Color Mask),
docs/target-app-parity.md.
The Window menu checked a panel whenever it was in front in the layout,
even while Tab, Shift+Tab or Presentation Mode hid every panel, so
choosing it, or pressing its function key, closed the panel it was
meant to show.
- A new panel_docking::visible adds the dock and Presentation Mode to
showing. The Window menu's check marks and the toggle use it, and
window.panel puts a flyout or floating panel away only while it can
be seen. With the dock hidden, the dock shows again with the panel in
its earlier place; the toolbar and the Control bar stay as they are.
- In Presentation Mode window.panel fails with "panels can't be shown
in Presentation Mode" and changes nothing.
- reveal_panel, the Gradient and Magic Wand tool double-click, the
Character field shortcuts and the Corner and Shared Edge Merge tool
items show a panel the dock hid instead of reporting it open or
closing a floating Anchor Inspector.
Docs: window.panel params text, docs/mcp.md, docs/target-app-parity.md.
Rewrap the prose in docs/plugins.md whose lines broke well short of
the file's 120-column width or ran past it, including the Safe Mode
sentence, the permission-name and install-confirmation sentences, and
the grants.json paragraph. Each rewrapped line is at most 120 columns.
No words, punctuation, code blocks or tables change.
A linked opacity mask moves with the art it masks, and an unlinked one
stays in place. Geometry effects on a group or layer reshaped its
members but left their linked masks where they were, Free Distort left
a linked mask behind, and an envelope bent unlinked masks too.
- Geometry effects on a group or layer run over the art of the linked
masks of the paths, compound paths and groups inside it, nested and
inverted masks included. Each Transform copy of a masked path carries
its own mask, and an image or symbol instance moved by a Transform
effect carries its linked mask. The effects on an object do not move
that object's own mask.
- When a mask can't take an effect as the art it masks does (a path in
either would pass the geometry budget, or the mask would get fewer
Transform copies), the art and its masks keep their shape under that
effect. Mask art counts toward the budget.
- Free Distort (`object.distort`) warps a linked mask with its object;
the params text says so.
- An envelope bends only a linked mask.
Docs: a line in docs/target-app-parity.md.
The save dialog read the portal's current_filter with zvariant's tuple
conversion, which panics on a structure with fewer fields than the
tuple. On Linux and the BSDs the dialog's thread then ended after the
user picked a file, and nothing was saved. The label is now read only
from a (sa(us)) structure, the shape the FileChooser portal defines.
An answer of another shape keeps the path and names no file type, as
an answer without current_filter does. A structure with more fields
than (sa(us)) also no longer names a file type.