Commit Graph
575 Commits
Author SHA1 Message Date
dotCooCoo f07b9ab765 Live Paint: Live Paint Bucket Options set what a click paints and the highlight
Double-clicking the Live Paint Bucket did nothing, and the tool always
filled on a click, stroked on Shift-click and highlighted in red at
4 px. It now opens Live Paint Bucket Options with Paint Fills, Paint
Strokes, Highlight, Color and Width.

- Paint Fills (on) and Paint Strokes (off) set what a click paints.
  With Paint Strokes alone, a click strokes the edge within 4 px of the
  pointer. With both on, a click strokes an edge within 4 px and
  otherwise fills the face. With both off, a click paints nothing.
- Shift switches Paint Fills alone to Paint Strokes alone and back, and
  switches both to Paint Fills alone. With the defaults, Shift-click
  strokes the edge as before.
- Highlight turns the outline of the face or edge under the pointer on
  or off; Color (a layer color or a custom color) and Width (1 to 20 px)
  set it. With Paint Strokes alone, a selection of ordinary paths no
  longer highlights a region, since a click there paints nothing.
- The options are tool options (tool.setOption {tool:
  "livePaintBucket"}): they last across tool switches and are saved
  with the preferences.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-01 08:32:57 +07:00
dotCooCoo ece78f052f Type: Standard Vertical Roman Alignment stands half-width characters upright in vertical type
Character panel menu > Standard Vertical Roman Alignment, with Show East
Asian Options, is now a check item. It sets a new character attribute,
`standardVerticalRoman` (text.setFormat, text.setRangeStyle), off by
default and saved only when on. In vertical type the marked Latin
letters, digits and other characters that would lie on their side stand
upright one below the other, each in its upright cell. Spaces keep their
width and tate-chu-yoko blocks stay across the column. Horizontal type
keeps the mark and does not change. A combining mark shaped as its own
glyph turns with its letter, in Latin and CJK upright type alike.

Character Style Options labels the Character Alignment row "Character
Alignment" and gives Standard Vertical Roman Alignment its own checkbox.
Reset Panel turns the attribute off. PDF and SVG export place the glyphs
from the layout and need no change.
2026-11-01 08:32:55 +07:00
Don Omondi 961694cba6 Fix #4918: delete nested picks safely, keep picks per document
symbol.delete {names} expands every instance of the named symbols,
round by round, before it removes any definition, so a symbol and the
one placed inside it delete alike in either order. The Symbols panel's
picks belong to the document they were made in, and a single picked
symbol is deleted only while symbol.unused still lists it.
2026-11-01 07:38:01 +07:00
Don Omondi 5b639169cd Fix #4918: Symbols panel Select All Unused
symbol.unused lists the symbols nothing places: instances in the art
(opacity masks included), graph designs, pattern tiles and brush art
count, and so do instances in a used symbol's art. The Symbols panel
menu's Select All Unused shows them selected, and Delete Symbol asks
once and deletes those still unused in one undo step
(symbol.delete {names}).
2026-11-01 07:38:01 +07:00
dotCooCoo 7410b7233e i18n: link, font and export status messages use real plural forms instead of "(s)"
The status bar's messages for relinked, replaced, updated and embedded
images, broken links, linked files that can't be read or changed on
disk, images that can't be decoded, added and unavailable fonts, copied
CSS, downloads and exports with notes read "1 image(s)" and similar.
They now say "1 image" and "2 images", and every catalog translates
both through @msgplural rows in the language's plural forms, as the
Package status does.

- i18n::msg_n writes such a message in English and fills its
  placeholders in one pass; the status bar's translation fills them in
  one pass too, so a path or name that holds "{n}" text stays whole.
- The old "(s)" @msg rows are replaced in all 26 catalogs, with new
  rows for Replaced and Break Link.
- Sites: dialogs/missing_links.rs, dialogs/missing_fonts.rs,
  app/links.rs, panels/css_properties.rs, dialogs/find_links.rs,
  panels/links.rs, place.rs, canvas.rs, io/export.rs and
  dialogs/save_for_web.rs.
