Commit Graph
3090 Commits
Author SHA1 Message Date
BFlat cebc4ed93e Merge pull request #2093 from dotCooCoo/feat/presentation-mode-artboard-keys
View: in Presentation Mode, the left and right arrow keys and a click go between artboards
2026-10-16 04:21:32 +07:00
BFlat 29bf7b7e06 Merge pull request #2099 from dotCooCoo/feat/artboard-navigator-list
Status bar: the artboard navigator lists the artboards by number and name
2026-10-16 04:21:15 +07:00
BFlat e965c0daa2 Merge pull request #2102 from dotCooCoo/feat/properties-artboard-name-options
Properties: Edit Artboards renames the active artboard and opens Artboard Options
2026-10-16 04:21:00 +07:00
BFlat aaeb658292 Merge pull request #2106 from dotCooCoo/feat/rotate-view-menu
View: Rotate View turns the view to a preset angle, and `view.rotate` sets any angle
2026-10-16 04:20:42 +07:00
BFlat d541eb9476 Merge pull request #2116 from dotCooCoo/feat/export-screens-selected-artboards
Export for Screens: the dialog opens with the Artboard tool's selected artboards checked
2026-10-16 04:20:26 +07:00
BFlat cf0be249ba Merge pull request #2134 from dotCooCoo/feat/free-distort-dialog-corners
Effects: Free Distort's corners are dragged in its dialog
2026-10-16 04:20:09 +07:00
BFlat 0594f04e30 Merge pull request #2136 from dotCooCoo/feat/color-panel-options-command
Color panel: Hide Options comes back after a restart, and `ui.colorPanel` sets the mode and options
2026-10-16 04:19:47 +07:00
BFlat b15c28b7c0 Merge pull request #2138 from dotCooCoo/fix/glowing-edges-raster-stylize
Effect menu: Glowing Edges moves to a Stylize submenu under Raster Effects
2026-10-16 04:19:23 +07:00
BFlat fc51d66659 Merge pull request #2140 from dotCooCoo/feat/save-template-ait
Templates: Save as Template can also write a PDF-compatible .ait
2026-10-16 04:19:04 +07:00
dotCooCoo 697f238b60 View: in Presentation Mode, the left and right arrow keys and a click go between artboards
In Presentation Mode the arrow keys moved the selection, and the
active tool received a click and selected or drew as it does in
Normal Screen Mode. No key or click moved the view to another
artboard.

Left Arrow and Right Arrow now go to the previous and the next
artboard, and a click anywhere goes to the next one, through
view.goToArtboard, as the status bar navigator's Previous and Next
buttons do. On the first artboard Left Arrow leaves the view as it
is, and on the last artboard Right Arrow and a click leave it as it
is. No arrow key moves the selection in the mode, and the tool gets
no press, drag or hover, so a click selects and draws nothing. A drag
with the middle button or with Space held no longer pans the view
there; the mouse wheel still zooms and scrolls it.

Docs: docs/target-app-parity.md.
2026-10-16 04:04:50 +07:00
dotCooCoo 8ca25c955e Status bar: the artboard navigator lists the artboards by number and name
The status bar's artboard navigator showed only the active artboard's
number between its first, previous, next and last buttons, and it had
no list of the artboards.

