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.
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.
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.
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.
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.
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.
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.
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.
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.
transparency.set and object.setProps with an object opacity or blend mode,
given a series group picked with Group Selection, set the group's own
opacity and blend mode, and the graph drew its series groups again
without them. The graph now stores them for the series (groupOpacity and
groupBlend) and puts them back on the series group when it is drawn
again. Commands that clear the group's own opacity and blend mode
(appearance.clear, graphicStyle.apply, appearance.transfer onto the
group, graphicStyle.redefine of a linked group) remove what the graph
stores.
A graph draws the art of a column or marker design inside a series again
from the stored design. Rows, effects and graphic styles that a command
gave that art were lost the next time the graph's data, type or size
changed. The paint commands already left the art out.
- The appearance.* row and whole-appearance commands, effect.apply,
appearance.addEffect and the effect.* commands that edit, move or
remove an effect, threeD.mapGraphic, graphicStyle.apply,
graphicStyle.addFromLibrary with apply, transparency.set with a fill
or stroke item, and appearance.copyFrom (as the target) leave out any
object inside a series group other than a path directly in it, given
by id, selected or reached through target: "contents". They edit the
other objects given, and a command whose objects are all design art
is an error.
- appearance.transfer with design art as its target, or as its source
without copy, is an error.
- A Pathfinder effect no longer groups selected design art.
- The paint commands given a design's copy with a fill or stroke item
leave it out as well.
docs/mcp.md states the rule, and the Graphs line in
docs/target-app-parity.md names it.
Deleting ruler guides and moving or scaling an artboard's guides asked
each layer whether its whole subtree held a matching guide, then asked
every sublayer the same question again on the way down. A layer nested
N deep was scanned N times, so a chain of N layers cost N(N+1)/2 layer
scans.
One read walk now records which children match and which sublayers hold
a match, and the edit visits and copies only those layers. The guides
removed, the count returned, the selection, the order the guides are
changed in and the sharing of untouched layers are the same as before.
The same walk replaces the repeated subtree scans in the other guide
edits in this file:
- tidying the ruler guides of an opened file (guides below art, in
objects, in opacity-mask art, in symbols and patterns)
- saving the guides as a list
- removing an editing layer while keeping its guides
A PDF-compatible .ai saved with Include Editing Data for Other Apps
wrote no text wrap options, so a wrap object opened from the file no
longer wrapped type. An object with only wrap options got no
dictionary at all.
The writer now writes each wrap object's options in its dictionary as
`AI11TextWrapOffset` (`/Real`) and `AI11TextWrapInvert` (`/Bool`, 1 or
0), the entries `text_wrap` in crates/eps/src/import/ai/read/document.rs
reads, beside the object's name, variables and opacity mask.
- The offset is the one in the art's space, so on a large canvas it is
written at 1/10 and read back at its size. An offset that is not
finite is written as the default 6 pt, and one past the -1000 to
1000 pt the reader keeps as the nearer end of that range.
- Art the writer draws for an object (a blend's steps, a symbol
instance written as its art, a brushed stroke's pieces, pattern
tiles, an object's drawn look) is written without the options of the
objects it is made from. The object itself and a symbol's own art
keep theirs.
- A clipping path written as its fills and its strokes has its options
once.
Docs: docs/file-format-parity.md, docs/target-app-parity.md.
On Linux and the BSDs, craft-window reads the desktop's window-button
layout (`button-layout` in `org.gnome.desktop.wm.preferences`) into
`Frame::App` when the desktop leaves the window's frame to the app, but
the app bar ignored it and always drew Minimize, Maximize and Close at
its right end.
- `CaptionLayout` lists the buttons at each end of the bar;
`caption_buttons` draws them there in the listed order, first one
leftmost, and the bar's other controls keep clear of both groups.
- The desktop app copies the layout of an app frame the desktop left to
it. An app frame turned on by `VECTORCRAFT_TITLEBAR=app` or by
VectorCraft Title Bar on Every Desktop, a window opened through
XWayland, macOS and Windows keep all three at the right.
Docs: docs/control-protocol.md, docs/target-app-parity.md.
A graph series kept a gradient with the document coordinates it had on
the one mark it was stored from, and gave that paint unchanged to every
mark when the graph was drawn again. The other marks showed the gradient
placed over the edited mark, and the placement stayed behind when the
data or the graph moved the marks.
The graph now stores a gradient relative to the unit box of the mark it
comes from (its geometric bounds, or its stroke's box for a stroke).
Each path of the series, the legend swatch and a Filled Lines band
included, takes it on its own box. Every store route does this:
paint.setFill and paint.setStroke, the Eyedropper, graphic styles,
Appearance commands, paint.setGradientGeom and the freeform point
edits. A command that writes a mark's paint as the graph drew it leaves
the stored gradient as it is and records no undo step.
The series paints save this as fillUnitBox and strokeUnitBox. A
gradient in a file saved without these flags is drawn where it was
stored. So is a gradient stored from a path with no width or height.
Docs: docs/mcp.md, the paint.setGradientGeom params text and the Graphs
line in docs/target-app-parity.md.