Commit Graph
1108 Commits
Author SHA1 Message Date
dotCooCoo 1e87e85ab7 i18n: Simplified Chinese translates status-bar and error messages
The Simplified Chinese catalog had 20 `@msg` rows, against 714 to 718
in each catalog listed in COMPLETE_MESSAGES, so with the interface in
Simplified Chinese most status-bar and error messages showed in
English.

- zh-hans.tsv gains the 694 missing `@msg` rows in one block with a
  header comment on its conventions: no final 。 unless the English
  ends with a period, a space between Chinese and adjacent Latin
  text, numbers or placeholders, and 、 between list items. The rows
  use the catalog's existing terms (画板, 图稿, 编组, 描边, 色板, 实时上色,
  图像描摹, 增效工具 ...).
- zh-hans joins COMPLETE_MESSAGES, so
  complete_languages_translate_every_message and the narrower message
  tests fail when a zh-hans message row is missing, and a new message
  needs a zh-hans row.
- The registry comment, docs/development.md (which also gains Greek,
  already in COMPLETE_MESSAGES), the zh-hans row of
  docs/localization-parity.md, and the interface-languages line of
  docs/target-app-parity.md (which also gains Czech, Greek, Hungarian,
  Swedish and Finnish) list Simplified Chinese among the languages
  that translate messages.
2026-10-17 13:52:05 +07:00
dotCooCoo 5bdd9d539f Variables: Import Data Sets… reads tab-separated files and files without a name column
dataset.import read only commas between cells and refused a file whose
first header cell wasn't `name`. A value that didn't match its
variable's kind, and a repeated data set name, were reported with the
row's record number, which is not the file line after a blank line or a
quoted line break. A data set name over 255 characters gave no line.

- When the header row, read with tabs between cells, has a tab and no
  comma outside quotes, tabs separate the cells. A quoted cell may then
  hold tabs and commas.
- Without a `name` column every header cell is a variable, and the rows
  take the first free names Data Set 1, Data Set 2 and so on, as Capture
  Data Set and blank name cells do. A first header cell `name`, in any
  case, still holds the data set names.
- Value errors, a repeated data set name and a name over 255 characters
  give the file line the row starts on.
- The Variables panel's Import Data Sets… dialog also lists .tsv files.
- import_fuzz.rs imports random text, random bytes and mutated exports,
  comma- and tab-separated, into a document with bound text, visibility
  and graph variables, selects up to three of the imported data sets in
  turn, and exports every data set.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-17 13:49:49 +07:00
dotCooCoo a285efda46 Print: Print, Print Preview and Print Setup take a print preset by name
file.print, print.preview and print.setup took print settings only as
settings, so an agent had to read a preset with print.presets.list and
copy its settings into the call. They now take preset, the name of
[Default] or of a saved print preset in any case. The preset's settings
are used instead of the document's, settings applies over them, and
print.setup saves them with the document as one undo step. An unknown
name is a parameter error that lists the presets. The app's file.print
with params passes preset on to the engine.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-17 13:49:49 +07:00
dotCooCoo d5e44b321e Swatches: Alt-click on a swatch recolors the selected gradient stop
With a gradient stop selected, an Alt-click on a color swatch painted
the inactive Fill or Stroke, as it does with no stop selected. The
reference app's Default keyboard shortcuts page lists "Apply swatch
color to active (or selected) color stop: Alt-click swatch in the
Swatches panel" for the Gradient panel.

Now, when the active Fill or Stroke is a linear or radial gradient with
a selected stop, an Alt-click on a color swatch or a tint swatch
recolors that stop in one undo step, and the stop stays selected. The
stop changes as a drop of the same swatch on the Gradient panel's ramp
changes it (drop_color and dropped_link in panels/gradient.rs): it
becomes fully opaque, and a global or spot color or a tint stays
linked, so editing the swatch recolors the stop.
With a freeform gradient, the selected point takes the color through
paint.freeform.setPoint. With no stop or point selected, Alt-click
paints the inactive Fill or Stroke as before. The Fill and Stroke chip
popovers show the same swatches and behave the same.

