Commit Graph
7090 Commits
Author SHA1 Message Date
dotCooCoo ba16468710 PDF export: a gradient that mixes a spot color with process colors keeps the spot ink
A linear or radial gradient whose stops mix a spot color with process
colors, or two spot colors, was written in process colors with a
warning. It is now written as a DeviceN shading of the process inks
its stops use and its spot inks, so each spot ink separates onto its
own plate. An off-center midpoint becomes a stop with the inks halfway
between its two stops. A gradient that mixes a spot color with RGB or
Lab colors is still written without the spot ink, with a warning that
says so.
2026-11-01 04:55:11 +07:00
dotCooCoo 3f5c6f3b5b Fix #3826: the toolbar's Gradient chip lines up with Color and None
Filled rectangles are drawn on whole pixels, but the gradient chip is a
mesh, which was drawn at its exact position. At a fractional position or
display scale the Gradient button under the Fill/Stroke proxy sat up to
half a pixel off the Color and None buttons beside it. gradient_chip now
rounds its rect to pixels first, which also lines it up wherever else a
gradient chip sits next to a color chip.
2026-11-01 04:55:11 +07:00
dotCooCoo bbcb886a40 Perspective: a stored projection whose determinant overflows reads back at a w row of 1
A stored projection whose determinant is not finite is read back as the
same map divided by the largest magnitude in its w row, the scale the
overflow branch of conjugated already uses, so points that overflowed at
the stored scale draw: the identity with every entry 1e308 maps (2, 2)
to (2, 2). The overflow branch of inverse scales the map so that the
largest of the products its determinant sums is near 1, so a map with
large entries and a small w row, such as a scale by 1e305 with a move
by -3.9e307, is still inverted and read back.

The two overflow tests in persp_text.rs build their stored projections
with a w row of 1, so they still overflow after the read-back.
2026-11-01 04:55:11 +07:00
dotCooCoo d098d33188 Perspective: a stored projection whose determinant overflows is judged on a scaled copy
Homography::from_array accepted nine finite numbers only when det().abs()
was above 1e-15. With large entries the determinant can be inf - inf, so a
valid stored projection was rejected on reading and its type drew flat, or
it can overflow to inf, so a projection that cannot be inverted was
accepted.

When the determinant is not finite, inverse() now inverts a copy divided
by a power of two (largest entry between 0.5 and 1), and treats that copy
as not invertible when its determinant is at most 1e-15 times the largest
of the six products it sums. from_array and the overflow path of
conjugated accept such a map only when that inverse exists. Maps with a
finite determinant are judged as before.

Follows #4912.
2026-11-01 04:55:11 +07:00
dotCooCoo 49cded55da Accessibility: Tab no longer stops on a dialog's backdrop; tests check a reachable control
The backdrop behind a modal dialog took clicks with Sense::click(), which
egui makes focusable, so Tab stopped on it. It now senses clicks without
taking the keyboard focus.

The Tab tests now check that Tab reaches a known control in each region
instead of only that some widget took the focus: the title bar's three
caption buttons, a control inside each dialog, a Tools panel button and a
floating strip's Put back in the toolbar button, and the isolation bar's
back button. The dialog test also checks that Tab skips the backdrop.
2026-11-01 04:55:11 +07:00
dotCooCoo 18510b77af Appearance: effect.apply reports the new effect's index in the object whose row it names
The reply's index came from the last object the effect was added to, while
its item came from the first selected object (or the first target for an
explicit item). When those objects held different numbers of effects on the
row, the reply named no effect of that object. The index is now read from
that object's effect list.
2026-11-01 04:55:10 +07:00
dotCooCoo ef69c82fca Actions: Delete Selection's question deletes the asked sets by id
Each action set now has an id of its own, assigned when the set is made
(Default Actions, New Set, Begin Recording on an empty panel) and when it
is loaded from the saved preferences. The id is not saved.

