Commit Graph
6140 Commits
Author SHA1 Message Date
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
dotCooCoo 6bb5398119 Pencil: Alt smooths as far from the drag as the Smooth tool does
With "Alt key toggles to Smooth Tool" on, an Alt drag with the Pencil
smoothed within the Pencil's "Edit selected paths" Within distance. At
0, which turns editing off, it smoothed nothing. It now smooths within
the Smooth tool's 12 px radius at every Within value.
2026-10-29 10:01:33 +07:00
dotCooCoo 4116fdbe47 Shape Builder: a merge looks up the picked points of a coverage once
The search for the faces a merge unites compared each reported face's
coverage with every picked point's coverage. The picked points are now
grouped by coverage once, before the walk, and each face is tested only
against the points of its own coverage.
2026-10-29 10:01:22 +07:00
dotCooCoo 32601a6bc3 Shape Builder: a merge walks the arrangement once per batch of faces
A merge found the contours of the faces it unites with one contour pass
over the whole arrangement for each coverage among them, and the search
for slivers next to them did the same for each neighboring coverage.
Each in-place remnant of a merge is such a merge too, so a click on
many overlapping shapes made one pass over the whole arrangement for
each coverage, for the merged faces and again for each remnant. Both
now use the batching that Divide's regions use: one pass for each batch
of coverages whose faces share no vertex. The batching looks a face's
coverage up by a hash of the inputs that cover it, computed as it walks
them. The search for slivers looks up the merged faces' coverages the
same way.

Merging a frame no longer takes in an island of the same coverage in
its hole: each face is its outer contour and the holes directly in it,
as the regions are.
2026-10-29 10:01:22 +07:00
NetterSilverandClaude Opus 5.5 8b4ebf50be Fix Shift-scaling a corner handle along a single axis
Fixes #4262

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 10:00:59 +07:00
dotCooCoo 7a2683d6d0 Stroke Weight: a spinner click from a weight shown as a preset goes past it
A weight of 2.004 pt shows as 0.167 p in picas, the same text as the
2 pt preset. One click down on the spinner went to 2 pt and the field
did not change. The spinner now treats a preset shown with the same text
as the weight as reached, as the field's arrow keys do, so the click
goes on to 1 pt. A plain step also passes a whole-point step shown with
the same text as the weight: 2.0004 pt goes down to 1 pt.
2026-10-29 10:00:43 +07:00
dotCooCoo c252d22465 Stroke Weight: a step from a weight between the presets goes to the next preset
A weight between the presets stepped to the next whole point, so 0.52 pt
went down to 0 pt. In the Stroke panel, the
Control bar and the Properties panel, a plain step of the spinner, the
arrow keys or the wheel now goes to the nearer of the next whole point
and the next preset in its direction: 0.52 pt goes down to 0.5 pt and
up to 0.75 pt, 0.4 pt goes down to 0.25 pt, and 1 pt goes down to
0.75 pt. From 1 pt up a step is still a whole point (14 pt to 15 pt),
and Shift and Ctrl/Cmd steps are unchanged.

In the field, a preset keeps its decimal places (0.0156 in), and a preset
the field shows with the same text as the value (2 pt as 0.167 p) counts
as reached, so the next press goes on to the next preset.
2026-10-29 10:00:43 +07:00
dotCooCoo 686cd1f2f5 Curvature: deleting a point re-curves the path through the remaining points
Deleting a point of a finished path with the Curvature tool sent
path.removeAnchor, which refits the two segments that met at the point so
one curve follows them. The path kept the bend of the deleted point
instead of curving through the points that remain.

