Commit Graph
8609 Commits
Author SHA1 Message Date
BFlat feee0865de Merge pull request #5825 from dotCooCoo/perf/eyedropper-single-stroke
Skip path rebuild for single-stroke Eyedropper samples
2026-11-06 00:08:09 +07:00
dotCooCoo 02f495e647 perf: skip stroke path rebuild for single-stroke samples 2026-11-05 23:55:53 +07:00
BFlat 34627134fa Merge pull request #5824 from dotCooCoo/fix/ai-brush-art-v7-patterns
.ai import: version 7 pattern fills in brush art use their operands
2026-11-05 23:54:52 +07:00
BFlat e442cee522 Merge pull request #5823 from dotCooCoo/perf/library-gradient-once
Avoid measuring selected art twice for library paint
2026-11-05 23:54:35 +07:00
BFlat 59e5fc48ba Merge pull request #5822 from sadkotheguest/fix/5752-pencil-keep-selected
Pencil: a new stroke with Keep selected off leaves nothing selected (#5752)
2026-11-05 23:54:18 +07:00
dotCooCoo 95df6982ee .ai import: version 7 pattern fills in brush art use their operands
A brush's art is read by a reader of its own, which was given the
patterns defined before it but not the record of which of them use the
version 7 form. A fill in that art with such a pattern then ignored its
offset, scale, rotation, reflection and shear operands, and placed the
tiles by the matrix alone. The brush-art reader now receives that record
as well, so those operands place the tiles. A brush whose art has such a
fill without all nine operands is now not read, as other art the reader
can't read whole isn't; before, the brush was kept.
2026-11-05 23:42:07 +07:00
dotCooCoo 934e6cba53 perf: reuse selected paint bounds for library gradients 2026-11-05 23:42:01 +07:00
Alex 9e2e0e0f69 Pencil: a new stroke with Keep selected off leaves nothing selected (#5752)
Drawing a new Pencil or Paintbrush stroke kept the earlier selection: the engine's
`insert_look` selects the new path only when `keepSelected` is on, and with it off left the
selection as it was. Illustrator starts such a stroke by dropping the selection, and the new
stroke is not selected with Keep selected off, so the command now clears the selection after
inserting a new path.

What stays as before: with Keep selected on a stroke selects only the path it draws (the
earlier selection is replaced); a stroke that continues or redraws a selected path with Keep
selected off deselects that path and keeps the rest of the selection. The Blob Brush keeps its
own Keep selected and Merge only with selection options.

`path.freehand`'s documentation, the engine test
`pencil_with_keep_selected_off_leaves_nothing_selected` and the Tool Options test
`the_new_path_is_selected_only_with_keep_selected_on` cover the three cases. Docs: roadmap,
target-app-parity and ui-parity carry the change.
2026-11-05 23:42:01 +07:00
BFlat 5e5b5af8ae Merge pull request #5821 from dotCooCoo/chore/ai-clip-checklist
Docs: the .ai editing-data checklist lists how several clipping paths clip
2026-11-05 23:40:55 +07:00
BFlat 87b5ef7235 Merge pull request #5765 from odysseexp/feat_shape_tools
Add-on: 3D Box tool and context-sensitive customizable shape controls
2026-11-05 23:40:36 +07:00
BFlat 58c882ba60 Merge pull request #5819 from dotCooCoo/fix/app-test-temp-cleanup
Clean up temporary files in desktop tests
2026-11-05 23:40:15 +07:00
BFlat ceee46e4d4 Merge pull request #5818 from dotCooCoo/perf/svg-path-bounds
Skip unused path bounds during SVG export
2026-11-05 23:39:58 +07:00
BFlat e19c1c92a6 Merge pull request #5817 from dotCooCoo/fix/ai-mask-placeholder-uncolored
Images: a colorized image's missing-link placeholder shows in its own colors
2026-11-05 23:39:41 +07:00
BFlat a0103d272b Merge pull request #5815 from Locme/ai-6d-calligraphic-brushes
.ai import: 6D Art Pen brushes open live, and Windows reads pen tilt and rotation (#372)
2026-11-05 23:39:24 +07:00
dotCooCoo d1def50140 Docs: the .ai editing-data checklist lists how several clipping paths clip
The private editing data list in docs/file-format-parity.md now says
that several clipping paths in a clipping group, a layer or an opacity
mask's art clip to their intersection, that a compound path of clipping
paths stays one clip, and that clipping paths that would nest the art
past the document's 32 levels stop the editing data from being read, as
#5789 made the reader do.
2026-11-05 23:25:05 +07:00
Harley Hawk a77b9e37d3 Add customizable shape tools and 3D Box add-on
- Extend vectorcraft-geom::shapes with clean-room open/pie/chord/arc ellipse and rectangle builders, per-corner radii, polygon/star corner rounding and deterministic vertex randomization, logarithmic/Archimedean spiral divergence and inner radius, and perspective/isometric 3D box face builders.
- Isolate 3D Box and customizable shape parameters as a VectorCraft add-on under crates/*/src/**/addons/:
  - crates/tools/src/addons/box3d.rs (Box3dTool and CustomShape extras stored under Node::extras["vc-shape-tools"])
  - crates/engine/src/cmd/addons/shapes.rs (addon.shapes.rectangle, addon.shapes.ellipse, addon.shapes.polygon, addon.shapes.star, addon.shapes.spiral, addon.shapes.box3d, and addon.shapes.configure)
  - crates/ui-egui/src/addons/shapes.rs (Object > Plug-ins > 3D Box > 3D Box Tool and context-sensitive Control bar options)
- Keep crates/engine/src/cmd/create.rs, crates/tools/src/shape.rs, and crates/tools/src/draw2/family.rs byte-for-byte identical to main.
- Add translations for "3D Box" and "3D Box Tool" across all 26 .tsv catalogs in crates/ui-egui/src/i18n/.
2026-11-05 23:25:05 +07:00
dotCooCoo b8155698b5 Remove temporary test files after failures 2026-11-05 23:25:05 +07:00
dotCooCoo edf2b78bc0 docs: record SVG export bounds optimization 2026-11-05 23:25:05 +07:00
dotCooCoo 84904020e8 Images: a colorized image's missing-link placeholder shows in its own colors
A linked 1-bit image mask from a .ai file keeps its fill color as a
colorize paint, so the image takes the color once its file is relinked.
Until then the image shows the missing-link placeholder, and the canvas
and PDF export colorized that placeholder too: its light tile turned
nearly transparent and its red cross took the fill color.

ImageBlob::takes_colorize is false for a preview whose pixels are not
grayscale. While it is false, the canvas draws the image and PDF export
writes it as it is, printed separations separate it as an uncolorized
image, and transparency flattening (EPS, PDF 1.3 and PDF/X-1a export,
Flatten Transparency) does not count its paint as transparency. The
paint stays on the image, and a grayscale preview is still colorized.
SVG and EPS export already write only grayscale images colorized.
2026-11-05 23:25:05 +07:00
Locme a3ec061995 .ai import: 6D Art Pen brushes open live, and Windows reads pen tilt and rotation (#372)
Squashed from #5815 onto main.
2026-11-05 23:25:05 +07:00
dotCooCoo 57bf6de206 perf: skip unused SVG path bounds 2026-11-05 23:25:05 +07:00
BFlat f6e3a44e42 Merge pull request #5811 from dotCooCoo/fix/ai-legacy-tab-stops
.ai import: legacy type keeps its tab stops
2026-11-05 22:38:33 +07:00
dotCooCoo f092b0b7a7 .ai import: legacy type keeps its tab stops
A tab definition in type of the legacy format (`numDots numTabs Xb`, a
`leader decimal tabType tabPosition Xe` for each stop, then `XB`) was
skipped, so every paragraph opened with only the default stops every
36 pt. The stops it describes now become the paragraph's tab stops
(left, center, right or decimal, at their positions), and they last
into the next paragraphs and text objects like the other paragraph
attributes. A definition with no stops, or whose descriptions were all
skipped, leaves the default ones. A description with an unknown type or
a position outside 0 to 100000 pt is skipped, and so is one past the
first 1024 of a definition. A text object's `To` ends a definition that
an earlier object left open.

Docs: docs/file-format-parity.md.
2026-11-05 22:26:49 +07:00
BFlat 7fa35a9bff Merge pull request #5810 from dotCooCoo/fix/mcp-gesture-key-order
Preserve queued key order before MCP tool selection
2026-11-05 22:26:37 +07:00
BFlat 01761ca36f Merge pull request #5809 from dotCooCoo/fix/thumb-flyout-active
Fix thumbnail work for active collapsed flyout tab
2026-11-05 22:26:20 +07:00
dotCooCoo 804d7cee57 fix: preserve queued key order before tool selection 2026-11-05 22:17:33 +07:00
dotCooCoo 869d558d66 fix: follow active flyout tab for thumbnail work 2026-11-05 22:17:33 +07:00
BFlat 550186c582 Merge pull request #5808 from dotCooCoo/feat/ai-active-artboard-reader
.ai import: the file opens on its active artboard
2026-11-05 22:17:23 +07:00
dotCooCoo 456487b873 .ai import: the file opens on its active artboard
VectorCraft now reads `CropAreaActive`, an `/Int` in the dictionary of
the editing data that holds the `ArtboardArray`, as the index of the
active artboard in that array. The reader ignored it before, and every
file opened on its first artboard.

The opened document starts with that artboard active, so the view the
document opens at and the Artboards panel use it. The index counts
every entry of the array, so an artboard that is left out (one with no
area) does not shift it. When the entry is missing, is not an `/Int`,
or names an artboard that does not open, the first artboard is active,
as before. A file that comes in as its PDF part, with its pages placed
where its artboards are, opens on the page of the active artboard, also
when the reading stops before the artboards. The same reader serves the
editing data of EPS and PDF files.

The active artboard is kept on the opened document only; native files
do not save it.
2026-11-05 22:03:55 +07:00
BFlat d6ef516bff Merge pull request #5807 from dotCooCoo/fix/link-classic-mac-path
Links: a classic Mac OS path is named by its file name
2026-11-05 22:00:48 +07:00
BFlat da604a816b Merge pull request #5806 from dotCooCoo/fix/layers-thumbs-close-running-job
Layers: closing a document drops its running thumbnail job's image
2026-11-05 22:00:28 +07:00
BFlat 54c71ab55d Merge pull request #5776 from Hamza0101/feat/paint-fill-to-stroke
Color Effects: Apply Fill to Stroke and Apply Stroke to Fill (#5530)
2026-11-05 22:00:09 +07:00
dotCooCoo 48cf28fe48 Links: a classic Mac OS path is named by its file name
A linked image read from a version 7 `.ai` file can keep its path in
the classic Mac OS form, with colons between folders
(`Macintosh HD:Images:photo.tif`). The link's name was the whole path,
so the Links panel showed it as one long name, and Relink to Folder,
the search of the document's folder and Find Linked Files looked for a
file with that whole string as its name.

A path with a colon and no `/` or `\` is now read as a classic Mac OS
path. Its name is the part after the last colon, and `links.info` gives
the rest as `location`. Relink to Folder, the document-folder search and
`links.findFiles` look for that name, and Find Linked Files compares the
path's folders with the folders of the files it finds. The link keeps
the path as stored. Paths with a `/` or `\` keep those as separators,
so a file name may still hold a colon (`/Users/a/x:y.png`).

Docs: docs/mcp.md (Links), docs/file-format-parity.md (version 7
linked images).
2026-11-05 21:46:43 +07:00
dotCooCoo 8caa0e0e59 Layers: closing a document drops its running thumbnail job's image
A thumbnail job that was running when its document closed still sent
its image back, and the image stayed with the worker until a panel next
collected results. ThumbWorker::forget now drops the jobs of the picked
slots, queued or running, and the Layers panel uses it when a document
closes, keeping the same worker. The close test now goes through
File > Close with no panel drawn afterward.
2026-11-05 21:46:43 +07:00
Hamza 728352269d Color Effects: Apply Fill to Stroke and Apply Stroke to Fill become add-on commands
As asked in review: the reference app has no such commands, so they ship
in the Color Effects add-on. paint.fillToStroke / paint.strokeToFill are
now addon.color.fillToStroke / addon.color.strokeToFill in
cmd/addons/color.rs, listed in Object > Plug-ins > Color Effects instead
of the Color panel menu, with catalog rows in all 26 catalogs.

Two fixes from CodeRabbit's review:
- A graph's series marks and labels give the graph the copied paint in
  the same undo step (capture_series_paints / capture_label_styles, as
  paint.setFill does), so drawing the graph again keeps it. Targets go
  through graph::paint_targets, so a series group stands for its marks.
- A copy that would leave the effective paint as it is skips the object,
  so None copied onto a missing fill or stroke adds no item and records
  no undo step.
2026-11-05 21:46:43 +07:00
Hamza 0db0c7ddae Paint: Apply Fill to Stroke and Apply Stroke to Fill (#5530)
paint.fillToStroke and paint.strokeToFill copy each target's own top fill onto its top stroke, or the other way, so a mixed selection keeps each object's colour. They aim and undo like Swap Fill and Stroke: groups and compound paths by their members, each text run with its own paint, and only the characters the Type tool has selected. A stroke given paint at width 0 gets 1 pt, skipNone leaves objects whose source paint is None alone, and the defaults for new art change the same way. Both are in the Color panel menu after Invert and Complement.
2026-11-05 21:46:43 +07:00
BFlat 2f5d746ee9 Merge pull request #5805 from Silvertree2010/fix/5796-object-path-menu-items-must-not
Disable Object > Path items when no path is selected
2026-11-05 21:46:32 +07:00
bflatastic b700369227 Path menu: the path check stops at the first path it finds 2026-11-05 21:34:32 +07:00
NetterSilverandClaude Haiku 5.5 0001a1c702 Disable Object > Path items when no path is selected
Fixes #5796

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 21:34:32 +07:00
BFlat 8a39f75b5c Merge pull request #5803 from dotCooCoo/chore/read-file-head-test-file
Tests: the read_file_head test creates its file exclusively and removes it on failure
2026-11-05 21:33:54 +07:00
BFlat 37498594d6 Merge pull request #5802 from dotCooCoo/fix/thumb-worker-hidden
Stop queued Layers thumbnails when both thumbnail panels are hidden
2026-11-05 21:33:37 +07:00
BFlat fb6eb76965 Merge pull request #5801 from dotCooCoo/fix/ai-legacy-text-masks
.ai import: legacy type used as a mask clips its clipping group
2026-11-05 21:33:19 +07:00
dotCooCoo 877b3de3ad Tests: the read_file_head test creates its file exclusively and removes it on failure 2026-11-05 21:18:44 +07:00
dotCooCoo 52438c7cea Fix item 1747: stop hidden thumbnail panel jobs 2026-11-05 21:18:44 +07:00
dotCooCoo 6e2a32c2a0 .ai import: legacy type used as a mask clips its clipping group
In the legacy format, `Tr` sets the rendering mode of the type that
follows. Section 5.7 of the version 7 specification says that modes 4 to
7 make the text object a mask: 4, 5 and 6 also fill, stroke, or fill and
stroke it, and 7 paints nothing. Sections 15.3.2 and 15.4.5.1 add that
these modes are used in pattern definitions, and the reader does not
read type in a pattern. The reader painted 4 to 6 like 0 to 2 and never
clipped, so the art a text mask clips showed whole.

A text object with characters in modes 4 to 7 is now a clipping path of
its clipping group (`q` ... `Q`, or the layer), as a path painted with
`W` is, and the whole object is the mask. Beside other clipping paths it
nests as they do, and the mode lasts into later text objects. Area type
with linked areas (threaded frames, also when the reader's limits keep
one frame), and type in wraparound text or in a compound path, a group
inside them included, doesn't clip, with a warning.

A `Tr` operand that is not a whole number from 0 to 9 now leaves the
mode as it was; before, 4.5 read as 4 and -4 hid the type.

The new warning and the reader's warning about linked type areas left
out get rows in every catalog.
2026-11-05 21:18:44 +07:00
BFlat cbb09c70d2 Merge pull request #5800 from dotCooCoo/feat/ai-global-name-suffix
.ai import: gradients and patterns are named up to the newline in their names
2026-11-05 21:18:35 +07:00
dotCooCoo e55c6d9d12 .ai import: gradients and patterns are named up to the newline in their names
The Adobe Illustrator File Format Specification 7.0, section 4 (p. 51),
says the name shown for a global object is the part of its name in the
file before the newline
(https://13thmonkey.org/documentation/fonts/AI7FileFormat.pdf). The
legacy reader kept the whole name, so swatches and patterns came in
named "Sky\n1". The reader now applies this rule to the files of every
version it reads.

- Gradient swatches, gradient fills, pattern definitions, pattern fills,
  palette cells and art-style pattern fills use the part before the
  newline. Lookups inside the reader still use the whole name.
- When that name is taken, the first free "Sky 2", "Sky 3" is used.
  Taken names are None and Registration, the palette's own swatch and
  group names, the default swatches when no palette replaces them,
  named colors (color operators, gradient stops, version 7 pattern
  strings, the header's and an EPS program's custom colors), the names
  of gradients and patterns that have no newline, and the names given
  to earlier gradients and patterns. Only content the reader reads
  counts: not the alternates of versioned content, the prolog, skipped
  sections or what follows the trailer.
- A name with nothing before the newline comes in as "Gradient" or
  "Pattern". Names without a newline do not change.
- docs/file-format-parity.md lists the rule.
2026-11-05 21:06:27 +07:00
BFlat b3193416b1 Merge pull request #5799 from dotCooCoo/fix/action-set-load-bounded-read
Actions: loading an action set checks its size before reading it
2026-11-05 21:04:24 +07:00
dotCooCoo 2cd68fbdcb Actions: loading an action set checks its size before reading it
Load Actions… read the whole file before checking the 8 MiB limit, so
picking a very large file could take a lot of memory before it was
refused. A new read_head service reads at most a given number of bytes;
the desktop app provides it, and loading an action set reads one byte
past 8 MiB with it. A larger file is refused without reading the rest.
Hosts without the service keep reading the whole file. Automation
roots apply to read_head as they do to read.
2026-11-05 20:55:58 +07:00
BFlat d63ce36b05 Merge pull request #5798 from devius/ka-update-2026-11-05
i18n(ka): Georgian for 1 new string
2026-11-05 20:55:50 +07:00