The question Delete Selection asks about sets holds their ids, and
ui.actionSet.delete takes ids in place of all: OK deletes the asked sets
wherever they are now, and deletes nothing when one of them no longer
exists. Before, the question matched sets by the list of names, so with
two sets of the same name, or a new set made under the asked one's name
while the question was open, OK could delete a set it did not ask about.
2026-11-01 04:55:10 +07:00
dotCooCoo 1e8c05f675 Actions: deleting an action set closes its Set Options or Batch dialog
ui.actionSet.delete runs while a dialog is open, from the control channel or MCP. An open
Set Options or Batch dialog for a deleted set now closes, and one for a later set has its set
index lowered so that OK renames or batches the same set.
2026-11-01 04:55:10 +07:00
dotCooCoo 979273f930 Actions: Delete Action Sets checks every set's name, and Shift-click selects a range with an action selected
The Delete Selection question now carries the names of all sets as they
were when it asked (`all`). `ui.actionSet.delete` deletes nothing unless
the panel's sets still have exactly those names in that order, so a set
with a repeated name that moves into the asked index is not deleted.

Shift-click on a set's name selects the sets from the current one to it
also while an action in the current set is selected.
2026-11-01 04:55:10 +07:00
dotCooCoo 35860ef68e Actions: Delete Action Sets checks the asked sets' names before deleting
The question Delete Selection asks now passes the names of the sets it
names along with their indexes. ui.actionSet.delete deletes nothing and
returns an error when the set at an index no longer has that name, so a
set deleted or added above them while the question is open does not
make OK delete a different set. An index above the platform's usize
range is refused as "no such action set" instead of wrapping on 32-bit
builds.
2026-11-01 04:55:10 +07:00
dotCooCoo 1f5cb914fd Actions: Delete Selection deletes the selected action set
Delete Selection in the Actions panel (the bottom bar's trash and the
panel menu's new Delete) now deletes the selected action set with its
actions and keeps the other sets, after asking. A selected action is
still deleted at once. Shift-click on a set's name selects the sets from
the current one to it, and one question deletes them together. Default
Actions and the last set can be deleted; New Set still works on the
empty panel.

ui.actionSet.delete {sets?: [index]} does the deletion: an index past
the last set is an error before anything is deleted, a recording into a
deleted set stops, and a recording into a later set stays in its set.
Undo does not restore a deleted set.
2026-11-01 04:55:10 +07:00
dotCooCoo 7211dc789f Eyedropper: color samples match the canvas and stay within their work limit
Squashed from #4979 onto main.
2026-11-01 04:55:09 +07:00
dotCooCoo dc6440d523 Fix #2960: Recolor Artwork keeps its Preserve checkboxes between uses
Recolor Artwork opened with Preserve White and Black on and Grays off
every time, so clearing them had to be repeated on each use. OK on art
now keeps the three checkboxes in the UI state (recolor_preserve, saved
with the other remembered dialog fields), and the dialog opens with
them. Cancel leaves them as the last OK set them.
2026-11-01 04:55:09 +07:00
bflatastic cdc3a03a1d Objects on Path: one catalog row each for Pivot and Rotate, one Objects on Path parity entry 2026-11-01 04:55:09 +07:00
dotCooCoo fa21866568 Properties: an Objects on Path group shows Objects on Path Options with Pivot and Rotate
Squashed from #4985 onto main.
2026-11-01 04:53:50 +07:00
dotCooCoo a6ee76ad35 i18n: French Pivot and Rotate labels put a no-break space before the colon 2026-11-01 04:53:41 +07:00
dotCooCoo 9ba55b3c03 Objects on Path: the tool's Rotate stays within -360 to 360
tool.setOption kept any finite rotate, while the Objects on Path Tool
Options dialog shows Rotate clamped to -360 to 360 and saves the value
it was given, so a rotate of 450 showed as 360 and the next attach used
450. The tool now clamps rotate to -360 to 360, and attach clamps the
saved rotate it falls back to the same way.
2026-11-01 04:53:41 +07:00
dotCooCoo af86b2c833 Objects on Path: double-clicking the tool opens its options
Double-clicking the Objects on Path tool opens Objects on Path Tool
Options: a nine-point Pivot grid, a Rotate field, Reset (the center and
0) and Save. Save sets the tool's options, which last across tool
switches and are saved with the preferences. The tool sends them with
each attach, and object.objectsOnPath.attach without pivot or rotate
uses them, so they apply to the objects attached next; groups attached
before keep theirs.
2026-11-01 04:53:41 +07:00
dotCooCoo cbde11d593 Fix #2105: the window asks the GPU for no more than it offers
eframe's default device descriptor asks for wgpu's default limits (WebGL2
defaults on OpenGL) with 8192 px textures, whatever the adapter offers. A GPU
short of any one of them, such as a Raspberry Pi 5's V3D 7.1 (15 inter-stage
shader variables on Vulkan, 4096 px textures on OpenGL), failed to create a
device, and the window fell back to the software rasterizer.

