Commit Graph
9906 Commits
Author SHA1 Message Date
dotCooCoo 89ee320591 Graphs: a series group also keeps its isolation and knockout
transparency.set and object.setProps with isolate, knockout or
knockoutShape on a series group now store them for the series
(groupIsolate, groupKnockout, groupKnockoutShape), and the series group
has them again when the graph is drawn again. Randomize Opacity, Sort
Objects and Global Edit store the opacity they give a series group, so
a redraw no longer puts back an older stored value over it.

A move or copy of an appearance onto a series group whose stored values
differ from its own now counts as a change, so the edit is kept. Tests
cover graphicStyle.redefine of a style linked to a series group.
2026-11-13 16:02:54 -08:00
dotCooCoo e06d0577b3 i18n: Japanese leaves out the rows #7211, #7214 and #7116 add
Open #7211, #7214 and #7116 add Japanese rows for 38 of the messages this
branch translates. A second row for the same key fails
bundled_catalogs_are_consistent once both sides merge, so this branch
drops its 38 rows and leaves those messages to the other pull requests.
The Japanese lines in docs/localization-parity.md and
docs/target-app-parity.md give the new counts.
2026-11-13 16:00:22 -08:00
dotCooCoo d5509c3b6c Guides: stripping and mapping ruler guides look at each child of a layer once
Node::strip_ruler_guides and Node::map_ruler_guide_positions asked a
layer whether its whole subtree held a ruler guide, then asked each
sublayer the same question again when filtering the children and again
when the recursive call started. A layer nested d deep was tested
2d + 1 times, so a chain of N layers cost about N^2 layer tests.

strip_ruler_guides runs when a document's objects are placed or pasted
(Clipboard::from_document), when a copy of the document is saved
(Document::guides_to_saved) and when a temporary editing layer is
removed (Document::remove_edit_layer). map_ruler_guide_positions runs
when an imported EPS is scaled.

A new held_guides reads the layer once and records which children are
ruler guides and which sublayers hold one; strip_held and map_held then
visit and copy only those sublayers. The guides removed, the order f is
called in, the art and its order, and the sharing of layers without a
guide are the same as before. Neither method records an undo step.
2026-11-13 15:58:43 -08:00
dotCooCoo 9a355b1a75 i18n: German leaves out the rows #7211, #7214 and #7116 add
Open #7211, #7214 and #7116 add German rows for 38 of the messages this
branch translates. A second row for the same key fails
bundled_catalogs_are_consistent once both sides merge, so this branch
drops its 38 rows and leaves those messages to the other pull requests.
The German lines in docs/localization-parity.md and
docs/target-app-parity.md give the new counts.
2026-11-13 15:58:36 -08:00
dotCooCoo c1572562de Merge main into fix/file-folder-param-classification 2026-11-13 15:55:47 -08:00
dotCooCoo d30831bd5a Merge main into feat/live-paint-cursor-swatch-preview 2026-11-13 15:54:47 -08:00
dotCooCoo 252ff7782a Merge main into fix/graph-series-gradient-per-mark
# Conflicts:
#	docs/mcp.md
2026-11-13 15:49:27 -08:00
dotCooCoo 92594378aa i18n: French leaves out the rows #7211, #7214 and #7116 add
Open #7211, #7214 and #7116 add French rows for 38 of the messages this
branch translates. A second row for the same key fails
bundled_catalogs_are_consistent once both sides merge, so this branch
drops its 38 rows and leaves those messages to the other pull requests.
The French row of docs/localization-parity.md gives the new counts.
2026-11-13 15:47:53 -08:00
dotCooCoo dd411ec6b4 Image Trace: a JPEG's 8 x 8 blocks no longer trace as staircase steps
A JPEG rounds each 8 x 8 block's tone on its own, which leaves a small
step at every block edge. Where a dark ground changes slowly, those steps
decided which of two palette colors a whole block got, and the trace
followed the block edges as a staircase.

