Commit Graph
1849 Commits
Author SHA1 Message Date
Taha-Mahmoodi 1b5d11ef4b Units: Preferences › East Asian Type reads, with Q and Ha units (#394)
Squashed from #4845 onto main.
2026-11-02 14:36:08 +07:00
Don Omondi 15a5e64134 #4919: Create Swatch Legend becomes an add-on under Object › Plug-ins › Color Effects with a dialog
addon.color.swatchLegend replaces swatch.legend. The dialog sets columns, chip size, gap, the values shown
and whether to use only the swatches selected in the Swatches panel, with a preview; duplicate value
kinds are refused. The Swatches panel menu item is removed. Catalog rows in all 26 languages.
2026-11-02 14:36:08 +07:00
Don Omondi 236a3c264d Swatch legend: no unreachable! in the test
The workspace lints ban it; the test panics with a message instead.
2026-11-02 14:36:07 +07:00
Don Omondi aa71acc29f Swatch legend: linked chips, labels that fit, exact Gray
Each chip's fill links to its swatch as paint.setFill {swatch} does, so
editing a global or spot swatch recolours the legend. Labels are area
type the size of the chip that shrinks text to fit. Gray values use the
app's own Gray conversion, and fractional column counts are refused.
2026-11-02 14:36:07 +07:00
Don Omondi c823e7f5b2 Fix #4919: Create Swatch Legend
swatch.legend draws a grid of chips, one per colour swatch (the given
ones, else every one), each filled with and linked to its swatch and
labelled with its name and colour values (HEX, RGB, CMYK, Lab or
Grayscale; by default its own model; spot swatches marked), black on
light chips and white on dark ones, as one selected group in one undo
step. The Swatches panel menu's Create Swatch Legend draws the selected
colour swatches, else every one.
2026-11-02 14:36:07 +07:00
Wadah Badawi 66e22f4ba1 M2.1: recurse into groups and compound paths for path.average 2026-11-02 14:36:07 +07:00
NetterSilverandClaude Sonnet 5.5 88d8a7839e fix: validate parse_date calendar dates with chrono
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-02 14:36:06 +07:00
NetterSilverandClaude Haiku 5.5 83ed70acce Validate hyphen placement and days in month in parse_date
Found while testing crates/engine/src/cmd/fileio/naming.rs:103

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-02 14:36:06 +07:00
dotCooCoo 2fafe25c27 Asset Export: Import Preset and Export Preset read and write preset files
Squashed from #5032 onto main.
2026-11-02 14:33:29 +07:00
dotCooCoo b1c98821d6 Clipboard: a bitmap pasted from another app is decoded off the UI thread
Squashed from #4277 onto main.
2026-11-02 14:33:02 +07:00
dotCooCoo e8e09af782 Brushes: Calligraphic and Scatter values follow pen tilt, bearing and rotation
Squashed from #5031 onto main.
2026-11-02 14:33:02 +07:00
bflatastic d5edca7452 Type: the East Asian character settings get their own method 2026-11-02 14:32:59 +07:00
dotCooCoo e13cf73ae0 Type: Tate-chu-yoko Settings move a block up, down, left or right
Squashed from #5206 onto main.
2026-11-02 14:32:59 +07:00
dotCooCoo ec0a98a77b Selection: a drag with Real-time Drawing off shows the bounds of a selection too big to outline
With Real-time Drawing and Editing off, a drag drew one outline per selected
object with no limit, so a selection with hundreds of thousands of points
built the overlay mesh that the canvas's 100,000-point limit keeps it from
drawing at rest (#525, #2460). Past the same number of points the drag now
draws the moved selection's bounds, as the canvas does for the selection at
rest.
2026-11-02 14:32:58 +07:00
dotCooCoo c4dfe6bfc2 Selection: with Real-time Drawing off, the bounding box moves with a move drag
With Preferences › Performance › Real-time Drawing and Editing off, a
Selection tool move drag leaves the object in place until release, and
the bounding box was hidden for the whole drag. The box, with its
handles, now follows the pointer during the drag (Session::deferred_move
gives the offset the document has not taken yet). Scale and rotate
drags, and drags with Real-time Drawing on, hide the box as before.

Docs: docs/target-app-parity.md.
2026-11-02 14:32:58 +07:00
dotCooCoo 79c5218f8a Fix #5161: Shape Builder merges across a line under a merged shape's edge
Where a line lies under the outline of a closed path in front of it (such as
a shape an earlier merge made, which takes the place of the art in front of
the lines), the planar map gave that stretch only to the closed path, so the
line had no piece there. A merge or an erase across it left the line whole,
and the next map split the new shape along it into two regions.

- pathops: each planar edge records every input it lies on, and
  BuilderArrangement::lines_under holds the lines' pieces under a closed
  outline in front of them. lines, edges and Live Paint are unchanged.
- tools: BuilderMap adds those pieces to its lines, so a merge or an erase
  removes the stretch between the regions it takes, as it does elsewhere.
  An Alt-click where a line lies under an edge hits the one in front.
2026-11-02 14:32:57 +07:00
dotCooCoo 82806d1441 Fonts: Find Font and Replace Missing Fonts reach the type in symbols
Exports warn about type in a symbol's art that is set in a missing
font and point to Find Font, but Find Font and Replace Missing Fonts
only looked at the type on the layers.

- text.fonts lists the fonts of the type in the document's symbols too;
  with selectionOnly, of the symbols the selected instances show.
- select.font (Find) also selects the instances of the symbols whose
  art uses the font in type that is not hidden or locked.
- text.replaceFont changes that type in the symbols in scope, so every
  instance follows. Type hidden or locked in a symbol's art, and the
  type of symbols that only a selected hidden or locked instance shows,
  keeps its font and is counted in skipped.
- addon.cleanup.replaceFonts replaces missing fonts in symbols' type.

While a symbol is edited, its type is taken from the editing layer
only, so it is counted and changed once.
2026-11-02 14:32:55 +07:00
dotCooCoo 405372555d .ai import: the document's graphic styles open in the panel with their objects linked
Squashed from #5155 onto main.
2026-11-02 14:32:53 +07:00
dotCooCoo 0e38796573 .ai import: placed files are found by the folder they keep relative to the document
Squashed from #5176 onto main.
2026-11-02 14:32:53 +07:00
dotCooCoo 56f6128f94 .ai import: a line width of 0 draws as a hairline
Squashed from #5174 onto main.
2026-11-02 14:32:53 +07:00
dotCooCoo e8cd6c173a Variables: Save Variable Library… writes the variables and data sets as an XML library
Squashed from #5147 onto main.
2026-11-02 14:32:52 +07:00
dotCooCoo 6be88a24b4 Fix #785: commands refuse an id that isn't an object id instead of using the selection
Commands whose `id` or `ids` the shared check in Session::execute does not
read still parsed them with id_param/ids_param, which drop anything that is
not a non-negative integer, and then acted on the selection or the current
layer. `object.blend.make {"ids": 3}` blended the selection,
`object.envelope.makeWithWarp {"ids": [2, "x"]}` warped the selection,
`graph.setData {"id": "2"}` changed the selected graph and
`layer.newSublayer {"parent": "2"}` added a sublayer to the current layer.

- cmd::named_ids and cmd::named_id read `ids`/`id` as targets does: a value
  that is not an object id, or an unresolved step reference, is an error.
- The symbol and brush, Live Paint, Shape Builder and Image Trace, blend,
  envelope and mesh, perspective, Liquify, Puppet Warp and graph helpers use
  them in place of the lenient readers.
- layer.clippingMask.toggle checks `id`, and layer.newSublayer checks
  `parent`, with checked_id before falling back to the highlighted row or the
  current layer.
2026-11-02 14:32:49 +07:00
Brandon Thomas cfb30d8139 Merge pull request #5214 from dotCooCoo/feat/recolor-global-adjust
Recolor: the Global Adjust sliders change every color at once
2026-11-02 00:34:59 -05:00
Brandon Thomas c4a394c536 Merge pull request #5203 from dotCooCoo/fix/empty-text-clip-kept
Artwork Cleanup: Empty Text and Off-Artboard Art leave type that clips art
2026-11-02 00:34:49 -05:00
Brandon Thomas 9269cb7cf3 Merge pull request #5197 from dotCooCoo/fix/cleanup-leaves-hidden-locked-art
Artwork Cleanup: Simplify Anchors and Deep Ungroup leave hidden and locked art alone
2026-11-02 00:34:43 -05:00
dotCooCoo 69e5eecde0 .ai import: artboard display options, raster effects settings and the header's author come in
Squashed from #5102 onto main.
2026-11-02 12:04:24 +07:00
bflatastic ae46139b20 Variables: Edit Data Set's rename test undoes the one step it adds 2026-11-02 12:04:22 +07:00
dotCooCoo ab0072a39e Variables: Edit Data Set's Name field renames the data set
Squashed from #5121 onto main.
2026-11-02 12:04:22 +07:00
dotCooCoo 899a4c2bcb Variables: Import Data Sets reads CSV files that are not UTF-8 as Windows-1252
Squashed from #5116 onto main.
2026-11-02 12:04:21 +07:00
dotCooCoo 2b7b12df33 Symbols: the edited symbol takes the text wrap its area type gets after a wrap object moves
Symbol editing copies the editing layer's art into the symbol before Text Wrap, list numbering and threaded re-flow update that layer, so moving a wrap object in the edit left the symbol, its other instances and the saved file with the old wrap. The edit now syncs the symbol again after those passes, and when that changes the symbol, inline graphics of it are refreshed and the threads holding them re-flow.
2026-11-02 12:04:20 +07:00
dotCooCoo 294d13d857 Symbols: an instance in an opacity mask follows an edit of its dynamic symbol
The appearance changes of the instances on the layers now follow the edited objects through the same pass as the instances in other symbols, graph designs, pattern tiles and brushes. That pass also reaches instances used as opacity-mask art, which keep their changes on the same objects when an edit reorders them and drop the change to an object the edit deletes.
2026-11-02 12:04:20 +07:00
dotCooCoo 5c678ed52c Symbols: instances in pattern tiles, graph designs and brushes follow an edit of their dynamic symbol 2026-11-02 12:04:20 +07:00
dotCooCoo 87dea538ae Symbols: instances inside other symbols' art follow an edit of their dynamic symbol
Editing a dynamic symbol moved each placed instance's appearance changes with the objects they
name, but an instance stored in the art of another symbol kept its changes at the old paths, so
placing that symbol showed a change on the wrong object. Those instances, opacity masks included,
now follow the edit too and keep only the changes to objects the art still has.
2026-11-02 12:04:19 +07:00
dotCooCoo 0af8096364 Symbols: a refused switch to another symbol keeps the current edit, and isolation stays on the editing layer
symbol.edit checks the new placement before it ends the symbol being edited, so a call with an out-of-range x or y fails and leaves the current edit open. While a symbol is edited, object.isolate refuses art outside the editing layer, and object.exitIsolation goes back to the editing layer only from a group inside it; from any other isolation it leaves symbol editing mode.
2026-11-02 12:04:18 +07:00
dotCooCoo 7a527fce64 Character Styles: New Character Style keeps a language tag the selected text holds
charStyle.new now validates attrs against the target text's attributes, so a
language tag that is not in the list but that the selected run already holds
(a native file can store any tag) is kept. Any other unlisted tag is still an
error.
2026-11-02 12:04:16 +07:00
dotCooCoo 6e7945773e Character Styles: Style Options sets Advanced Character Formats
Character Style Options and New Character Style get an Advanced
Character Formats section with Horizontal Scale, Vertical Scale,
Baseline Shift, Character Rotation and Language. Empty fields stay
unset, an explicit 100%, 0 degrees or English: USA stays distinct from
unset, and Reset Panel on the section clears only these five. Scales
take 1% to 10000% and baseline shift -1296 pt to 1296 pt, as
text.setRangeStyle does; rotation is stored from -180 to 180 degrees.
Language sets the language the characters are shaped in; hyphenation
and spelling do not change.

A field still as it opened keeps its stored value without the range
check, so a style captured from a scaled type object can be renamed.
The same applies to Basic's Size and Leading minimum.

charStyle.edit keeps a language tag that is not in the list when the
style already has it, so a style read from a file with such a tag can
be edited.
2026-11-02 12:04:16 +07:00
dotCooCoo 3cb252198a OpenType: the panel's Position menu sets superscript, subscript, numerator or denominator glyphs
The OpenType panel gets a Position menu after Figure, with Default
Position, Superscript, Subscript, Numerator and Denominator. `numr` and
`dnom` join the extra features (the existing bits keep their indices),
so they round-trip through the stored tags and reach the shaper.

text.setStyle and text.setRangeStyle take `featureChanges`, which turns
features on or off on top of each character's own features in one
command and keeps every tag the list does not name. The Figure menu,
the Position menu and the checkboxes send it, so on a selection whose
characters have different features each character keeps its other
features. Reset OpenType Features still sends `features`.

Catalog rows for Position:, Default Position, Numerator and
Denominator; one line each in docs/type-parity.md and
docs/target-app-parity.md.
2026-11-02 12:04:15 +07:00
dotCooCoo a6c64e2cf2 Type: choosing Optical kerning clears manual pair values, as Auto does 2026-11-02 12:04:15 +07:00
dotCooCoo d8d0602c64 File formats: JPEG 2000 prefers the display resolution box over the capture box in either order 2026-11-02 12:04:14 +07:00
dotCooCoo 3dad9dbbfc Transparency: makeOpacityMask refuses objects in ids that cannot be edited
A layer among the targets already stood only for its art that can be
edited. An object named in ids is now checked the same way: a hidden or
locked object, or one on a locked artboard, is refused with an error
instead of becoming the mask, being masked or getting an empty mask.
2026-11-02 12:04:14 +07:00
dotCooCoo 8a5ea9488e Gradient mesh: test Create Gradient Mesh at a point inside one of two selected objects 2026-11-02 12:04:12 +07:00
dotCooCoo 76be75400e Mesh: Create Gradient Mesh at a point outside the object keeps the path
object.mesh.create with `at` ignored a failed line placement and still replaced the
path with a bare 1x1 mesh. When the new mesh can't place its lines at the point, the
object is left as it is, and when nothing was converted the command fails with
"point is outside the object" and adds no undo step.
2026-11-02 12:04:11 +07:00
dotCooCoo e4a066f12a Appearance: effect.move's reply follows an explicit toItem to the first target 2026-11-02 12:04:10 +07:00
dotCooCoo 468102e101 Appearance: test effect.move's reply when the first selected object has no effect to move 2026-11-02 12:04:10 +07:00
dotCooCoo d57d0b8e67 Appearance: effect.move reports the effect's index in the object whose row it names
With the Appearance panel's active row, the row belongs to the first
selected object, which need not paint first. effect.move reported where
the effect landed in the first target in paint order; it now reports
where it landed in the first selected object for the active row, and in
the first target for an explicit fromItem, as effect.apply does.
2026-11-02 12:04:09 +07:00
dotCooCoo 53e24b5fdc Export for Screens: a folder named with dotless ı is not merged into i
Export for Screens compared names and folders by upper-casing each
character, which turned dotless ı into I. A row with the folder ı then
wrote into the folder i, and an artboard named ı was numbered as a
second i. NTFS keeps ı apart from i and I, and so does Unicode case
folding outside Turkic languages, so fold now leaves ı as it is.
2026-11-02 12:04:08 +07:00
dotCooCoo f46427167c .ai import: area type keeps its rows, columns, gutters and first baseline
Area type made from the editing data's text document came in with one
row, one column, the 18 pt gutter and the Ascent first baseline,
whatever its frame kept. Each area frame now keeps its rows and columns,
the gutter between rows and the gutter between columns, and its first
baseline (Fixed, Cap Height, Leading or x Height) with its minimum,
scaled with the art's units. Each frame of a thread keeps its own, and a
key that is missing or can't be read leaves that option as it was. A
first baseline the frame keeps is no longer replaced by the fixed one
that matches the file's first line.

AreaOptions gets row_gutter (rowGutter, left out while unset), which
layout spaces rows by; text.areaOptions takes and reports rowGutter, a
gutter given alone sets both, and the Area Type Options dialog shows
Row Gutter.
2026-11-02 12:04:07 +07:00
dotCooCoo d4f5004580 .ai import: area type flows around its text wrap objects
Fixes #2763. An object whose editing-data dictionary holds the text wrap
options keeps them (offset in points, 6 pt by default, clamped to
±1000 pt; Invert Wrap), and the objects after the text in a version 7
wraparound group (`*w` … `*W`) are wrap objects at the default options.
Area type below a wrap object in its layer flows around it before the
layers are compared with the page, and threaded type flows on into its
next frames. A Large Canvas file's offset is scaled with its art.

The wrap resolver moves into `vectorcraft_doc::text::resolve_wrap` for
the import and the edit-time refresh, and builds each wrap object's
outline once per layer. A file whose wrap shapes would copy more than
2,000,000 anchors is not read from its editing data.

Docs: docs/file-format-parity.md.
2026-11-02 12:04:05 +07:00
dotCooCoo 100730d4d3 .ai import: a file whose PDF part can't be read opens from its editing data
Squashed from #5051 onto main.
2026-11-02 12:04:04 +07:00
dotCooCoo 54436b0aa2 i18n: open, save and recovery messages name their counts in the singular or the plural
The status bar said "Opened with 1 note(s)", "Saved <path> with 1 note(s)",
"Discarded 1 recovered document(s)" and "Restored 1 recovered document(s)",
and the Global Edit options showed "Result(s): 1". They now use the singular
for 1 and the plural otherwise, in English through i18n::msg_n and in every
catalog through @msgplural rows (the Results line through an @plural row).

The engine's warnings for linked images and placed documents output as their
previews, and its errors for a page past a placed file's last page or
artboard, also name their counts in the singular or the plural.

The catalogs drop the rows no message reads any more: the plain "(s)" rows
of the changed messages and the @msg row for "Packaged {n} file(s){note}".

Follows #5002.
2026-11-02 12:04:04 +07:00