Commit Graph
6243 Commits
Author SHA1 Message Date
bflatastic 1924ddd1dd Properties: one filter leaves out Lock and Isolate Group while they're off (keeps show() within the cognitive complexity lint #4299 added) 2026-10-29 11:22:51 +07:00
dotCooCoo 7d04096840 Transparency: Make Opacity Mask is off for a targeted layer in isolation mode 2026-10-29 11:20:08 +07:00
dotCooCoo dfe201dec3 Transparency: isolation mode and opacity mask editing can't be entered from each other
Enter Isolation Mode worked while an opacity mask was edited, and Edit
Opacity Mask and View Opacity Mask worked in isolation mode, so each
mode replaced the other's isolated art. In the reference app, isolation
mode can't be entered while a mask is edited, and mask editing can't be
entered in isolation mode.

object.isolate and perspective.editText, which shows type in isolation
mode, are now off while an opacity mask is edited, and a call returns
an error that ends "stop editing the opacity mask first". In isolation
mode transparency.editOpacityMask and transparency.viewOpacityMask are
off, and transparency.makeOpacityMask refuses one target, an object or
a layer, which it would take into mask editing; a call returns an error
that ends "exit isolation mode first". Make Opacity Mask with two
objects still masks one with the other. Pattern editing mode does not
count as isolation mode for these commands.

Object > Perspective > Edit Text, the canvas context menu and the
Transparency panel's menu and Make Mask button follow the commands'
enablement. A click or Alt-click on the mask thumbnail in isolation
mode shows the error and does not edit the mask. While a mask is
edited, the Contextual Task Bar leaves out Isolate, and the Properties
panel's Quick Actions leave out Isolate Group.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-29 11:20:08 +07:00
dotCooCoo e251bbf159 Contextual Task Bar: the Fill and Stroke chips show the proxies' paints
The chips drew the first selected object's fill and stroke. They now show
the paints the Fill and Stroke proxies show, a group's painted art
included, and a "?" when the selected objects' paints differ. A click on
either chip shows the Swatches panel through `window.panel.activate`, so
it also appears when the panel is floating, closed or in an expanded dock
column; an open flyout stays open. The progress doc describes the
reference app's bar in its own words.
2026-10-29 11:20:08 +07:00
dotCooCoo 93bbe36bc9 Contextual Task Bar: a Stroke chip beside Fill picks the stroke color
The task bar's Fill chip had no Stroke counterpart. A Stroke chip now sits
beside it, drawn as a ring with the selected object's stroke paint, as the
Control bar's Stroke chip is. A click on it brings the Stroke proxy forward
and opens the Swatches panel, as a click on the Fill chip does for the
Fill proxy. The chip is left out with the Artboard tool, as Fill is.

