The Appearance panel's inline effect editor showed a parameter that
picks one of some values (Roughen's Points, Offset Path's Joins, the
menus of Smart Blur, Glass, Texturizer and De-Interlace) as a text
field holding the stored value, where the effect's dialog has a
dropdown. Its labels did not have the dialog's mappings ("Channel1"
and "Max Radius" for "Channel 1:" and "Max. Radius:"), and a plug-in
choice named mode whose value is a blend mode name showed the blend
mode list.
The editor now shows the other parameters that effect::choices lists
as dropdowns with the dialog's labels (Drop Shadow's Shade keeps its
radio buttons), translated in the "effect" context, and a pick sends
the dialog's value with effect.setParams. Glass's Texture menu ends
with Loaded Texture once a texture is loaded. A plug-in's choice lists
the plug-in's values, and the blend mode dropdown is only for our own
effects. The labels are form::humanize's without the colon. The dialog
and the panel both call form::choice_label and effect::glass_textures.
Docs: docs/target-app-parity.md.
In a rotated view the resize and rotate cursors were the ones for an
unturned view. With the view turned 90°, the right-middle handle of a
selection's bounding box shows at the middle of the box's bottom edge
and drags up and down, but its cursor was the left-right arrow. This
affected the Selection, Free Transform, Artboard, Slice Selection, Crop
Image, Perspective Grid and Perspective Selection tools, ruler guides,
and the spread handle of a freeform gradient.
Now each of these cursors turns with the view to the nearest 45°. The
Selection tool and the Perspective Selection tool turn the handle's
direction by the view's angle before they round it to a cursor.
ToolContext::view_angle reads the view's angle from the screen frame,
and Cursor::turned turns a resize or rotate cursor by it. The new
Cursor::rotate_about_in_view turns the pointer's direction from the
center by the view before it picks one of the rotate cursor's eight
directions. Cursor::rotate_about keeps its signature and behavior. At
0° every cursor is as it was.
Docs: docs/target-app-parity.md.
Three original Artistic filters on the pixel pipeline, each with a
catalogue row, the generic live dialog, translations and tests.
- Cutout: colours softened by Edge Simplicity (less with Edge Fidelity),
split into Number of Levels steps per channel and painted as flat
pieces in their average colour; slivers along softened edges take the
nearest large piece's colour.
- Poster Edges: channels posterized to Posterization + 2 levels, black
lines on the edges of any channel and of the outline, widened by Edge
Thickness and darkened by Edge Intensity.
- Neon Glow: dimmed greys screened with a glow colour from the light
areas (positive Glow Size) or the dark ones (negative), as strong as
Glow Brightness.
All keep coverage and work in document units at any Document Raster
Effects resolution. Photoshop filters 33/57; cargo xtask ci passes all
9 steps.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Native review of the rows added in the Finnish merge: "artboard" is
piirtoalusta everywhere else in the catalog, so the two export rows that
said piirtoalue now match; "Color Scheme" becomes Väriteema so it no
longer reads the same as Swatches (Värimallit). The other added rows
read correctly and are kept.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
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.
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.
When pressing Ctrl+P to open the Print dialog and clicking Setup (or Settings), print.printerSetup previously discarded the selected printer name and unconditionally launched explorer ms-settings:printers. On Windows 10, this opened the Windows Settings Printers and scanners page, displaying the list of installed printers instead of the printer driver printing preferences.
Launch Windows native Printing Preferences dialog for the target printer using rundll32.exe printui.dll,PrintUIEntry /e /n printer, falling back to the system default printer or Settings if no printer is available or detected. Add unit tests covering command construction and fallback behavior.
Fixes#2569.
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.
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.
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.
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.
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.
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.
A document assigned a CMYK profile (Edit > Assign Profile) keeps it when
it is saved, but the working spaces are the app's, and a new session
starts with the defaults. Opened again, such a document exported its CMYK
colours tagged with the working CMYK space (VectorCraft Generic CMYK
(SWOP-like)) instead of its own profile, made that profile the PDF/X
output intent, and separated its RGB colours through it; print
separations did the same. edit.assignProfile still reported the assigned
profile, and document.exportPdf's documentation says CMYK colours are
tagged with "the document's CMYK profile".
Found on a book cover assigned FOGRA39L Coated: built in several
vectorcraft-cli runs, each reopening the saved document, its PDF/X-4
came out tagged with the SWOP-like profile unless every run set FOGRA39
as the working CMYK space again.
Export and print now work in the document's colour spaces: the active
settings with the assigned profiles in their place (document_cms). An
assigned profile that isn't available leaves the working space, with a
warning.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
File > Place read text files only as plain `.txt`, and an RTF file
could not be placed. The reference app lists RTF among the formats it
places as text, keeping the file's font and style settings.
File > Place now reads RTF files, written from the Rich Text Format
Specification 1.9.1, and sets their text as area type the way a text
file is placed. Each run keeps its font from the font table, its size,
bold and italic, underline, strikethrough, all caps, small caps,
superscript or subscript (in Document Setup's proportions), baseline
shift and its color from the color table. Each paragraph keeps its
alignment, left, right and first-line indents, space before and after,
and direction. Table cells are separated by tabs and each table row is
a paragraph. Unicode characters, Windows-1252 and Mac Roman bytes and
the special-character control words are read, and of a \upr group's
ANSI and Unicode text, the Unicode text is read. Hidden text, pictures,
objects, headers, footers, notes, field instructions and other
destinations are left out, and unknown control words are skipped.
A file is read as RTF when it starts with {\rtf, whatever its name,
except a .txt file, which stays plain text. RTF files share the 4 MiB
limit of text files. Groups nested more than 512 deep share the
formatting of the deepest one read, the font and color tables keep at
most 4,096 entries, and a file with more than 100,000 paragraphs or
runs is refused. The Place dialog lists RTF files, and file.place,
file.place.info and file.place.queue report the format `rtf`.
The tests in tests_textimport.rs fail without the change, and
text_import_fuzz.rs places random RTF token streams.
Docs: docs/file-format-parity.md, docs/mcp.md,
docs/target-app-parity.md.
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.
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.
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.