The tool now sends path.removeAnchor with curvature: true, which uses the
new curvature_remove. Each smooth neighbor takes new handles from its new
neighbors, and an end beside one of them takes its end handle again. A
corner neighbor keeps its handle directions, and its handle on the new
segment scales with the segment's chord. With two points left, the points
that curve lose their handles. Object > Path > Remove Anchor Points and
the Delete Anchor Point tool still refit the curve.
2026-10-29 10:00:30 +07:00
ham9zah 4661615af4 Properties: test that typed transforms turn about the reference point (#4285) 2026-10-29 10:00:18 +07:00
NetterSilverandClaude Opus 5.5 ec98f498fd Apply Transparency opacity to the clicked gradient mesh point
Fixes #4206

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 10:00:05 +07:00
el-j c0d7d22d42 Fix #4151: verify continuous angular direction for cubic arc conversion (#4151) 2026-10-29 09:57:34 +07:00
dotCooCoo 8e93155ed9 Tests: the idle cursor test renders every frame on the test thread
the_canvas_hands_the_tool_cursor_to_the_os_and_idles_while_the_pointer_rests
asserts that the window asks for no repaint once the pointer rests. On a
loaded machine a canvas frame takes longer than 8 ms, so later frames go
to the render worker, and a worker frame that finishes during the idle
frames asks for a repaint (repaint delay 0, cause render_worker.rs:63).
The test now sets canvas.worker_started, as the canvas tests do, so every
frame renders on the test thread.
2026-10-29 09:57:34 +07:00
dotCooCoo c3a6fbf250 Appearance: Add New Fill and Add New Stroke with an empty ids list run nothing without a selection
Called with `"ids": []` and nothing selected or targeted, the two commands
ran and put "select objects or give ids" in the status bar. An empty ids
list now counts as no ids, so the commands run nothing, as they do when
ids is left out. A non-empty ids list still adds to those objects.
2026-10-29 09:57:34 +07:00
ham9zah 411f96b7c8 Appearance: the object chip of a selection whose fills differ shows "?" (#4174)
The object row drew the None swatch when the selected objects' fills
differ, which reads as "no fill". It now draws the "?" chip the Control
bar and Properties panel use for differing paints.
2026-10-29 09:57:34 +07:00
HassanKhanandClaude Opus 5.5 a5961f264b Fix #4237: Add Anchor Point selects the path it adds to
An anchor added to a path that wasn't selected now selects that path,
the new anchor direct-selected, so the point shows and can be edited at
once instead of only after a Direct Selection click. Undo restores the
old selection; a path already selected (the Pen's Auto Add) keeps it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 09:57:34 +07:00
NetterSilverandClaude Opus 5.5 bcbc8a1713 Expand the stroke of stroked type into filled outlines
Fixes #4306

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 09:57:34 +07:00
dotCooCoo 6026772765 Fix #3773: Offset Path offsets a path whose ends meet as a closed shape
Offset Path outlined an open path on both sides, so a shape whose last
anchor sits on its first came out as a ring with a hole. Such a path is
now offset as a closed shape: its last anchor merges into its first,
which takes the last anchor's in-handle, with the same 1e-6 test that
Object › Path › Join uses for one path (crates/engine/src/cmd/path.rs).
The Offset Path effect calls the same function.
2026-10-29 09:57:34 +07:00
NetterSilverandClaude Opus 5.5 b6422e5ba1 Keep compound path holes when using the Eraser and Knife
Fixes #4495

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 09:57:34 +07:00
el-j c96f0c30f7 perf(ui-egui): eliminate zero-filling allocation on canvas texture upload in color_image (#4504)
- Replace vec![Color32::TRANSPARENT; N] zero-initialization with direct single-copy bytemuck::cast_slice(&img.pixels).to_vec() in color_image.
- Eliminates redundant zero-filling of ~20.7 MB buffer on every canvas frame render on Retina displays, saving memory bandwidth and allocation overhead.
- Fallback preserves transparent image for undersized or mismatched pixel buffers.

Fixes #4504.
2026-10-29 09:57:34 +07:00
bflatastic ace60bd542 Edit Colors: import f64_req and check_numbers in colorcmds.rs (#4299 made the imports explicit) 2026-10-29 09:57:34 +07:00
el-j a24326e046 fix(cad): verify circular subpaths complete a full turn without reversing (#4151) 2026-10-29 09:57:34 +07:00
el-j 7f48664fed test(cad): add regression test for closed sliver along a circle in DXF (#4151) 2026-10-29 09:57:34 +07:00
bflatastic 49509be9a8 Layers: import switch_or in layer.rs and layerpanel.rs (#4299 made the imports explicit) 2026-10-29 09:57:33 +07:00
dotCooCoo 0622a10415 Docs: the artboard refusal line names null and every other wrong type 2026-10-29 09:57:33 +07:00
NetterSilverandClaude Haiku 5.5 ad43722a56 Accept whole-number floats as grid divider counts
Found while testing crates/engine/src/cmd/create.rs:584 (dividers)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-29 09:57:33 +07:00
bflatastic cfe21231c8 SVG import: import NodeId and SvgError in importer.rs (#4299 made its imports explicit) 2026-10-29 09:57:33 +07:00
Don Omondi def9e0f08e Blend: nested blends keep to a step budget (#3579)
A blend whose keys are blends draws each of its steps as a copy of a key,
and that copy makes its own steps when it is drawn, so step counts capped
per pair multiplied with nesting: five levels of 15 steps were 1.3 million
steps from a 23 KB file, 3.4 GB to export.

A blend now makes at most 100,000 steps in all (MAX_BLEND_STEPS), counting
the steps of the blends inside its keys and steps. Past the budget each pair
of keys keeps the same share of its steps; a copy of a blend spaced by
distance counts the most steps its spacing can make, since scaling it up
adds steps. Blends within the budget draw every step as before.
2026-10-29 09:57:33 +07:00
dotCooCoo 78c51b86e6 Docs: Edit Colors and Color Guide read a null parameter as one left out 2026-10-29 09:57:33 +07:00
dotCooCoo 4519346cfb Layers: the Layers panel's commands refuse a boolean given as text
layer.new, layer.selectAll, layer.target, layer.move, layer.template,
layer.pasteRemembersLayers and layer.releaseToLayers read their on/off
params with bool_or or as_bool, which falls back to a default for a
value that is not true or false. layer.new {"top": "true"} added the
layer above the current one instead of on top, layer.template
{"on": "false"} and layer.pasteRemembersLayers {"on": "false"} turned
the option on when it was off, layer.move {"copy": "true"} moved the
rows instead of copying them, layer.selectAll and layer.target with
"add": "true" replaced the selection, and layer.releaseToLayers
{"build": "true"} released the objects without building up copies.

These commands now fail with "`<key>` must be true or false" for a
value that is not true, false or null, as the artboard and Object menu
commands do, and leave the document, the selection, the highlighted
rows and the undo history as they were. layer.newSublayer, which takes
layer.new's options, refuses such a top too. A null is read as a key
left out.

docs/mcp.md also lists showCenterMark, showCrossHairs and
showVideoSafeAreas among the keys artboard.new and artboard.setProps
refuse in this way, as they already did.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-29 09:57:33 +07:00