The device now asks for eframe's limits lowered to the adapter's wherever the
adapter offers less, and for the adapter's own texture side, which still
raises it above 8192 px when the adapter allows more (#1459).
2026-11-01 04:53:40 +07:00
bflatastic f22caa6108 Fix #4938: Dynamic symbols keep per-instance appearance linked to the symbol 2026-11-01 04:53:38 +07:00
BFlat 3f1928efc8 Merge pull request #4991 from storytold/feat/artboard-fill
Fix #4937: artboard background colours are included in exports and print
2026-11-01 04:31:59 +07:00
bflatastic ea0539976e Fix #4937: document artboard fills in exports, print and Export for Screens 2026-11-01 04:13:58 +07:00
bflatastic 9c17301c46 Fix #4937: artboards can have a background fill, included in exports and print 2026-11-01 04:13:57 +07:00
BFlat aab25476bb Merge pull request #4983 from storytold/feat/global-edit-groups
Fix #4939: Global Edit finds and edits groups like the selected one
2026-11-01 03:41:05 +07:00
BFlat 53187dc0b8 Merge pull request #4981 from storytold/feat/indic-digits
Fix #4942: native Indic digits in the Digits menu
2026-11-01 03:40:50 +07:00
bflatastic 8c35bacfb3 Global Edit: the menu checks a selected group's kind only; its contents are checked on start 2026-11-01 03:36:43 +07:00
bflatastic 3146ca513b Fix #4939: Global Edit finds and edits groups like the selected one 2026-11-01 03:36:43 +07:00
bflatastic b8365d6197 Fix #4942: native Indic digits in the Digits menu 2026-11-01 03:36:40 +07:00
BFlat e9c2aa2491 Merge pull request #4974 from storytold/feat/addon-tools-2
Add-ons: Group Overlapping Objects, Divide into Dashes, Save a Timestamped Copy, New Symbols from Layers
2026-11-01 02:58:55 +07:00
bflatastic 68391bdde4 Fix #4926: New Symbols from Layers 2026-11-01 02:44:16 +07:00
bflatastic 916b60898a Fix #4927: Save a Timestamped Copy 2026-11-01 02:44:16 +07:00
bflatastic 9e3f8dccec Fix #4950: Path Precision Tools: Divide into Dashes
addon.pathtools.divideDashes cuts the selected paths (or only their
direct-selected segments) into separate open paths of a dash length
measured along the curve, with an optional gap (gap pieces dropped
unless removeGaps is false) and Fit to Corners and Ends; pieces keep
the path's appearance, one undo step, at most 100000 pieces. Geometry
in vectorcraft-pathops; dialog with unit fields and Preview; tests,
sweep cases, catalog rows and docs.
2026-11-01 02:44:16 +07:00
bflatastic 69985f4998 Fix #4928: Arrange Tools: Group Overlapping Objects
addon.arrange.groupOverlapping groups the selected top-level objects
whose visual bounds overlap or touch, chains included (union-find over a
sweep along x, at most 20000 objects), only within one layer or group.
Each group takes its frontmost member's stacking place; one undo step,
all groups made in one pass over the tree. Menu item, tests, sweep case,
catalog rows and docs.
2026-11-01 02:44:15 +07:00
BFlat a261bce002 Merge pull request #4958 from dotCooCoo/fix/issue-3187
Part of #3187: a gradient mesh made from an ellipse keeps its shape
2026-11-01 02:23:58 +07:00
BFlat 1beb821d39 Merge pull request #4960 from dotCooCoo/feat/caps-lock-crosshair
Cursors: Caps Lock gives the drawing tools the crosshair
2026-11-01 02:23:42 +07:00
bflatastic cf656e2b70 Gradient mesh tests: add_lines_at takes the click tolerance (#4954) 2026-11-01 02:07:08 +07:00
dotCooCoo 23da2fe461 Part of #3187: a gradient mesh made from an ellipse keeps its shape
Create Gradient Mesh and a Mesh tool click estimated each border edge's
handles from the surface's derivatives, so the mesh's border cut across a
curved outline: a 1x1 mesh over a 400 x 300 pt ellipse came out up to
7 pt off it, with corners at its four mesh points. Each border edge now
takes the handles of the cubic that best fits the outline between its
points, and handles where two border edges meet along a side stay
collinear.

Deleting a mesh line (Alt-click with the Mesh tool) joined the two edges
on either side with a straight line, which turned the ellipse's border
into a diamond. The joined edge now keeps the outer handles, grown back
to the length they had before the line split the edge.
2026-11-01 01:59:57 +07:00
dotCooCoo dfd07552c8 Cursors: Caps Lock gives the drawing tools the crosshair
While Caps Lock is on, the tools whose pointer General > Use Precise
Cursors changes show the crosshair, and the saved preference does not
change. The desktop app reads the lock state on macOS, Windows and
Linux X11 and passes each change to the new view.capsLock command. A
change to view.capsLock or usePreciseCursors through app.run refreshes
the canvas pointer. The view.preciseCursors command is labeled Use
Precise Cursors, so command search finds it by the preference's name.
2026-11-01 01:59:54 +07:00
BFlat 1bb52c5b38 Merge pull request #4959 from storytold/feat/text-language
Fix #4940, #4946: text is shaped in its language, with a Language setting per text and Indian languages (#4943)
2026-11-01 01:53:48 +07:00
BFlat 6f26d88ac2 Merge pull request #4957 from storytold/fix/ui-4931-4933-4944-4953
Fix #4931, #4933, #4944, #4953: save version menu, refused-save alert, Contributors header, freeform point swatch
2026-11-01 01:53:32 +07:00
bflatastic 214fca7ca7 Character: apply() sets the font in a helper of its own 2026-11-01 01:39:16 +07:00
bflatastic 2bdaaa8981 Fix #4946: a Language setting per text, with Indian languages (#4943)
Character panel > Language sets the selected characters' language;
text.setFormat and text.setRangeStyle take `language` by name or tag
(unknown: an error), and character styles carry it. Document Setup's
language list gains Hindi, Marathi, Gujarati, Bengali, Punjabi, Tamil,
Telugu, Kannada, Malayalam, Odia and Urdu, with catalog rows; the
Digits menu's numeral names move to a digits context, as Hindi is now
also a language name.
2026-11-01 01:39:16 +07:00
bflatastic a85487ad39 Fix #4940: text is shaped in its language
Characters get a language (CharStyle::language, a BCP 47 tag of one of
Document Setup's languages; none for the default, English: USA, saved
only when set). The shaper sets it on the HarfRust buffer, so fonts use
their language forms (OpenType locl): Turkish keeps fi apart and the dot
on its i. Runs in different languages are shaped apart. New type takes
the document's language.
2026-11-01 01:39:11 +07:00
bflatastic 14c4616202 Fix #4953: the Gradient panel's freeform point swatch opens the point's popover 2026-11-01 01:39:08 +07:00
bflatastic 6caa2f74ef Fix #4944: About › Contributors table keeps its header above the scrolling rows 2026-11-01 01:39:08 +07:00
bflatastic 78d801395a Fix #4933: a save refused before writing shows the Can't save alert 2026-11-01 01:39:08 +07:00
bflatastic 7ad5ee0dff Fix #4931: native Save As Version is a menu of the versions VectorCraft writes 2026-11-01 01:39:08 +07:00
BFlat 0014e4e1f0 Merge pull request #4932 from dotCooCoo/fix/issue-2678
Fix #2678: Ungroup no longer multiplies the group's opacity into its members
2026-11-01 01:32:38 +07:00
BFlat 9d642d9826 Merge pull request #4945 from dotCooCoo/fix/ai-zstd-trailing-zero
.ai import: a Zstandard frame that ends in a zero byte keeps it
2026-11-01 01:32:23 +07:00
BFlat fdc1c41884 Merge pull request #4951 from dotCooCoo/fix/drag-regions-not-tab-stops
Accessibility: Tab no longer stops on window, dialog, panel-grip and ruler drag regions
2026-11-01 01:32:08 +07:00