Commit Graph
9035 Commits
Author SHA1 Message Date
BFlat 449425e200 Merge pull request #6092 from dotCooCoo/fix/fill-changed-part
Canvas: moving anchors of a long path redraws only around them
2026-11-08 13:39:35 +08:00
BFlat c6025d74b9 Merge pull request #6091 from dotCooCoo/fix/ai-pdf-later-page-artboard
.ai import: type on a later page of a PDF of some artboards goes to its artboard
2026-11-08 13:39:20 +08:00
BFlat 6711bb1b70 Merge pull request #6088 from dotCooCoo/feat/prefs-search
Preferences: a search field finds a setting and goes to its category
2026-11-08 13:39:05 +08:00
BFlat 584a1665da Merge pull request #6087 from dotCooCoo/fix/shortcuts-path-param
Shortcuts: export, import, set, list and preset reject a param of the wrong type
2026-11-08 13:38:48 +08:00
BFlat 05aab8b437 Merge pull request #6086 from dotCooCoo/feat/snap-to-last-location
Smart Guides: Snap to Last Location puts a moved selection back where it began
2026-11-08 13:38:33 +08:00
BFlat 2f49bb6aa2 Merge pull request #6082 from dotCooCoo/fix/style-face-once
Type: layout looks up each style run's face once
2026-11-08 13:38:17 +08:00
BFlat b1f6203509 Merge pull request #6081 from dotCooCoo/fix/tr-unquoted-keys
i18n: error messages keep the keys and values they name without backticks
2026-11-08 13:38:02 +08:00
BFlat 91437c2091 Merge pull request #6080 from dotCooCoo/feat/ctrl-enter-ends-text-edit
Type: Cmd+Enter (Ctrl+Enter) ends text editing and keeps the text
2026-11-08 13:37:47 +08:00
BFlat 2c95bc9b87 Merge pull request #6079 from dotCooCoo/fix/issue-5816
Fix #5816: CJK and other fallback faces in the interface sit on the Latin baseline
2026-11-08 13:37:32 +08:00
BFlat d17dd59247 Merge pull request #6076 from dotCooCoo/feat/symbol-reset-transformation
Symbols: Reset Transformation returns an instance to its symbol's scale, rotation and shear
2026-11-08 13:37:16 +08:00
BFlat 263ddbea00 Merge pull request #6075 from dotCooCoo/fix/more-tests-without-time-limits
Tests: the CSS, glow and .ai Zstandard guards count work instead of timing it
2026-11-08 13:37:00 +08:00
BFlat e9271a7a00 Merge pull request #6074 from dotCooCoo/feat/history-new-document
History: the New Document button makes a document from the selected state
2026-11-08 13:36:45 +08:00
BFlat 70427de13d Merge pull request #6073 from dotCooCoo/fix/group-drag-outline
Selection: a group dragged with Real-time Drawing off shows each member's outline
2026-11-08 13:36:29 +08:00
dotCooCoo 4fefdaf95a Canvas: moving anchors of a long path redraws only around them
When only anchors of a path or compound path move, the area an edit
changed is now the box of the segments that start or end at a moved
anchor (and the line that closes an open subpath's fill at a moved
end), before and after, grown by the farthest the strokes reach. The
canvas then draws that part of the frame again instead of the whole
object. Objects with a non-solid paint, dashes, a width profile,
arrowheads, a brush, effects or an opacity mask still count whole.

At 1600 x 1200, single-threaded, the frame after one anchor of a filled
closed path moves takes 16.6 million CPU cycles instead of 56.4 million
with 50,000 anchors, and 65.6 million instead of 180.0 million with
200,000 anchors.
2026-11-08 12:21:58 +07:00
dotCooCoo 0f39b54a05 .ai import: type on a later page of a PDF of some artboards goes to its artboard
A PDF saved with some of its artboards has a page for each of them, while
the editing data keeps them all. The importer took the pages after the
first to show the artboards right after the first page's artboard. In a
PDF of artboards 2 and 4 of 4, the second page's type went to artboard 3.
In a PDF of artboards 1 and 3 of 4, the second page's type went to the
left edge of artboard 2.