The new deblock pass finds the block grid in the image: the mean step
between neighboring opaque pixels must peak at the same one of eight
positions at both block edges of a 16 px span, across and down. Cropped
JPEGs and JPEGs saved in another format are found the same way; pictures
of flat 8 x 8 cells are not. At each block edge, a stretch of eight lines
whose step is under the limit and whose pixels hold no edge has the step
spread over the eight pixels around the edge, as the deblocking filters
of ITU-T H.263 Annex J and MPEG-4 Part 2 Annex F.3.1 do. Larger steps are
kept. The limit, the edge guard and how much of each line's own step is
smoothed depend on the mode: Black and White smooths only the smallest
steps, and traces of more than 16 colors move every line of a stretch
by the same amount. The pass runs before the photo pre-filter and works
in strips of rows, so only its output is as large as the image.
2026-11-13 15:47:30 -08:00
dotCooCoo 1f6c9beb8c Tests: recorded steps keep a path only where the command takes it
recorded_steps_filter_only_unreadable_locations expected
object.setLiveShape's `path` to stay, but that command does not take a
`path` param, so the recorded step reads the key as a file and drops a
path outside the read root. The case now expects that, and
text.createInPath, whose `path` is the id of a path in the document,
covers a key that names part of the document.
2026-11-13 15:46:41 -08:00
dotCooCoo 76d99d6afb Merge main into fix/ai-graphs-keep-data 2026-11-13 15:46:07 -08:00
dotCooCoo 6fb49b9c4b Merge main into fix/issue-6784 2026-11-13 15:40:31 -08:00
dotCooCoo d7da446cd7 Text Wrap: Offset is a distance in the document's units
Text Wrap Options showed Offset as a plain number in points. It is now a
distance field in the document's General unit: a bare number is in that
unit, a typed unit is read as typed, and OK sends points.

The field's range is the one object.textWrap.options keeps an Offset to,
-1000 to 1000 pt, read from the engine's TEXT_WRAP_OFFSET_RANGE. A value
typed outside it, or text that doesn't read, is refused: the field
flashes and the dialog stays open. The ends as the field shows them in
another unit (352.7778 mm for 1000 pt) read back as the ends.

In the dialogs drawn by the shared dialog window, a click on OK no
longer confirms the dialog when the field it takes the focus from
refuses its text, as Enter already did not. OK pressed from the keyboard
after such a click still confirms.
2026-11-13 15:39:15 -08:00
dotCooCoo c477db87ba Live Paint: an edit that changes nothing records no undo step
A Live Paint Bucket click or drag over faces that already have the
fill, a stroke on an edge that already has the paint and width, Gap
Options with the options the groups have and no gap to close, and Make
or Merge given one Live Paint group alone now leave the document, the
undo and redo steps and the saved state as they are, and reply as
usual. Such a fill or stroke also leaves the recent colors as they are.

