Commit Graph
1232 Commits
Author SHA1 Message Date
dotCooCoo a3e7dc9e41 i18n: the message scan reads errors made with bad() and error variants, and new ones need rows
complete_languages_translate_every_message read a message literal only
right after a marker such as Err( or Other(. It did not read the
message given to the engine's bad(cmd, ...), so this test did not
require a row for a parameter error. It also did not read the messages
given to the engine's err() and error(), to the PDF writer's bad() and
failed(), or to an error enum's variant such as PsError::Limit(...).
1,122 of these messages have no row in any complete catalog.

The scan now reads those messages, a literal or a format! string, in
the same template form as the catalogs' rows. It skips PsError::Ps and
EngineError::UnknownCommand, whose first argument is a PostScript error
name or a command id. The 1,122 messages are listed in
untranslated_messages.txt next to the tests, together with the 71 that
pull requests open at 009384b add without rows, and the test lets a
listed message through whether or not it has rows. Every other message
needs a row in each complete catalog, so a new message made this way
fails the test until it has its rows.
VECTORCRAFT_I18N_DUMP_UNTRANSLATED=<file> writes the messages in the
sources that lack a row. No catalog rows change.

Docs: docs/development.md, docs/localization-parity.md.
2026-10-22 00:40:10 +07:00
bflatastic 0c9a7a89a0 Docs: Photoshop filter count after Colored Pencil (52/57), one Artistic row 2026-10-22 00:31:30 +07:00
bflatastic 03a2da13ba G2: Effect › Artistic › Colored Pencil raster filter
Squashed from #3028 onto main.
2026-10-22 00:30:39 +07:00
bflatastic 3c6d2b371e Docs: Photoshop filter count after the Artistic batch (51/57) 2026-10-22 00:23:51 +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 bbe026607f Variables: Load Variable Library… reads a variable library's text variables and data sets
Squashed from #2853 onto main.
2026-10-22 00:12:39 +07:00
KnottyDyesandClaude Opus 5.5 73cbba8b8d PDF import: even gaps alone still read as word spaces
Glyphs placed one by one with even gaps could be letters set apart or
words of one letter each, and a file's positions can't tell them apart.
The spacing a line's letters share is now taken off its gaps only when
the line also shows where its words break: with spaces it draws (as
with Tc), or with gaps wider than the rest (tracked words placed glyph
by glyph). Otherwise every gap past a fifth of an em is a space, as
before, so A, B, C and D placed with ordinary word spaces between them
still come in as "A B C D".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 00:10:57 +07:00
bflatastic 609c98f458 Docs: one row per area after the batch 2026-10-22 00:10:57 +07:00
bflatastic e7cdf154ca Commands: a boolean or number given as text is refused
Squashed from #3428 onto main.
2026-10-22 00:10:57 +07:00
bflatastic 14f804cdee Type: ruby (ふりがな) for live text
Squashed from #3448 onto main.
2026-10-22 00:10:56 +07:00
bflatastic 2cd7f156fb Add lighting presets to 3D effects
Squashed from #3442 onto main.
2026-10-22 00:01:37 +07:00
dotCooCoo 4d1581f3da Document Info: a Repeat Objects category lists the document's repeats
Document Info had no Repeat Objects category, and document.info
refused category "repeats". The reference app's Document Info panel
menu lists Repeat Objects after Font Details.

Document Info now has a Repeat Objects category after Embedded Images.
It lists each radial, grid and mirror Repeat object by name with its
kind and the number of instances it makes. For a grid it gives the
rows and columns instead, followed by the number of instances it
draws when that is fewer. The count comes from the new
RepeatSpec::instances, which gives the number of instances a repeat
draws. That number is smaller than its options give when repeats
nested in its source would pass the instance budget. With Selection
Only the category lists the Repeat objects in the selection.
document.info gives them as repeatObjects, the panel's flyout offers
the category, and the text report that Document Info › Save… and
File › Package write has a REPEAT OBJECTS section. The title has a row
in every catalog.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-22 00:01:36 +07:00
Drew DibbleandClaude Opus 5.5 f19b33c219 G1: Properties: Edit Clipping Path and Edit Contents for one clip group
With one clip group selected, the Properties panel has Edit Clipping
Path and Edit Contents at its top, under the Clip Group heading, as the
reference app does: "With the clip group selected, click the Edit
Clipping Path button at the top of the Properties panel to select and
edit the mask, or click the Edit Contents button to select and edit the
masked content"
(https://www.adobe.com/learn/illustrator/web/crop-using-masks). They
run the existing object.clippingMask.editMask and editContents, which
select the clipping path or the clipped art for the selection tools, as
Object > Clipping Mask does. Edit Contents shows only when the group
clips something. With several objects selected they don't show (the
tutorial describes one selected clip group); the Contextual Task Bar
does the same. Both labels are already in every catalog.

Test: panels::properties::tests::one_clip_group_has_edit_clipping_path_and_edit_contents_at_the_top
(first under the heading, each selecting its part; Edit Clipping Path
alone once the clipped art is deleted; neither for a clip group
selected with another object in either order, or for a plain group).
Documented in docs/target-app-parity.md, docs/ui-parity.md and
docs/gaps.md.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 00:01:36 +07:00
bflatastic e5471be4d9 Commands: an index of 2^32 or more no longer wraps around on 32-bit builds
Squashed from #3292 onto main.
2026-10-21 23:38:03 +07:00
nrq6993-a11yandCursor c7df7a56e8 docs: note G4 Paragraph panel mixed indent fields
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-21 23:38:03 +07:00
nrq6993-a11yandCursor 2d85d8818e docs: mark G5 Key Color eyedropper done in gaps.md
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-21 23:38:03 +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
nrq6993-a11yandCursor 2dcceea8e1 G1: limit Cmd+Alt Group Selection to active Direct Selection
Pen Cmd-borrow keeps Direct Selection when Alt is held so guide copy and other Alt modifiers on the lent tool still work.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-21 23:38:02 +07:00
nrq6993-a11yandCursor fface52206 G1: Cmd+Alt lends Group Selection for one gesture
When Direct Selection was last used or is active, Cmd+Alt borrows Group Selection for pointer presses, matching the documented modifier chord.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-21 23:38:02 +07:00
bflatastic 58066428c6 Artboards: the Artboards panel locks an artboard and the art on it
Squashed from #2592 onto main.
2026-10-21 23:38:02 +07:00
bflatastic 9c20027778 Keyboard Shortcuts: each Align and Distribute button of the Align panel can be given a key
Squashed from #3317 onto main.
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
bflatastic 1cfeaabb2d Docs and format: one row per area after the batch, rustfmt
Rows two PRs of the batch both changed came out twice in localization-parity, target-app-parity and type-parity; the newest of each is kept. prefs_dialog.rs is formatted.
2026-10-21 23:38:01 +07:00
dotCooCoo 7d58ce4f9d Place: Word's low, medium and high kashida justification sets Insert Kashidas
A Word paragraph justified with w:jc lowKashida, mediumKashida or
highKashida placed as plain justified type, and its kashida length was
dropped. ECMA-376 Part 1, 17.18.44 (ST_Jc) gives these values a
slightly longer, a medium and the widest kashida length.

Such a paragraph now places justified with Insert Kashidas set to
Short, Medium or Long. A paragraph justified with both, and every other
alignment, still places with Insert Kashidas set to None. VectorCraft
writes no Word or RTF files, so this change does not affect export.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-21 23:32:26 +07:00
dotCooCoo 3884cf9704 Tabs: a stop placed or moved on the ruler lands on a whole point
A click on the Tabs panel's ruler added a stop, and a drag moved one,
at the fraction of a point under the pointer. The reference app's Tabs
page says that the tab ruler does not set stops in increments smaller
than 1, and that the X or Y field sets them as finely as 0.01 point.
The page does not name the unit of 1. The ruler here uses 1 point, the
unit the page gives for the X or Y field, in every General unit.

With Snap to Unit off and Shift not held, a stop placed or dragged on
the ruler now lands on the nearest whole point. With Snap to Unit on,
or Shift held, it still lands on the ruler's nearest tick, which on a
millimeter ruler is a fraction of a point. A position typed in the X
or Y field keeps its hundredths of a point.

Docs: docs/target-app-parity.md.
2026-10-21 23:32:26 +07:00
Drew DibbleandClaude Opus 5.5 e321c7179b Text: an embedder of the egui panels may leave the bundled fonts out
#2027 gave vectorcraft-text and vectorcraft-engine a `bundled-fonts`
feature for an embedder that supplies every document font at run
time, but vectorcraft-ui-egui (and vectorcraft-mcp) named the engine
with its default features, so an embedder that hosts the panels got
the fonts whatever it asked for. Each now has a `bundled-fonts`
feature of its own, on by default, that turns the engine's on, so a
downstream user keeps the fonts unless it asks otherwise. For a
member to leave the engine's default features out, the workspace has
to declare the engine without them, as it already declares
vectorcraft-text; the crates that used the engine's default now ask
for the fonts: the three apps and vectorcraft-testkit. Off,
vectorcraft-text's copy of the fonts (3.4 MB) is left out; theme.rs's
own copies of five of them, the panels' interface faces, stay either
way.

Nothing the workspace builds changes: for every workspace member and
for the whole workspace, with and without dev-dependencies, for all
targets, wasm32-unknown-unknown, aarch64-apple-darwin and
x86_64-pc-windows-msvc, `cargo tree -e normal[,dev] -f '{p} [{f}]'`
resolves the same features for every package as on main, apart from
the new feature names (the engine's `default` no longer listed;
ui-egui's and mcp's `bundled-fonts` and `default`).

A test of the panels can't see their configuration without the fonts
(their dev-dependencies turn them on), so `cargo xtask ci`'s
`no-bundled-fonts` step now also reads that tree for
vectorcraft-ui-egui and vectorcraft-mcp: with their default features
it must show the fonts, and without them, for any target (a wasm-only
dependency too), it must not. Documented in docs/development.md
(Fonts › Leaving out the bundled fonts).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-21 23:32:26 +07:00
dotCooCoo 6807e757af PDF export: PDF and .ai files carry File Info's copyright status, notice and URL
The PDF writer's metadata has no copyright fields, so the XMP packet of
PDF exports and PDF-compatible .ai and .ait saves left out File Info's
copyright status, notice and URL. A PDF exported without its editing
data opened with the status Unknown and an empty notice and URL,
although the reader takes them from dc:rights, xmpRights:WebStatement
and xmpRights:Marked.

The export now adds those three properties to the XMP packet after
the writer has written it, as it does for the modification date.
Marked is True for Copyrighted and False for Public Domain, and is left
out for Unknown. The notice and URL are escaped for XML, and characters
XML 1.0 does not allow are left out. A document without a copyright
gets none of the properties.

Docs: docs/mcp.md (File Info), docs/target-app-parity.md.
2026-10-21 23:32:26 +07:00
Midasdf 32d012f6cc Print: Japanese paper sizes (JIS B4/B5/B6, はがき・封筒・四六判)
The Print dialog's Media list only had Letter/Legal/Tabloid and the ISO A
and B papers, so Japanese papers had to be entered as a custom size, and
"B4"/"B5" were ISO 216 (250 × 353 and 176 × 250 mm) although Japanese
printing uses the JIS sizes (257 × 364 and 182 × 257 mm, JIS X 6310).

Media gains JIS B4, B5 and B6 next to the ISO ones, and はがき
(japanese postcard, 100 × 148 mm), 往復はがき (japanese double postcard,
148 × 200 mm), 封筒 長形3号/長形4号 (japanese envelope #3/#4, 120 × 235
and 90 × 225 mm), 角形2号/角形3号 (kaku #2/#3, 240 × 332 and 216 × 277 mm),
四六判 (yonroku-ban, 127 × 188 mm) and A6, all in millimetres at 72/25.4.
b4 and b5 keep their ISO 216 dimensions so print settings and presets
saved before the Japanese papers existed keep their paper; the dialog
labels say "B4 (ISO)"/"B5 (ISO)" beside "B4 (JIS)"/"B5 (JIS)".

A paper is named by its JSON id or by its dialog label, any case and
spacing ("b5 (jis)", "B5 (JIS)" and "b5jis" all mean the JIS B5), so
agents and the control channel need not know the id spelling; an unknown
name is still refused. Media is written out instead of through the
choice! macro to carry that lookup.

The print.setup/file.print parameter docs and docs/mcp.md list the new
papers; the Print dialog picks them up from Choice::ALL with no UI code
change, and the Japanese labels are translated in ja.tsv (はがき,
往復はがき, 長形3号, 長形4号, 角形2号, 角形3号, 四六判).

Tests: japanese_paper_sizes checks every added size in points, that the
ISO B4/B5 values did not change, name resolution and id/label round
trips, and that each paper prints a PDF page with its own MediaBox size.

Validation: cargo fmt --all -- --check clean; cargo clippy
-p vectorcraft-pdf --all-targets -- -D warnings clean; cargo test
-p vectorcraft-pdf -> 330 passed, 0 failed (328 lib + 2 integration).
2026-10-21 23:32:26 +07:00
Grant Colloty 84d5d8797f EPS/.ai editing data: type keeps stacked art styles as live appearance
**What:** Illustrator type styled through the Appearance panel came in as its drawn look (outlined compound paths). Comic and "text effect" templates are the common case, and the type couldn't be retyped. This keeps it as editable type with the style as a live VectorCraft appearance.

**Changes**
- **Art styles parsed as a tree.** Compound filters close at their `;`, basic ones at `/Part`. Each fill and stroke in a stack keeps its own effects, opacity and blend mode, and object-level effects stay on the object.
- **Type keeps any plain stack.** That covers several fills and strokes, pattern and gradient fills, Warp, Offset Path, Transform with copies, Drop Shadow, Outer Glow, Feather, Gaussian Blur and Bas Relief. Bas Relief settings are left at their defaults, because Illustrator stores them in a Photoshop plug-in's binary block. Gradients and patterns are placed as the drawn look places them. Other objects keep the existing plain-style rule, since their drawn look is the more faithful option.
- **Point type without a frame matrix.** Illustrator 24 omits the matrix when point type is neither rotated nor scaled. Such stories were left out entirely; they're now read with an identity matrix.
- **Page comparison.** The page's rendering of a style isn't held to match VectorCraft's live rendering where the replaced drawn look lay, and styled made type isn't pruned as unseen.
- **EPS override.** `editingData: "always"` / `convert --editing-data` now applies to Illustrator EPS as well as `.ai`.

**Tests:** 6 new tests, written from scratch; `vectorcraft-eps` passes all 298 on current main. clippy `-D warnings` and rustfmt are clean for eps, engine and cli. `docs/file-format-parity.md` has been updated, including its revision history.

**Clean-room note:** I found the bugs with a user's licensed stock EPS, used locally only; nothing from it is committed. Filter and key meanings come from the public Illustrator Effect docs and public LiveEffect scripting examples (`jntp`, the Warp style order).

**Not included:** VectorCraft's pixel effects treat transparent content as empty instead of using Document Raster Effects Settings › Background (white by default). Because of that, Bas Relief on a transparent pattern gives flat grey. That needs a separate renderer change.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-10-21 23:16:30 +07:00
KnottyDyesandClaude Opus 5.5 52b63e2198 PDF import: letter-spaced text keeps its word spaces
PDF import read every gap wider than a fifth of an em between two
glyphs as a space. Letter-spaced type (Tc, or glyphs placed one by one
with tracking) has such a gap between every pair of letters, so
"OPEN DAILY" came in as "O P E N D A I L Y".

A line now records every gap between its glyphs and decides which are
spaces when it finishes: the spacing its letters share (the gap a third
of the way up from the narrowest, when the line has three or more) is
taken off each gap first. That shared spacing is at most half an em, so
glyphs set wider apart, such as figures in columns, keep their spaces.
Right-to-left lines and glyphs along a curve read their gaps as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 23:16:29 +07:00
bflatastic 398c6316d9 G4: Fractional Widths rounds a type object's advances to whole points
Squashed from #3411 onto main.
2026-10-21 23:16:04 +07:00
Jürg Lehni af2618c9e4 Threaded text: type on a path threads, mixed with area type
Illustrator links type in an area or along a path (https://helpx.adobe.com/illustrator/using/manage-text-area.html); until now only area type threaded here. Type on a path that overflows ends its line where its text stops fitting, so a story flows on from it, and its red out port, just past its end bracket, loads the Selection tool with the text as area type's does. A new frame threaded from it at a point is type on a path of its shape.
2026-10-21 23:15:45 +07:00
dotCooCoo 5ac70a9b07 Brush Options: Tips shows each colorization method on a sample
Scatter, Art and Pattern Brush Options had no Tips button. The
reference app's Brushes page has one for Colorization, with information
and samples about each method.

A Tips button beside Method now opens Colorization Tips. For each
method it shows the name, what the method does, and a sample of the
brush as OK would make it, painted with that method on a blue stroke.
Hue Shift's sample uses the dialog's Key Color. A second click on Tips,
Escape or a click outside the popover closes it, and the dialog field
tips opens it from a command. Screen readers name the button, the
popover and each sample.

In every dialog, Escape with a dropdown list open now closes the list
and leaves the dialog open. Before, it canceled the dialog and
discarded its edits.

The stroke preview and the samples no longer panic when ui.dialog.set
writes a brush definition (__def) that is not a JSON object.

Docs: docs/target-app-parity.md.
2026-10-21 23:15:43 +07:00
bflatastic bbd9f51096 G4: No Break keeps marked characters on one line
Squashed from #3398 onto main.
2026-10-21 23:15:27 +07:00
dotCooCoo 7d6eb3246e Type: Optical Margin Alignment hangs punctuation in right-to-left paragraphs
Optical Margin Alignment and Roman Hanging Punctuation left every
right-to-left paragraph of point and area type, and type on a path
whose first paragraph runs right to left, as it was: the quotation
marks, full stops and commas at the ends of its lines stayed inside
the margins.

A right-to-left line now hangs at the margins its alignment places it
against, as a left-to-right line does. Auto aligns a right-to-left
line at its right, so it hangs there. The line is read from right to
left: where it hangs at its left margin, a full stop and the quotation
mark after it that end the line hang together. In vertical type,
where the characters of a right-to-left paragraph run from the top
down, the pair is read from the top.

Type on a path whose first paragraph runs right to left hangs at its
brackets by the same rule. In horizontal type, Auto places it at the
end bracket, so it hangs there. On a closed path, its hang at the end
bracket gets the space between the end and start brackets before its
hang at the start bracket does, as in right-aligned type.

A justified right-to-left line of one word is spread between its
letters as they are drawn. The gap after each letter went to the
letter that follows it in the text, so the two leftmost letters
touched and the word ended one gap short of the right margin.

Docs: docs/mcp.md, docs/type-parity.md, docs/target-app-parity.md.
2026-10-21 23:15:07 +07:00
dotCooCoo 963922beaf Symbols: F8 opens Symbol Options for a new symbol from the selection
The reference app creates a new symbol with F8 on Windows and macOS.
VectorCraft opened Symbol Options for a new symbol from the Symbols
panel's New Symbol button, from the panel menu's New Symbol… item and
from Help › Search Commands…, but no key ran it, and F8 did nothing.

ui.symbolOptions (Symbol Options…) now has the default F8 on every
platform. With a selection the key opens Symbol Options for a new
symbol, as the New Symbol button does: OK makes the symbol and puts an
instance of it in place of the art, and Cancel makes none. With nothing
selected the key opens no dialog, and the status bar says that nothing
is selected. Shift+F8, Cmd+F8 and Cmd+Shift+F8 keep their commands.
Keyboard Shortcuts now lists the command with its key.

Docs: docs/ui-parity.md, docs/target-app-parity.md,
docs/control-protocol.md.
2026-10-21 23:15:07 +07:00
bflatastic b008e83658 Brushes: New Brush asks for the type and opens its Brush Options
Squashed from #3390 onto main.
2026-10-21 23:15:05 +07:00
dotCooCoo 79c4647665 Dialogs: sliders step their field's number with the arrow keys
A dialog's slider could take the keyboard focus from Tab, but it
responded only to the pointer, so an arrow key moved the focus to the
nearest widget in the arrow's direction and a keyboard user could not
move the slider. Screen readers could not step it either.

These dialog sliders, each beside a number field, now respond to the
keyboard. A click or Tab gives a slider the focus, which an outline
shows. Then the Right and Up arrows step the field's number up to the
next whole number and the Left and Down arrows step it down to the
next whole number. Shift with an arrow, Page Up and Page Down step it
by ten, and Home and End set the slider's first and last value. No
step goes past either end, and a number past the slider's range steps
from its nearer end. Screen readers' increment and decrement actions
step the slider as the arrows do. A step sets the field's number in
the field's own unit, so a Move slider in a millimeter document steps
one millimeter. When the field holds a number past the slider's range,
Home, End or a drag to that end of a form slider now sets the end's
number; before, such a drag left the field's number as it was.

The form sliders get this through the new color_slider_stepped, next
to color_slider_valued, and so do the Pencil, Paintbrush and Smooth
Fidelity, the Perspective Grid's Opacity, the 3D dialogs' sliders and
the flattener's balance, which the Flattener Preview panel also shows.
The Color panel, Swatch Options, the Color Picker's channel slider,
the Navigator and the Character panel keep their sliders as they were.

Docs: docs/target-app-parity.md.
2026-10-21 23:14:36 +07:00
dotCooCoo 4b56ce44a1 Brushes: renaming or deleting a brush updates every stroke that uses it
Delete Brush and a rename in Brush Options changed only the strokes in
the layers. Strokes in symbol definitions, graph designs, pattern
tiles, opacity masks, graphic styles and the art of other brushes kept
the old brush name. After a rename they drew as plain strokes, and
after a delete a brush made later with the same name painted them.

brush.delete and brush.options with newName now rename the brush, or
clear it, in every stroke in those places, and in the tile that
pattern editing's Cancel puts back. Only the objects that change, and
the groups that hold them, are copied. It is still one undo step.

Docs: docs/target-app-parity.md.
2026-10-21 23:14:35 +07:00
dotCooCoo 7aa25698d2 Brushes: dragging a brush reorders it within its type
The reference app reorders a brush that is dragged to a new place in
its Brushes panel, among the brushes of its type only. VectorCraft's
Brushes panel could not reorder brushes, and no command moved one.

brush.move {name | names, to?, type?} moves brushes to index to among
the brushes of their type, in brush.list order, as one undo step. A
move that keeps the order records no step. Brushes of different types,
or a type other than theirs, are refused with "brushes move only within
their type". In the Brushes panel, a brush dragged onto another brush
of its type goes before or after it by the half of the tile or row
under the pointer, and a bar marks the slot while it is held there. A
brush dropped on a brush of another type stays where it is, and the
status bar shows the refusal.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-21 23:14:33 +07:00
dotCooCoo b4fef5dc98 Library panels: a persistent panel whose file is gone stays listed as missing
At startup, a persistent swatch or graphic style library panel whose
file could not be read was closed and left out of the preferences,
with only a status-bar note. The next preferences save dropped it, so
moving or renaming the file once lost the panel and its settings.

Such a panel now reopens where the saved layout had it and stays in
the preferences. Its tab shows the file's name without the extension,
and its body shows "Missing:" with the file's path and a Locate
Library… button. The new command ui.libraryPanel.locate {panel,
path?} loads the library from the file given, or from one picked in
an open dialog, and shows it in the same panel, which keeps its view,
Show Find Field and Persistent. When the file's library is open in
another panel, the missing panel closes and that panel is brought
forward and made persistent.

A persistent panel whose User Defined library file is deleted while
the app runs shows the library as missing the same way; other panels
still close. window.swatchLibrary and window.graphicStyleLibrary take
a missing library's id, so a closed missing panel opens again.
Previous Library and Next Library are dimmed in a missing panel's
menu.

Docs: docs/mcp.md, docs/ui-parity.md, docs/target-app-parity.md.
2026-10-21 23:14:32 +07:00
dotCooCoo 7d4ae444b6 Docs: localization parity lists the Dutch, Danish and Indonesian catalogs
main registers nl, da and id catalogs with complete_menus, but
docs/localization-parity.md gave Indonesian 0 rows and the status
"none", had no Dutch or Danish row, and said "Nineteen non-English
catalogs".

The Indonesian row and new Dutch and Danish rows give the counts on
main at cb0a7d9: 5,279 rows, 750 of them @msg, for id and da, and 5,317
and 777 for nl. None of the three is in COMPLETE_MESSAGES, so the rows
say that the tests hold their menus and tl! literals complete but not
their messages. The page now counts 23 non-English catalogs. By the
page's rule (rows over 4,020, capped at 100% per part), Indonesian's
term in the 12-language score goes from 0 to 100, and the score goes
from ~74% to ~82%.

Docs: docs/localization-parity.md.
2026-10-21 23:14:31 +07:00
dotCooCoo bc6ffd9c1e Docs: localization parity names the counting commit and what each i18n check covers
The rows with a count date were counted on main at cb0a7d9; the method
sentence now names that commit. The sentence on the tests now says that
complete_menus covers menu strings and tl! literals, COMPLETE_MESSAGES
covers status and error messages, and Bulgarian is in the first only.
2026-10-21 23:14:27 +07:00
dotCooCoo 80088bbf25 Docs: localization parity row counts match the catalogs on main
docs/localization-parity.md gave the zh-hant catalog 4,741 rows, 742
of them @msg, while the catalog in #2784 had 4,784 and 756. On main it
has 4,892 and 790. Other rows that give a row count were also behind
main. For example, the Korean row gave 4,151 rows (4,870 on main), and
the Swedish row gave 668 @msg rows (795 on main).

Thirteen rows now give the counts on main, with "(counted 2026-10-21)".
A row is a non-blank line of the catalog that does not start with "#",
the rule that gives the page's French reference of 4,020 rows at
01e165af. The method sentence now says that a row with a count date was
counted on main on that date. The "N / 4,020" rows and every percentage
stay as they were.

The Bulgarian row said the tests hold its messages complete, but bg is
not in COMPLETE_MESSAGES. It now says the tests hold its menus and tl!
literals complete. The Portuguese row's "one|other plurals" gave the
row nine cells in an eight-column table. It now reads "one/other
plurals".

Docs: docs/localization-parity.md.
2026-10-21 23:14:27 +07:00
dotCooCoo 76058fb1b5 Type: the AltGr tests expect Ctrl+Alt+L to open Layer Options
Since #3355, Ctrl+Alt+L is New Layer Options… and opens Layer Options
for a new layer instead of adding a layer. On main merged with this
branch, ctrl_alt_chords_without_typed_text_still_run failed: its
Ctrl+Alt+L steps expected a new layer. They now expect Layer Options
in mode new with no layer added, while the Type tool edits and with
the Selection tool, and the test cancels the dialog between the two.

The doc comment of altgr_characters_typed_in_text_run_no_command names
New Layer Options… (Cmd+Alt+L) instead of New Layer, and the
docs/target-app-parity.md line says AltGr+L does not also open Layer
Options for a new layer.
2026-10-21 23:14:25 +07:00
dotCooCoo acb017e1f1 Type: a character typed with AltGr while editing text runs no command
Firefox on Windows reports AltGr as Ctrl and Alt held. In the web
build, while the Type tool edited text, a character typed with AltGr
was typed and also ran the command chord of its key: AltGr+L (ł on a
Polish layout) added a layer through Cmd+L, AltGr+Q (@ on a German
layout) ran Reset Tracking and Kerning, AltGr+E (€) opened Export for
Screens, AltGr+A (ą) ran Select All on Active Artboard, and AltGr+Z
(ż) undid the typing through Cmd+Z.

While the Type tool edits text, a key press with Ctrl and Alt held
that is followed by the text it typed is now dropped before the
command chords are matched. A Ctrl or Ctrl+Alt chord that types no
character runs its command as before, and key presses outside text
editing are handled as before. The desktop app receives AltGr
without Ctrl and Alt, and a press with Ctrl held types no text
there, so it behaves as before.

Docs: docs/target-app-parity.md.
2026-10-21 23:14:25 +07:00
dotCooCoo bac132d8d4 Docs: the document.open pages sentence names the file saved without PDF compatibility
docs/mcp.md said that `pages` that name every page "of such a file"
open it from its editing data. The sentence before it is about a file
without editing data, so "such a file" could be read as that file.

The sentence now says "a file saved without PDF compatibility".

Docs: docs/mcp.md.
2026-10-21 23:14:23 +07:00
bflatastic 1f6a76afa8 Save As: a typed extension of a format the save doesn't write is replaced
Squashed from #3372 onto main.
2026-10-21 23:14:20 +07:00
bflatastic 30203e60a1 PDF/.ai import: a .ai saved without PDF compatibility is placed and pasted from its editing data
Squashed from #2182 onto main.
2026-10-21 17:11:08 +07:00
dotCooCoo 1267efbcf9 Use Preview Bounds: objects are measured with their geometry effects
With Use Preview Bounds on, the bounding box, the Transform panel,
Align, Distribute, Distribute Spacing and object.setBounds measured
each object without its geometry effects. A square with Offset Path
10 measured as the square, and type with Outline Object measured by
its layout box instead of its glyphs.

The new vectorcraft_effects::preview module measures objects as they
are drawn. A path is measured by its effected shape, with the
geometry effects of each fill and stroke that paints. Type, images,
live objects and symbol instances are measured by their reshaped art.
A group or layer with geometry or Pathfinder effects, or with a fill
or stroke of its own that has geometry effects or paints members with
geometry effects, is measured by its evaluated art. A blend, envelope
or repeat whose objects have geometry effects is measured by its
evaluated art, with those objects measured after their effects. Raster
effects are not measured. In one object, the art of at most 4,096 symbol
instances is measured with its geometry effects, and the other
instances are measured without them. With Use Preview Bounds off, the
measures are unchanged.

object.setBounds sizes objects with geometry effects by measuring
them after each scale it tries, so type with Outline Object set to
100 pt wide gets a glyph box 100 pt wide.

Selection::anchors_box is split out of Selection::anchor_bounds. The
doc comment of VectorcraftApp::selection_bounds said that it includes
effects; it now says that it leaves them out.
2026-10-21 17:11:08 +07:00