2026-11-01 07:16:32 +07:00
bflatastic 7d8f1d4e06 Fix #4978: Area Type Options › Text Flow by rows or by columns 2026-11-01 06:11: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 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 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
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
bflatastic f22caa6108 Fix #4938: Dynamic symbols keep per-instance appearance linked to the symbol 2026-11-01 04:53:38 +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
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 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
dotCooCoo d2418d6e7a Accessibility: Tab no longer stops on window, dialog, panel-grip and ruler drag regions
Regions that only the pointer uses were made with Sense::drag() or
Sense::click_and_drag(), which egui makes focusable, so Tab stopped on
each of them and no key acted there. They now sense drags (and clicks
where they use them) without taking the keyboard focus: the custom
title bar's background and the window's resize zones, the band that
moves a dialog, the Tools panel's grip, a flyout's and a floating
strip's tear-off bar, the isolation bar's background, and the rulers
and their origin box. Their pointer behavior is unchanged, and the grip
and tear-off bars keep their screen-reader names.

Each region has a test that tabs through its UI and fails without the
change.
2026-11-01 01:22:08 +07:00
dotCooCoo 6f8e0294ff i18n: a package status with a note names the folder last, so a folder name with parentheses keeps it whole after a language switch
A package status with a note, such as "Packaged 1 file in /out/card (draft) (fonts not copied: Mono)", was translated after a language switch as if the folder ended at its first " (", so German showed "1 Datei in /out/card verpackt (draft) ...". The English status now puts the note before the folder ("Packaged 1 file (fonts not copied: Mono) in /out/card (draft)"), and each catalog's @msgplural row for it reads the folder as the rest of the line after ") in ".
2026-11-01 01:22:07 +07:00
dotCooCoo 62401182e6 i18n: an English package status is translated after a language switch, in each language's plural form
The package status now says "file" or "files", and the catalogs' `@msg`
rows for it still matched only the old "file(s)" text, so a status
written in English stayed in English after a switch to another
language.

- Catalogs take a new `@msgplural` row: the English one|other forms as
  the source and the language's plural forms as the translation. The
  `{n}` value picks the form, so Czech shows "Zabaleny 3 soubory" for 3
  files and "Zabaleno 5 souborů" for 5.
- Every catalog replaces its four package status rows with `@msgplural`
  rows. The row for a status with a note finds the note by its opening
  parenthesis, so a folder name with spaces stays whole.
- `package_status` builds the status line for the folder and the web
  download.
2026-11-01 01:22:07 +07:00
dotCooCoo 6f0d5f509f i18n: package, missing-font, missing-link and CSS counts use each language's plural forms
The Package status and question, the missing-links note, the Missing Fonts
and Find Linked Files search counts, the modified-links questions, Apply to
All, and the CSS Properties panel's notes no longer use a fixed "(s)" or
plural template. They use the plural rows of each catalog, so "1 linked file
not found" and Czech "Nenalezeny 2 propojené soubory" read correctly.

The searched line is built from two plural phrases, "{n} folder" and
"{n} file", in a "{folders} and {files} searched" frame. Package rows that
joined the note to the folder without a space now keep the space.
2026-11-01 01:22:06 +07:00
dotCooCoo f8bba3388e Batch: data set files name by File + Number, File + Data Set Name or Data Set Name
The Batch dialog has a File Name choice for a Data Sets source, starting
with File + Number (`source001`), as well as File + Data Set Name
(`source_Alpha`) and Data Set Name (`Alpha`). `action.batch` takes it as
`datasetFileNaming`; a call without it keeps File + Data Set Name, and a
folder source ignores it. An unknown value is an error.

A data set output whose name already exists in the destination folder
now takes the next free `-2`, `-3` suffix instead of replacing the file,
and a Windows device name under Data Set Name gets a trailing `-`.
2026-11-01 01:22:06 +07:00
dotCooCoo 14100bfab2 Character Styles: Style Options edits the name and Basic Character Formats
Squashed from #4809 onto main.
2026-11-01 01:22:04 +07:00
dotCooCoo 012af4fd49 Brushes: each Pattern Brush Options tile can be set to a pattern swatch or None
A menu under each of the five tiles in Pattern Brush Options lists None,
Original and the document's pattern swatches; the corner menus keep the
four automatic corners. A swatch choice copies the swatch's whole art and
its tile frame into the brush, so the brush keeps drawing after the swatch
is deleted, and the menu then shows that art as Original. Side cannot be
None: OK shows "You must choose a side pattern." and keeps the dialog open.