Each page after the first now goes to an artboard of its size that comes
after the previous page's artboard and leaves an artboard for each later
page. The artboard chosen for the first page also leaves one for each
later page. When several artboards fit a later page, the importer
compares their art with the page and takes the closest one, or the first
of them on a tie. It compares at most 16 artboards for all the later
pages together, the same limit it uses for the first page. A later page
with no comparisons left takes the first artboard that fits it.

When the PDF has fewer pages than artboards and its first page shows the
first artboard, the first page's type and page art still go to the art's
box or to the editing data's artboard.
2026-11-08 12:21:54 +07:00
dotCooCoo aa2aa40166 Preferences: a search field finds a setting and goes to its category
The Preferences dialog has a Search Preferences field above the category
list. It has the keyboard focus when the dialog opens, and Cmd/Ctrl+F
focuses it again. While it has text, the list shows every setting whose
label, section or category contains it (ignoring case, in the interface
language or in English), or "No settings found". Choosing a setting shows
its category, scrolls to its row and highlights it. Escape in the field
with text clears it; Escape in the empty field closes the dialog.

The dialog's `__search` field holds the text, so `ui.dialog.set` drives
the search too.
2026-11-08 12:21:47 +07:00
dotCooCoo 7a035cd88f Shortcuts: export, import, set, list and preset reject a param of the wrong type
shortcuts.export and shortcuts.import read `path` only when it was a
string, so a `path` such as 5 or true was dropped and the file dialog
opened. They now return "`path` must be a string" and open no dialog;
an omitted or null `path` still asks for the file.

shortcuts.set (`id`, `shortcut`), shortcuts.list (`query`) and
shortcuts.preset (`name`) give the same error for a value that is not a
string, and shortcuts.set gives "`force` must be true or false" for a
`force` that is not true, false or null. Nothing changes when a param
is rejected.
2026-11-08 12:21:44 +07:00
dotCooCoo 313768efd5 Docs: Snap to Last Location line sits after the Shift move line and names every test 2026-11-08 12:21:37 +07:00
dotCooCoo 6270fda90b Smart Guides: Snap to Pixel takes precedence over Snap to Last Location
A short move with View > Snap to Pixel on returned to where it began and
showed a "last location" label, skipping the pixel step. Snap to Last
Location is now off while Snap to Pixel is on, for the Selection tool and
for paths Direct Selection moves by an anchor, so the move lands on whole
pixels as it does with the option off.
2026-11-08 12:21:37 +07:00
dotCooCoo 61a99ed4ed Smart Guides: Snap to Last Location puts paths Direct Selection moves by an anchor back
A path selected whole that Direct Selection moves held by one of its anchors snapped only through the anchor-drag targets, so Snap to Last Location never put it back. The move now goes back to where it began within Snapping Tolerance, labeled "last location", as a Selection tool move does; an Alt copy is not pulled back.
2026-11-08 12:21:36 +07:00
dotCooCoo b093e53e77 Smart Guides: Snap to Last Location puts a moved selection back where it began
Preferences > Smart Guides gets Snap to Last Location (`snapToLastLocation`,
off by default). With it and Smart Guides on, a selection moved by dragging
with the Selection, Group Selection or Direct Selection tool, Shift too, goes
back to where the move began while the move is within Snapping Tolerance,
labeled "last location". An Alt copy is not pulled back onto its original.

Source: https://helpx.adobe.com/illustrator/desktop/measure-and-align/grids-and-guides/smart-guides-options.html
The distance, the label and the copy rule are VectorCraft's own.
2026-11-08 12:21:36 +07:00
dotCooCoo f42fdf900f Type: layout looks up each style run's face once
Layout kept no record of a run's face, so each paragraph looked up the face
of its first character three times for its line metrics and once more to
shape it. The layout now keeps each run's face the first time it is looked
up and uses it for shaping, for paragraph metrics, for on-path type's empty
line and for the column offset of vertical point type. Glyphs, positions,
bounds and baselines do not change.

A test-only helper lays text out looking every face up at each use, and a
new test requires point, vertical point, area and path type laid out both
ways to match exactly.