Docs: docs/control-protocol.md, docs/target-app-parity.md.
2026-10-17 13:49:49 +07:00
bflatastic 6902e1ab3f Dialogs: drop the slider wrappers nothing calls since the named ones 2026-10-17 13:49:49 +07:00
dotCooCoo f0bb2760c9 Accessibility: buttons, toggles, checkboxes and sliders have names for screen readers
The controls that the shared widgets draw had no name in the
accessibility tree: icon, flat, primary, secondary and split buttons,
chips, toggles, checkboxes, radio buttons, tabs, sliders, the angle
dial, the Reference Point's squares, the spinner and preset arrows and
the searchable combo boxes. Screen readers announced each clickable one
as an unnamed element of unknown role, and a disabled icon button was
not in the tree. The Color Guide's library button, the Color Themes
Save button and the status bar's artboard buttons also had no name.

Each helper in widgets.rs except color_field now gives its response a
role, a name and its state. The name is the text, label or translated
tool tip the helper shows. The spinner, the preset arrow, the angle
dial, the harmony wheel and the Reference Point's squares, which show
none, are named "Step up or down", "Presets", "Angle", "Color wheel"
and Top Left to Bottom Right. A toggle, checkbox, radio button, tab or
Reference Point square reports whether it is on, an icon button reports
that it is pressed while it is lit, the angle dial reports its angle,
and a searchable combo box reports the text it shows. A checkbox or
radio button drawn without text is named by the label beside it. The
Tools panel's tool buttons, flyout rows and floating strips are named
by their tools' tool tips, with the active tool pressed. The title
bar's column toggle, the tear-off bars, a floating strip's close box
and the Color, Gradient and None buttons are named by their tool tips.

The status bar's First, Previous, Next and Last Artboard buttons now
have tool tips, and the Fill and Stroke chips' tool tips are
translated. The six new strings (the four artboard tips, "Color wheel"
and "Step up or down") have rows in every catalog.

split_button, chip_button, color_slider, channel_slider and the dialog
form's slider_field and slider_rail keep their arguments. New _named
variants beside them take the arrow's tool tip, the chip's tool tip or
the slider's name, and every caller in the tree uses them.