brush.options takes side_tile, outer_corner_tile, inner_corner_tile,
start_tile and end_tile (a pattern name, none, original, the corner auto
ids, or {"pattern": name} for a swatch named like one of those words), and
rejects side_tile "none" and unknown names before editing.
2026-11-01 01:22:03 +07:00
dotCooCoo bb56345290 Brushes: the Delete Brush question deletes nothing once another document is active
The question records the document it was opened for. If another document has become the active one by the time it is confirmed, it closes as Cancel does.
2026-11-01 01:21:54 +07:00
dotCooCoo 3a6770e784 Brushes: Yes in Delete Brush asks again when a stroke started using a brush meanwhile
The question for unused brushes checks again when Yes is chosen. If a stroke uses one of the brushes by then, the dialog asks with Remove Strokes and Cancel instead of deleting.
2026-11-01 01:21:54 +07:00
dotCooCoo 3937473e54 Brushes: the Delete Brush question for brushes in use no longer mentions expanding strokes
The dialog offers Remove Strokes and Cancel, so the question asks only about taking the brushes off the strokes. Both questions are reworded in every catalog.
2026-11-01 01:21:54 +07:00
dotCooCoo b1aa576764 Brushes: Delete Brush asks Yes or No for unused brushes, and Remove Strokes or Cancel for brushes in use
The question for brushes no stroke uses reads "Delete the brush selection?" with Yes and No, from the bottom button and the panel menu, and Alt-click (Option-click on macOS) on the button still deletes them without asking. When a stroke uses one of the brushes, the button, Alt-click and the menu item ask with Remove Strokes and Cancel; Remove Strokes deletes the brushes and the strokes that used them become plain strokes.

brush.unused also counts the tile that pattern editing's Cancel puts back, which brush.delete already clears, so the panel asks the in-use question for a brush only that tile uses.
2026-11-01 01:21:54 +07:00
dotCooCoo a8b3786f8c Symbols: Delete Symbol asks first, and Alt-click deletes an unused symbol without asking
The Symbols panel's Delete Symbol button and menu item now ask before
deleting. A symbol no instance uses gets "Delete the selected symbol?"
with Yes and No. A symbol with placed instances gets Expand Instances,
which turns the instances into ordinary art, Delete Instances, which
removes them, and Cancel; either Instances button deletes the symbol in
one undo step. Alt-click on the button deletes an unused symbol at once
and still asks about one with instances.

The question is bound to the document it was asked in: once another
document is active, or the symbol is gone, Yes deletes nothing, and a
symbol that gained instances while the question was open gets the
in-use question instead. symbol.delete itself does not ask.

