Commit Graph
439 Commits
Author SHA1 Message Date
Dylan M. TaylorDylan M. Taylorcoderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
125df6d8ec G9: Preserve supplied passwords when confirming the Save PDF dialog (#3836)
Co-authored-by: Dylan M. Taylor <277927+dylanmtaylor@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-10-23 10:15:23 -04:00
Taha-Mahmoodi 64f6d2db50 Artboards: Artboard Options' Show Center Mark and Show Cross Hairs draw on the canvas
The Artboard Options help pages describe two display options
(https://helpx.adobe.com/illustrator/desktop/create-manage-artboards/organize-manage-artboards/modify-display-settings-of-artboards.html,
.../set-video-display-options-for-artboards.html): a mark at the artboard's
center, and lines from the middle of each side through the center. The
document already had show_center_mark and show_cross_hairs on Artboard, but
nothing set or drew them.

artboard.setProps (each `artboards` entry too) and artboard.new take
showCenterMark and showCrossHairs as true/false, in the same single undo
step as the other fields; a locked artboard can still change them.
Artboard Options has both checkboxes, filled in from the artboard whether
it opens from the panel or a double-click with the Artboard tool, and its
New Artboard form passes them to artboard.new. The canvas draws them in the
new theme token artboard_mark, 1 point wide on screen at any zoom: a cross
12 points across at the center whose arms follow the artboard's sides, and
the two cross hairs. They are screen-only like the edges; exports and print
never read the fields. inspect_document reports them when on. Saved files
are unchanged: the two keys were already always written, so a document that
never shows them saves byte for byte as before, and a file without the keys
opens with both off. Video safe areas, video rulers and the pixel aspect
ratio are not part of this change.

Verification: artboard_display_marks_are_set_and_cleared_in_one_undo_step,
artboard_display_marks_round_trip_through_the_native_format,
artboard_display_marks_stay_out_of_exports (SVG and PDF identical with the
marks on and off), an_artboard_shows_its_center_mark_and_cross_hairs
(positions, screen-constant size under zoom, rotated view) and
artboard_options_show_center_mark_and_cross_hairs. cargo xtask ci: all 10
steps passed.
2026-10-23 09:42:09 +07:00
Taha-Mahmoodi 08cfb45561 Simplify: Object › Path › Simplify opens its slider at the Auto-Simplify level for the selection
The Simplify help page says the slider starts at an auto-simplified value
(https://helpx.adobe.com/illustrator/desktop/draw-shapes-and-paths/modify-paths/manually-simplify-paths.html).
The slider opened at a fixed level 50 (1 pt), whatever the size of the
selection, so the first preview was the same tolerance for a 30 pt icon as
for a 1000 pt drawing.

The level Auto-Simplify picks for the selection is now one engine function,
vectorcraft_engine::auto_simplify_level (the existing 1/400-of-the-longer-
side rule in vectorcraft_pathops), which object.path.simplify {auto: true}
and the slider's opening fields both use. Object › Path › Simplify (and
ui.menuDialog, the Properties and contextual task bar buttons, which go
through the same menu dialog) opens the slider there, and the canvas
previews that result; Auto-Simplify still moves the slider back to it.
The retained Simplify dialog path is unchanged.

Verification: simplify_slider_opens_at_the_auto_simplify_level_of_the_selection
opens the slider on 1140, 285 and 28.5 pt waves (levels 35, 55, 89) and
checks the preview is exactly object.path.simplify {auto: true}'s result;
without the change it fails with level 50 != 35, and
simplify_opens_a_slider_whose_drag_previews_fewer_or_more_points fails with
{"level": 50} != {"level": 55}. cargo xtask ci: all 10 steps passed.
2026-10-23 09:42:07 +07:00
dotCooCoo ddaca94e5c Export for Screens: files are encoded and written on the background thread
Export for Screens and the Asset Export panel's Export encoded and wrote
every file on the UI thread, so the window stopped responding until the
last file was written. For 50 artboards in PNG at 1x, 2x and 3x, PDF and
SVG (250 files, 47 MiB), the dialog's OK took a median of 43.8 s in a
release build on Windows.

With Enable Background Export on (Preferences › File Handling), OK now
checks the settings, remembers them and takes a snapshot of the
document, and the dialog closes. The thread that writes background
saves and exports then encodes the files and writes them into the
folder, or one ZIP in it, and the export progress dialog's Cancel stops
it before the next file. The same OK takes under 0.001 s, and the files
have the same names and bytes. With the preference off, without a
folder, on the web and over MCP and scripts (document.exportForScreens
and assets.export), the files are made at once with the same reply as
before.

Both commands report one progress step per file, so the progress dialog
shows "File 3 of 250" and MCP progress notifications count the files in
place of the encoders' artboards and pages.

Docs: docs/target-app-parity.md, docs/control-protocol.md, docs/mcp.md.
2026-10-23 09:22:20 +07:00
dotCooCoo 5fe4f3ead1 Place: files are read and decoded on a background thread
Squashed from #3740 onto main.
2026-10-23 09:07:55 +07:00
Angelo Bernardini ef1fa1d228 G12: Constrain Angle for the arrow keys, Shift drags and new objects (#394)
Squashed from #3363 onto main.
2026-10-23 08:54:57 +07:00
Louise FoxandClaude Opus 5.5 79cb38f678 Plug-ins: heavy filters, allowed at install and run in the background (G17)
A filter plug-in gets 50 M instructions and a minute for each run.
Filters that order a plotter's paths, pack shapes or run a simulation
need minutes, and the app shouldn't freeze while they compute.

A filter's manifest may now ask for "budget": "heavy" (Budget): each run
gets HEAVY_FUEL (1 G instructions) and HEAVY_WALL_TIME_MS (300 s). Only a
filter may ask. plugin.install refuses such a filter without allowHeavy:
true, and plugin.inspect returns the entry a module would have without
installing it. Install Plug-in… and File › Open ask the user and install
on OK; the plug-in store keeps the answer, and folder loads skip heavy
filters with a note, since they ask nobody.

The app runs a heavy filter on a thread of its own (plugin_runs), not in
Background Save's queue, with the status bar and a progress window
(Cancel, Continue in Background) that it shares with Background Export
(export_progress::window). FilterRun splits plugin.run: prepared on the
session, run on any thread, its output handed in, and the next
plugin.run with the same params applies that output instead of running
the plug-in again, so the edit stays one guarded, journaled command. A
result whose document or plug-in changed meanwhile is dropped, and the
status bar says to run it again. A cancelled plug-in run is now
EngineError::Cancelled.

What a filter keeps with the document (#3720) goes with the run: it is
given _context.documentData when the run is prepared, and the
documentData of its output is applied with its objects, in the same undo
step, when the run is handed in (FilterRun::finish).

Tests: plugins/tests/abi.rs (100 M loop steps out of a light budget,
within a heavy one; folders skip heavy filters), manifest.rs, engine
tests_plugins.rs (consent, inspect, the store, hand-in, a handed-in
run's document data, cancel) and
ui-egui tests_plugin_runs.rs (installing asks, no Preview, a background
run as one undo step, a stale result kept out, the progress window).
CRAFT_UI_HEAVY_FILTER_WASM=<folder> writes a test filter to try in the
app. Its strings and messages have rows in each complete catalog
(COMPLETE_MESSAGES).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhvnnnD5fTFupK8WWq35un
2026-10-23 08:18:47 +07:00
Angelo Bernardini 3f16fabd89 G11 #885: Transform effect options (Transform Objects, Transform Patterns, Scale Strokes & Effects)
Squashed from #3358 onto main.
2026-10-23 06:07:37 +07:00
FractalEncrypt a6c0911d72 G1: Honor artwork scaling in Artboard Options size changes 2026-10-23 04:48:28 +07:00
skylar taylor-barrick f39c9544eb #1490: test that selected text in value fields is in the strong text colour
Selected text in a value field was drawn in the accent on a selection tinted with the same accent, hard to read in every brightness. The tests focus a panel number field and a dialog text field, select their text and read the colours of the glyphs drawn, in all four brightnesses: all must be the strong text colour. Without strong_selected_text the glyphs come out in the accent.
2026-10-23 03:33:30 +07:00
makesomethingshit 6a394c3a6f #3607: follow the active artboard with every tool 2026-10-23 01:53:47 +07:00
makesomethingshit 4d9749f4c7 #3607: open Save for Web on the active artboard 2026-10-23 01:53:35 +07:00
bflatastic efe2429618 Shape Builder: in merge mode, a click on a stroke splits the path there
Squashed from #3665 onto main.
2026-10-23 01:53:34 +07:00
BFlat ab330e4adc Merge pull request #3649 from nrq6993-a11y/stream/vc-feat3-g4-mixed-hyphenation-dialog
G4: Mixed Hyphenation dialog fields
2026-10-23 00:10:09 +07:00
bflatastic 329916c2b8 G4: Mixed Hyphenation dialog fields
Squashed from #3649 onto main.
2026-10-22 23:46:14 +07:00
dotCooCoo 4a4c8c9d49 Package: a file the writer refuses is named once in the error
File › Package… put the file's path in front of every error its writer
returned. A refusal from the automation write root already names the
path, so the dialog's error and the status bar named the file twice,
for example on Windows for a document named aux:
`<path>: automation path rejected: reserved device names are not
allowed: <path>`.

The dialog now keeps a writer error that already contains the path as
it is, and puts the path in front of one that does not, such as the
desktop's "Access is denied. (os error 5)".
2026-10-22 23:36:57 +07:00
bflatastic a99d81e9aa Fix Spiral tool click options dialog
Squashed from #3636 onto main.
2026-10-22 22:57:26 +07:00
Taha-Mahmoodi bd6d076484 Effects: Sketch › Conté Crayon draws the dark areas in a black crayon and the light areas in a white one on textured paper 2026-10-22 21:18:34 +07:00
Taha-Mahmoodi 28ac044c74 Fix #3370: stepping a number field stops at its bounds: a stroke weight at 0, a miter limit at 1
Wheel notches and the arrow keys over a focused number field step the
value its text shows (widgets::step_value), and nothing there knew the
field's bounds: the Stroke panel's Weight went on to -3 pt and its Limit
to 0 x in the field, while the panel only clamped what it applied (the
spinner's min, Limit's clamp to 1..500), so the next step went on from
the out-of-range text. A label scrub (scrub::field) had the same gap.

step_value and scrub::field now take the field's bounds and stop at
them, so the field shows where they stopped and the value applied is
the same. The fields that have bounds pass them:
- spin_field / spin_field_auto / spin_plain: their `min` (the spinner
  and a typed value already stopped there);
- range_field: its range; it now also takes a value that may be blank
  (None), as mixed_field does;
- opt_field (dash and gap lengths): 0;
- the Revolve dialog's values: their range.
Fields that clamped only what they applied now say their range with
range_field instead: the Stroke panel's Limit (1..500), the Transparency
and Properties opacity (0..100), the Transform panel's polygon sides,
and the dialogs' bounded counts, percentages and lengths (Blend Options,
Envelope, Flattener, Liquify, Freehand, Live Paint, Path ops, Perspective
Grid, PNG ppi, Print, Save for Web, Shape Builder, Slices, Swatch
Options, Symbol options, Justification, Dimension, PDF page, the effect
dialogs' number rows). docs/ui-parity.md's number-field row says so.

Test: panels::stroke::tests::the_wheel_stops_weight_at_zero_and_limit_at_one
(the Stroke panel in a headless frame; focus Weight at 1 pt and turn the
wheel down four notches: the field shows 0 pt and the stroke is 0 pt;
the same with Limit at 2 x: 1 x and a limit of 1). It fails without the
change (the field showed -3 pt) and passes with it; the other numeric
field, scrub and dialog tests still pass.
2026-10-22 18:56:33 +07:00
dotCooCoo cbf2d9cc43 Export: a typed extension of a format the export doesn't write is replaced
An export through the desktop save panel kept any typed extension
that names a known format, whatever format it wrote. Export As with
PNG chosen and card.svg typed wrote PNG data to card.svg, and Save as
PDF, Save for Office Documents, Text Export Options, Export Library
and the other writes that go through pick_path did the same.
document.exportSelection with a format suggested and added .png
whatever the format.

Such an extension is now replaced with the written format's, as Save
As has done since #3372: card.svg is written as card.png. An extension
of the written format stays as typed in any letter case (photo.JPEG
for JPEG), Export As SVG (and file.exportAs, file.export.svg) keeps
art.svgz and writes it compressed, and document.exportSelection
without a format still writes the format the typed extension names.
With a format, it suggests and adds that format's extension.

Docs: docs/target-app-parity.md.
2026-10-22 18:13:11 +07:00
dotCooCoo 052bbb14b4 Package: File › Package collects and writes the package on the background thread
File › Package… read every linked file and font and wrote the package
on the UI thread, so the window stopped responding until the package
was written. For a document that links 50 images of 21 MB each, OK
with Background Export off, which does the same work, takes a median
of 2.25 s in a release build on Windows.

With Enable Background Export on (Preferences › File Handling), OK now
takes the options, the report's Document Info text and a snapshot of
the document, and closes the dialog. The thread that writes background
saves and exports then collects the links and fonts and writes the
package. The same OK takes 0.001 s, and the package holds the same
bytes. A save of unsaved changes that Package starts is written first.
With the preference off, on the web and over MCP and scripts, the
package is made at once with the same reply as before.

Docs: docs/target-app-parity.md.
2026-10-22 17:20:48 +07:00
makesomethingshit e56e40dd85 M3.78: keep Recolor Edit chips within the screen (#3416) 2026-10-22 17:10:16 +07:00
bflatastic 5498b62a3d G4: Mixed Justification dialog fields
Squashed from #3542 onto main.
2026-10-22 15:35:44 +07:00
Cursor Agentandnrq6993-a11y 5359c92a19 G11: Arc segment dialog options wired to shape.arc
Replace length/angle with Length X/Y, reference point, Type, Base Along, Slope and Fill Arc; extend geom and shape.arc params.

Co-authored-by: nrq6993-a11y <nrq6993-a11y@users.noreply.github.com>
2026-10-22 13:38:04 +07:00
Cursor Agentandnrq6993-a11y d6e64cb080 G11: open Arc tool options on canvas click
## Summary
A click on the artboard with the Arc tool (no drag) opens an Arc options
dialog at the pointer, matching Illustrator. Length, angle, and Closed
follow the same form as Line Segment; OK runs shape.arc and remembers
Closed via tool.setOption.

## Tests
- dialogs::tests::arc_click_opens_options_and_ok_draws
- Existing draw2::family::tests::click_opens_dialog_and_arc_shift (tools)

Part of gap G11

Co-authored-by: nrq6993-a11y <nrq6993-a11y@users.noreply.github.com>
2026-10-22 13:38:04 +07:00
Cursor Agentandnrq6993-a11y fa3d6d9298 G11: open Arc tool options on canvas click (WIP)
Co-authored-by: nrq6993-a11y <nrq6993-a11y@users.noreply.github.com>
2026-10-22 13:38:04 +07:00
Cursor Agentandnrq6993-a11y fd8459592d Fix #3494: package status spacing without notes
## Summary
Package status notes are parenthetical fragments joined with spaces; templates without {note} are used when there are no missing links or skipped fonts, so folder paths are not followed by stray spaces or double gaps.

## Tests
- package_status_without_notes_has_no_extra_spaces
- package_status_message_templates_parse extended

Closes storytold/vectorcraft#3494

Co-authored-by: nrq6993-a11y <nrq6993-a11y@users.noreply.github.com>
2026-10-22 11:32:58 +07:00
Cursor Agentandnrq6993-a11y b14fa518fb Fix #3494: translatable package status message
## Summary
Package completion status and the show-folder prompt use i18n templates with
literal text between {folder} and {note}, so @msg rows parse and translate in
every locale (Illustrator-style localized status feedback).

## Tests
package_status_message_templates_parse; dialogs::tests_package; complete_languages_translate_every_message.

Closes storytold/vectorcraft#3494

Co-authored-by: nrq6993-a11y <nrq6993-a11y@users.noreply.github.com>
2026-10-22 11:22:56 +07:00
bflatastic 438c6194a6 Add shared presets and artwork fitting to Artboard Options
Squashed from #3277 onto main.
2026-10-22 10:40:37 +07:00
Don Omondi f639f449d7 M1: merge main and complete Turkish artwork drag translations
Add the three Turkish catalog entries requested by the maintainer on #3479. Preserve upstream catalog additions and place existing tab-drag entries beside stable menu labels to avoid append conflicts. Update feature progress notes for all 24 catalogs.

Simplify an equivalent Effect Gallery selection predicate required by the Rust 1.95 clippy gate. Full cargo xtask ci passed all 10 checks, including tab-drag regressions and wasm.
2026-10-22 04:16:24 +03:00
Murat Vural e33094e11d i18n: add Turkish (tr) localization
- Add crates/ui-egui/src/i18n/tr.tsv covering all menu strings, commands, UI labels, and status/error messages with standard Turkish vector software vocabulary.
- Register Turkish in LANGUAGES with plural_none and complete_menus: true.
- Support tr, tr-TR, tr_TR.UTF-8, tr-CY locale mapping in lang_from_tag.
- Add Turkish typographic quotation marks in crates/doc/src/setup.rs.
- Add turkish_reads_as_turkish unit test and register tr in KEEPS_MENU_NAMES and COMPLETE_MESSAGES.
- Include RTF diagnostic message with exact TSV escaping.
2026-10-22 07:21:51 +07:00
Murat Vural 9bd9f570ae i18n: size Document Setup Edit Artboards button to fit localized labels 2026-10-22 07:04:00 +07:00
Cursor Agentandnrq6993-a11y 757eaf9afa Effect Gallery: plain filter list and live stack preview
Remove hash-coloured thumbnails; preview the selection with the applied
filter stack on the canvas (Cancel rolls back). OK commits via batch.

Co-authored-by: nrq6993-a11y <nrq6993-a11y@users.noreply.github.com>
2026-10-22 07:03:19 +07:00
nrq6993-a11yandCursor e72735bcf9 G2: satisfy clippy and rustfmt on Effect Gallery dialog.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-22 06:52:07 +07:00
nrq6993-a11yandCursor dd9c285252 G2: Effect Gallery six categories and per-filter settings
Limit gallery folders to the six Photoshop-style sets and edit stack params via the existing effect dialog body before apply.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-22 06:52:07 +07:00
nrq6993-a11yandCursor ae3a8fe4c3 G2: Effect Gallery dialog to browse and apply raster filter stacks
Adds Effect → Effect Gallery with category browsing, procedural thumbnails, and a reorderable stack applied via command.batch as separate appearance effects.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-22 06:52:07 +07:00
Louise FoxandClaude Opus 5.5 2f893566ee Export As: a held Enter doesn't confirm the options; exporters get their file
Follow-ups to the review of the exporter plug-ins PR (#3171):

- Export As opens its format's options once the save panel has picked
  the file. The Enter that closed the panel, still held, confirmed
  them at once: Save As marks such a dialog (dialogs::AFTER_PANEL) so
  it waits for Enter to be let go, Export As didn't. Every options
  dialog it opens after the panel is marked now, an exporter plug-in's
  included, through one helper (dialogs::opened_by_panel) that Save As
  uses too.
- io::export with options that aren't a JSON object dropped the path
  and format it adds for the encoder: an exporter plug-in was told the
  document's name and its first extension instead of the file it
  writes. Such options now count as none.
- The exporter UI tests remove the plug-ins they install, so no other
  test's Export As lists them.

tests_export.rs reproduces the held Enter for every options dialog
(PNG, SVG, Save PDF, Text, DXF, EPS and an exporter's), and
tests_plugin_export.rs the options that aren't an object; both failed
before the fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhvnnnD5fTFupK8WWq35un
2026-10-22 06:40:28 +07:00
bflatastic 10a178f64a Shape Builder: Gap Detection and Tool Options (#2523)
Squashed from #2526 onto main.
2026-10-22 02:53:17 +07:00
bflatastic 62776d5f46 Recolor: recolor.apply takes a model option for the new colour's model (#2170)
Squashed from #2520 onto main.
2026-10-22 02:01:57 +07:00
Jürg Lehni a92f0264c2 Canvas: each update copies the rendered frame whole instead of pixel by pixel
The renderer's pixels and egui's are both premultiplied RGBA8, so color_image copies the bytes in one go. At 3456×2234 that takes 0.9 ms instead of 3.4 ms per update, at 5120×2880 1.6 ms instead of 6.8 ms. Every rendered image the UI shows (canvas, thumbnails, previews) goes through it.
2026-10-22 00:54:44 +07:00
bflatastic 695f7c0d4b G2: Effect › Artistic › Underpainting raster filter
Squashed from #3035 onto main.
2026-10-22 00:23:50 +07:00
bflatastic 03bd5e5a53 G2: Effect › Artistic › Paint Daubs raster filter
Squashed from #3032 onto main.
2026-10-22 00:23:49 +07:00
bflatastic 2cd7f156fb Add lighting presets to 3D effects
Squashed from #3442 onto main.
2026-10-22 00:01:37 +07:00
bflatastic c895f64063 Format: rustfmt after the batch 2026-10-21 23:38:03 +07:00
nrq6993-a11yandCursor ab0ddf0eae G1: Live Corners relative rounding (#1144)
Store corner radii as fractions of each corner's max so rounding scales with the shape; expose via Corners dialog and object.setLiveShape relativeRadii.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-21 23:38:03 +07:00
Cursor Agentandnrq6993-a11y b13072b77c M3: rustfmt eyedropper and brush key-color UI
Co-authored-by: nrq6993-a11y <nrq6993-a11y@users.noreply.github.com>
2026-10-21 23:38:03 +07:00
nrq6993-a11yandCursor 6433b6ca3a G5: Pattern brush Key Color eyedropper in Brush Options
Hue Shift colorization can sample key color from canvas art via the
eyedropper next to the swatches, matching Illustrator's brush workflow.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-21 23:38:03 +07:00
nrq6993-a11yandCursor cdef620083 G2: Share glass_fields for Glass and Texturizer load-texture UI.
Drop duplicate texturizer_fields/texturizer_params per review.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-21 23:38:02 +07:00
nrq6993-a11yandCursor dfa7bd12d9 G2: Texturizer Load Texture matches Glass and Illustrator.
Users can pick an image in the Texturizer dialog; it is stored as relief heights and survives save/open like Glass textures.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-21 23:38:02 +07:00
bflatastic 5e24e59bd3 Brushes: New Brush and Bristle Brush Options take a bristle brush name of at most 31 characters
Squashed from #3312 onto main.
2026-10-21 23:38:01 +07:00