Commit Graph
4793 Commits
Author SHA1 Message Date
Don Omondi c43ead202f M1: verify tab drag tool reset and scope clipboard evidence
Exercise Selection-tool busy state before takeover and verify it is idle after tab activation, drop, Escape and outside release. Session::set_active already reconstructs the tool via reset_tool_for_doc_switch, so the reported missing-Up busy state does not reproduce and no additional synthetic release is needed.

Narrow documentation to the internal clipboard asserted by the regressions and correct the stationary-pointer sentence. All 10 cargo xtask ci gates pass.
2026-10-22 04:30:22 +03: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
BFlat aef00190ed Merge pull request #3493 from nrq6993-a11y/stream/vc-feat1-3465-ase-library-picker
Fix #3465: Swatch Libraries Other Library lists .ase on Linux
2026-10-22 07:39:07 +07:00
BFlat 3dd8c3ec28 Merge pull request #3492 from nrq6993-a11y/stream/vc-feat1-g11-proxy-paint-drop-3467
G11: Copy fill/stroke by dragging between proxies (#3467)
2026-10-22 07:38:52 +07:00
BFlat f3863ef50f Merge pull request #2581 from Muratv07/feature/turkish-localization
i18n: add Turkish (tr) localization
2026-10-22 07:38:37 +07:00
BFlat 6a4a739178 Merge pull request #3491 from dotCooCoo/fix/tests-expand-reply-names-every-object
Tests: the Expand Appearance reply test fails when the reply leaves out the expanded object (#3374)
2026-10-22 07:38:20 +07:00
Cursor Agentandnrq6993-a11y 1fbec667ec Fix #3465: Swatch Libraries Other Library lists .ase on Linux
## Summary
Linux file portals grey out files that do not match the open dialog's default
filter. Other Library… and Locate Library… used File › Open filters, whose
first entry is All readable files and omits swatch-library extensions such as
.ase. Add library_open_filters with the library formats first (matching
Illustrator's Swatch Libraries › Other Library…) and use it from swatch and
graphic style library pickers.

## Tests
- engine: library_open_filters_list_library_formats_first
- ui-egui: other_swatch_library_asks_off_the_ui_thread asserts Swatch libraries
  is the default filter and includes ase

Closes storytold/vectorcraft#3465

Co-authored-by: nrq6993-a11y <nrq6993-a11y@users.noreply.github.com>
2026-10-22 07:21:53 +07:00
Cursor Agentandnrq6993-a11y 1388b8ec1a G11: clippy collapse in proxy_paint_drop
Co-authored-by: nrq6993-a11y <nrq6993-a11y@users.noreply.github.com>
2026-10-22 07:21:52 +07:00
Cursor Agentandnrq6993-a11y fe9ceb3dfa G11: copy fill/stroke by dragging between proxies (#3467)
## Summary
Dragging the Fill or Stroke proxy onto the other square applies that paint
there, like dropping a swatch on art. Matches Illustrator's fill/stroke
chips accepting a dragged color from the other.

## Tests
- panels::tests::dropping_a_proxy_paint_on_the_other_proxy_applies_it

Closes storytold/vectorcraft#3467

Co-authored-by: nrq6993-a11y <nrq6993-a11y@users.noreply.github.com>
2026-10-22 07:21:52 +07: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
Don Omondi 633ad1d749 M1: keep tab drag current and isolate feature progress notes 2026-10-22 03:19:24 +03:00
BFlat f832625e0b Merge pull request #3490 from dotCooCoo/fix/library-panel-locate-refuses-a-panel-that-has-its-library
Library panels: Locate Library… refuses a panel whose library is there
2026-10-22 07:13:54 +07:00
BFlat 2dfe6613ad Merge pull request #2883 from nrq6993-a11y/stream/vc-feat-2434-effect-gallery
ui: Effect Gallery dialog (browse raster filters and apply a stack)
2026-10-22 07:13:32 +07:00
BFlat 9219e41440 Merge pull request #3484 from lehni/fix/mitred-text-redraw
Render: moved type with mitred strokes redraws where its spikes reach
2026-10-22 07:13:16 +07:00
Don Omondi 490c8da696 M1: reconcile tab drag with upstream and document transfer contracts 2026-10-22 03:08:30 +03:00
Murat Vural 9bd9f570ae i18n: size Document Setup Edit Artboards button to fit localized labels 2026-10-22 07:04:00 +07:00
dotCooCoo 66655c67c2 Tests: the Expand Appearance reply test fails when the reply leaves out the expanded object (#3374)
the_reply_names_each_expanded_copy_by_its_own_id checked that no id in
the effect.expandAppearance reply repeats and that each one names a
node in the document. Only for group copies did it check which ids the
reply holds. In the other four cases a reply that left out the
expanded object, or held no ids at all, passed.

The test now checks in every case that the reply starts with the id of
the selected object, and keeps the exact check of the group and the
two copies of the square for group copies.
2026-10-22 07:03:54 +07:00
dotCooCoo 17fbf6ad6a Library panels: Locate Library… refuses a panel whose library is there
ui.libraryPanel.locate checked only that the panel was open. Run on an
open panel whose library was there, such as the built-in Pastels, it
loaded the file given or picked and showed that library in the panel
in place of Pastels.

It now answers "library panel `{given}` isn't missing its library" for
such a panel, before it asks for a file or loads one, and the panel
keeps its library. A persistent panel whose library's file is gone
locates as before.

Docs: docs/mcp.md (ui.libraryPanel.locate).
2026-10-22 07:03:20 +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 d275fbf725 G2: catalog Effect Gallery dialog tl! strings for all locales.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-22 06:52:12 +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
Jürg Lehni 60f4c4f145 Render: moved type with mitred strokes redraws where its spikes reach
Follows #3461: character strokes' miter spikes reach past half the weight, which the redrawn area missed.
2026-10-22 06:52:06 +07:00
BFlat 79dca4c8f9 Merge pull request #3488 from KaboomFox/export-dialog-guard
Export As: a held Enter doesn't confirm the options; exporters get their file
2026-10-22 06:50:50 +07:00
BFlat afd66ad695 Merge pull request #3487 from dotCooCoo/fix/transform-each-refuses-switches-given-as-text
Commands: Transform Each, artboards and more refuse a boolean or number given as text
2026-10-22 06:50:35 +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
dotCooCoo caa6962508 Commands: Transform Each, artboards and more refuse a boolean or number given as text
object.transformEach refused reflectX, reflectY, random and copy given
as text, but read strokes, corners, objects and patterns given as text
as the key left out. With Scale Strokes & Effects on,
{"scaleH": 200, "scaleV": 200, "strokes": "false"} scaled the stroke,
recorded an undo step and kept the params for Transform Again, which
repeated the call. artboard.rearrange, artboard.move and
artboard.duplicate read their patterns option the same way, and
artboard.setProps reads its patterns, strokes and corners options the
same way.

These commands now refuse such a value with "`<key>` must be true or
false" before they change anything. So do the other options and
numbers of artboard.setProps and artboard.move, the art of Duplicate,
Copy and Cut Artboard, the shape commands and path.create, path.close,
path.setHandle, path.moveAnchors, the Pencil, Curvature, Reshape
Segment and Blob Brush options, text.create, text.createInPath,
text.setRangeStyle, text.editRange, text.getRange, text.touchType,
text.areaOptions, type.step, the font size steps,
type.opticalMarginAlignment, type.systemLayout, type.fractionalWidths,
type.ruby, the symbol and swatch commands, the Appearance panel's
commands, the gradient and freeform gradient commands, Shape Builder,
Live Paint, Image Trace, the opacity of object.setProps, the radius,
sides and relativeRadii of object.setLiveShape, the reference point of
object.setBounds and the artboard of Align, Distribute and Distribute
Spacing. They refuse a number given as text with "`<key>` must be a
number, not <value>", and a gradient stop's tint with "stop <n>:
`tint` must be a number". A null still reads as the key left out.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-22 06:40:27 +07:00
Dylan M. Taylor f64db69b53 Use chrono instead of hand-rolled UTC conversion (#3387)
* Use chrono for UTC/calendar conversion instead of hand-rolled copies

Replaces the hand-rolled Howard Hinnant civil/days-from-civil copies and the
leap-year/days-in-month tables with chrono as a workspace dependency:
- apps/vectorcraft/src/logging.rs: timestamp (log line time)
- crates/doc/src/metadata.rs: civil (Unix seconds -> [y,m,d,h,mi,s]) and iso8601
- crates/pdf/src/file_info.rs: unix (date -> seconds) and in_month, used by the
  PDF/XMP date parsers (pdf_date, xmp_date)
Output formats and parsing semantics are unchanged and pinned by the existing
tests (PDF D:... and XMP dates, offsets, leap-year rejection, year clamp 0-9999,
pre-epoch clamp). chrono uses only std, so wasm stays safe. AGENTS.md/CLAUDE.md
now say time goes through chrono.

Follow-up to storytold/cadcraft#1785

* Never panic on a clock outside chrono's range; keep 5-digit years unprefixed

chrono's From<SystemTime> unwraps, so a clock past year 262143 panicked
inside the logger. timestamp now uses the fallible DateTime::from_timestamp
and reads such a clock (or a pre-epoch one) as the epoch instead. Years past
9999 are written with {:04} like before, because %Y would add a '+'. Tests
cover the out-of-range and 5-digit-year cases.

* Don't build an unrepresentable SystemTime in the far-future test

UNIX_EPOCH + Duration::from_secs(u64::MAX / 2) overflows Windows'
SystemTime and panicked before timestamp() ran, failing the Windows
test job. Build it with checked_add and only assert where it exists.

* time: preserve old out-of-range date conversion (no epoch fallback)

`DateTime::from_timestamp(...).unwrap_or_default()` silently reset any instant
past chrono's year range to 1970-01-01. Restore the old conversion domain with
a cycle-based helper that routes the calendar through chrono (the calendar
repeats every 400 years = 146_097 days, so month/day/time come from chrono and
only the year is carried in i128, keeping every i64 exact).

- apps/vectorcraft/src/logging.rs: `timestamp` via `utc_parts`; keep the
  pre-1970 epoch clamp; u64 secs past i64::MAX saturate, not epoch.
- crates/doc/src/metadata.rs: `civil` cycle-based, keeping its clamp EXACTLY
  as the old code had it: the input is clamped to 0000-01-01..9999-12-31 first
  and the year is clamped to 0..=9999 afterwards. (With the input clamp the old
  `unwrap_or_default()` was already unreachable; this drops it and makes the
  conversion explicit, with identical output.)

Pinned old outputs in tests:
  logging u64::MAX/2 s -> 292277026596-12-04T15:30:07.000Z (was epoch),
          10_000_000_000_000 s -> 318857-05-20T17:46:40.000Z
  metadata civil(i64::MIN)[0]=0, civil(i64::MAX)[0]=9999;
          iso8601(i64::MIN)=0000-01-01T00:00:00Z,
          iso8601(i64::MAX)=9999-12-31T23:59:59Z (year clamp, as before)

* Don't build a year-318857 SystemTime unchecked in the logging test

Windows' SystemTime only reaches about year 30828, so
UNIX_EPOCH + Duration::from_secs(10_000_000_000_000) panicked before
timestamp() ran and failed the Windows test job. Build it with
checked_add and assert where the platform can hold it. The year-10000
case fits everywhere and stays unconditional.

* Name the 400-year range extension as the one exception to the time rule

The rule said never to hand-roll calendar math, but the range fix
(shifting by whole 400-year Gregorian cycles so dates past chrono's year
range keep their old output) is cycle arithmetic, so the rule and the code
disagreed. The rule now names that exception: the library still computes
month, day and time, and only whole cycles are carried in the year.

* Say the library computes month and day; time-of-day is plain arithmetic

Narrows the range-extension wording: the date library computes the
calendar fields, and splitting seconds into hours, minutes and seconds
is ordinary arithmetic, which is what the code does.
2026-10-21 19:36:32 -04:00
Dylan M. Taylor 2b8a11876a security: enforce HTTPS on curl downloads (SonarCloud S6506) (#3475)
Add --proto '=https' to curl invocations so redirects cannot downgrade to
plaintext HTTP. Resolves SonarCloud S6506 (shell/docker/githubactions).
2026-10-21 19:35:52 -04:00
BFlat dc9d751015 Merge pull request #3468 from nrq6993-a11y/stream/vc-featD-3451-ellipse-pie-properties
Ellipse pie angles in Transform and Properties (#3451)
2026-10-22 06:35:19 +07:00
Cursor Agentandnrq6993-a11y 6066b4b8c7 Properties: regression test for ellipse pie in Transform section (#3451)
Co-authored-by: nrq6993-a11y <nrq6993-a11y@users.noreply.github.com>
2026-10-22 06:29:30 +07:00
Cursor Agentandnrq6993-a11y 718c65c855 Ellipse pie angles in Transform and Properties (#3451)
## Summary

Live ellipses already support pie start/end angles, canvas widgets and Invert Pie
like Illustrator. Label the Properties panel Transform section with Ellipse
Properties so the pie fields match the Transform panel and are easier to find.

## Tests

- `an_ellipse_shows_its_pie_properties` in `panels/transform` tests.

Closes storytold/vectorcraft#3451

Co-authored-by: nrq6993-a11y <nrq6993-a11y@users.noreply.github.com>
2026-10-22 06:29:30 +07:00
BFlat a4f5ae3b16 Merge pull request #3482 from dotCooCoo/fix/vector-exports-one-decode-note
Export: EPS, legacy .ai, EMF/WMF and DXF give one note for images that can't be decoded
2026-10-22 06:22:29 +07:00
BFlat de917a138a Merge pull request #3486 from dotCooCoo/fix/tests-data-set-export-fails-on-a-stale-folder
Tests: the data set export test fails when its folder cannot be emptied (#3389)
2026-10-22 06:22:14 +07:00
dotCooCoo e66bca39b2 Export: legacy .ai gives the size note for an image with empty data
An image whose data is empty failed to decode before the size check, so a
version 7 .ai said it couldn't be decoded. The writer now checks for empty
data first and gives "an image that is empty or too large for legacy .ai
was left out". docs/mcp.md now says the DXF decode note applies to R13 and
later; R12 leaves out every image with its own note.
2026-10-22 06:13:32 +07:00
dotCooCoo 4e4723699d Export: EPS, legacy .ai, EMF/WMF and DXF give one note for images that can't be decoded
EPS, EMF, WMF and DXF exports gave each image they left out because it
couldn't be decoded its own warning, "image '<key>' could not be
decoded and was left out", which names the internal key the document
stores the image under. A version 7 .ai said "an image that can't be
decoded or is too large was left out".

The four writers now give the note raster exports, PDF and the legacy
.ai flattening give, "an image couldn't be decoded and is missing from
the picture", once per export. In a version 7 .ai it is one line with
the note for flattened art. The other image notes in the same
functions no longer name the key: EPS's note for an image too large to
write, and DXF's notes for an image with no pixels (its rows in 23
catalogs are reworded) and one that could not be written. Legacy .ai
gives a separate note for an image that is empty or too large.

Docs: docs/mcp.md (EPS, DXF export, EMF and WMF, aiVersion "7").
2026-10-22 06:13:32 +07:00
dotCooCoo 3bb0f07a4b Tests: the data set export test fails when its folder cannot be emptied (#3389)
variables_panel_data_sets_ask_off_the_ui_thread empties its folder
before Export Data Sets… writes out.csv, then checks that the file is
exactly the header and the row for data set B. It ignored the result
of remove_dir_all, and create_dir_all succeeds on a folder that is
still there. When the folder could not be emptied, an out.csv left by
an earlier run passed the check even when the export wrote nothing.

The test now fails when emptying the folder fails with an error other
than NotFound.
2026-10-22 06:07:55 +07:00
BFlat 92a8a45d32 Merge pull request #3464 from dotCooCoo/fix/pdf-14-writes-16-bit-images-at-8
PDF export: a 16-bit PNG is written at 8 bits for PDF 1.3 and 1.4 instead of failing the export
2026-10-22 06:07:26 +07:00
dotCooCoo 5f6c7b8da9 PDF export: a 16-bit PNG is written at 8 bits for PDF 1.3 and 1.4 instead of failing the export
When the Compression settings keep a PNG as it is, the PNG goes to
the PDF writer unchanged, and the writer refuses images of 16 bits a
sample below PDF 1.5. Saving a document with a placed 16-bit PNG as
PDF 1.4, or as a .ai file at 1.4, failed with "PDF writer error:
SixteenBitImage(...)" and wrote nothing. PDF 1.3 and PDF/X-3 failed
the same way for an opaque 16-bit PNG, and PDF/X-1a failed for a
16-bit gray PNG.

In PDF 1.3 and 1.4 files, such a PNG is now decoded and encoded again
at 8 bits a sample, with the same color type and ICC profile, before
the writer reads it. From PDF 1.5 on, it keeps its 16 bits. A 16-bit
PNG whose pixel data can't be decoded is left out with the note "an
image couldn't be decoded and is missing from the picture".

Docs: docs/mcp.md (PDF options).
2026-10-22 05:57:11 +07:00
BFlat 14a70449f7 Merge pull request #3483 from nrq6993-a11y/stream/vc-feat1-g11-guide-align-artboard-3463
G11: Align panel moves ruler guides to artboard (#3463)
2026-10-22 05:28:22 +07:00
Cursor Agentandnrq6993-a11y c8082facb1 G11: Align panel moves ruler guides to artboard (#3463)
## Summary
object.align now moves selected ruler guides when aligning to the artboard,
matching Illustrator and the existing Distribute behaviour. Guide-only
selection can run align; the Align panel enables its buttons when only
guides are selected. Guides still stay put when objects are in the selection
and Align To is Selection; key-guide behaviour is unchanged.

## Tests
- engine tests_keyguide: guides_selected_alone_align_to_artboard; updated
  selected_guides_align_to_a_clicked_key_object for artboard align
- ui-egui align panel: the_align_buttons_align_guides_selected_alone_to_artboard

Closes storytold/vectorcraft#3463

Co-authored-by: nrq6993-a11y <nrq6993-a11y@users.noreply.github.com>
2026-10-22 05:20:10 +07:00
BFlat 430741f074 Merge pull request #3481 from dotCooCoo/fix/save-as-extension-compare-ignores-case
Save As: the suggested extension typed in another case gets the picked type's
2026-10-22 05:19:59 +07:00
dotCooCoo bd9a508d49 Save As: the suggested extension typed in another case gets the picked type's
On Linux and the BSDs, where the save dialog reports the file type
picked in it, a name that still ends in the suggested name's extension
gets the picked type's extension. The comparison was case-sensitive,
so Untitled-1.VECTORCRAFT with "PDF-compatible .ai" picked was saved
as a native file named Untitled-1.VECTORCRAFT instead of Untitled-1.ai.

with_picked_type now compares the lower-case extensions that
fileio::extension gives. A name typed with the picked type's own
extension in another case (a.AI with .ai picked) stays as typed.

This follows up #3372.

Docs: docs/target-app-parity.md.
2026-10-22 05:09:55 +07:00
BFlat b15230bfb5 Merge pull request #3461 from lehni/update/canvas-partial-redraw
Canvas: an edit redraws only the area it changed
2026-10-22 05:09:38 +07:00
BFlat 15434b6db4 Merge pull request #2539 from vangel76/feat/1124-blend-easing
Blend: Ease In / Ease Out and separate Color Ease in Blend Options (#1124)
2026-10-22 04:50:42 +07:00
Don Omondi 84e76c1d70 M1: support dragging editable artwork between document tabs
Activate visible tabs after a delayed Selection drag and copy artwork through a document-scoped command without changing the clipboard or source. Cancel stale transfers, preserve pattern alignment and transparency, and insert into the editable destination context. Cover pointer gestures, resource rendering, input bounds and locked layers; translate the new labels and messages.
2026-10-22 00:48:57 +03:00
Jürg Lehni ede08590a0 Canvas: an edit redraws only the area it changed
Wide effect rasters cropped to the frame also serve parts of it.
2026-10-22 04:45:43 +07:00
bflatastic 92f295d2a2 Blend: Ease In / Ease Out and separate Color Ease in Blend Options (#1124)
Squashed from #2539 onto main.
2026-10-22 04:40:10 +07:00
BFlat cc42a333b7 Merge pull request #3477 from dotCooCoo/fix/ruby-tests-with-ci-fonts
Type: the vertical ruby test passes with craft-fonts' Shippori Mincho
2026-10-22 04:39:15 +07:00