The shared dialog frame takes a Cancel label (DialogSpec::cancel) for
the No button. The new strings have rows in every catalog.
2026-11-01 00:37:07 +07:00
dotCooCoo 6fb9152fa7 Blob Brush: the tip preview test checks that a drag gives it the focus
The test moves the focus to the Roundness field before the drag and
steps the Angle with an arrow key after it, so it fails if a drag stops
giving the preview the keyboard focus.
2026-10-31 23:48:55 +07:00
dotCooCoo 5751dcc293 Blob Brush: the tip preview is a named Angle slider with arrow keys
The tip preview square in the Blob Brush Tool Options set the Angle by a
drag but had no accessible name, no value and no keyboard control.
Screen readers now get it as the Angle slider with the Angle in degrees
as its value. A click or a drag gives it the keyboard focus, and the
arrow keys, Shift with an arrow, Page Up and Page Down, Home and End
step the Angle within -180 to 180 degrees, as the dialog sliders built
on color_slider_stepped do (crates/ui-egui/src/widgets/color.rs). The
new widgets::stepped_area gives a caller-drawn control that slider's
screen-reader node, focus, keys and focus outline.
2026-10-31 23:48:55 +07:00
bflatastic 06043139e6 Fix #4893: New Document saves a preset after More Settings 2026-10-31 22:22:30 +07:00
bflatastic ca0785573d Add-ons: Arrange Tools — Arrange in Grid, Swap, Replace with Top Object, Set Size of Each, Zoom to Selection
A built-in add-on in Object › Plug-ins › Arrange Tools (#4830, #4831, #4832, #4833, #4834):

- addon.arrange.grid lays the top-level selected objects out in rows and
  columns, a row or a column (stacking order from the back, visual bounds,
  each object centred in its cell), from the selection's top-left or
  centred on the artboard.
- addon.arrange.swap swaps two objects' bounds centres, and with `size`
  their widths and heights.
- addon.arrange.replace puts a copy of the topmost selected object centred
  on each of the others, in its stacking place, kept, stretched or fitted
  in proportion; the replaced objects are deleted unless `keep`.
- addon.arrange.size gives each selected object an exact width and/or
  height about a reference point.
- addon.arrange.zoomSelection (a UI command) fits the active view to the
  selection.

Places and sizes are measured as object.setBounds measures them (its
transform, now also available per object), strokes scale as Scale Strokes
& Effects says, each command is one undo step, and Arrange in Grid,
Replace with Top Object and Set Size of Each open previewed dialogs.
Catalog rows, command sweep cases, docs/mcp.md, parity docs and the
ROADMAP progress log.
2026-10-31 22:22:15 +07:00
bflatastic 7a2acbc178 Export for Screens: the dialog is laid out as Illustrator's 2026-10-31 21:43:13 +07:00
Taha-Mahmoodi 59eb658fd7 Fix #2651: Grid Repeat Options has a Preview checkbox
The grid options' public page lists a Preview option: the repeat on the canvas follows the fields while the dialog is open. Object > Repeat > Options had none, so a change showed only after OK. Now a Grid Repeat's dialog has the checkbox: Cancel puts the original back without a history step, OK keeps the previewed values as one undo step. Radial and Mirror Repeat Options are left as they are, since their public pages list no Preview.
2026-10-31 19:43:16 +07:00
dotCooCoo 2a5e2e8588 Blob Brush: the tip preview draws 0% Roundness as thin as the brush
The Tool Options tip preview floored the short axis at 1% of the long one, while the brush draws 0% Roundness at 0.1%. The preview now uses the same 0.1% minimum, with a test that compares it with the tip the brush draws.
2026-10-31 19:43:15 +07:00
dotCooCoo baaffd63e7 Blob Brush: Tool Options set the brush's Angle and Roundness
Blob Brush Tool Options gain Angle (-180 to 180 degrees, 0 by default)
and Roundness (0 to 100 percent, 100 by default), with a preview of the
tip and three dabs; a drag in the preview square sets the Angle. The
elliptical tip keeps its angle on the page along a stroke, a 0 percent
tip is drawn 0.1 percent as wide as it is long, and Size set to
Pressure still varies its size. path.blob takes angle and roundness,
and both values are kept with the tool's options.

While a non-round tip drags, the Blob Brush shows the outline of the
area it covers with its length label, and an Alt drag that smooths
shows the Smooth tool's thin line.
2026-10-31 19:43:15 +07:00
bflatastic e13c4bc9d0 Add-ons: Path Precision Tools — live path effects 2026-10-31 06:10:47 +07:00
dotCooCoo 6a034c77c3 Transform tools: backquote drag transforms only the pattern
Holding backquote while dragging with the Selection tool (move, bounding-box
scale or rotate) or the Rotate, Reflect, Scale or Shear tool applies the drag
to the selected objects' pattern fills and strokes and leaves their geometry
in place. The key state at release decides the result: the key may be pressed
after the mouse button goes down, and releasing it before the button comes up
commits an ordinary transform. Objects without pattern paint do not move.

PointerEvent gains a `backquote` flag (false when absent). The desktop canvas
reads it from the held key on every pointer event, and `ui.pointer` and the
`pointer_gesture` tool accept it per event or as a default for the gesture.
2026-10-31 03:34:55 +07:00
bflatastic ebc5b7038c Add-ons: Color Effects — Duotone effect and Print Ink Fixes
Effect › Color Effects › Duotone… (addon.color.duotone, also in Object ›
Plug-ins › Color Effects) prints the grey-equivalent tone of each colour
with one to four inks, each with its own tone curve. It is a colour
adjustment like the add-on's others, so it stacks with them and works as
a filter through addon.color.filter.

- One tone of a swatch the document has gives a tint of that swatch,
  linked, so a spot tone separates onto its plate; several tones give
  the CMYK mix of their tints (the inks overprint, so they multiply).
- Colour adjustments now map paints with their swatch links
  (ColorMap::apply_link); the existing adjustments behave as before.
- Skip Objects with Spot Colors leaves spot-linked colours as they are.
- The dialog has a row per tone and the picked tone's curve (the Curves
  graph, reused), its points and Reset to Linear / Inverse.