The number is now a drop-down field that shows the active artboard's
number and name. Its list shows every artboard by number and name, as
the Artboards panel lists them. Choosing one runs view.goToArtboard,
the command the buttons run, which makes that artboard the active one
(and the Artboard tool's, while that tool is in use) and fits it in
the window. The list lays out only the rows in view and at most one
more, and opens with the active artboard's row in view. In a test
build with 1,000 artboards, the two frames that open the list take
0.12 ms and 0.04 ms, and a frame with the list open takes 0.03 ms. The
timed frames are headless and draw only the status bar.

Docs: docs/target-app-parity.md.
2026-10-16 04:04:50 +07:00
dotCooCoo 5a5f1a0995 Properties: Edit Artboards renames the active artboard and opens Artboard Options
With the Artboard tool, the Properties panel showed the active
artboard's name as a label, and no control in the panel opened
Artboard Options.

The name is now a text field. Typing a new name and pressing Enter or
clicking elsewhere renames the active artboard in one undo step
through artboard.setProps, as the Artboards panel's rename does;
pressing Escape or leaving the field empty keeps the old name. A click
on the Artboard Options icon beside the field runs tool.options with
tool "artboard", which opens Artboard Options for the active artboard,
as a double-click on the Artboard tool's button does.

Docs: docs/target-app-parity.md.
2026-10-16 04:04:50 +07:00
dotCooCoo 799155cdd0 View: Rotate View turns the view to a preset angle, and view.rotate sets any angle
In the View menu, Reset Rotate View was the only rotation item. The
status bar's angle menu set its twelve preset angles by writing the
view's rotation itself, and no command took an angle to turn the view
to.

View › Rotate View now lists the status bar's angles (0°, 15°, 30°,
45°, 60°, 90°, 180°, -15°, -30°, -45°, -60° and -90°) and checks the
one the view is turned to. The new UI command `view.rotate {angle}`
turns the view to any angle about the center of the canvas and
returns the angle it set, normalized to (-180, 180] as a Rotate View
drag normalizes it. The menu's items and the status bar's angle menu
run it from one list of angles; the status bar sets the same angles as
before. Without a document the command returns "no document" and the
items are disabled. Run from the command palette, which passes no
angle, Rotate View opens a dialog that asks for the angle, with the
view's current angle filled in.

The de, it, ja, ko, pl, pt-br, ru, uk, vi and zh-hant catalogs have a
new "Rotate View" row. The strings the catalogs cover leave out the
angle labels, as they leave out Type › Size's point sizes.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-16 04:04:49 +07:00
dotCooCoo 1f6ef9dcf3 Export for Screens: the dialog opens with the Artboard tool's selected artboards checked
Export for Screens opened on the artboard choice the document last
exported with (all artboards by default), whichever artboards were
selected with the Artboard tool or in the Artboards panel.

While the Artboard tool is in use, File › Export › Export for Screens…
now opens with the artboards the tool has selected checked, and Export
Artboard writes only those. They are the artboards the Artboards panel
highlights, and they are checked even after a Full Document export.
With another tool in use, the dialog still opens on the saved artboard
choice. The other fields show the saved settings in both cases, and the
params text of file.exportForScreens describes the rule.

Docs: docs/control-protocol.md, docs/target-app-parity.md.
2026-10-16 04:04:49 +07:00
dotCooCoo fc0e926cda Effects: Free Distort's corners are dragged in its dialog
Free Distort's dialog showed the four corners as read-only text, and
so did the Appearance panel's inline editor. Only effect.apply and
effect.setParams could set them.

The dialog now shows a box in the proportions of the first selected
object's bounds with a handle on each corner. Dragging a handle moves
that corner, and the preview follows. A handle focused by a click or
Tab moves 1% of the box with each arrow key, and 10% with Shift. Reset
puts the four corners back on the box. Each handle has a
screen-reader name. On the corners row of the Appearance panel's
inline editor, Edit… opens the dialog.

Docs: docs/effects-parity.md, docs/target-app-parity.md.
2026-10-16 04:04:49 +07:00
dotCooCoo 940f425a01 Color panel: Hide Options comes back after a restart, and ui.colorPanel sets the mode and options
Show Options and Hide Options were kept in egui's temporary memory, so
the Color panel showed its options again after every restart. No
command set them or the panel's mode.

- `UiState::color_hide_options` holds Hide Options and is saved with the
  preferences. Its reader reads `true` as hidden and any other value as
  shown, so a bad value leaves the other preferences as they are.