Docs: docs/target-app-parity.md.
2026-10-17 13:49:49 +07:00
vangel76andClaude Opus 5.5 a8e45f0e2d Persistence: saved PDF presets and loaded ICC profiles survive a restart (#2168, #2174)
PDF presets are kept one file each in a PDF Presets folder, ICC profiles as copies in a Color Profiles folder, next to the preferences; the desktop app and vectorcraft-cli use them. Adds color.removeProfile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:49:48 +07:00
bflatastic 51f8582c25 MCP: a cancelled export keeps no partly drawn tile or raster, and its message is translated (#2165) 2026-10-17 13:49:48 +07:00
Roman Vasilyev 8b8c164e3f CI: simplify boolean guards and translate EPS mask errors 2026-10-17 13:48:06 +07:00
dotCooCoo 5eea7e4f66 Appearance: the inline effect editor's text fields keep what is typed
The Appearance panel's inline effect editor drew each text parameter
(such as Drop Shadow's color and Revolve's edge) as a text field over
a copy of the stored value made again in every frame. A character
typed in one frame was gone in the next, so the field changed a value
only when its new text and the Enter press arrived in the same frame,
as with a paste.

The field is now the panels' shared exact_text_field, which keeps the
text typed while it has the focus, as the number fields beside it do.
Enter or a click elsewhere sends the value with effect.setParams as
one undo step, and Escape drops it.
2026-10-17 13:20:23 +07:00
dotCooCoo 2e9870b1d0 Rotate View: a Space+Shift drag rotates the view from any tool
A drag with Space and Shift held panned the view, as a Space drag does.

With Space and Shift held and Cmd up, a drag on the canvas now turns
the view about the canvas center, as a Rotate View tool drag does,
whatever the tool. Shift does not round the angle to 15° as it does
with the Rotate View tool, and the drag keeps turning the view when
Shift is let go. Space alone still pans, and Cmd+Space still zooms
with or without Shift. The pointer shows the rotate cursor while Space
and Shift are held without Cmd, and during the drag. The Rotate View
tool also shows it now, where it showed the arrow.

Docs: docs/target-app-parity.md.
2026-10-17 13:20:23 +07:00
dotCooCoo 951f7c2842 View: in Presentation Mode no key but ←, → and Escape acts, and no context menu opens
In Presentation Mode the canvas showed the active tool's cursor, a
right click selected the object under the pointer and opened the
context menu, and every key other than the arrows and Escape worked as
in Normal Screen Mode: tool keys, Delete, Enter, Tab, F and the
command shortcuts. A two-finger tap undid. With a tool that claims
Escape, such as the Intertwine tool, Escape did not leave the mode.

In the mode only the Escape, Left Arrow and Right Arrow keys now act,
and Escape leaves the mode whatever the tool. Every other key press,
the text it types and the clipboard keys are dropped before any
shortcut reads them, the macOS menu bar's key equivalents included. A
right click or a long touch opens no context menu, a two- or
three-finger tap undoes or redoes nothing, and the pointer over the
canvas is the default one. F and Shift+F no longer leave the mode;
Escape does.

Docs: docs/target-app-parity.md.
2026-10-17 13:20:23 +07:00
dotCooCoo 34ae88292d Links: Shift-click selects a range of links
In the Links panel, Shift-click and Cmd/Ctrl-click both added or
removed the image of the one row clicked. Shift-click now selects the
images of every row from the last row clicked without Shift to the
clicked one, in the order the panel shows them (its Show filter and
Sort order), and Cmd/Ctrl-Shift-click adds them to the selection.
Cmd/Ctrl-click still adds or removes one image, a plain click selects
one, and a double-click still goes to the link. When the last row
clicked is not shown, or the last click was in another document,
Shift-click acts as a click without Shift.

A click on a row runs select.set, select.add or select.toggle, and the
range is worked out as in the Layers panel's Shift-click.

Docs: docs/target-app-parity.md.
2026-10-17 13:20:23 +07:00
dotCooCoo a8fbae1b1f Graphic Styles: Shift-click selects a range of styles
In the Graphic Styles panel, Shift-click and Cmd/Ctrl-click both added
or removed the one style clicked. Shift-click now adds to the selection
every style from the last one clicked without Shift through the
clicked one, in the order the panel lists them, and Cmd/Ctrl-click
still adds or removes one. A plain click applies the style and selects
it alone, Alt-click still adds it on top, and the Control bar's Style
picker still applies on every click.

The panel uses swatches::click_selection, as the Swatches panel and
the library panel do.

Docs: docs/target-app-parity.md.
2026-10-17 13:20:23 +07:00
dotCooCoo 3c5d0e7ce4 Libraries: a plain click sets where a Shift-click range starts
A plain click on an item in the library panel selected the item but did
not record it as the anchor that a Shift-click ranges from. A later
Shift-click then selected only the clicked item, or ranged from an
older anchor set by an earlier Cmd/Ctrl-click or folder click. This
applied to swatch libraries and graphic style libraries.

Every click on an item or folder now goes through click_selection, as
in the Swatches panel. A plain click still selects the item alone and
adds and applies it.
2026-10-17 13:20:23 +07:00
vangel76andClaude Opus 5.5 577239d734 Gradient chips: follow the angle and the gradient type (#2494)
gradient_chip now takes the GradientPaint and lays the gradient out as it would be on an object of the chip's shape: linear along its angle, radial from the centre, freeform from its colour points. Gradient panel swatch menu and the Swatch Options dialog carry the full paint.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:20:22 +07:00
bflatastic 39979d4753 Tests: the floating-panel test skips fills that paint nothing (#2421) 2026-10-17 13:20:22 +07:00
bflatastic 47b6b3285d Panels: floating groups get an opaque fill beneath them; the docked card keeps its rounded corners (#2421) 2026-10-17 13:06:52 +07:00
vangel76andClaude Opus 5.5 ecbbba4f2e Panels: floating panel groups paint an opaque background (#2421)
The shared dock left its pane and tab strip backgrounds transparent because the docked card behind them is filled. Floating groups lie on the canvas, so the canvas showed through. They now paint the panel colour, which is what the card shows when docked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:06:52 +07:00
bflatastic 424a49604c Layers: Merge Selected keeps to the highlighted layers, as documented (#2383)
Reverts the fallback that merged the layers of art selected on the canvas when no
layer row is highlighted: Illustrator's Merge Selected merges the highlighted rows
into the last one highlighted.
2026-10-17 13:06:52 +07:00
vangel76andClaude Opus 5.5 fdc08e25d6 Layers: Merge Selected merges the layers of art selected on the canvas (#2383)
With no highlighted rows and art selected in two or more layers (Select All), layer.merge merges those layers; the panel menu enables it then.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:06:51 +07:00
vangel76andClaude Opus 5.5 5fd7fd4312 Character: the Kerning field at a caret kerns the pair, not the whole text (#2217)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:06:51 +07:00
vangel76andClaude Opus 5.5 37dfdd5da5 Cursor: keep the system pointer where no cursor theme loads on Wayland (#2450)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 12:50:38 +07:00
dotCooCoo 476d228262 Tests: a language one ui-egui test sets no longer translates the tests running beside it
The language the UI is drawn in was one process-wide value in unit
tests too, and the tests run on parallel threads.
current_language_is_a_frame_setting sets Traditional Chinese for a
moment, and a test that drew text in that moment read it in Chinese.
chrome::tests::the_zoom_hint_follows_animated_zoom failed that way in
29 of 500 runs together with the i18n tests.

The drawing language is now one per process in the app and one per
thread in unit tests, as ui_mirror! keeps the shortcut and workspace
mirrors. The app keeps the same static. A new test sets the language
on another thread and checks that its own thread still draws in
English.
2026-10-17 12:50:38 +07:00
Fabio William Conceição 8689863fbf Part of #394: Highlight Alternate Glyphs paints pink behind OpenType substitutions. 2026-10-17 12:26:13 +07:00
Michael GiesonandClaude Opus 5.5 2d0da1472f Cursors: 36 more tool states get cursors of their own, listed in cursors.toml
Node editing as the public manual describes it: Direct Selection's anchor squares (hollow
or filled), Reshape Segment over a curved segment, Group Selection's plus (also Direct
Selection with Alt), the arrow hollow while a drag snaps, and Alt-copy arrowheads. The
Anchor Point caret, the Curvature pen and Free Transform's side-shear arrows (ShearH,
ShearV) are drawn in code. Lasso, the freehand, symbolism and other tools return cursors
of their own that borrow their old look until drawn (Cursor::stand_in).

crates/tools/src/cursors.toml lists every Cursor value, when it shows and its hotspot,
for whoever draws them; `cargo xtask cursors` (in ci) warns about a missing, unknown,
repeated or incomplete entry and never fails. The busy cursor is listed as missing (G1).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-17 12:26:12 +07:00
sanches 816097c6bf i18n: add Dutch, Danish and Indonesian interfaces
Complete catalogs for nl, da and id, registered with their locales. Hindi from the same PR waits for a Devanagari UI font decision (with Lao and Georgian), and the strings main gained since the catalogs were written are added.
2026-10-17 12:26:11 +07:00
dotCooCoo 35b9d5a645 Hide Edges: the hidden bounding box, type widget and corner widgets do not answer the pointer
With View › Hide Edges on, the canvas does not draw the bounding box,
the type widget beside it or the Live Corners widgets, but the
selection tools still answered the pointer on them. A press on a hidden
corner widget rounded the corners, a drag from a hidden handle scaled
the selection, a double-click on the hidden type widget converted the
type, and the cursor changed over each of them.

While edges are hidden, the app now tells the tools that the bounding
box and the corner widgets are off. A press at their places reaches the
art or the canvas under them.

Docs: docs/target-app-parity.md.
2026-10-16 16:07:22 +07:00
GameDirection 6fc79c33b7 Export for Screens: batch exporting with name patterns, folders and presets (#1935)
Issue #1935 asks for batch exports of many logo variations in many
formats, each format in its own folder. This builds on Export for
Screens, which already writes every chosen artboard in every format row.

Names: a file name pattern (`name`) names every file alike. Tokens:
<filename> (the document), <name> (the artboard, asset, layer or
object), <index>, a run of # (a counter, zero-padded to the run's
length, from counterStart; counterPer item or file), YYYYMMDD,
YYYY-MM-DD, <date>, <time>, <YYYY>, <MM>, <DD>, <format>, <scale> and
<suffix>. A trailing .ext is dropped. Words are not changed: only the
date patterns and the bracketed tokens are. `date` sets the day (the
default is today, UTC). Different files that a pattern names alike get
-2, -3... Without a pattern, two rows with one name still write the
first row only, as before.

Folders: `folders` puts all files in one folder, a folder per row (as
Create Sub-folders did), per extension, per item, or per item and then
extension.

What is exported: besides artboards, assets and the full document,
`layers` (each layer's art alone, sublayers included) and `selection`
(one file of the selection, or a file per object).

Formats: rows can also be EPS, AI and VectorCraft (a document of the
item alone, its one artboard). A PDF row with printer's marks (PDF
Print in the dialog: trim, registration, colour bars, page information,
suffix -print) sits next to a plain PDF row.

Presets: document.exportPresets.list, .save and .delete keep batch
export presets with the preferences, and `exportPreset` uses one under
the call's own params. Built-in: Logo Package (SVG, PNG 1x and 2x, PDF
and print PDF, a folder per format) and Print-Ready PDF.

Dialog: Layers and Selection tabs with thumbnails; an Export Preset
menu with Save and Delete; Folders; File Name with Insert for the
tokens, Start at, Prefix, and an example of the first file's name. The
OK button says Export Layer or Export Selection on those tabs.

Tests: the pattern tokens, the request's example (SVG, PNG, PDF and
print PDF for artboards 1-3, a folder per extension, the print PDF a
bigger page), folders by item and both, the counter by item and by
file, numbered duplicates, layers and the selection, EPS, AI and
VectorCraft per artboard, presets (built-in, saved, used, replaced,
deleted, kept with the preferences), bad params, and the dialog (every
tab, the example name, a pattern export into folders, the Layers and
Selection tabs, presets applied and saved). The three tests that
refused EPS and VectorCraft rows now check those files. New labels
are translated in all 19 catalogs.
2026-10-16 15:27:55 +07:00
dotCooCoo 24583effe0 Paragraph: the Hyphenation dialog sets each paragraph's hyphenation limits
The Paragraph panel menu's Hyphenation… was always disabled, and
automatic hyphenation used fixed limits: words of 6 letters or more,
3 letters on each side of the hyphen, any number of hyphenated lines
in a row, and capitalized words hyphenated.

Each paragraph now has hyphenation options: Words Longer Than, After
First, Before Last, Hyphen Limit, Hyphenation Zone and Hyphenate
Capitalized Words. The defaults are the fixed limits, and documents
keep their line breaks. The options are saved only when they differ
from the defaults. text.setFormat takes wordsLongerThan, afterFirst,
beforeLast, hyphenLimit, hyphenationZone and hyphenateCapitalized, and
paragraph styles carry the options. Hyphen Limit applies with both
composers. Hyphenation Zone applies with the Single-line Composer: a
line whose text before the next word already ends within the zone
breaks before that word instead of hyphenating it.

Hyphenation… is enabled with type selected and opens a Hyphenation
dialog (ui.hyphenation) on the values the Paragraph panel shows. OK
runs text.setFormat with the values that changed, as one undo step.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-16 15:27:55 +07:00
turtwig b795d15d69 Artboard tool: a double-click on an object fits one artboard, and the canvas name renames
A double-click on an object or group fits one artboard to the visible bounds and does not open Artboard Options. The second click does not fit another artboard. Other artboards stay. Double-clicking empty artboard space still opens Artboard Options. Double-clicking the name drawn above an artboard renames it.
2026-10-16 15:27:54 +07:00
Gert Pellin 065e237f7f Align Stroke on live type: tests for the Type tool's selection, docs (#2294)
The Stroke panel enables Align Stroke while the Type tool edits text, and
styles the selected characters. docs: mcp.md (stroke.set and strokeOptions
align on type), type-parity and target-app-parity rows.
2026-10-16 15:27:54 +07:00
Gert Pellin ca0673e0bc Align Stroke inside or outside on live type (#2294)
The characters' stroke takes Align Stroke like an object stroke: CharStyle
keeps stroke_align (written only when not centred), stroke.set and
text.setRangeStyle strokeOptions apply align to type, and the Stroke panel
enables the buttons for type. Canvas, PDF and EPS draw it around the glyphs
through stroke_layer(); SVG keeps the text live and writes the aligned
stroke on the glyph outlines, clipped or masked. Type's visual bounds grow
with its character strokes.
2026-10-16 15:27:54 +07:00
dotCooCoo dfe215ca30 Effects: Effect › Path › Outline Object turns type into live, editable outlines
Effect › Path had Offset Path and Outline Stroke but not Outline Object.
The new effect (path.outlineObject) has no options: the Effect menu
applies it at once, and effect.apply refuses any parameter. It is a
geometry effect that returns its input. Type already reaches geometry
effects as its glyph outlines, so type that carries it is drawn,
exported (PDF and SVG as paths, with no font) and expanded as those
outlines, stays editable type, and the effects after it reshape the
outlines. Paths, compound paths and images draw as before, and no
bounds change: with Use Preview Bounds on, type is still measured by
its layout box.

Every complete catalog gets a row for the label.

Docs: docs/effects-parity.md, docs/target-app-parity.md (an evidence
line), docs/mcp.md (the effect, and what Expand Appearance does to
type).
2026-10-16 15:27:54 +07:00
dotCooCoo 56acb8d3b6 Select: Update Selection replaces the recalled saved selection with the current selection
The Select menu had no Update Selection: to add objects to a saved
selection or take objects out of it, the selection had to be saved
again under the same name. Select › Update Selection (`select.update`)
now gives the saved selection last recalled the objects that are
selected, in one undo step. It is enabled while objects are selected
and the document still holds that saved selection.

Each open document keeps session ids for its saved selections, so the
recalled one is found under a new name after Edit Selection…, and after
Undo and Redo. Deleting it disables Update Selection until another
saved selection is recalled or the delete is undone.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-16 15:27:54 +07:00
Marco Arnulfo 0ca6503f09 Canvas: scroll bars along the window's right and bottom edges (#2322) 2026-10-16 15:27:54 +07:00
dotCooCoo 917dcdeeef Simplify: add Corner Point Angle Threshold, Convert to Straight Lines and Show Original Path
The Simplify dialog had Tolerance, Preview and the anchor point counts.
It now also has three of the options of the reference app's advanced
Simplify dialog:

- Corner Point Angle Threshold is a slider from 0° to 180° that opens
  at 150°, with its label above it so the dialog stays under the
  420-point width that menu_parameter_dialogs_are_compact allows. An
  anchor whose corner is sharper than the threshold stays a corner, so
  moving the slider right keeps more corners. The dialog sends
  object.path.simplify's cornerAngle as 180° less the threshold, so the
  opening value gives the same result as before.
- Convert to Straight Lines sends straightLines.
- While Preview is on, Show Original Path draws the paths as they were
  before the preview, in a faint band of their layer's color under the
  selection outlines.

The three labels have rows in the 19 catalogs that translate every
label.

Docs: docs/target-app-parity.md, docs/ui-parity.md.
2026-10-16 15:27:53 +07:00
dotCooCoo 25d348f391 Rotate View: fitting, the Zoom marquee, canvas guides and the Navigator follow a turned view
In a rotated view, seven parts of the canvas and the Navigator worked as
if the view were not turned. Fit Artboard in Window and Fit All in
Window sized the zoom from the unturned width and height, so at 45° a
612 x 792 pt artboard ran off a 1000 x 800 canvas. The Zoom tool's
marquee (Animated Zoom or GPU Performance off) set the zoom to 3.13% at
90° and 180°. Ruler guides on no artboard were drawn square to the
screen while the tools pick them, snap to them and move them by their
position in the document. The rectangle a tool drags out (the selection
marquee, and the drags of the Type tool, the Artboard tool, the Place
cursor and Rectangle Cut) was drawn as a box square to the screen while
the tools work in the document rectangle. Show Hidden Characters skipped
type whose turned outline reached into the canvas when the box between
two of its corners did not. At 180° the Contextual Task Bar covered the
selection, and the Navigator's red box outlined an area that the window
did not show.

Now fitting uses the size of the artboard or art turned with the view,
and the Zoom tool's marquee zooms by its size on screen and centers on
its middle. A canvas guide is drawn along its document line, cut to the
canvas. Rectangles that tools drag out are drawn through the screen
corners of the document rectangle the tools use. Show Hidden Characters
uses the type's turned outline on screen, and the task bar uses the
selection's. The Navigator draws the canvas's corners mapped into the
document. At 0° each of these does what it did before.

Docs: docs/target-app-parity.md.
2026-10-16 15:27:53 +07:00
Marco Arnulfo 403b335039 Effects: Effect › Sketch › Halftone Pattern redraws an object through a halftone screen of dots, rings or lines 2026-10-16 15:27:53 +07:00
dotCooCoo ddfd08f321 Blob Brush: Keep selected and Merge only with selection options
A Blob Brush stroke merged with every touching closed path of its
color that had no stroke, and the blob it drew or merged into was
always left selected. The Blob Brush Tool Options had Size only.

The Blob Brush Tool Options now have Keep selected and Merge only
with selection, both off by default. A blob that a stroke draws or
merges into is no longer left selected unless Keep selected is on,
and the rest of the selection stays as it was. While Merge only with
selection is on, a stroke merges only with selected blobs, and with
nothing selected it draws a new blob. The options persist like the
tool's Size, and path.blob takes keepSelected and mergeOnlySelection,
both false by default. Keep selected stays on by default for the
Pencil and Paintbrush.

Docs: docs/target-app-parity.md, docs/control-protocol.md.
2026-10-16 15:27:53 +07:00
dotCooCoo f0d3f81f3b Canvas: a right-click on locked objects offers Unlock with each object's name
A right-click on the canvas now records the locked objects under the
pointer with vectorcraft_doc::hit::locked_objects_at, topmost first and
at most 20. A locked group is listed instead of the objects it holds.
Hidden objects and objects on hidden, locked or template layers are not
listed, and in isolation mode only the isolated group's contents are
listed. While the menu is open, it has an Unlock submenu after Undo
and Redo that lists each of them by the name the Layers panel shows.
Choosing a name runs layer.setProps {ids: [id], locked: false}, as the
Layers panel's lock column does, in one undo step. ui.contextMenu.list
shows the same items.

Docs: docs/control-protocol.md, docs/target-app-parity.md.
2026-10-16 15:27:53 +07:00
dotCooCoo 3b683bbeec Ellipse: dragging a pie widget on the canvas sets its pie angle
The Selection tool shows two pie widgets just outside a selected live
ellipse while the bounding box shows: one at the Pie Start Angle and
one at the Pie End Angle. Dragging one sets its angle to the angle of
the outline's point that lies in the direction of the pointer from the
ellipse's center, in one undo step, through `object.setLiveShape`'s
`pieStart` or `pieEnd`. Double-clicking one makes the ellipse whole
again (0° to 360°). Where the two widgets coincide, as on a whole
ellipse, a press takes the End widget.

Docs: docs/target-app-parity.md, docs/ui-parity.md.
2026-10-16 15:27:53 +07:00
dotCooCoo 5527418234 Selection: pressing E while dragging a marquee selects only the objects inside it
A Selection tool marquee selected every object it touched, a Group
Selection marquee selected the anchors inside it, and E pressed during
the drag did nothing. Now E switches either marquee to selecting only
the objects that lie entirely inside it, measured by their geometric
bounds, and E pressed again switches it back. Each marquee starts in
the default mode.

- The Selection tool selects a group only when the whole group lies
  inside. Group Selection selects the objects inside groups, each as a
  whole object. Shift still toggles. Direct Selection does not take E.
- The ruler guides the marquee selects with the art are limited the same
  way: an artboard guide is selected when its whole length lies inside,
  and a canvas guide is not selected.
- Tools receive letter keys as ToolKey::Letter. While a tool is busy, the
  desktop app sends it each press of a letter it claims, without Cmd,
  Ctrl or Alt and without key repeats, and headless press_key sends a
  claimed letter the same way. With nothing dragged, press_key {key: "e"}
  still chooses the tool bound to E.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-16 15:27:53 +07:00
Fabio 38dd835af6 G5: Symbol Options Export Type (Graphic / Movie Clip)
Store Export Type on symbols for Animate handoff; New Symbol and Symbol Options set it, and symbol.list reports it.
2026-10-16 15:27:52 +07:00
dotCooCoo 21b4e70150 Shaper: an arrow widget switches a Shaper Group between Face Selection and Construction mode
A Shaper Group had no arrow widget for switching between Face Selection
and Construction mode.

With the Shaper or Selection tool active, a selected Shaper Group, or a
group with one of its faces selected, now shows an arrow beside the
middle of the right side of its source shapes' bounds. A click on it
isolates the source shapes (object.isolate). A second click leaves
isolation with the group selected (object.exitIsolation). The arrow
points right in Face Selection mode and left in Construction mode.

In Construction mode a Shaper click selects an original shape of the
isolated group. Before, it selected the whole group outside the
isolation, and shaper.select with source could pick an original of
another Shaper Group lying above it.

Docs: docs/shaper.md, docs/target-app-parity.md.
2026-10-16 15:00:07 +07:00
dotCooCoo 6dfdf643d9 Type: Cmd/Ctrl+Shift+X resets horizontal scale to 100%
The reference app resets the horizontal scale of type to 100% with
Cmd/Ctrl+Shift+X. VectorCraft had no command for it, and the chord
cut the selection: egui reports it as a Cut with Shift held.

type.resetHorizontalScale (Reset Horizontal Scale, default
Cmd+Shift+X) sets the horizontal scale to 100% in the text the Type
tool has selected, or else in all the text of every selected type
object, in one undo step. The value is the one the Character panel
shows, so a type object stretched to twice its width keeps 50% stored.
The vertical scale does not change. At a caret the command leaves the
text as it is. Type objects given in ids are reset in full, as
type.resetTracking does.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-16 14:58:09 +07:00
dotCooCoo ad1e8d1112 Type: Cmd/Ctrl+Alt+Shift+. and , step the font size by five increments
No command held Cmd/Ctrl+Alt+Shift+. and Cmd/Ctrl+Alt+Shift+,, so the
chords reached Increase and Decrease Font Size (Cmd/Ctrl+Shift+. and ,)
and changed the size by one Size/Leading increment.

Two commands, type.size.increaseByFive and type.size.decreaseByFive,
now hold the chords. They step the font size of the selected type, or
of the text the Type tool has selected, by five times the Size/Leading
increment (Preferences › Type). Agents reach them with press_key too.
Their labels have rows in every complete catalog.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-16 14:58:09 +07:00
dotCooCoo cc3299dc0f Artboards: Fit to Artwork Bounds fits each selected artboard to the art on it
Fit to Artwork Bounds resized the active artboard to the bounds of all
the art in the document, wherever that art was. With art on two
artboards, fitting one of them stretched it over both.

artboard.fitToArt now takes `indices` and fits each artboard to the
art on it, in one undo step. An object counts for every artboard its
drawn bounds overlap, and the artboard is fitted to all of its bounds,
also where it reaches past the artboard's edge. Art flush with an edge
from outside does not count. An artboard with no art on it keeps its
size and place, and the command fails with "no artwork" when none of
its artboards has art. Object › Artboards and the Artboards panel menu
pass the selected artboards (the Artboard tool's, else the active one),
and a recorded action leaves them out. Fit to Selected Art still
resizes the active artboard.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-16 14:58:09 +07:00
dotCooCoo 467c47b719 Transform: Ctrl/Cmd+Enter in W or H scales the selection proportionally
In the Transform panel, the Properties panel's Transform section and
the Control bar, Ctrl+Enter (Cmd+Return on a Mac) in W or H left the
field active and applied nothing. Now it applies the value as Enter
does and sends `proportional: true` to `object.setBounds`, so the other
side scales by the same factor with the Constrain Width and Height
Proportions link off. With the Artboard tool, the Transform panel's W
and H keep the active artboard's proportions the same way. X, Y,
Rotate, Shear and the number fields of dialogs keep Ctrl/Cmd+Enter as
it was.

- widgets::size_field is a num_field that Ctrl/Cmd+Enter also commits.
- transform::proportional gives the `proportional` param of the W and
  H fields: the link, or true after Ctrl/Cmd+Enter.

Docs: docs/target-app-parity.md.
2026-10-16 14:58:09 +07:00
dotCooCoo 03ffe790be View: Rotate View to Selection turns the view square to the selected object
A rotated object's bounding box stands at the object's angle. No
command turned the view to the angle of the selection: `view.rotate`
turns the view only to an angle passed to it.

View › Rotate View to Selection, between the Rotate View submenu and
Reset Rotate View, runs a new UI command, `view.rotateToSelection`. It
turns the view about the center of the canvas to the angle the
selected objects share, the angle `document.inspect` reports as
`selectionRotation`, so their bounding box is square to the window.
Objects turned to different angles share no angle, and the view turns
back to 0. The zoom and the view's center stay as they were. The
command returns `{angle}`. With nothing selected it returns "nothing
selected" and the menu item is disabled; without a document it
returns "no document".

Every catalog that translates the menus has a new "Rotate View to
Selection" row.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-16 14:58:08 +07:00