The layouts of 5,000 short point type objects take a median of 215 million
CPU cycles of the laying-out thread instead of 236 million in a release
build (11 alternating runs of each build on Windows 11, measured while
other builds were running).
2026-11-08 12:21:32 +07:00
dotCooCoo a9fc7216a9 i18n: error messages keep the keys and values they name without backticks
Turkish error rows translated parameter keys and values that the English
writes without backticks, so a message named a key or value the command
does not accept: `group must be true or false` read as "grup doğru veya
yanlış", `index must be ≥ 0` as "dizin", and `span` with "object" and
"selection" as "yayılma", "nesne" and "seçim". The rows for the docking,
option and setting errors (onto, below, above, anchor, before, panel,
zone, column, group, action, move, tool, kerning, balance, brightness,
decimals, lang, percent, plane, scale, control, span, index) now keep the
key and its values as the English has them. `included` and `others` lose
the double quotes the English does not have.

Bulgarian and Catalan rows that translated bare true and false now keep
them. Hindi messages whose double-quoted values were translated or
misspelled ("auto", "contents", "none", "start", "corner", "selection" and
others) now keep the values as the English spells them.

A new test checks that every translated status or error message keeps
each value its English puts in double quotes.
2026-11-08 12:21:29 +07:00
dotCooCoo 0382ba5ee8 Type: Cmd+Enter (Ctrl+Enter) ends text editing and keeps the text
While the Type tool edits text, Cmd+Enter on macOS and Ctrl+Enter on
Windows and Linux typed a line break. It now ends editing as Escape
does: the typed text stays, the type stays selected, and the tool used
before editing is selected again. A held chord ends editing once; its
repeats type nothing and do not open the Move dialog.

Enter, Shift+Enter and Ctrl+Enter on macOS still type line breaks, and
so does the chord with Alt or Shift. Cmd+Ctrl+Enter on macOS ends
editing too. A command bound to the chord still runs instead, and
editing continues. While an IME composes, the chord stays the IME's.
2026-11-08 12:21:23 +07:00
dotCooCoo 5db4cfe9bc Fix #5816: bundled fallback faces and monospace text share the Latin baseline
The bundled craft-fonts Japanese, Georgian and Devanagari faces now get
the same baseline shift as installed fallback faces, so every glyph in
an interface label sits on the baseline of its family's first face.