- `ui.colorPanel {mode?, options?}` picks a mode as the panel menu does
  (the active color converts to the mode's model as one undo step) and
  shows or hides the options. It answers `{mode, options, shown}`. A mode
  the menu does not list, `lab` included, answers an error. The panel
  menu's Show Options and Hide Options call the command's function.
- `ui.inspect` reports the setting as `ui.color_hide_options`.

Docs: docs/control-protocol.md, docs/target-app-parity.md.
2026-10-16 04:04:49 +07:00
dotCooCoo ea59b066d4 Effect menu: Glowing Edges moves to a Stylize submenu under Raster Effects
On main, Glowing Edges… is listed in the Effect menu's vector Stylize
submenu, after Drop Shadow, Inner Glow, Outer Glow and Feather. The
reference app lists it in the Stylize submenu of its Photoshop effects,
below the vector effects.

The Effect menu now has a Stylize submenu under Raster Effects, between
Sharpen and Texture, and Glowing Edges is listed there. The menu sends
the effects at the Stylize path that PIXEL_EFFECTS names to that
submenu, and the vector Stylize submenu keeps its six effects. The
effect's id, its catalog entry, its effect.list entry and Apply Last
Effect do not change.
2026-10-16 04:04:49 +07:00
dotCooCoo 427cd65f30 Templates: Save as Template can also write a PDF-compatible .ait
File › Save as Template always wrote a .vctemplate. The save panel
offered only that type, file.saveAsTemplate ignored its format param,
and a name typed with .ait got .vctemplate added. New from Template
already opened a .ait as an untitled document.

Save as Template now also writes a .ait: the PDF-compatible file Save
As writes for .ai, carrying the document. The desktop save panel lists
VectorCraft Template first and the .ait type beside it, and the web
build's Save as Template dialog gets a Format menu with the same two
types. file.saveAsTemplate writes .ait for format: "ait", or for a path
ending in .ait when no format is given, and takes the .ai options;
file.formatOptions answers for ait. .vctemplate stays the default.
Exports and Export As still do not write .ait.

Docs: docs/mcp.md, docs/file-format-parity.md (.ait row),
docs/target-app-parity.md.
2026-10-16 04:04:49 +07:00
BFlat ed96a12196 Merge pull request #2201 from dotCooCoo/fix/paste-copied-svgz
Clipboard: a .svgz file copied in a file manager pastes as its art
2026-10-16 04:02:01 +07:00
BFlat be97caf90b Merge pull request #2148 from dotCooCoo/fix/paste-ai-file
Clipboard: a .ai or .ait file copied in a file manager pastes as its art
2026-10-16 04:01:44 +07:00
BFlat c48aba77e3 Merge pull request #2149 from dotCooCoo/fix/postscript-message-and-params
PDF/.ai import: the PostScript file error names File › Open and File › Place, which read the file
2026-10-16 04:01:28 +07:00
BFlat 6a56c7a5f6 Merge pull request #2202 from EricKuck/fix/pdf-shading-curve-stops
PDF import: an axial or radial shading keeps its function's curve when sampled into stops
2026-10-16 04:01:11 +07:00
BFlat 4a6d52e7ea Merge pull request #2218 from dotCooCoo/fix/same-value-spot-inks
PDF/.ai import: spot inks with the same values and different names keep their own swatches
2026-10-16 04:00:54 +07:00
BFlat fda7c9fae3 Merge pull request #2129 from dotCooCoo/fix/pdf-page-user-unit
PDF/.ai import: a .ai whose page has a UserUnit opens with its layers at the page's size
2026-10-16 04:00:36 +07:00
BFlat 0b10aa67a8 Merge pull request #2199 from dotCooCoo/fix/ai-cmyk-images-keep-samples
.ai import: CMYK images in the editing data keep their ink amounts
2026-10-16 04:00:18 +07:00
BFlat 2133a21096 Merge pull request #2051 from EricKuck/fix/ai-mesh-edge-points
AI import: a gradient mesh patch's edges bend through the anchors listed between its corners
2026-10-16 03:59:59 +07:00
BFlat ca8fb9a543 Merge pull request #2058 from EricKuck/fix/ai-pattern-gradient-canvas
AI import: a gradient in a pattern's definition is placed from the canvas, as the file's PDF part draws it
2026-10-16 03:59:49 +07:00
BFlat faba555c63 Merge pull request #2052 from EricKuck/fix/ai-styled-object-keeps-look-transparency
AI import: a styled object read in place of its drawn look keeps the transparency written on the look
2026-10-16 03:59:31 +07:00
BFlat 97d7e7488a Merge pull request #2050 from EricKuck/fix/ai-blurred-art-drawn-look
AI import: a drawn look that is an image stands for its object, as one of paths does
2026-10-16 03:59:15 +07:00
BFlat 029ab098a3 Merge pull request #2046 from EricKuck/fix/ai-clip-path-in-group
AI import: a clipping path alone in a group clips the clipping group around it
2026-10-16 03:58:57 +07:00
BFlat 2422d0ea5b Merge pull request #2030 from midasmatterhorn/fix/issue-2004-ai-opacity-mask
eps: an opacity mask in the editing data is named, not drawn whole (#2004)
2026-10-16 03:58:38 +07:00
BFlat e24edbab41 Merge pull request #2029 from midasmatterhorn/fix/issue-2003-ai-layer-opacity
eps: a layer's own transparency in the editing data is read (#2003)
2026-10-16 03:58:21 +07:00
BFlat 16af375873 Merge pull request #2060 from Silvertree2010/fix/2005-pdf-ai-import-a-document-with-on
Open PDFs and .ai files with an image over 256 MB decoded
2026-10-16 03:58:01 +07:00
dotCooCoo c246fc2f0e Clipboard: a .svgz file copied in a file manager pastes as its art
Paste takes a file copied in a file manager by its flavor, which
file_flavour tells from the file's first 4,096 bytes through
fileio::detect. detect names gzip data SVGZ unless it is a compressed
native file, and file_flavour gave no flavor for the format id svgz.
So a copied .svgz file did not paste as its art, although
clipboard.importSvg, the SVG flavor's command, reads SVGZ data.

A copied file whose gzip data unpacks to SVG markup now pastes through
the SVG flavor. file_flavour unpacks the head it is given with the
gzip decoder the SVGZ reader uses, up to where the head ends, and
checks the first 4,096 unpacked bytes with looks_like_svg, as detect
checks an uncompressed file, reading them as UTF-16 after a UTF-16
byte order mark. Other gzip files get no flavor, as before.

Docs: docs/target-app-parity.md.
2026-10-16 03:36:20 +07:00
dotCooCoo c5a1504e99 Clipboard: a .ai or .ait file copied in a file manager pastes as its art
Paste takes a file copied in a file manager by its flavor, which
file_flavour tells from the file's first 4,096 bytes through
fileio::detect. detect names PDF or PostScript bytes in a file called
.ai or .ait by that extension, and file_flavour gave no flavor for
the format ids ai and ait. So a copied .ai or .ait file did not paste
as its art, while the same bytes in a .pdf or .eps file did.

A copied .ai or .ait file whose bytes are a PDF now pastes through the
PDF flavor (clipboard.importPdf), and one whose bytes are PostScript
pastes through the EPS flavor (clipboard.importEps). Other files
with those extensions paste as before. A .ai saved without its PDF
part also gets the PDF flavor, and Paste answers it with
clipboard.importPdf's error, as it does for the same file named .pdf.

Docs: docs/control-protocol.md, docs/development.md,
docs/target-app-parity.md.
2026-10-16 03:36:20 +07:00
bflatastic b9341d3b3b i18n(bg): the PostScript file error names File › Open and File › Place 2026-10-16 03:36:20 +07:00
EricKuckandClaude Opus 5.5 f3b4c3ec78 PDF import: an axial or radial shading keeps its function's curve when sampled into stops
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 03:36:20 +07:00
bflatastic 136810bee2 PDF/.ai import: the tint transform test passes no ink names to space_of 2026-10-16 03:36:20 +07:00
bflatastic 90e6ff3de1 PDF/.ai import: the tests added on main pass the page's unit to layered_ai 2026-10-16 03:36:20 +07:00
dotCooCoo dc179c3671 .ai import: CMYK images in the editing data keep their ink amounts
When a .ai file, or an EPS with editing data, opened from its editing
data, the reader converted each embedded 8-bit CMYK image to RGB and
stored it as a PNG, so the document lost the image's ink amounts. When
the same .ai opens from its PDF part, the PDF importer keeps them in a
CMYK TIFF.

The reader now stores those samples with ImageBlob::cmyk_tiff, as the
PDF importer does (crates/pdf/src/import_image.rs). An alpha channel
that hides part of the image becomes the image's opacity mask, a
grayscale image over it, as in PDF import. Grayscale, RGB and 1-bit
images still open as RGBA PNGs.

Docs: docs/file-format-parity.md, docs/target-app-parity.md.
2026-10-16 03:36:20 +07:00
bflatastic 8af0459232 AI import: a gradient mesh keeps at most 65,536 points, however its patches are cut 2026-10-16 03:36:20 +07:00
EricKuck e93ba4c83f AI import: a gradient in a pattern's definition is placed from the canvas, as the file's PDF part draws it 2026-10-16 03:36:20 +07:00
EricKuckandClaude Opus 5.5 9ebd30b8bb AI import: a styled object read in place of its drawn look keeps the transparency written on the look
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 03:36:20 +07:00
dotCooCoo 31ffbb2152 PDF/.ai import: the PostScript file error names File › Open and File › Place, which read the file
document.pdfInfo and clipboard.importPdf, given a PostScript file (an
EPS, or an .ai in an older PostScript format), failed with "this is a
PostScript file (...), which can't be opened yet: save it as PDF,
PDF-compatible .ai or SVG". document.open and file.place read the same
file through the EPS reader. The error told users to convert a file that
VectorCraft opens.

The error now says the file is not a PDF and that File › Open and
File › Place read it as EPS. The 13 catalogs that carry the message get
the new text.
2026-10-16 03:36:20 +07:00
dotCooCoo ca145c5265 PDF/.ai import: spot inks with the same values and different names keep their own swatches
A PDF can define spot inks that have different names and the same
alternate space and tint transform, such as Blue1 and Blue2, both RGB
0 0 255. The interpreter drops the ink name, so the importer matches an
interpreted color to the file's Separation and DeviceN spaces by the
tint transform. The spaces of two such inks matched the same color, so
their paths imported as plain RGB and neither ink became a spot swatch.
This happened with both inks on one page, with each on its own page,
and in the PDF part of a .ai file.

The page walk in import_scan.rs, which follows the interpreter's order
for layers and overprint, now also records the ink of each path, from
the color space set by cs and CS or from the shading of the pattern set
by scn and SCN or drawn by sh, and the ink of the color space of the
text between two paths. When the spaces of several inks match a color,
the importer takes the space with the walk's ink names. It applies
these names to a page only when the page uses such an ink and a
counting pass of the interpreter draws as many paths there as the walk
counted. Otherwise the import works as before.

The file now opens with a spot swatch for each ink. Solid fills and
strokes of paths and type, and the stops of gradients on paths, link
to the swatch of their ink, the points of a gradient mesh keep the
ink's color, and PDF export writes each ink as its own separation.
Paint in these inks inside pattern cells, soft masks and type 3 glyphs,
and gradients on type in these inks, still import as RGB. Type in one
of these inks can also import as RGB when type in another Separation or
DeviceN ink is shown with no path drawn between them.
2026-10-16 03:36:20 +07:00
dotCooCoo 16b8aeb6b7 PDF/.ai import: a .ai whose page has a UserUnit opens with its layers at the page's size
A PDF page's UserUnit (PDF 1.6) sets the size of its user space unit
in multiples of 1/72 inch. The PDF reader has applied it since #1894, so
a page with /UserUnit 10 and a 36 × 50.4 media box opens at 360 × 504
pt. A .ai whose editing data has its artboards in the page's own units
then no longer matched its PDF part. It opened from the PDF part,
without its layers, its hidden objects and the art outside its
artboards, and with its artboards in a row instead of where the
editing data puts them. document.pdfInfo gave such a page's size in
points and its boxes in the file's numbers.

Editing data whose first artboard has the page's size in the page's
units, and not in points, is now compared with the PDF part scaled
down by the UserUnit. The document read from it is then scaled up by
the UserUnit, with its stroke weights, dashes, effects and pattern
tiles. When the layers can't be read, the artboard layout taken from
the editing data is scaled the same way. document.pdfInfo gives the
boxes in points, as it gives the size.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-16 03:36:20 +07:00
EricKuckandClaude Opus 5.5 76888366e7 AI import: a mesh patch's anchors run in the mesh's direction whatever their key
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 03:36:20 +07:00
EricKuckandClaude Opus 5.5 1682d59b65 AI import: a gradient mesh patch's edges bend through the anchors listed between its corners
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 03:36:20 +07:00
EricKuckandClaude Opus 5.5 6545d8b886 AI import: a drawn look that is an image stands for its object, as one of paths does
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 03:36:19 +07:00
EricKuckandClaude Opus 5.5 fb6fc437c3 AI import: a clipping path alone in a group clips the clipping group around it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 03:36:19 +07:00