Commit Graph
3872 Commits
Author SHA1 Message Date
dotCooCoo 9703b86074 Merge commit 'refs/check/v4447-main' into fix/blend-pick-resets-on-history-step
# Conflicts:
#	crates/tools/src/meshblend.rs
2026-10-29 06:31:24 -07:00
bflatastic 906e496fbb Keep the existing message 2026-10-29 19:57:59 +07:00
bflatastic bbbc711b6a Fix #4382: the Eyedropper's Alt-click puts what it picked up on the object clicked when nothing is selected
With nothing selected, a click with the Eyedropper picks up an object's attributes and an Alt/Option-click on another object applies them, as the reference app's Eyedropper does. Alt-click only copied from a selected object, and with nothing selected it failed. The session now keeps a copy of what appearance.copyFrom picked up last, and a reversed copy with nothing selected applies it.
2026-10-29 19:57:59 +07:00
bflatastic d3d1e31219 Format 2026-10-29 19:57:58 +07:00
bflatastic a353ad3e7a Fix #4523: a new document's VectorCraft Options start as the last native save used them
Preview, Embed ICC Profiles, Create PDF-Compatible File and the other VectorCraft Options went back to their defaults for every document not saved yet. A native Save or Save As now records the options it used in the preferences (not the artboards it picked, nor Use Compression, which its preference decides), and file.formatOptions offers them for a document not yet saved as a native file. A document saved before keeps its own.
2026-10-29 19:57:57 +07:00
el-j 6e2e0740b0 Isolation mode: breadcrumbs are clickable to navigate hierarchy levels (#4468) 2026-10-29 19:54:35 +07:00
bflatastic 9534a36416 Fix #4538: New Layer and New Sublayer are refused while an opacity mask is edited
While an opacity mask is edited the Layers panel lists only the mask, so a new layer was added where no row showed it, and only the panel's layer count went up. Both commands are now disabled then, as isolation commands already are (outside_mask_editing).
2026-10-29 19:54:34 +07:00
dotCooCoo cdf4453051 Libraries: gradients and patterns can be added to a library and applied from it
Squashed from #4442 onto main.
2026-10-29 19:21:33 +07:00
dotCooCoo c9853094d4 Image Trace: Manage Presets saves, renames and deletes custom tracing presets
Squashed from #4071 onto main.
2026-10-29 19:21:32 +07:00
dotCooCoo e492c4298c Blend: a click picks again when the Blend tool's first pick is gone
Squashed from #4447 onto main.
2026-10-29 19:21:32 +07:00
Taha-Mahmoodi b41599f657 Fix #3089: a stroked line with an effect expands to a stroked line, then Expand outlines it
Squashed from #4169 onto main.
2026-10-29 18:54:59 +07:00
dotCooCoo 3cfdb58b90 Transparency: pattern editing mode and opacity mask editing can't be entered from each other
Squashed from #4458 onto main.
2026-10-29 18:54:45 +07:00
dotCooCoo c8a7420b93 Place: an image whose pixels can't be read is refused instead of placed blank
Squashed from #4257 onto main.
2026-10-29 18:54:38 +07:00
dotCooCoo e764d770db Image Trace: Document Library fills link to the document's global swatches
Squashed from #4396 onto main.
2026-10-29 18:50:56 +07:00
dotCooCoo 74b408e8da Blend: choosing the Blend tool again finishes the blend
Squashed from #4454 onto main.
2026-10-29 18:50:34 +07:00
dotCooCoo 6fd042e4be Tests: the MCP concurrency, folder search and artboard export tests pass on a loaded machine
Squashed from #4473 onto main.
2026-10-29 18:50:24 +07:00
el-j 31a482bade perf(engine): rerun objects_on_path when dimension refresh mutates artwork 2026-10-29 18:46:48 +07:00
el-j 3e70c38d7b perf(engine): gate post-edit Shaper and Text-Wrap maintenance via edited-root diffing (#4554)
- In `shaper::refresh`, replace full document walks with `changed_shaper_groups`,
  diffing `before` and `after` layers and short-circuiting on pointer-equal (`Arc::ptr_eq`)
  subtrees in O(1).
- Return whether Shaper groups rebuilt or modified artwork (`Result<bool>`),
  allowing `Session::edit` to skip the second `cmd::objects_on_path::refresh`
  call when no artwork was modified.
- In `textwrap::refresh`, check pointer equality on layers against `before.layers`,
  skipping untouched layers in O(1) and checking only modified layers.
2026-10-29 18:46:47 +07:00
dotCooCoo d93657c631 Object: Hide Unselected Artwork keeps a selected layer's art and groups that hold locked guides
With a layer selected, Object > Hide > Unselected Artwork hid every object
on that layer, since the selected layer was dropped from the objects to
keep. The objects of a selected layer now count as selected.

While Lock Guides is on, a group that held a guide path was hidden whole,
which hid the guide with it. Guide paths now count as selected, so the
command keeps such a group visible and hides its other members one by one.
2026-10-29 18:46:47 +07:00
dotCooCoo cfdeda35c4 Tests: the non-sRGB Drop Shadow test fails when its child test does not run
svg_darkness_uses_rendered_shadow_in_non_srgb_working_space runs itself
again in a child process with --exact and checked only the exit status.
libtest exits 0 when --exact matches no test, so a rename of the test
would have left the parent passing without running the non-sRGB check.
The parent now also requires "1 passed" in the child's output, as
layout_cache_follows_fonts_added_later in crates/tools does.
2026-10-29 18:45:54 +07:00
dotCooCoo f5d8329cb1 Batch: do not export into a subfolder that holds source files
With `includeSubdirs` and the destination folder the same as the source
folder, the Export for Screens folder of `a.svg` was `a`, and its
`Artboard-1.svg` replaced the source `a/Artboard-1.svg` before Batch
opened it. Batch now keeps the names of subfolders of the destination
folder that hold source files, so that export folder is `a-2`.
2026-10-29 04:43:40 -07:00
dotCooCoo adbb4a4b53 Merge main into feat/native-save-precision
EPS saves, new on main, name `precision` in their warnings as SVG, PDF and .ai saves do.
2026-10-29 04:37:09 -07:00
dotCooCoo cf5ed86729 Merge main into fix/shape-builder-merge-off-ui-thread 2026-10-29 03:59:34 -07:00
dotCooCoo 9ac89ec6f6 Merge main into fix/outline-stroke-keeps-effects-on-outline 2026-10-29 03:55:50 -07:00
dotCooCoo 9a05e8ad36 Batch: do not save over another source file in the destination folder
With the destination folder the same as the source folder, `a..svg` gets
the name `a` and was saved as `a.svg`, replacing the source `a.svg`
before Batch opened it. Batch now keeps the names of the source files in
the destination folder for their own output, so `a..svg` is saved as
`a-2.svg` and `a.svg` is saved over itself.
2026-10-29 03:43:25 -07:00
dotCooCoo efd7f3e97a Blend: a pending pick starts over when the document's history changes
The Blend tool kept its first pick, its clicked anchor and the blend it
was adding to through edits made outside the tool. Picking A, recoloring
other art and clicking B made a blend of A and B; undoing A's creation
left the next click doing nothing.

History::step names the current step by the serial numbers of the newest
undo step and the next redo step. The session keeps the active document's
uid and step from the tool's last pointer event and calls the new
Tool::history_moved at the next pointer event, or before drawing
overlays, when they differ. The tool's own edits are recorded after its
actions; a selection tool lent by Cmd is not told. BlendTool clears its
pick and chain there, as Escape does. A selection change keeps them.
2026-10-29 03:38:35 -07:00
dotCooCoo 8a7d83e00f Batch: number export folders that have the name of a file an earlier source wrote
With the Folder destination, `a.svg` is saved as `destinationFolder/a.svg`.
A later source `a.svg.svg` then got the Export for Screens folder `a.svg`,
which already existed as a file, and its export failed. Batch now numbers a
source's name when its folder or any file it writes in the destination
folder has the name of a file or folder an earlier source wrote, so that
folder is `a.svg-2`.
2026-10-29 02:42:05 -07:00
dotCooCoo e11e7a39d9 Recolor: count left-out art by the colors it shows
A recolor of everything counted a locked or hidden object as left
unchanged when the pass would only have linked it, or the tiles of a
pattern it is filled with, to a swatch of the same color. With
`group`, it also counted one as changed when the group's rewrite only
removed its link to a dropped swatch, and as unchanged when the
rewrite recolored a pattern it is filled with.

The trial pass now leaves out changes to swatch links alone, patterns'
tiles included, and the count compares the colors the object shows,
its patterns' tiles included, before the recolor and after the
rewrite.
2026-10-29 02:37:19 -07:00
dotCooCoo a4ca347692 Shaper: dragging a shape out of a Shaper Group's bounds takes it out of the group
Squashed from #4415 onto main.
2026-10-29 15:16:17 +07:00
dotCooCoo b860a7b9af Direct Selection: a drag from a fill moves only the selected anchors of partly selected paths
Squashed from #4443 onto main.
2026-10-29 15:16:11 +07:00
dotCooCoo 6d66eaf3dc Object: Cmd/Ctrl+Alt+Shift+3 hides every unselected object
Squashed from #4418 onto main.
2026-10-29 15:16:05 +07:00
dotCooCoo dfa9f883c0 Fix Drop Shadow Darkness in source color space 2026-10-29 14:36:41 +07:00
dotCooCoo bb869dd9df Swatches: global swatch edits also update graph designs and the art of brushes
Squashed from #4489 onto main.
2026-10-29 14:36:04 +07:00
bflatastic efc1501ac9 Path: Object › Path › Smooth smooths the selected paths with a slider and Auto-Smooth (#4115) 2026-10-29 13:51:51 +07:00
dotCooCoo 8f377bac81 Batch: drop trailing periods from export folder names before numbering
A source file named `a..svg` gave the folder `a.` and a data set named
`a.` gave `Untitled_a.`. Windows drops a trailing period from a folder
name, so these folders were the same as the ones for `a.svg` and the
data set `a`, and the second export replaced the first one's files.
Batch now passes each name through `safe_file_name` before it numbers
repeated names, so the second folder is `a-2` or `Untitled_a-2`.
2026-10-28 23:35:18 -07:00
dotCooCoo 8a0b796945 Recolor: report the locked and hidden art a recolor of everything left out
When the selection is exactly what select.all takes, recolor.apply and
edit.colors.invert, toCMYK, toGrayscale, toRGB, saturate and
adjustBalance now count the objects select.all left out whose colors
they would have changed: locked or hidden objects, the objects of
locked or hidden layers and sublayers, and objects on locked artboards
(counted as locked). In isolation mode the count covers the isolated
group's members. An object both hidden and locked counts as hidden.
Template layers' art is not counted. Locked and hidden members of a
selected group are recolored as before and are not counted. With any
other selection, or with ids, both counts are 0. Lock and visibility
work as before.

The reply carries notChanged: {locked, hidden}, and a warning when a
count is above 0, which the app shows in the status bar, for example
"Recolor completed; 3 locked objects and 1 hidden object were left
unchanged". A trial pass over the left-out objects finds which ones
would change. In recolor.apply, an object that the group rewrite then
changes is not counted.

The message has rows in the 20 catalogs that translate messages.
docs/mcp.md describes the counts.
2026-10-28 23:05:23 -07:00
Don Omondi 1196d9a335 fix(eps): import bool_or after main's explicit command imports
Main replaced the glob import of the command helpers in fileio/eps.rs
with an explicit list; the EPS Save path's selectedOnly check uses
bool_or, so it is added to that list.
2026-10-29 13:00:49 +07:00
Don Omondi c6070f633e Support original-format EPS Save and Save As 2026-10-29 13:00:47 +07:00
bflatastic 828d784c8c Shape Builder: import replace_leaves in buildcmds/shape_builder.rs (#4299 made the imports explicit) 2026-10-29 13:00:46 +07:00
dotCooCoo f30819b7eb Shape Builder: a merge replaces only the paths it uses, where they are
Squashed from #4094 onto main.
2026-10-29 13:00:46 +07:00
dotCooCoo 6923939460 Document Color Mode: also converts graph designs, graphic styles, opacity masks and brush art
File > Document Color Mode and document.open {colorMode} converted the
colors of the layers, symbols, pattern tiles and swatches only. Graph
designs, graphic styles, the art of opacity masks, the tile that
pattern editing's Cancel puts back and the art of brushes kept their
old color model (only a tint of a global swatch in a graphic style or
a mask followed the swatch), so a CMYK document could still apply,
place or print RGB colors from them.

These now convert with the rest, in the same undo step: their solid
colors, gradient stops, text runs and mesh points, nested masks
included. A Hue Shift brush's key color takes the converted color of
the art color it matches, a tint of a global swatch included. The
brush library is stored again only when one of its colors changed. A
tint of a global swatch in any of these places becomes the converted
swatch's color at its tint, as in the layers. The reply's changed
count covers the colors of the layers, symbols, graph designs, pattern
tiles and opacity masks; the colors of graphic styles and brushes
convert without being counted.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-29 13:00:40 +07:00
dotCooCoo edc2602ae4 Shaper: Shaper Group edits keep the opacity mask and pattern editing layers isolated
While an opacity mask or a pattern was edited, a Shaper scribble and
Object › Shaper › Release and Expand ended isolation, and a Shaper
double-click on a Shaper Group isolated the group's original shapes.
Each replaced the editing layer's isolation while the document stayed
in mask or pattern editing. A click on the Shaper Group's mode widget
did the same through object.isolate.

A scribble, Release and Expand now keep the editing layer isolated in
these modes, and end isolation as before outside them. A double-click
with Shaper selects the original shape under the pointer without
isolating the group's original shapes, and the mode widget does not
show while a mask or a pattern is edited.

Docs: docs/shaper.md, docs/target-app-parity.md.
2026-10-29 13:00:36 +07:00
dotCooCoo fa7df461bc Live Paint: a Live Paint Selection marquee selects the faces and edges it touches
The Live Paint Selection tool acted only on the press, so a drag
selected at most the one face or edge under the pointer. The reference
app selects every face and edge a marquee touches, partly enclosed ones
included, and a Shift-drag adds them to the selection or removes them.

A drag of 3 pixels or more now draws a marquee. On release, select.set
selects the faces and edges it touches, or select.none runs when it
touches none. With Shift held at the press, select.toggle runs with
what it touches, and nothing runs when it touches none. A face that holds the whole marquee counts. Select Fills off
leaves faces out, and Select Strokes off leaves edges out.

A click now changes the selection on release instead of on the press,
so Escape between the press and the release, which also removes the
marquee, leaves the selection as it was. The tool no longer highlights
or selects the faces and edges of a Live Paint group that is locked, on
a locked layer or on a locked artboard, or that is outside the isolated
art in isolation mode.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-29 13:00:33 +07:00
dotCooCoo 5a2e3c3d82 Merge main into feat/character-anti-aliasing-method 2026-10-28 21:55:37 -07:00
dotCooCoo 9cd5e3df8f Save As .ai: place the editing data's art on its artboard and carry it on every page
The editing data wrote art space with its origin at the first artboard's
bottom-left corner, its artboard records lacked keys a reader requires, and
its %%Creator line made the reader measure %AI3_TemplateBox on an
8640-point canvas. Other apps opened the art 3,871.5 points away from its
artboard.

Art space is now ruler space, as in the .ai files users sent: y up from the
first artboard's top-left corner. The artboards together are centered on the
16383-point canvas. Each artboard's record gives its top-left corner there
(RulerOrigin), its pixel aspect ratio (PAR), DisplayMark and whether it is
selected, and %AI3_TemplateBox holds the canvas's center. %%Creator names
the format's app and holds no version number. %AI3_Cropmarks and
%AI3_TileBox give the first artboard, %AI5_ArtSize is 14400 14400, and the
/Document dictionary gives the canvas size.

A file with several artboards carried the data on its first page only, and
other apps opened it as a PDF, page by page. Every page now refers to the
one data dictionary, as the files users sent do.

The format details come from users' own .ai files, static analysis of
Illustrator's program and the user's manual testing in Illustrator.
2026-10-28 21:47:14 -07:00
dotCooCoo 968642da45 Merge main into fix/shape-builder-merge-off-ui-thread
# Conflicts:
#	crates/ui-egui/src/menus/invoke.rs
2026-10-28 21:37:57 -07:00
dotCooCoo d4a30cc084 Brushes: Pattern Brush Options' corner tiles can be None or made from the side tile
Pattern Brush Options has a menu below the Outer Corner Tile and the Inner
Corner Tile. Each can be the brush's own corner art (Original), None, or one
of four tiles made from the side tile at each corner of the path:

- Auto-Centered stretches one side tile around the corner, centered on it.
- Auto-Between bends a side tile on each side into the corner, the two
  meeting on the corner's diagonal.
- Auto-Sliced lays a side tile on each side past the corner and masks it
  at the diagonal, so the two meet like a mitered frame.
- Auto-Overlap lays a side tile on each side past the corner, overlapping.

The tiles are straight at the corner and follow the path towards the side
tiles, so they meet a curve that runs into the corner. A side tile taller
than the corner can reach is stretched along until the two sides meet. On a
short path, a corner's tile is squeezed along so that it covers at most the
path up to an open path's end and half way to the next corner, and its two sides still meet on the
corner's diagonal.

The definition stores the choice as `outer_source` and `inner_source`
(`none`, `autoCentered`, `autoBetween`, `autoSliced`, `autoOverlap`), which
`brush.options` sets. Corner art wins over a source. A brush saved without
a source draws as before: a kind of corner without art takes the other
kind's art. None leaves that kind of corner empty.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-29 11:22:56 +07:00
dotCooCoo 3ea2bba6e3 Blend: Escape drops the Blend tool's first pick
After a click picked the first object with the Blend tool, Escape did
nothing: the pick stayed, and the next click on another object blended
the two. After a blend was made, Escape did not stop the next click
adding to it either.

Escape now drops the object picked first and stops the next click
adding to the blend just made, as a click on empty canvas does, so the
next click picks a new first object. The document and the selection
stay as they are, and no undo step is added.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-29 11:22:56 +07:00
dotCooCoo 7d04096840 Transparency: Make Opacity Mask is off for a targeted layer in isolation mode 2026-10-29 11:20:08 +07:00
dotCooCoo dfe201dec3 Transparency: isolation mode and opacity mask editing can't be entered from each other
Enter Isolation Mode worked while an opacity mask was edited, and Edit
Opacity Mask and View Opacity Mask worked in isolation mode, so each
mode replaced the other's isolated art. In the reference app, isolation
mode can't be entered while a mask is edited, and mask editing can't be
entered in isolation mode.

object.isolate and perspective.editText, which shows type in isolation
mode, are now off while an opacity mask is edited, and a call returns
an error that ends "stop editing the opacity mask first". In isolation
mode transparency.editOpacityMask and transparency.viewOpacityMask are
off, and transparency.makeOpacityMask refuses one target, an object or
a layer, which it would take into mask editing; a call returns an error
that ends "exit isolation mode first". Make Opacity Mask with two
objects still masks one with the other. Pattern editing mode does not
count as isolation mode for these commands.

Object > Perspective > Edit Text, the canvas context menu and the
Transparency panel's menu and Make Mask button follow the commands'
enablement. A click or Alt-click on the mask thumbnail in isolation
mode shows the error and does not edit the mask. While a mask is
edited, the Contextual Task Bar leaves out Isolate, and the Properties
panel's Quick Actions leave out Isolate Group.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-29 11:20:08 +07:00