Each fallback face's shift is measured against the first face of the
family it is added to (Inter for the proportional families, JetBrains
Mono for `mono`, egui's face for `Monospace`). Families whose first
faces need the same shift share one copy of the face; the others get a
copy named after their first face.

Tests: craft_fonts_sit_on_the_baseline_of_each_family checks each
bundled face in every family against its own baseline, and
fallback_faces_sit_on_the_ui_baseline now checks every family,
monospace ones included.
2026-11-08 12:21:20 +07:00
dotCooCoo 0ad4d4f06c Fix #5816: CJK fallback faces in the interface sit on the UI font's baseline
An installed face added for characters the interface fonts lack (Microsoft
YaHei for Simplified Chinese on Windows, for example) now gets a FontTweak
y_offset_factor computed from its ascent, descent and line gap against the
first face of the Proportional family, so its glyphs share that face's
baseline instead of centering the difference in row height. The bundled
faces and Latin text do not move.

This follows designcraft#394 (baseline_tweak from line metrics) and
effectcraft#1395. vectorcraft-text gains line_metrics, and a test face with
a CJK system face's vertical proportions checks the baseline at 13, 24 and
40 pt in the interface families.
2026-11-08 12:21:20 +07:00
dotCooCoo fff2ecd76b Symbols: Reset Transformation tests cover a mixed selection and negative stored sizes
An instance in perspective selected with a turned instance stays as it
was while the other is reset and returned in one undo step. Stored
natural sizes that are negative on either side give the art its own
size, unmirrored, as a zero size does.
2026-11-08 12:21:14 +07:00
dotCooCoo 283d46c1cc Symbols: Reset Transformation's enabled check does not measure the symbol's art 2026-11-08 12:21:14 +07:00
dotCooCoo 1cd607f596 Symbols: Reset Transformation keeps the art's size when the stored size is not positive 2026-11-08 12:21:14 +07:00
dotCooCoo 98265b7435 Docs: list every Reset Transformation test in the progress line 2026-11-08 12:21:13 +07:00
dotCooCoo d687456978 Symbols: Reset Transformation returns an instance to its symbol's scale, rotation and shear
The Symbols panel menu's Reset Transformation and the Control bar's Reset
(shown while symbol instances are selected) give the selected instances
their symbol's own scale again, without rotation, shear or reflection, as
one undo step (symbol.instance.resetTransform). Each instance keeps the
center of its art's bounding box in place. Instances in perspective and
instances already at their symbol's scale are left as they are, no undo
step is added when nothing changes, and both controls are enabled only
while a selected instance would change.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-08 12:21:12 +07:00
dotCooCoo 1d32aff63f Tests: the CSS, glow and .ai Zstandard guards count work instead of timing it
Three tests failed on a loaded machine because they asserted elapsed
time. Each now counts the work that the slow behavior it guards
against would repeat, with a counter compiled only into tests:

- The CSS cascade test counts selector tests, at most two per element
  (testing every rule against every element tests N x N). It styles
  5,000 elements, so the slow behavior fails on the count rather than
  on the hang guard, which now waits 300 s.
- The stacked-glow test counts the silhouettes drawn, 30 for 30 glows
  with and without the shadow cache.
- The Zstandard frames test counts the bytes looked at to find the
  zero padding.

The hang guards for invalid dash patterns, text layout and script
checks of a pipe wait 300 s instead of 20 s.
2026-11-08 12:21:06 +07:00
dotCooCoo 0ce3147aab History: the New Document button makes a document from the selected state
The History panel gets a New Document from State button at its bottom,
which runs the new edit.newDocumentFromState command. The command makes
a new document holding the art of a History panel row ({index?}, the
current state when omitted) and makes it the active document. An index
that names no state is an error and changes nothing.

The new document takes the next Untitled-N name, is marked unsaved, has
nothing selected, no steps to undo or redo and no modified date, and
leaves symbol, opacity-mask and pattern editing; the art drawn in a
pattern's tile is stored in the pattern, as Done stores it. Its links point at the files the
source finds, including files found in the source's folder away from the
links' paths. Those files are looked for only within the folders the
asking caller may read; for a caller without limits, within the folders
the caller that opened the source may read. The source
document, its steps and its saved state stay as they are; typing or a
drag in progress is first kept as a step, as Undo keeps it. While an IME
composes, the command waits, as Undo does.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-08 12:20:59 +07:00
dotCooCoo 17dc4ed46d Selection: tests check mesh lines in drag outlines; docs list the changed cases
The mesh tests now count each feedback path's subpaths, so a mesh that
drew its boundary instead of its mesh lines fails them. The progress-doc
lines name the Pathfinder, mesh and symbol instance outlines and the
limit's count of evaluated objects.
2026-11-08 12:20:55 +07:00
dotCooCoo 63de44dcca Selection: a group dragged with Real-time Drawing off shows each member's outline
With Real-time Drawing and Editing off, each pointer move of a drag ran one
boolean union of a group's members to draw its outline. A group of 256
overlapping ellipses took seconds per move, and at 1,024 overlapping ellipses
the union went over its budget and no outline showed.

A move or handle drag now draws the outline of each visible member of a group
or intertwine, and of each object a blend, envelope, repeat, Pathfinder effect
or object effect evaluates to, without uniting them. A gradient mesh draws its
mesh lines and a symbol instance its bounds, as their selection highlights do.
The limit of 100,000 counts outline points and evaluated objects, so a
selection past it shows its moved bounds.

A compound shape or Pathfinder effect still evaluates its boolean on each move,
and so does a clip group whose clipping path is a group.
2026-11-08 12:20:55 +07:00
BFlat 3362176c10 Merge pull request #6070 from dotCooCoo/fix/render-reuse-pixels
Canvas: a pan by whole pixels copies the pixels that stay on screen
2026-11-08 13:20:32 +08:00
BFlat effc49465d Merge pull request #6069 from dotCooCoo/fix/graph-series-paint-follows-appearance
Graphs: Appearance commands and the Eyedropper update a series' stored paint
2026-11-08 13:20:16 +08:00
dotCooCoo cda188864b Canvas: a pan by whole pixels copies the pixels that stay on screen
Squashed from #6070 onto main.
2026-11-08 12:01:47 +07:00
dotCooCoo 90cd4797ea Graphs: an added or duplicated top row sets the series' stored paint
appearance.addFill, appearance.addStroke and appearance.duplicateItem can
put a new topmost row on a series mark with the paint the mark already
shows. When another mark of the series had set a different stored paint,
the mark's top paint did not change, so the graph kept the other mark's
paint and drew it again. A new topmost visible row now stores its paint,
as an Eyedropper append already does.
2026-11-08 12:01:39 +07:00
dotCooCoo 0ce16936b7 Graphs: docs say a band's stroke opacity is still kept
The Appearance commands do not store a stroke paint or weight for a series
that draws a Filled Lines band, but they do store a stroke opacity set on the
band, and the band's 0.25 pt black outline takes it when the graph is drawn
again. docs/mcp.md now says so, and a test covers it.
2026-11-08 12:01:39 +07:00
dotCooCoo d136ddb0cc Graphs: Appearance commands' params text names the stored opacity
The params text of the Appearance commands that update a series' stored
paint said the graph stores the paint and weight of the topmost visible
fill and stroke. Each of them also stores that row's opacity, as
docs/mcp.md says. The text now names the opacity too.
2026-11-08 12:01:39 +07:00
dotCooCoo 9a08f64a04 Graphs: Appearance commands and the Eyedropper update a series' stored paint
paint.setFill, paint.setStroke, paint.none, Apply Fill to Stroke and Apply
Stroke to Fill stored a series' paint on the graph. appearance.setItem, the
Eyedropper, appearance.transfer, Clear Appearance, Reduce to Basic Appearance
and the add, remove, move and duplicate row commands stored no paint or weight.
An Eyedropper pick of a blue fill at 40% onto a red column drew red at 40%
after the next redraw.

These commands and Show All Hidden Attributes now store the paint and weight
of the topmost visible fill and stroke of a path directly in a series group,
in the same undo step. A color, weight or opacity that a command writes to that
row replaces the stored value even when the mark's own value does not change. A
row that has no paint before and after the command does not change the stored
paint. These commands store no stroke for a series that draws Filled Lines
bands, and a band no longer takes its color from an empty stored stroke.

The stored opacity also comes from the topmost visible row: hiding a top row
stores the row under it, and an opacity set on a hidden top row is not stored.

Follows #5501.
2026-11-08 12:01:39 +07:00
BFlat 5a820855bf Merge pull request #6068 from dotCooCoo/feat/shortcuts-export-text
Keyboard Shortcuts: Export Text saves the shortcut list as a text file
2026-11-08 13:00:56 +08:00
BFlat b99038e6ac Merge pull request #6058 from dotCooCoo/fix/wasm-font-menu-fields
Font menu: the wasm build has no unread wheel-field warnings
2026-11-08 13:00:40 +08:00
BFlat 212ac6191d Merge pull request #6057 from dotCooCoo/fix/pdfx-bleed-warning
PDF export: warn when a PDF/X file leaves out the document's bleed
2026-11-08 13:00:24 +08:00
BFlat 9d430637b5 Merge pull request #6056 from dotCooCoo/fix/tests-without-time-limits
Tests: the shape builder and large edit guards count work instead of timing it
2026-11-08 13:00:08 +08:00
BFlat 9a1ff5e246 Merge pull request #6055 from dotCooCoo/fix/tr-keys-kept
i18n: Turkish error messages keep the parameter keys they name
2026-11-08 12:59:53 +08:00
BFlat f83ef70b5e Merge pull request #6054 from dotCooCoo/fix/open-layout-once
Open: the first frame drawn after the open uses the layouts it made for type objects
2026-11-08 12:59:39 +08:00
BFlat 436faefd83 Merge pull request #6053 from dotCooCoo/fix/wasm-menu-open-import
Menus: the wasm build has no unused import warning for menu_open
2026-11-08 12:59:24 +08:00
BFlat 8388520700 Merge pull request #6051 from dotCooCoo/docs/stroke-outline-line
Docs: the stroke outline reuse line is listed once
2026-11-08 12:59:09 +08:00