Print Ink Fixes (addon.color.printFixes, Object › Plug-ins › Color
Effects › Print Ink Fixes…) scales CMYK colours over a total ink limit
down to it, removes white overprint and sets black overprint (Overprint
Black's logic) in a CMYK document, as one undo step, and reports what
changed. RGB documents are refused.

The panel opens both under Inks.

Deferred: an opaque undercoat, tones for type only, extra gradient stops
for smoother tints, curve flip and all-100 % buttons.
2026-10-31 00:26:18 +07:00
dotCooCoo aea9296fa2 Character and Paragraph Styles: a style made by the New style dialog or the panel menu is highlighted
Squashed from #4713 onto main.
2026-10-30 23:45:42 +07:00
bflatastic f4c245286e Add-ons: Color Effects — live Vector Halftone effect
Effect › Color Effects › Vector Halftone… (addon.color.halftone, also in
Object › Plug-ins › Color Effects) draws its object as the halftone dots
Object › Vector Halftone makes, live: mono (one dot colour, or each dot in
the art's colour under it) or CMYK screens, the five dot shapes,
frequency, angle, invert and clip to the art's outline.

- The screens, dots and caps move to vectorcraft_effects::addons::halftone,
  shared by the command (its behaviour and tests unchanged) and the effect.
- The renderer samples the art (vectorcraft_render::addons::halftone) and
  keeps the dots by the object's content and what it reads from the
  document, so unchanged art isn't sampled again; past 100000 cells per
  screen the object draws as it is.
- Expand Appearance turns the object into its dots, and the SVG, PDF, EPS
  and AI exporters write them as paths.
- Its dialog reuses the command's fields, without Keep Original.

Deferred: stochastic and radial patterns, a dot-gain curve, per-screen
separation settings, type or symbols as dots.
2026-10-30 22:13:33 +07:00
bflatastic 9ec7805e54 Gradient stop popover: an eyedropper samples the stop's colour from the art (#4681) 2026-10-30 17:49:06 +07:00
Taha-Mahmoodi 092cb2ab04 Tests: assert rendered field text displays 4 pt after sub-minimum commit and invalid input rejection 2026-10-30 16:55:55 +07:00
Taha-Mahmoodi 6ec5178708 Text: remove debug print in recessed_text and test invalid input in single dialog session 2026-10-30 16:55:55 +07:00
Taha-Mahmoodi 956412e978 Tests: assert rejection highlight and dialog retention on invalid Enter commit 2026-10-30 16:55:55 +07:00
Taha-Mahmoodi e2828bc064 Dialogs: keep dialog open on invalid Enter commit and prevent lock nesting in numeric widget 2026-10-30 16:55:55 +07:00
Taha-Mahmoodi 5da8c8e495 Numeric: clamp committed values in point units, schedule rejection highlight repaint, and update roadmap/area evidence 2026-10-30 16:55:55 +07:00
Taha-Mahmoodi 418f1bffc3 Fix #4638: clamp bounded effect length inputs on commit and reject invalid input visibly
In effect dialogs (like Color Halftone), length fields with defined bounds
(e.g. Max Radius 4..127 pt) were previously checked only after num_field
returned, leaving the field's temporary buffer holding the un-clamped string
(e.g. '0.5 px'). Subsequently entering invalid text caused the field to
fall back to that sub-minimum buffer.

- Added num_field_within to pass effect parameter bounds directly to unit_field.
- When committed, clamp the parsed value within bounds and update the field
  buffer to the formatted clamped value so the UI reflects what is applied.
- When invalid text is committed, clear the invalid buffer and trigger a
  one-frame border highlight so invalid input is rejected visibly.
2026-10-30 16:55:55 +07:00
bflatastic 427752ce65 Add-ons: Color Effects — live exposure, desaturate and invert, apply as filter, panel
A built-in add-on in Effect › Color Effects and Object › Plug-ins › Color Effects:
- Exposure (stops of linear light, offset and gamma), Desaturate and
  Invert Colors as live colour adjustments, evaluated in stack order with
  those of Effect › Color Adjustments.
- addon.color.filter applies any colour adjustment to the colours
  themselves, through the Edit Colors pass, as one undo step.
- A panel picks an adjustment and its values, then adds it as a live
  effect or applies it as a filter.

The add-on lives in its own modules (effects, engine and ui-egui addons
folders) and leaves the existing effects, commands and menus as they
were.
2026-10-30 14:14:33 +07:00
bflatastic beb0ae6515 SVG export: rectangles, circles, ellipses, lines and straight paths as SVG shape elements (#4652) 2026-10-30 09:45:59 +07:00