Commit Graph
1139 Commits
Author SHA1 Message Date
Dan Green 6daf74fb6d Move dialog opens on the last drag or Move, with its last checkboxes 2026-10-17 15:14:43 +07:00
dotCooCoo b9309f7985 Graphs: Object › Graph › Column draws columns with graph designs
Object › Graph › Column… was a menu stub, so a graph's columns and bars
were always plain rectangles. The reference app fills them with a graph
design, vertically scaled, uniformly scaled, repeated with a value for
each copy, or stretched at a guide line.

graph.column (Column…) draws the columns, bars or stacked segments and
the legend swatch of the series picked with Group Selection with a
design saved by Object › Graph › Design. Vertically Scaled stretches the
design to each column's length at the column's width. Uniformly Scaled
scales it both ways to that length and centers it on the column.
Repeating stacks a copy for each Each Design Represents value out from
the zero line, and For Fractions chops the last copy at the value or
scales it down. Sliding keeps the part above the design's horizontal
guide line in proportion and stretches the part below. The design and
its options are saved with the graph, and the graph follows the design
when it is renamed or deleted. Columns drawn with a design cast no drop
shadow.

A marker or legend design made of one path is now drawn in a group of
its own. Painting a series with Group Selection then leaves the design's
paint alone, as it already did for designs of several objects.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-17 15:14:43 +07:00
dotCooCoo f9759afa30 Live Paint: Gap Options find and close gaps in Live Paint groups
Object > Live Paint > Gap Options was a stub, and paint leaked through
any gap between the paths of a Live Paint group. The reference app's
Gap Options stop paint at small gaps, close them with unpainted paths
and preview them on the canvas.