The bar's width estimate, which centers the bar under the selection, grows
by the chip's width. The drag test's first square moves 20 pt right so its
bar still starts inside the canvas.
2026-10-29 11:20:08 +07:00
bflatastic 0362ae5453 Object: import choice in object/arrange.rs (#4299 made the imports explicit) 2026-10-29 11:20:07 +07:00
dotCooCoo 02f2dd8c5a Object: Unlock All and Show All with Shift+Alt act only within the selected object's group
Squashed from #4439 onto main.
2026-10-29 11:18:38 +07:00
dotCooCoo a8c166a957 Selection tool: Escape cancels a move, scale, rotation, marquee or widget drag
Escape during a Selection tool move or Alt-drag copy, a bounding-box
scale or rotation, a marquee, or a drag of a corner widget, a pie widget
or the brackets of type on a path did nothing, and the release then
applied the drag. Only a ruler guide, mirror axis or grid repeat drag
and the loaded text took Escape.

Escape in any of these drags now cancels it, the way Direct Selection
cancels its drags: the art returns to its state at the press, an
Alt-drag leaves no copy, no undo step is added, and the release does
nothing.
Outside a drag Escape works as before.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-29 11:18:38 +07:00
dotCooCoo bbf01223cb Snap to Glyph: the x-height guide stays on the glyphs' x-height
Character Rotation turned a glyph's baseline shift and scaling with the glyph, and the Skew path effect slants a glyph's height away from the path's normal, so the x-height guide moved off the glyphs. Each positioned glyph now carries the transform that removes its Character Rotation (PositionedGlyph::unturned), and the guide goes through the glyph's x-height point placed without it, measured across the baseline. Snap to Glyph also takes Smart Guides being on in the tools, as View › Snap to Glyph already does in the engine.
2026-10-29 11:18:38 +07:00
dotCooCoo f87b8af62b Snap to Glyph: points land on glyph anchors and line up with x-height, character widths and angles
With View › Snap to Glyph and Smart Guides on, a point drawn near a single
line of live type now also lands on the anchor points of its glyphs and lines
up with its x-height (raised or lowered by Baseline Shift) and with the edges
of each character's advance width along the baseline (proximity guides). In
rotated type the baseline, x-height and proximity guides run at the type's
angle, and type of one glyph also has angular guides along the glyph's slanted
straight segments; a segment that Shift keeps to its angle slides onto them.
A paragraph shows glyph bounds only, so its baselines are no longer guides.

FontFace::x_height gives a face's x-height in font units.
2026-10-29 11:18:38 +07:00
bflatastic b97098367a Render: import the shape-mask helpers in renderer/nodes.rs and blobs.rs (#4299 made the imports explicit) 2026-10-29 11:18:37 +07:00
bflatastic 103ec3050f Envelopes: import Color and PreserveShape in live/expand.rs (#4299 made the imports explicit) 2026-10-29 11:16:30 +07:00
dotCooCoo acc5e53c91 Envelopes: a pixelated CMYK image with its own grid mask is written without /Interpolate
PDF export writes a CMYK image whose opacity mask is a gray image on its
own pixel grid with the mask as the image's soft mask. That path always
asked viewers to smooth the image, so a pixelated piece of an envelope
with Anti-Alias off was still written with /Interpolate when it had such
a mask. It now takes the pixelated flag as images without a mask do, and
caches the smoothed and pixelated versions apart.
2026-10-29 11:07:58 +07:00
dotCooCoo ab69d8f6d9 Envelopes: Anti-Alias and Preserve Shape Using change how distorted images draw
Envelope Options stored Anti-Alias and Preserve Shape Using, but nothing that
draws an image read them: a distorted image was always smoothed and always
cut into clip groups.

- With Anti-Alias off, each piece of a distorted image is marked pixelated
  (saved as `pixelated`). The renderer draws it with nearest-neighbor
  sampling and without mips, SVG export writes `image-rendering: pixelated`,
  and PDF export writes it without /Interpolate.
- With Preserve Shape Using Transparency, each piece is the image with a
  white opacity mask in the piece's shape instead of a clip group. The
  renderer paints an image whose mask is one plain white path straight into
  that path, as it does for an image in a clip group, when the path lies
  inside the image's frame.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-29 11:07:57 +07:00
dotCooCoo 4651e80973 Star tool: Ctrl/Cmd holds the inner radius the star shows when the key goes down
The reference app keeps the inner radius of a star constant when Ctrl
or Command is held after the drag starts. VectorCraft's Star tool took
the held radius from the first drag event that carried the key, using
that event's outer radius. The canvas sends a drag only once the
pointer moves, so a key pressed with the pointer still scaled the
inner radius with the next move before holding it.

Ctrl/Cmd now holds the inner radius the star showed at the last drag
position before the key went down, with Alt's straight shoulders when
Alt was held. A new press and Escape clear the held radius. Before,
after a drag canceled with Escape, the next star took the canceled
star's inner radius when Ctrl/Cmd went down before that star's first
drag event.

Docs: docs/target-app-parity.md.
2026-10-29 11:07:53 +07:00
dotCooCoo 25e8836af9 Tools: Escape cancels an Anchor Point, Mesh, Shape Builder or Measure drag
Escape did not cancel a drag with the Anchor Point, Mesh, Shape Builder
and Measure tools, or a Direct Selection drag of a mesh point, a corner
widget or the brackets of type on a path: the drag went on until the
mouse was released. Escape cancels every other Direct Selection drag
and a drag with the Free Transform, Rotate, Reflect, Scale, Shear and
Gradient tools.

Escape now cancels an Anchor Point drag, a Mesh tool drag of a mesh
point or handle, and a Direct Selection drag of a mesh point or handle,
a corner widget or the brackets of type on a path. The art goes back to
how the press found it, no undo step is added, and the rest of the drag
and the release send nothing. Escape during a Shape Builder drag ends
it, so the release merges and deletes nothing; the tool takes Escape
only during the drag. Escape during a Measure tool drag ends it and
brings back the measurement shown before the press. Escape after an
Anchor Point or Direct Selection press that has not moved yet drops the
press. Otherwise, outside a drag, Escape does what it did before.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-29 11:07:46 +07:00
Don Omondi 92904ebcab fix(doc): forget removed objects and their layers' guides (#3575)
drop_beyond_canvas removed objects but left what names them: saved
selections, Asset Export entries and variable bindings kept their ids,
and layer guides of a removed sublayer named a layer that was gone. It now
runs tidy_saved_selections, prune_assets and prune_variable_bindings when
it removes objects, as edits do, and removes the layer guides of the
layers it removed.
2026-10-29 11:07:40 +07:00
Don Omondi 8f5b6b81b0 fix(doc): look into containers for objects beyond the canvas (#3575)
A layer's bounds leave out its hidden objects and a clipping container's
are its clipping path's, so objects beyond the canvas inside them were
kept. Layers and groups are now looked into object by object.

A clipping path beyond the canvas goes with the objects it clips, so no
other object becomes the clip; a top-level clipping layer is emptied and
stops clipping. A removed artboard's ruler origin goes and its id is
retired, as deleting it does.
2026-10-29 11:07:40 +07:00
Don Omondi 5b18da25a8 fix(format): remove what a native file has beyond the canvas (#3575)
Edits refuse to leave anything beyond MAX_COORD (doc_sane checks the
artboards, the guides, the ruler origin and the objects an edit touches),
but the native loader didn't check them. A file with one object, artboard,
guide or ruler origin out there opened without a warning, and then every
move failed with "result would exceed the canvas", in-range objects
included; saving kept it that way.

Document::drop_beyond_canvas removes objects whose geometric bounds aren't
finite or reach past MAX_COORD (a layer or non-clipping group keeps its
children within it), artboards with their artboard guides, and guides out
there, and puts the ruler origin back at the origin. load_file runs it
after the depth limit and reports what it did with the other load notes; a
file whose artboards all lie beyond the canvas is refused.
2026-10-29 11:07:40 +07:00
Don Omondi d60b6bf883 fix(doc): count the values buffered before an object's type (#3587)
NodeKind's reader buffers the fields that come before `type` as
serde_json::Values. VectorCraft writes `type` first, but a crafted file
can put a long array there: a group whose children held 50M numbers before
its type (a 96 KB gzip) peaked at 1.6 GB, and the cost grows with the
array up to MAX_JSON, before any object in it is counted.

The buffer is read through a counting visitor: each JSON value counts
against MAX_BUFFERED_VALUES (32M, 4M on wasm32) as it is read, and values
replayed from the buffer aren't counted twice. load_file reads within it;
the same file is now refused at a 1.1 GB peak.
2026-10-29 11:07:37 +07:00
Don Omondi eeae8c9136 fix(format): read a native document within an object budget (#3587)
Opening a native document now reads at most MAX_READ_NODES objects (4M,
512K on wasm32) and refuses the file past that with a message naming the
budget. Paths already read within MAX_READ_ANCHORS and the web build's JSON
cap is 256 MB, but the number of objects had no bound: a gzip'd document of
empty groups costs about 270 bytes per object once read against some 50 in
its JSON, so 10M groups in a 24 MB file took 2.7 GB to open.

NodeWire's id is read through counted_id, so each object counts once as it
is read. load_file reads through a private load_file_within so a test can
exercise the budget without a 4M-object document.
2026-10-29 11:07:37 +07:00
BFlat 2b36d641c1 Merge pull request #4426 from dotCooCoo/fix/leading-catalog-terms
i18n: each catalog names leading with one term
2026-10-29 11:02:49 +07:00
BFlat 21001e037a Merge pull request #4424 from el-j/fix/window-menu-order-4143
Fix #4143: Window menu lists panel items alphabetically by localized name
2026-10-29 11:02:32 +07:00
BFlat 718e87e54e Merge pull request #4423 from dotCooCoo/fix/shortcuts-hide-commands-needing-values
Keyboard Shortcuts: commands that need a value are not listed unless given a shortcut
2026-10-29 11:02:09 +07:00
BFlat 51357f0e9c Merge pull request #4422 from dotCooCoo/fix/hide-lock-disabled-in-isolation
Object: Lock, Hide, Unlock All and Show All are off in isolation mode
2026-10-29 11:01:56 +07:00
BFlat 1780af28f2 Merge pull request #4421 from dotCooCoo/fix/escape-cancels-distort-tool-drags
Distort tools: Escape cancels a Puppet Warp, perspective or Liquify drag
2026-10-29 11:01:42 +07:00
BFlat d43ba6d230 Merge pull request #4419 from dotCooCoo/fix/style-menu-delete-clears-highlight
Text styles: the panel menu's Duplicate highlights the copy and Delete clears the highlight
2026-10-29 11:01:22 +07:00
BFlat da9329ee7f Merge pull request #4417 from dotCooCoo/fix/closed-arc-y-base-sector
Arc tool: a closed arc with Base Along Y draws the X-axis sector mirrored
2026-10-29 11:01:07 +07:00
BFlat 4d634dae92 Merge pull request #4416 from dotCooCoo/fix/tabs-position-label-translated
Tabs: the position field's label is translated
2026-10-29 11:00:43 +07:00
BFlat 9c03111c84 Merge pull request #4414 from dotCooCoo/feat/blob-brush-fidelity-option
Blob Brush: Tool Options set its Fidelity
2026-10-29 11:00:30 +07:00
BFlat f60f707e85 Merge pull request #4413 from dotCooCoo/feat/style-drag-to-new-or-delete
Character and Paragraph Styles: a style dropped on New is copied, and one dropped on Delete is deleted
2026-10-29 11:00:16 +07:00
BFlat 7ebcd18eff Merge pull request #4410 from dotCooCoo/fix/blob-brush-merge-rule
Blob Brush: a stroke merges with the topmost matching path and its neighbors in its group or layer
2026-10-29 10:59:58 +07:00
BFlat 0ed947f162 Merge pull request #4407 from dotCooCoo/feat/layers-cmd-alt-click-new-layer-placement
Layers: Cmd/Ctrl+Alt-click places a new layer below the current one and a new sublayer at the bottom
2026-10-29 10:59:35 +07:00
BFlat 8ad8b5f2c3 Merge pull request #4405 from dotCooCoo/fix/issue-4036
Fix #4036: a .ai swatch library without layers loads its palette, not the default swatches
2026-10-29 10:59:20 +07:00
BFlat 7fa66e8c61 Merge pull request #4404 from dotCooCoo/feat/type-caret-follows-undo
Type: Undo and Redo put the caret where the undone or redone edit was
2026-10-29 10:59:06 +07:00
BFlat eead185a75 Merge pull request #4403 from dotCooCoo/fix/kerning-tracking-catalog-terms
i18n: Character panel Kerning and Tracking terms agree in each catalog
2026-10-29 10:58:55 +07:00
BFlat 47e0fa2a41 Merge pull request #4395 from dotCooCoo/fix/issue-3235
Part of #3235: PDF import keeps the spot swatch of a DeviceN color that mixes inks
2026-10-29 10:58:33 +07:00
BFlat 4072363c22 Merge pull request #4394 from dotCooCoo/feat/export-pixel-width-height
Export: document.export takes a pixel width or height for raster files
2026-10-29 10:58:15 +07:00
BFlat b5f126a464 Merge pull request #4393 from dotCooCoo/feat/screens-zip-deflates
Export for Screens: a ZIP export deflates its files
2026-10-29 10:57:59 +07:00
BFlat daffac2c2d Merge pull request #4401 from dotCooCoo/feat/layers-alt-click-selects-layer
Layers: Alt-click on a layer name selects the layer's art
2026-10-29 10:57:39 +07:00
BFlat 59ba74067b Merge pull request #4400 from dotCooCoo/feat/gradient-reset-click
Gradient: Cmd/Ctrl-click on the Gradient Fill box or the Gradient button resets to White, Black
2026-10-29 10:57:18 +07:00
BFlat a04c068ae0 Merge pull request #4399 from dotCooCoo/feat/color-bar-complement-inverse-clicks
Color panel: Cmd/Ctrl-click and Cmd/Ctrl+Shift-click on the spectrum apply Complement and Invert
2026-10-29 10:56:40 +07:00
BFlat 372809c891 Merge pull request #4398 from dotCooCoo/fix/issue-4326
Part of #4326: a drag whose mouse-up was lost ends once macOS reports no button down
2026-10-29 10:56:17 +07:00
BFlat f96144c784 Merge pull request #4388 from dotCooCoo/feat/scissors-alt-add-anchor
Scissors: Alt held switches to the Add Anchor Point tool
2026-10-29 10:55:56 +07:00
BFlat fddec26707 Merge pull request #4387 from dotCooCoo/feat/type-tool-modifier-switch
Type tools: Shift switches between horizontal and vertical, and Alt switches between area and path type
2026-10-29 10:55:35 +07:00
BFlat a101ebe44d Merge pull request #4386 from dotCooCoo/feat/units-cycle-shortcut
Document: Cmd+Alt+Shift+U switches to the next unit of measurement
2026-10-29 10:55:09 +07:00
BFlat 301caf5851 Merge pull request #4385 from dotCooCoo/feat/width-tool-escape-deselects
Width tool: Escape deselects the selected width points
2026-10-29 10:54:45 +07:00
BFlat ef815a00d3 Merge pull request #4384 from dotCooCoo/feat/arc-tool-drag-keys
Arc tool: C, F and Up/Down change the arc while it is dragged out
2026-10-29 10:54:11 +07:00
BFlat c4dda01263 Merge pull request #4380 from dotCooCoo/feat/blob-brush-alt-smooth
Blob Brush: Alt switches to the Smooth tool while it is held
2026-10-29 10:53:57 +07:00
BFlat 63aa7fc38c Merge pull request #4376 from dotCooCoo/fix/pencil-alt-smooth-radius
Pencil: Alt smooths as far from the drag as the Smooth tool does
2026-10-29 10:53:40 +07:00