Commit Graph
6170 Commits
Author SHA1 Message Date
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
BFlat 575b3027f6 Merge pull request #4375 from dotCooCoo/fix/shape-builder-merge-fewer-passes
Shape Builder: a merge walks the arrangement once per batch of faces
2026-10-29 10:53:21 +07:00
BFlat 1da191ae76 Merge pull request #4367 from Silvertree2010/fix/4262-resize-bug-locked-ratio-scaling
Fix Shift-scaling a corner handle along a single axis
2026-10-29 10:53:00 +07:00
BFlat 1fb627749a Merge pull request #4363 from dotCooCoo/fix/stroke-weight-steps-off-list
Stroke Weight: a step from a weight between the presets goes to the next preset
2026-10-29 10:52:37 +07:00
BFlat 489790826d Merge pull request #4361 from dotCooCoo/fix/curvature-delete-reshapes
Curvature: deleting a point re-curves the path through the remaining points
2026-10-29 10:52:18 +07:00
BFlat 12f29b40f1 Merge pull request #4335 from ham9zah/test/properties-reference-point
Properties: test that typed transforms turn about the reference point (#4285)
2026-10-29 10:51:49 +07:00
BFlat 5464dc644c Merge pull request #4331 from Silvertree2010/fix/4206-bug-gradient-mesh-node-level-tra
Apply Transparency opacity to the clicked gradient mesh point
2026-10-29 10:51:23 +07:00
BFlat 340b8644b7 Merge pull request #4433 from el-j/fix/dxf-circular-sliver-4151
Fix #4151: DXF export: verify closed circular subpaths complete a full turn without reversing
2026-10-29 10:50:36 +07:00
BFlat fe45b77d69 Merge pull request #4425 from dotCooCoo/fix/cursor-idle-test-timing
Tests: the idle cursor test renders every frame on the test thread
2026-10-29 10:49:15 +07:00
BFlat 9309b2f6ed Merge pull request #4408 from dotCooCoo/fix/appearance-add-keys-empty-ids
Appearance: Add New Fill and Add New Stroke with an empty ids list run nothing without a selection
2026-10-29 10:48:07 +07:00
BFlat b095504986 Merge pull request #4316 from ham9zah/fix/appearance-mixed-fill-chip
Appearance: a mixed selection's object chip shows "?" when the fills differ
2026-10-29 10:47:43 +07:00
BFlat c40e641421 Merge pull request #4325 from Hassan1305/fix-4237-add-anchor-select
Fix #4237: Add Anchor Point selects the path it adds to
2026-10-29 10:47:20 +07:00
BFlat 9824a6459e Merge pull request #4328 from Silvertree2010/fix/4306-expand-does-not-work-as-intended
Expand the stroke of stroked type into filled outlines
2026-10-29 10:46:45 +07:00
BFlat 8e93bcb1bf Merge pull request #4362 from dotCooCoo/fix/issue-3773
Fix #3773: Offset Path offsets a path whose ends meet as a closed shape
2026-10-29 10:46:22 +07:00
BFlat 9392c872f5 Merge pull request #4501 from Silvertree2010/fix/4495-bug-eraser-tool-breaks-compound
Keep compound path holes when using the Eraser and Knife
2026-10-29 10:45:59 +07:00
BFlat cd64f6d14a Merge pull request #4512 from el-j/perf/canvas-upload-buffer-4504
perf(ui-egui): eliminate zero-filling allocation on canvas texture upload in color_image (#4504)
2026-10-29 10:43:58 +07:00
BFlat 4251afb7fa Merge pull request #4483 from dotCooCoo/fix/saturate-requires-intensity
Edit Colors: Saturate without an intensity is an error instead of a pass at 0
2026-10-29 10:43:31 +07:00
BFlat 1f452229cc Merge pull request #4429 from dotCooCoo/fix/layer-commands-refuse-text-booleans
Layers: the Layers panel's commands refuse a boolean given as text
2026-10-29 10:43:08 +07:00
BFlat e547aac113 Merge pull request #4448 from dotCooCoo/fix/artboard-commands-refuse-bad-numbers-and-names
Artboards: artboard.new and artboard.setProps refuse a number or name of the wrong type
2026-10-29 10:42:46 +07:00
BFlat ccf274b0c3 Merge pull request #4315 from Silvertree2010/fix/h3006-shape-rectangulargrid-and-shape
Accept whole-number floats as grid divider counts
2026-10-29 10:42:10 +07:00
BFlat 899b76ec74 Merge pull request #4436 from el-j/fix/svg-nested-images-node-cap-3564
Fix #3564: SVG import: cap converted objects and nested images
2026-10-29 10:41:46 +07:00
BFlat eb0a59a75f Merge pull request #4513 from mockydevs/fix/3579-nested-blend-memory
Blend: nested blends keep to a step budget (#3579)
2026-10-29 10:41:18 +07:00
bflatastic db982ad896 Package: drop the EngineError import #4393 left unused 2026-10-29 10:10:57 +07:00
dotCooCoo 1cecdfb985 Export for Screens: a folder export cancelled after its last file returns its files
The check after the last file returned the cancelled error for every
export. A folder export without a ZIP has written each file by then, so
a cancel that came during a final step that writes nothing (a row whose
file repeats the one before it) reported a finished export as
cancelled. The check now runs only for exports that still hold their
files: those without a folder and those that make a ZIP.
2026-10-29 10:03:27 +07:00
dotCooCoo 2731ffacdd Export for Screens: a cancel while the archive is made returns no archive
A cancel that came after the last file's check was not seen: an export
without a folder returned its files or its archive anyway. The export now
checks once more after the last file and again after deflating the
archive, so a cancel returns the cancelled error and nothing is written
or returned.

zip::deflate takes a `stop` callback that it calls before each 1 MiB of
a file. Export for Screens passes the cancel state, so deflating stops
at the next MiB. file.package passes one that never stops, so its
behavior does not change.
2026-10-29 10:03:27 +07:00
dotCooCoo 3b01769d46 Export for Screens: a ZIP export deflates its files
With `zip: true`, document.exportForScreens deflated nothing: every file
went into the archive stored. Each file is now deflated, or stored when
deflating does not make it smaller, as file.package's archive does. The
file list, the names and the reply's fields stay the same; `bytes` and
the archive's contents change. Entries keep the fixed 1980-01-01 date, so
the same files still give the same archive.

The deflating writer moves from package.rs into fileio/zip.rs as
`zip::deflate`, beside `zip::store`, and file.package calls it there with
its own date and error text. The test reader `zip::entries` reads
deflated entries too. The `zip` option's text in docs/mcp.md,
docs/control-protocol.md and the command's params says the files are
deflated.
2026-10-29 10:03:27 +07:00
dotCooCoo 71a67601a5 Layers: Alt-click selects only on the drawn name, and in an isolated layer
An Alt-click right of a short layer name, inside the wider rename
target, no longer replaces the selection. The isolated layer's own row
now selects the art inside it (layer.selectAll), where it cleared the
selection before. The doc line says the click selects visible, unlocked
art and clears the selection on a hidden or locked layer.
2026-10-29 10:03:20 +07:00
dotCooCoo ec988442b5 Layers: Alt-click on a layer name selects the layer's art
The reference app selects all objects on a layer with an Alt-click
(Option-click) on the layer's name in the Layers panel. In VectorCraft
an Alt-click on a name did what a plain click does: it highlighted the
row and made the layer current, and the art stayed unselected.

An Alt-click on the name of a layer or sublayer now also selects its
visible, unlocked art, as the row's selection square does
(layer.selectAll), and the layer still becomes current
(layer.setCurrent). On a locked or hidden layer the click clears the
selection, as that row's selection square does. On a group or object
row, beside the name, and with Shift or Ctrl/Cmd held as well, the
click does what it did before.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-29 10:03:20 +07:00
dotCooCoo 5c1ab5042f Gradient: the Cmd/Ctrl-click reset paints only the selected characters and gives an unpainted stroke its weight
The reset ran paint.editGradient, which changes every run of a type
object and leaves a stroke without paint at weight 0. It now runs
paint.setFill or paint.setStroke with the linear White, Black gradient:
characters selected with the Type tool take it and the rest keep their
paint, and a stroke without paint gets the 1 pt weight, as a plain click
on the Gradient button already does.
2026-10-29 10:03:12 +07:00
dotCooCoo 85d7913f10 Gradient: Cmd/Ctrl-click on the Gradient Fill box or the Gradient button resets to White, Black
The reference app resets a gradient to black and white when the
gradient button in the Tools panel is Cmd/Ctrl-clicked, and to the
default black and white linear gradient when the Gradient Fill box in
the Gradient panel is Cmd/Ctrl-clicked. In VectorCraft a Cmd/Ctrl-click
on either did what a plain click does, and the reset was only in the
Gradient panel menu.

A Cmd/Ctrl-click on the Gradient panel's thumbnail or on the Tools
panel's Gradient button now makes the gradient of the active Fill or
Stroke a linear gradient with the White, Black stops, through
paint.editGradient, as one undo step. A solid or no paint becomes that
gradient, and with nothing selected the default paint changes. A plain
click keeps its behavior, and the panel menu's Reset to White, Black
is unchanged.

Docs: docs/target-app-parity.md.
2026-10-29 10:03:12 +07:00
dotCooCoo 62b231aaa5 Color panel: Cmd/Ctrl-click and Cmd/Ctrl+Shift-click on the spectrum apply Complement and Invert
The reference app selects the complement of the current fill or stroke
on a Cmd/Ctrl-click of the Color panel's color bar and the inverse on a
Cmd/Ctrl+Shift-click, and with Alt (Option) also held it changes the
nonactive one. In VectorCraft these clicks picked the spectrum's color,
and a Cmd/Ctrl+Shift-click cycled the color modes.

A Cmd/Ctrl-click on the spectrum now applies Complement and a
Cmd/Ctrl+Shift-click applies Invert to the active Fill or Stroke, as
the panel menu's items do: a selected gradient stop or freeform point
is recolored in place, and a solid color goes through paint.complement
or paint.invert. With Alt also held, the click runs the command on the
inactive proxy, which stays behind. A Cmd/Ctrl drag still picks colors,
and plain, Alt and Shift clicks keep their behavior. The panel menu's
Invert and Complement use the same code.

Docs: docs/target-app-parity.md.
2026-10-29 10:03:02 +07:00
dotCooCoo fa75b6f53d Part of #4326: a lost mouse-up after the pointer moved does not click at the press
The released buttons go after the frame's last pointer movement, at its
position. Before, they went first, at the press position, so a press that
moved past the click distance in the same frame ended as a click on the
widget under the press.
2026-10-29 10:02:50 +07:00
dotCooCoo f9fc20b3b9 Part of #4326: a drag whose mouse-up was lost ends once macOS reports no button down
egui ends a drag only on a button release or Escape. When the window
never receives the mouse-up, a drag such as a dock column's resize keeps
following the pointer with no button held.

On macOS, each frame's input now gets a release for every button egui
still holds when NSEvent.pressedMouseButtons reports no button down, at
the pointer's last position. Frames that carry a button event, and
control-channel input that holds a button between steps, are left as
they are.
2026-10-29 10:02:50 +07:00
dotCooCoo 914a109dc9 Scissors: Alt held switches to the Add Anchor Point tool
A click with the Scissors tool cut the path whether or not Alt was
held, and the cursor stayed the Scissors cursor. The reference app's
shortcut list has "Switch Scissors tool to Add Anchor Point tool" on
Alt (Option).

While Alt is held, a click with the Scissors tool now does what a click
with the Add Anchor Point tool does: on a segment it adds an anchor
point with path.insertAnchor in one undo step, and the path is not cut.
The cursor is the Add Anchor Point tool's while Alt is held. When Alt
is let go, the cursor is the Scissors again and a click cuts.

Docs: docs/target-app-parity.md, crates/tools/src/cursors.toml.
2026-10-29 10:02:43 +07:00
dotCooCoo f0c5de420b Type tools: Shift switches between horizontal and vertical, and Alt switches between area and path type
The reference app's shortcut list switches between its Type tools with
Shift and with Alt (Option). VectorCraft's Type tools had no such switch.

While no type is being edited, a press with Shift held makes new type
with the chosen tool's horizontal or vertical counterpart: Type and
Vertical Type, Area Type and Vertical Area Type, Type on a Path and
Vertical Type on a Path. A press with Alt held makes it with Type on a
Path in place of Area Type, or the reverse, in the same writing
direction. With both keys held, both switch. The keys held when the
press starts are the ones that count. The pointer shows the tool the
press acts as, and the chosen tool stays selected. While type is being
edited, Shift and Alt work as they did.

Docs: docs/target-app-parity.md.
2026-10-29 10:02:34 +07:00
dotCooCoo 7bc7ea58b5 Document: Cmd+Alt+Shift+U switches to the next unit of measurement
The reference app switches the units of measurement with
Ctrl+Alt+Shift+U on Windows and Option+Shift+Command+U on macOS.
VectorCraft could set the document's units with document.setUnits or
a right-click on a ruler, but no command stepped through them and no
key did it.

document.switchUnits (Switch Units, default Cmd+Alt+Shift+U) sets the
document's units to the next one in the order a right-click on a
ruler lists them: Points, Picas, Inches, Millimeters, Centimeters,
Pixels, Feet & Inches, Meters, Yards, Feet, and from Feet back to
Points. Each press is one undo step, and the reply names the new
units. Keyboard Shortcuts lists it under Document.

The precise cursors shortcut-editor test used Cmd+Alt+Shift+U as a
free key; it now uses Cmd+Alt+Shift+Q.

Docs: docs/mcp.md, docs/ui-parity.md, docs/target-app-parity.md.
2026-10-29 10:02:27 +07:00
dotCooCoo a4ba07dd1b Width tool: Escape deselects the selected width points
With the Width tool, Escape did not deselect the selected width points:
they stayed selected, Delete still removed them, and in isolation mode
the same Escape left isolation mode. The reference app's shortcut list
gives Esc for deselecting a width point.

Escape now deselects the Width tool's selected width points. The path,
its widths and the undo history do not change, and no command is sent.
While width points are selected the tool takes Escape, so that Escape
does not also leave isolation mode. With no width point selected, and
during a drag, Escape does what it did before.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-29 10:02:18 +07:00
dotCooCoo aa503c2648 Arc tool: C, F and Up/Down change the arc while it is dragged out
The reference app switches an arc between open and closed with C,
flips it with F and changes its angle with Up/Down while it is dragged
out. VectorCraft's Arc tool ignored these keys during a drag.

While an arc is dragged out, C now switches it between an open and a
closed path, F switches its base between the X and Y axes in the same
box, and Up/Down raise and lower its slope by 10 within -100 to 100.
Each press switches once. The arc drawn on release uses the new values,
and they stay as the Arc tool's options. With nothing dragged, C and F
are shortcuts as before.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-29 10:02:03 +07:00
dotCooCoo 46721fe093 Blob Brush: a release away from the press point paints with Alt down
A release that arrives at a new position with no drag before it now counts
as movement, so Alt pressed at that moment no longer switches the stroke
to the Smooth tool.
2026-10-29 10:01:53 +07:00