livePaint.gapOptions (Gap Options) sets a group's options: detect (Gap
Detection), size (small 3 pt, medium 6 pt, large 12 pt, or a custom
size over 0 up to 72 pt), color (the Gap Preview Color, #rrggbb or a
layer color's name) and closeGaps, which adds an unpainted path across
each gap to the group's paths. A gap runs from a loose end of a path
to the nearest point of any path within the size, unless the paths
already join the two close by. With detection on, the faces are made
again as if a line closed each gap, and each face or edge keeps the
look of the old one it lies in or on. The options are stored on the
group, so they are saved, copied and undone with it, and Expand drops
them. Merge keeps the bottom group's options when its Gap Detection is
on, or else turns Gap Detection on with Small when another merged
group has it on. When Gap Detection is off in every merged group,
Merge keeps it off. livePaint.info lists the options and the gaps up
to the size wide that no path closes.

The menu item opens a Gap Options dialog. With Preview on, the options
apply live and the gaps show on the canvas in the preview color, and
OK keeps them as one undo step. vectorcraft-pathops gains find_gaps
and live_paint_with_gaps.

Docs: docs/mcp.md, docs/target-app-parity.md.
i18n: the 19 complete catalogs have rows for the dialog's labels, and
bg's Gap Options menu label now names gaps instead of line spacing.
2026-10-17 15:14:43 +07:00
dotCooCoo be553fa3cf Window: the SVG Interactivity panel attaches JavaScript events and files for SVG export
Window › SVG Interactivity was a disabled menu item. VectorCraft could
not attach JavaScript to an object's events or link JavaScript files
for SVG export.

The SVG Interactivity panel lists 19 events, from onfocusin to
onscroll. Pick one, type its JavaScript and press Enter to add it to
the selected objects; the list shows their events. Remove Selected
Entry removes the picked event, and the panel menu's Clear Events
removes all of them. Link JavaScript Files… opens the JavaScript
Files dialog, which adds a path or URL to the document's list and
removes the selected one. Its Choose… button puts a picked file in
as a file:/// URL. The commands are svgInteractivity.info,
setEvent, removeEvent, clearEvents, addFile and removeFile, and
ui.javascriptFilesDialog. Each edit is one undo step. A document
links at most 64 files.

SVG export writes each event as an event attribute on the object's
element and each file as a <script xlink:href> element. With the SVG
Tiny 1.2 profile, export leaves the events out with a warning. SVG
import reads the listed event attributes and the script links back
as text. It never reads a linked file or runs a script, and it leaves
inline scripts and the links after the first 64 out with a warning.
The native format keeps both.

An unnamed <g> with data-* attributes of its own around a single
object now imports as a group. Before, import folded it into the
object, which then took the group's data-* or, when it had its own,
dropped the group's. An unnamed <g> with event attributes stays a
group in the same way. The SVG import fuzz tests now include event
attributes and <script> elements.

Docs: docs/mcp.md, docs/control-protocol.md, docs/target-app-parity.md,
docs/ui-parity.md.
2026-10-17 15:14:43 +07:00
dotCooCoo 8bcebf0e48 Artboards: Alt-click on New Artboard opens Artboard Options for the new artboard
An Alt-click (Option-click on macOS) on the Artboards panel's New
Artboard used to add an artboard at once, as a plain click does. It now
opens Artboard Options for the new artboard, filled in with the name and
size that artboard.new {} would give it, and adds nothing yet. OK adds
the artboard with the fields where artboard.new {} would place it (20 pt
to the right of the last artboard) in one undo step, and makes it the
active artboard; Cancel adds no artboard. A plain click and a row
dropped on the button work as before.

The new UI command ui.newArtboard ("New Artboard Options…") opens the
dialog. It is listed after ui.newLayer, and its label has a row in each
catalog.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-17 15:14:42 +07:00
dotCooCoo a6bac3298b Contextual Task Bar: the Artboard tool offers Resize, Duplicate, Rearrange All and Export
The Contextual Task Bar showed only with the selection tools and
selected objects. With the Artboard tool it never showed.

With the Artboard tool, the bar now sits under the selected artboards
and offers Resize, which opens Artboard Options for the active
artboard; Duplicate, which copies each selected artboard in one undo
step and selects the copies; Rearrange All, with two or more
artboards, which opens Rearrange All Artboards; and Export, which
opens Export for Screens with the selected artboards checked. The
objects' Fill, Recolor Artwork and Lock buttons are not shown with
the Artboard tool. "Resize" has a row in every catalog.

Docs: docs/target-app-parity.md.
2026-10-17 15:14:42 +07:00
dotCooCoo 0b6f3285ab Control bar: the Artboard tool shows the active artboard's preset, name, X, Y, W and H
With the Artboard tool in use, the Control bar showed Move and Scale
Artwork with Artboard and then the object controls (Fill, Stroke,
Opacity and the rest). The reference app's help lists the Control
panel, with the Artboard tool, among the places to add, delete,
rename, resize and position artboards, set their orientation and
reference point, and open Artboard Options.

While the tool is in use, the Control bar now shows the active
artboard's controls in place of the object controls: Preset, Portrait
and Landscape, New Artboard, Delete Artboard, the Name field, Artboard
Options, Rearrange All Artboards, the Transform link, Move and Scale
Artwork with Artboard, and the reference point with X, Y, W and H and
the Constrain Width and Height Proportions link. Each control runs the
command its Properties or Transform panel counterpart runs, and the
reference point is the one the Transform panel uses. In an 800-point
window the controls up to the Transform link fit, the two artwork
options show as their boxes with their names in tooltips, and the link
opens the position and size in a popover, as it does for objects.

Docs: docs/target-app-parity.md.
2026-10-17 15:14:42 +07:00
dotCooCoo d949c3d8b7 Type: Optical Margin Alignment hangs punctuation and letter edges outside the frame
Type › Optical Margin Alignment was a disabled menu item. The reference
app's Optical Margin Alignment hangs Roman punctuation and the edges of
letters such as W and A outside the margins of every paragraph of a
type object.

type.opticalMarginAlignment (Type › Optical Margin Alignment) turns it
on or off for the selected type in one undo step, and the menu item is
checked while the type has it on. In every left-to-right paragraph of
point and area type, quotation marks, hyphens, full stops and commas at
a line's start or end hang wholly outside the margin there. Asterisks,
tildes, ellipses, en and em dashes, colons and semicolons hang by half
their width, and A, V, W, Y, v, w and y hang by a tenth of theirs. A
punctuation mark followed by a quotation mark hangs with it.
Left-aligned lines hang at their left margin, right-aligned lines hang
at their right margin, and centered and justified lines hang at both.
Lines break where they did before, and the space that justification
adds between glyphs leaves out the gaps next to a hanging punctuation
mark.

The setting is off for new type and for documents from before it, and
the type object saves it only when it is on.

The Type menu's checks for Optical Margin Alignment, Type Orientation
and the Type on a Path effects now read the type inside a selected
group, as the commands do.

Docs: docs/mcp.md, docs/target-app-parity.md, docs/type-parity.md.
2026-10-17 15:14:42 +07:00
dotCooCoo 62fd793603 Expand: pattern fills expand into their tiles clipped by the shape
Object > Expand with Fill expanded gradient fills only. A pattern fill
stayed a live pattern, and object.expand.info did not report it, so the
dialog's Fill option was disabled for it. In the reference app, Expand
with Fill turns a pattern fill into the pattern's tiles, and the shape
becomes their clipping mask.

The Fill step now turns each visible pattern fill of a path or compound
path into a clip group shaped like the object, holding the tiles the
pattern lays over the object's box with fresh ids. The group isolates
the tiles' blending and takes the fill's opacity, blend mode and other
effects. Geometry effects of the fill or the object, such as Offset
Path, shape the group's outline and the box the tiles cover. A path in
the tile art with a random Transform effect is baked with its own id
first, and a path with a brush that varies at random (calligraphic or
scatter with Random variation, or bristle) is baked where the pattern
defines it first, so every tile matches the canvas. The object's other
fills and strokes stay on copies of it in paint order, and Expand stays
one undo step. Type with a pattern fill expands the same way once
Object outlines it, and object.expand.info reports pattern fills under
fill. It also reports gradient fills under a new gradient key, and the
dialog enables Expand Gradient To only when the selection has one. A
pattern fill stays as it is when it lays no tiles over the box, when a
group or type in its art has a random Transform effect, when the
pattern is scaled, rotated, reflected, stretched or sheared and its art
holds a symbol instance, and when the pattern is rotated, reflected,
stretched or sheared, or scaled while its art has geometry effects, and
its art has raster or 3D effects, or a geometry effect on a group or
type.

PatternDef gains instances_in_with, which places the tiles with a given
Scaling. Expand has stroke weights, effect distances and the tiles' own
pattern paints scale with the pattern's transform. When the pattern is
rotated, reflected, stretched or sheared, or scaled while its art has
geometry effects such as Roughen, the strokes and geometry effects of
the tiles' paths become filled art first (bake_appearance, and Outline
Stroke's conversion for brushed strokes), and their live shapes become
plain paths, in their opacity masks too. Tiles place their opacity
masks with them, unlinked ones included (place_art), which also fixes
unlinked masks in pattern tiles in PDF, EPS, EMF and WMF export and in
Distort Pattern Fills.

Faults in the shared code are fixed for every caller. assemble
dropped the effects of a sole part, so Expand lost a lone gradient
fill's own effects and Outline Stroke lost those of a stroke with a
gradient along or across it. Outline Stroke also dropped a brushed
stroke's raster effects from its brush art. Expand replaced an object
whose gradient fill could not be expanded with a plain copy; it now
leaves it as it was. Expand left the geometry effects of a gradient
fill, and with Object off those of the object, on the expanded art,
where they reshaped every strip; they now shape the clip group's
outline, and the gradient fits it, as for pattern fills.
bake_appearance dropped a stroke's raster effects from its filled
outline and filled the outline of a stroke with a gradient along or
across it with a gradient across the outline's box; it now keeps the
effects and makes the gradient meshes clipped to the outline, as
Outline Stroke does. Envelope Options > Distort Appearance uses it too.
PatternDef::offsets_covering overflowed on a region too large to count
in integers, as for a pattern scaled by 1e-20; it now gives no offsets.

Docs: docs/mcp.md, docs/control-protocol.md, docs/target-app-parity.md.
2026-10-17 15:14:42 +07:00
dotCooCoo f526671534 Save and Export ask before replacing a file that an added extension names
After the desktop save panel closes, the app adds the file type's
extension to a name typed without it (or with one the save does not
write). The panel asked only about the name as typed, so on Linux
typing `card` with `card.vectorcraft` in the folder wrote over
`card.vectorcraft` without a question. On Linux the save panel is the
XDG desktop portal, and its GTK and GNOME file choosers return the
name as typed. Windows and macOS add the extension themselves only
when the panel lists file types, and the panels of Document Info's
Save, the presets dialogs' Export…, the CSS Properties export, the
swatch and graphic style library saves and the Libraries panel's
export list none.

When the added extension names a file that exists, Save, Save As, Save
a Copy, Save as Template, the exports and the other writes through a
save panel now ask "“card.vectorcraft” already exists. Replace it?"
first (dialog `replaceFile`). OK runs the write again with the same
answer and replaces the file. Cancel writes nothing and shows the
dialog it was asked over again. The host reports whether a file exists
through a new `Services::exists`.

Docs: docs/control-protocol.md, docs/target-app-parity.md.
2026-10-17 15:14:42 +07:00
dotCooCoo 53100a458f Type: the Touch Type tool moves, scales and rotates single characters
The toolbar listed the Touch Type tool (Shift+T), but choosing it did
nothing. The reference app's Touch Type tool moves, scales and rotates
one character of live type by dragging the handles of a box around it.

A click with the tool now selects one character and shows a box around
it. Dragging the box or its lower-left handle moves the character along
its line and up or down. The upper-left handle scales it vertically,
the lower-right handle scales it horizontally, the upper-right handle
scales it proportionally, and the upper-middle handle rotates it. A
character rotated by up to about 84 degrees follows the pointer too.
Near a quarter turn, a drag moves it only along its line. Escape
cancels a drag, and otherwise lets go of the character.

Each drag is one text.touchType command and one undo step. It sets the
character's baseline shift, scales and rotation, and moves it along its
line by changing its own kerning and the kerning of the character
before it, within the kerning range. The characters after it stay
where they are. Where the font kerned the character with its
neighbors, the two kerning values also keep the character in place
when it is only raised, scaled or rotated. The characters after it
stay where they were, or move by the change in its width when it is
scaled. The first character of a line and a right-to-left character
move only up and down. The type stays editable.

Docs: docs/mcp.md, docs/target-app-parity.md, docs/type-parity.md.
2026-10-17 15:14:42 +07:00
dotCooCoo e7b78e7150 Brushes: Shift-click and Ctrl/Cmd-click select several brushes, and Delete Brush deletes them
A Shift-click or Ctrl/Cmd-click on a brush in the Brushes panel used to
apply the brush, as a plain click does. It now selects brushes without
applying one. Shift-click adds the brushes from the last brush clicked
without Shift (else the highlighted brush) to the clicked one, in the
order the panel shows them. Ctrl/Cmd-click adds the clicked brush to the
highlighted brushes or removes it. The panel highlights the selected
brushes, and the bottom bar's Delete Brush and the panel menu's
Duplicate Brush and Delete Brush act on all of them. A plain click
works as before and ends the multi-selection, and so does selecting
other art, another document or another current brush.

brush.delete and brush.duplicate also take {names: [name...]}. Each
call is one undo step, and an unknown name fails before anything
changes. brush.duplicate answers {names} for a names list.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-17 15:14:41 +07:00
dotCooCoo 77f39084de Blend: Window › Blend opens a Blend panel with the blend's spacing, orientation and commands
The reference app has a Blend panel, opened with Window > Blend, that
makes and edits blends in one place. VectorCraft had the Blend tool,
Object › Blend and the Blend Options dialog, but no Blend panel.

Window › Blend opens a panel with Make, the selected blend's Spacing and
Orientation, Reverse Front to Back, Reverse Spine, Replace Spine, Expand
and Release. Each control runs its Object › Blend command, so a change
of the selected blend's spacing or orientation shows on the canvas at
once and is one undo step. With two or more objects selected and no
blend, Spacing and Orientation set the options new blends start with,
as Blend Options does. Make is dimmed until two or more objects are
selected. Spacing and Orientation are dimmed until a blend or two or
more objects are selected, and the other buttons are dimmed until a
blend is selected. The Blend Options dialog's orientation toggles now
have names for screen readers.

Docs: docs/target-app-parity.md, docs/ui-parity.md.
2026-10-17 15:14:41 +07:00
dotCooCoo ab1c386ca4 i18n: blend spine errors are translated in every complete language
The errors of the four blend spine commands (Move Spine Point, Reshape
Spine Segment, Add Spine Point and Delete Spine Point), which Direct
Selection, the Pen and the Anchor Point tool send, had no @msg row in
any catalog, so an error that reached the status bar, for example from
a Pen click, showed in English. The scan in
complete_languages_translate_every_message does not read messages
built with bad(), so that test did not report them.

Each of the 13 messages now has a row in the 16 catalogs that translate
every status and error message, in Bulgarian and in Simplified Chinese.
The rows that name the spine use each catalog's term for it. No English
string changes.

Docs: docs/target-app-parity.md.
2026-10-17 15:14:41 +07:00
dotCooCoo 0e26b258eb Fields: Shift+Enter applies a panel field's value and keeps the field active
Shift+Enter in a panel or Control bar field ended its editing, as Enter
does. The reference app's default keyboard shortcuts list "Apply value
and keep text box active" under Use panels and "Apply a value and keep
focus in edit field" under Transform panel, both Shift+Enter on Windows
and Shift+Return on macOS.

- A focused single-line field of the shared widgets (num_field,
  mixed_field, plain_field, range_field, spin_field, spin_field_auto,
  spin_plain, text_field, exact_text_field, opt_field and hex_field)
  takes Shift+Enter before its text box reads it, applies the text as
  Enter does and keeps the focus. In the next frame it shows the value
  as it now is, all selected, so typing replaces it.
- A text box of several lines keeps Shift+Enter as a line break.
- While a dialog is open, Shift+Enter applies the field's value and
  confirms the dialog, as before. The app sets widgets::set_dialog_open
  at the start of each frame.

Docs: docs/target-app-parity.md.
2026-10-17 14:46:20 +07:00
dotCooCoo d7026367f7 Paragraph: Reset Panel also resets the Hyphenation options
The Paragraph panel menu's Reset Panel turned Hyphenate off but left
the Hyphenation options: Words Longer Than, After First, Before Last,
Hyphen Limit, Hyphenation Zone and Hyphenate Capitalized Words. A
paragraph kept its custom hyphenation limits after a reset.

Reset Panel now also sets those six options to the values of
HyphenationOptions::default(), in the same text.setFormat call. The
reset paragraphs then save no hyphenation options.
2026-10-17 14:46:20 +07:00
Marco Arnulfo 8e69146160 Recolor Artwork: dragging a wheel handle of CMYK art keeps the linked handles in place (fixes #1733) 2026-10-17 14:43:14 +07:00
Marco Arnulfo cb968353a5 Missing Fonts: a folder the search refuses says why in the dialog, not "Not found" (part of #2200) 2026-10-17 14:43:14 +07:00
Marco Arnulfo 63b95c8dd3 Type: emptying the text while editing keeps its character style (fixes #2119) 2026-10-17 14:43:13 +07:00
dotCooCoo 4650ccbe26 Character: Reset Panel resets every attribute the panel shows except the font and size
The Character panel menu's Reset Panel reset tracking, leading,
kerning, baseline shift, the scales, rotation, underline,
strikethrough and All Caps, but left Small Caps, superscript or
subscript, Character Alignment, Proportional Metrics and Digits at
their custom values.

Reset Panel now also sets those five to their defaults in the same
text.setFormat call, with the values taken from CharStyle::default().
It resets them in the same characters as the other attributes: those
of the selected type, or, while the Type tool edits text, its
selection (all of that text at a caret). It resets them whether or
not Show East Asian Options and Show Indic Options (Preferences ›
Type) are on.
2026-10-17 14:43:13 +07:00
dotCooCoo 4f1e4979fc Layers: the panel menu's Save Selection submenu saves, lists and updates saved selections
The Layers panel menu had no saved-selection items, and the Select
menu was the only menu that listed saved selections. The reference
app's help also names a Save Selection menu in the Layers panel that
lists the saved selections and holds Save Selection, Update Selection
and Edit Selection.

The Layers panel menu now has a Save Selection submenu after Locate
Object. It holds Save Selection…, Update Selection and Edit Selection…,
which are enabled and run as in the Select menu, and below them the
active document's saved selections. Choosing a name runs select.recall
with that name, as the Select menu's list does.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-17 14:43:13 +07:00
bflatastic 40dd19d17a i18n: Danish, Dutch, Indonesian and Simplified Chinese rows for the strings this batch adds 2026-10-17 14:09:46 +07:00
Marco Arnulfo 8148d024ea Transform: a percentage typed alone in W or H scales the size it shows (fixes #2401) 2026-10-17 13:52:06 +07:00
Marco Arnulfo 68c9d440ab Transform panel: the menu's Flip Horizontal and Flip Vertical keep the reference point (fixes #2398) 2026-10-17 13:52:06 +07:00
dotCooCoo cdb0bbe315 Artboards: Duplicate Artboards, Copy and Cut take every selected artboard
With several artboards selected, the Artboards panel menu's Duplicate
Artboards copied only the active one, and Copy and Cut with the
Artboard tool took only the tool's active artboard.

artboard.duplicate, artboard.copy and artboard.cut now take `indices`,
and without `index` or `indices` they act on the artboards the
Artboard tool has selected. Duplicate Artboards passes the selected
artboards and selects the copies. Duplicate and Cut are one undo step
each, and Paste adds every copied artboard back, with its art, in one
undo step. The copies keep their places relative to each other,
together right of the last artboard. A cut fails when it names every
artboard.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-17 13:52:06 +07:00
bflatastic 32e22891d6 i18n(ja): a radial gradient kind reads 円形, as Radial Gradient does 2026-10-17 13:52:06 +07:00
dotCooCoo 69a90f6033 i18n: file filters, preset names and mark styles are translated in every complete language
Labels that the UI looks up through a variable or a context (#1259) had
rows only in the Bulgarian, Czech, Greek, Spanish, Finnish, French,
Polish, Brazilian Portuguese and Swedish catalogs. In German, Hungarian,
Italian, Japanese, Korean, Russian, Ukrainian, Vietnamese and both
Chinese, the UI showed most of them in English: the file dialogs' filter
names, the status bar's render and UI timings, New Document's preset
name, and the contributor tooltips with their plurals. The Printer mark
type list showed English "Roman" in each of those languages except
Hungarian, and in Japanese, Korean, Vietnamese and both Chinese it
showed the language's name for Japanese.

Those catalogs get the rows, each next to its related entry. German also
gets rows for the 3D gizmo's light, which the UI showed as "Hell"
(bright), and for Grain's Regular type, which the UI showed in English.
complete_catalogs_translate_render_site_labels requires the rows those
catalogs get and the light's row in every complete catalog, and checks
German's Regular row.

Docs: docs/localization-parity.md, docs/target-app-parity.md.
2026-10-17 13:52:06 +07:00
dotCooCoo 14de645441 Templates: Save as Template always writes a file with a template extension
file.saveAsTemplate kept a name whose extension named another format
and wrote the template into it: {path: "card.png"} wrote .vctemplate
JSON to card.png, and card.pdf typed in the desktop save panel got it
too. file.saveAs {format: "ait"} answered that document.export writes
other formats, but document.export does not write .ait either.

file.saveAsTemplate now replaces another format's extension (card.png
is saved as card.vctemplate, or card.ait for format: "ait") and adds
the extension to a name whose extension names no format. The desktop
panel adds the template's extension to any name that does not end in
a template extension (card.pdf.vctemplate), as Save As adds its own.
Save and Save As still refuse ait, and the error now names
file.saveAsTemplate.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-17 13:52:06 +07:00
dotCooCoo b9c3dd4519 Effects: effect.apply and effect.setParams refuse a color the effect can't draw
effect.apply and effect.setParams stored any string as the color of
Drop Shadow, Inner Glow, Outer Glow and Shift to Color. When the
effect could not read it, it drew its default color with no message,
so a typo such as #ff00 in the Drop Shadow dialog turned the shadow
black.

The commands now refuse such a color before they edit, with
"`color` must be a #rrggbb color", and the document and its undo
history stay as they were. Hex colors, the five named colors,
[r, g, b] and color objects still pass. The check runs in the
commands, so the app, command.batch steps and replayed journals get
it too. The effect dialog's OK shows the error and keeps the dialog
open, with Preview on or off. Saved documents open as before.

Docs: docs/mcp.md (effect params).
2026-10-17 13:52:06 +07:00
dotCooCoo b9b681c748 Type: redefining a text style back to a default updates the text that uses it
A style captured from text left out the attributes that the text's
JSON skips at their defaults, such as the Hyphenation options, the
Composer, tab stops, Auto kerning and the character alignment.
Redefining a paragraph or character style from text set
back to the defaults therefore did not reach the text using the
style: a paragraph that had the old Hyphen Limit or Single-line
Composer from the style kept it. setAttrs dropped a default value it
was given in the same way.

New and Redefine now capture every attribute of the selected text,
and charStyle.setAttrs and paraStyle.setAttrs keep a default value.
When a style changes, text whose value equals the old definition's
takes the new value, a default included. Local overrides on text that
uses a style other than the Normal styles stay, and an attribute that
setAttrs leaves out still leaves the text's value alone. The Character
Styles and Paragraph Styles panels compare the attributes a style holds
with the same attributes of the selection. A paragraph style made from
type with Auto alignment no longer shows "+" on that type.

Two existing behaviors change. Applying a style made with New or
Redefine from text, without Clear Overrides, now also sets the
attributes that text had at their defaults, such as Auto kerning, no
OpenType features, the Every-line Composer, no tab stops and the
default Hyphenation options. Redefining [Normal Paragraph Style] or
[Normal Character Style] from text gives every paragraph or run that
uses it those attributes too, so local values of them on that text are
reset.

Docs: docs/target-app-parity.md.
2026-10-17 13:52:05 +07:00
dotCooCoo 187a75ca3f Character: Small Caps, Superscript and Subscript buttons and menu items set the text
The Character panel's Small Caps, Superscript and Subscript buttons
were disabled, with "(on the roadmap)" tips, and always drawn off, and
the panel menu's items of the same names were disabled, although
text.setFormat and text.setRangeStyle already set smallCaps and
position. The reference app applies all three from the Character
panel menu.

The three buttons and menu items now turn small caps and the
superscript or subscript position on and off for the selected type, or
for the text the Type tool has selected, in Document Setup's
proportions. Turning Superscript on turns Subscript off, and turning
Subscript on turns Superscript off. They show as on when the first
selected character has the attribute, as the All Caps, Underline and
Strikethrough toggles do.

docs/mcp.md did not mention smallCaps and position; it now describes
them for text.setFormat and text.setRangeStyle.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-17 13:52:05 +07:00
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