Gap Options with Close Gaps With Paths makes a group's faces again only
when it adds a path or what paint stops at changes, so the faces keep
their ids otherwise.
2026-11-13 15:39:04 -08:00
dotCooCoo a8a0316da7 Type: Create Outlines keeps the type object's own fills and strokes
Type > Create Outlines dropped the fills and strokes of the type object
itself (the items around the Appearance panel's Characters row), so the
outlines no longer drew what the type drew. On type without effects of
its own, Object > Expand outlines the type with the same command, so it
lost them before Fill or Stroke could expand them.

- Create Outlines puts those items on paths of the type's whole outline:
  the items below the Characters row on one path under the glyph paths,
  the others on one path over them, in their order. Unplaced gradients
  are fixed to the type's layout box, as the canvas paints them.
- object.expand.info reports the type object's own strokes, pattern
  fills and gradient fills, measuring a gradient on the whole outline.
  It counts them only when the type has an outline: type of only spaces
  reports none of them.
- The stroke flag of object.expand.info counts every stroke Outline
  Stroke outlines, not only the topmost one, for paths as well as type.
  Expand skipped Stroke for a visible stroke under a stroke with no
  paint.

Create Outlines still does not carry over the type object's own effects.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-13 15:39:04 -08:00
dotCooCoo 06031b7c9d Graphs: a series mark's gradient written unchanged leaves the kept gradient
A command that writes a series mark's paint compared the mark's gradient
with the series' kept gradient placed on the mark's box exactly. After
the mark was moved, the two differed by rounding, so the graph stored a
slightly different gradient and recorded an undo step. The vector,
focal point and freeform points now match within 1e-6 pt.
2026-11-13 15:35:01 -08:00
dotCooCoo 3429bbc76a Save, Export for Screens: warnings name an option the file doesn't read
The save commands' warnings now follow an export's .ai rules: a legacy
.ai file (aiVersion "7") reads only its own options, and the other .ai
and .ait files don't read outlineText, hiddenObjects, transparentImages
or preserveEditing. They name any option given beside the path that the
file doesn't read, not only compress, version, preview and precision,
and any such key in options. The bytes a save writes don't change.

The Save Options dialog sends a .ai save only the options the chosen
version reads, so a save from the dialog gets none of these warnings.
When the document's own file is already a .ai, the .ai options that a
save doesn't give and its file doesn't read keep their remembered
values, so the dialog still shows them; the save doesn't write them, and
a retry in another folder doesn't send them.

Export for Screens and Export Assets already accepted a key in a format
row or in a format's settings that only another format takes. Their
warnings now name it as given (formats[0].quality, settings.png.quality).
A key in a format's settings is named only when no row of that format,
as the export writes it, reads it. The options of an exportPreset, and
for assets.export the settings the document keeps, get no warning.

Docs: params text of document.save, document.exportForScreens and
assets.export; docs/mcp.md; docs/target-app-parity.md.
2026-11-13 15:34:25 -08:00
dotCooCoo f6d90063fc Merge main into fix/graph-label-paint-recolor 2026-11-13 15:33:30 -08:00
dotCooCoo af48843ff8 Tests: Image Trace's top-level paths key names a file
The location sweep listed imageTrace.make's `paths` as a document part
at the top of its params, so catalog_path_keys_match_location_policy
failed: Image Trace's path fidelity `paths` is exempt only inside its
tracing settings, and a top-level `paths` names a file, as it already
does for imageTrace.makeAndExpand.
2026-11-13 15:31:05 -08:00
dotCooCoo 9484b116ab Tests: screen-mode drags and popups start clear of the task bar
In Full Screen Mode with Menu Bar and Full Screen Mode the canvas is
about 390 pt wide, so the Contextual Task Bar under the selected
rectangle now wraps onto a second row and covers the canvas's center.
The middle-button pan, hand, zoom and context menu tests pressed there
and reached the bar instead of the canvas. They now press low on the
canvas, at a point the helper checks is clear of the bar.
2026-11-13 15:31:04 -08:00
dotCooCoo 71fab5bd81 Merge main into fix/it-message-rows 2026-11-13 15:30:48 -08:00
dotCooCoo 9594d39bd5 Edit Colors: no undo step when a recolor changes nothing
Invert Colors, the Convert to commands, Saturate, Adjust Color Balance,
the Blend commands and Recolor Artwork recorded an undo step even when
they changed no color, for example Invert Colors with fills and strokes
off, Saturate at 0 or a second Blend Front to Back. The empty step also
cleared the redo steps. paint.invert and paint.complement on whole
objects, Apply as Filter (addon.color.filter) and Apply Nearest Swatch
run the same pass and did the same.

These commands now run on a copy of the document and record the step
only when something changed. Convert to Indexed Color uses the same
helper. Recolor Artwork also compares the documents when it counted no
recolored paint, so rewriting a color group's swatches still records
its step.
2026-11-13 15:29:04 -08:00
dotCooCoo 6829dc02b8 Merge main into feat/smooth-cursor-without-path 2026-11-13 15:27:54 -08:00
BFlat 0b29b2b1f6 Merge pull request #7267 from dotCooCoo/fix/doc-info-values-translated
Document Info: values show in the interface language
2026-11-14 06:27:27 +07:00
BFlat 4a0f4b924e Merge pull request #7305 from dotCooCoo/fix/one-anchor-edit-no-remeasure
Path: anchor edits on a long selected path skip measuring it for the canvas check
2026-11-14 06:27:14 +07:00
BFlat b6fb2212c4 Merge pull request #7308 from dotCooCoo/fix/canvas-range-guides-one-pass
Canvas range: removed guides are looked up through sets, and nested layers are walked once
2026-11-14 06:27:05 +07:00
BFlat 26de97ee06 Merge pull request #7299 from dotCooCoo/fix/type-commands-thread-lookup
Type: thread checks look up the threads once per command
2026-11-14 06:26:56 +07:00
BFlat f6e84df143 Merge pull request #7306 from dotCooCoo/fix/path-type-rtl-fit
Type on a path: overflowing right-to-left type shows the longest start that fits
2026-11-14 06:26:48 +07:00
BFlat efba8bfd89 Merge pull request #7295 from dotCooCoo/fix/negative-wrap-offset
Text Wrap: a negative Offset lets text run into the wrap object
2026-11-14 06:26:39 +07:00
BFlat be1810e0c9 Merge pull request #7263 from dotCooCoo/feat/smooth-free-end-tangent
Smooth tool: an open path's end turns with the smoothing when a drag reaches it
2026-11-14 06:26:31 +07:00
BFlat 6fa41d4f76 Merge pull request #7304 from dotCooCoo/fix/graph-series-object-opacity-other-commands
Graphs: Global Edit, Randomize Opacity and Sort Objects keep what they give a series
2026-11-14 06:26:22 +07:00
BFlat 2beda0487e Merge pull request #7251 from ncic/snap-labels
Snap to Point draws no Smart Guides labels or lines with Smart Guides off
2026-11-14 06:26:14 +07:00
dotCooCoo 4129587abe Graphs: recolor, stroke and gradient edits on labels are kept for their kind
A recolor of a graph (Invert and Complement on the proxy, the Edit Colors
commands, Recolor Artwork, the color filters, Apply Nearest Swatch and the
ink limit of Print Ink Fixes) stored the new paint of the series marks but
not of the labels. stroke.set, the stroke weight steps, the gradient edits,
Swap Fill and Stroke and Default Fill and Stroke stored nothing when they
changed a label's characters. When the graph was drawn again, the labels
went back to their stored style.

- These commands now store, for every label of the kind they reach, the
  label's object rows when they change, and the fill, stroke, stroke weight,
  caps, joins, miter limit, dashes and stroke alignment of its characters
  when all of them show the change alike.
- A gradient is stored without its placement, and each label fits it to its
  own box. A stroke weight and dashes are stored as a scaled label shows
  them.
- When labels of one kind change differently, the frontmost one sets what
  the kind keeps.
- On a pie with Legends in Wedges, the legend labels' fill is stored only
  when every legend label reached ends up with the same fill, so a recolor
  of the whole pie leaves them black or white by their wedge.
- Axis lines, ticks and radar rings are not stored and are drawn again with
  their default paint.

Docs: docs/mcp.md, the commands' params text, docs/target-app-parity.md.
2026-11-13 15:22:55 -08:00
dotCooCoo 7a366b7c17 Merge main into fix/hindi-label-senses 2026-11-13 15:22:50 -08:00
dotCooCoo 96833747dc Merge main into fix/de-message-rows 2026-11-13 15:18:54 -08:00
dotCooCoo d132c330d0 Merge #7304 (fix/graph-series-object-opacity-other-commands) into fix/graph-series-group-opacity 2026-11-13 15:18:09 -08:00
dotCooCoo b9377cb7fe Merge main into fix/fr-message-rows 2026-11-13 15:17:58 -08:00
dotCooCoo 0fc37a0ddf Merge main into fix/slanted-seam-tolerance 2026-11-13 15:17:12 -08:00
dotCooCoo 9d3717b0c0 Merge main into fix/colored-solid-faces-one-order-limit 2026-11-13 15:16:25 -08:00
dotCooCoo 6280c90b0b Tests: split the file-key depth test
a_file_key_counts_at_any_depth grew past clippy's cognitive complexity
limit (34 of 30) and stopped the gate's clippy step. Its Image Trace
`paths` cases, its custom arrowhead cases and its deep-nesting case now
run as three tests of their own, with the same assertions.
2026-11-13 15:15:58 -08:00
dotCooCoo 492b76ace3 Merge main into fix/ai-warped-image-pieces-cropped 2026-11-13 15:15:36 -08:00
dotCooCoo aab26c2b31 Image Trace: a nearly flat dark ground keeps one color in a Limited palette
The Limited palette's median cut ranks cuts by pixel-weighted gain. A
large near-black ground with faint noise therefore took two colors less
than 0.02 apart in Oklab, and the trace drew blotches of one over the
other.

With 9 to 16 colors, a cut whose two sides both have a dark gray mean
(Oklab lightness under 0.30, chroma under 0.03) and lie less than 0.03
apart now has its gain scaled by (distance / 0.03)^2 while the cut is
chosen. The ground keeps one color, and the color it would have taken
goes to another cut. Document Library without swatches follows Limited.
Other color counts, Full Tone and Automatic choose the same cuts as
before.
2026-11-13 15:13:54 -08:00
dotCooCoo 5d543c906a Merge main into fix/item-4459 2026-11-13 15:13:10 -08:00
dotCooCoo aa18c36039 UI commands: catalog row for Save Actions with folder preferences
crates/mcp/src/ui_catalog.rs now carries the ui.actionSet.save params
text from crates/ui-egui/src/menus/ui_commands.rs, so `cargo xtask
ui-commands --check` passes.
2026-11-13 15:11:53 -08:00
dotCooCoo 38127af144 UI commands: catalog row for Export As with confined script links
crates/mcp/src/ui_catalog.rs now carries the file.exportAs params text
from crates/ui-egui/src/menus/ui_commands.rs, so `cargo xtask
ui-commands --check` passes.
2026-11-13 15:11:52 -08:00
dotCooCoo eb5ecde44a Merge main into fix/i18n-literal-brace-messages 2026-11-13 15:11:32 -08:00
dotCooCoo 11ecbe4e9a Merge main into fix/legacy-ai-type-kerning 2026-11-13 15:00:02 -08:00
dotCooCoo 90be8fba18 Brushes: art along a smooth curve keeps smooth edges
Art and pattern brushes bent their art along the chords of the flattened
path, with the tangent blended linearly between vertices, and scatter
brushes placed and turned their copies on the same chords. On a smooth
curve the bent art's edges followed the chords, and the curve fitted to
the result turned by up to a few degrees at its smooth anchors.

- On a chord that comes from flattening a curve, the frame now follows
  the cubic through both vertices with their tangents, so position and
  tangent meet at every vertex. A vertex tangent between two such chords
  is the tangent of the circle through the vertex and its neighbors, and
  it stays within a few times the flattening tolerance of each chord, so
  the frame stays near the curve next to a long chord. A curved chord
  whose end tangents turn further than that keeps to the chord.
- Art on a line of the path stays on the line, and a line keeps its own
  direction where it meets a curve.
- A calligraphic nib that follows the pen samples between vertices on
  the same frame, so its outline keeps its distance from the curve.
2026-11-13 14:58:15 -08:00
dotCooCoo bf05693305 Merge main into fix/i18n-select-a-path-reason 2026-11-13 14:55:39 -08:00
dotCooCoo 419698529c Merge main into fix/graph-series-gradient-per-mark
# Conflicts:
#	crates/engine/src/cmd/gradient.rs
#	crates/engine/src/cmd/graph.rs
#	docs/target-app-parity.md
2026-11-13 14:54:23 -08:00