Commit Graph
1493 Commits
Author SHA1 Message Date
BFlat c6f861808b Merge pull request #6481 from dotCooCoo/fix/repeat-param-types
Repeat, Pattern: the Repeat and pattern commands reject a param of the wrong type
2026-11-11 06:57:27 +07:00
BFlat fb10a6092f Merge pull request #6479 from dotCooCoo/fix/cut-ellipse-end-drag
Scissors: a cut leaves one of the two new end points selected
2026-11-11 06:52:41 +07:00
BFlat 8b34f0f826 Merge pull request #6476 from dotCooCoo/fix/answer-dialog-one-request
MCP: answer_dialog sets the fields and answers the dialog in one request
2026-11-11 06:41:16 +07:00
dotCooCoo 81dc541d5d Repeat, Pattern: the Repeat and pattern commands reject a param of the wrong type
object.repeat.radial, object.repeat.grid, object.repeat.mirror and
object.repeat.options, and object.pattern.make, object.pattern.edit,
object.pattern.saveCopy, pattern.options and pattern.delete, read their
params with helpers that fell back to the default for a value of the
wrong type: "instances": "8" made 8 instances whatever the text said,
"rows": "2" made 3 rows, "edit": "false" entered pattern editing mode,
and a `name` that was not a string edited the selected object's pattern.
Each such value is now an error naming the param, and the document, the
selection and the undo history stay as they were. An omitted or null
param keeps its default.

- pattern.options refuses an `overlap` that is not an object, and an
  `overlap.h` other than left or right or an `overlap.v` other than top
  or bottom.
- object.repeat.options refuses a `center` that is not [x, y].
- object.repeat.radial refuses a negative `radius`; it used the
  automatic radius before.
- object.repeat.grid reads `rows` and `cols` as object.repeat.options
  does: a fraction is cut to a whole number, within 1 to 500.
- object.repeat.options applies `brickOffset` given without `gridType`
  to a brick grid, and its params text lists the key.

Docs: docs/mcp.md.
2026-11-10 15:08:03 -08:00
dotCooCoo 7eb1006abb Scissors: a cut leaves one of the two new end points selected
After a Scissors cut (`path.split`) the whole path stayed selected: both
pieces of an open path, or the opened path of a closed one. A Direct
Selection drag from the cut then moved every anchor, so an ellipse cut
at an anchor could not be pulled open by dragging its end.

- `path.split` selects the first anchor of the piece after the cut and
  nothing else, as `path.cutAtAnchors` does: anchor 0 of an opened
  closed subpath, of the new path when an open path becomes two, or of
  the subpath added to a path of several subpaths.
- A Direct Selection press on anchors of a selected path that lie on top
  of each other takes the selected one. It took the first in path order,
  which in a path of several subpaths was the unselected end.

Docs: docs/mcp.md, docs/target-app-parity.md, the `path.split` params
text.
2026-11-10 15:04:50 -08:00
BFlat 667237ab47 Merge pull request #6473 from dotCooCoo/fix/opacity-mask-param-types
Transparency: opacity mask commands reject a param of the wrong type
2026-11-11 05:55:33 +07:00
dotCooCoo d9e9adbf45 MCP: answer_dialog sets the fields and answers the dialog in one request
answer_dialog sent ui.dialog.set and then ui.dialog.confirm or
ui.dialog.cancel as two requests. A dialog another control connection
opened between them was confirmed or canceled without the fields.

ui.dialog.set takes `action: confirm | cancel`, checked before any field
is set, and confirms or cancels the dialog the fields were set in within
the same request, replying {dialog, result}. answer_dialog sends set and
action together; an app whose reply has no `dialog` key did not answer
it, and the dialog is then confirmed or canceled with its own request.
2026-11-10 14:51:50 -08:00
BFlat 811bce73ae Merge pull request #6468 from dotCooCoo/fix/compound-member-copy-style
Edit: a copied compound member takes the compound's graphic style link
2026-11-11 05:33:49 +07:00
BFlat 3c55b60e52 Merge pull request #6467 from dotCooCoo/fix/pathops-param-types
Path commands: Offset Path, Simplify, Split Into Grid, Clean Up, Trap and Contour reject a param of the wrong type
2026-11-11 05:25:49 +07:00
dotCooCoo 68b9f6305c Transparency: opacity mask commands reject a param of the wrong type
transparency.makeOpacityMask read `clip` and `invert` with bool_or,
transparency.setOpacityMask read `clip`, `invert`, `disabled` and
`linked` with as_bool, and the New Opacity Masks and page toggles read
`value` with bool_or, so a value of the wrong type was dropped:
"clip": "false" made a clipping mask, "invert": "yes" next to another
flag was ignored, and "value": "on" toggled the page knockout group.
They are now read with switch_or, and such a value is an error that
names the param, before anything changes. Omitting a param or giving
null keeps its default.
2026-11-10 14:14:31 -08:00
BFlat 349385fd56 Merge pull request #6418 from dotCooCoo/fix/3d-more-object-kinds
3D: effects build from clipping groups, blends and symbol instances
2026-11-11 05:13:37 +07:00
BFlat 2f117ba967 Merge pull request #6466 from dotCooCoo/fix/expand-param-types
Expand: object.expand rejects a param of the wrong type
2026-11-11 05:13:27 +07:00
BFlat 92b61461f9 Merge pull request #6457 from slafebre/fix/6335-remember-color-settings
Fix #6335: Color Settings are remembered across restarts
2026-11-11 04:51:27 +07:00
BFlat 3cb6f44c9b Merge pull request #6464 from dotCooCoo/fix/issue-6382
Fix #6382: PDF export says how a page longer than 200 inches is written
2026-11-11 04:46:38 +07:00
BFlat 54092a0a01 Merge pull request #6462 from dotCooCoo/feat/plugin-call-commands
Plug-ins: an API level 2 plug-in calls the commands its manifest lists
2026-11-11 04:37:37 +07:00
dotCooCoo bf3e6b12ed Path commands: Offset Path, Simplify, Split Into Grid, Clean Up, Trap and Contour reject a param of the wrong type
object.path.offsetPath, object.path.simplify, object.path.splitIntoGrid,
object.path.cleanUp, object.pathfinder.trap and addon.contour.set read
their params with helpers that fell back to the default for a value of
the wrong type: "offset": true offset by 10 pt, "joins": 3 gave mitered
joins, "addGuides": "yes" added no guides. Each such value is now an
error naming the param, and the document and the undo history stay as
they were. An omitted or null param keeps its default, and a distance
still takes a string with a unit ("5 mm"). An unknown `joins` name is
refused as well.
2026-11-10 13:31:54 -08:00
dotCooCoo c92dad3838 Edit: a copied compound member takes the compound's graphic style link
Make Compound Path leaves each member's graphic style id in place. A
member copied or cut on its own took the compound's appearance but kept
that old id, so the clipboard carried an unrelated style and the pasted
path was linked to a style that did not match its look.

The copied member or piece now takes the compound's link while it has
that style's look, and no link otherwise (no style on the compound, or
a gradient pinned to the compound's bounds). It also takes the
compound's knockout setting with the rest of its transparency.
2026-11-10 13:28:28 -08:00
dotCooCoo 626db59d53 Expand: object.expand rejects a param of the wrong type
object.expand read `object`, `fill` and `stroke` with bool_or, `steps`
with f64_or and `gradient` with str_param, so a value of the wrong type
fell back to the default: "fill": "yes" expanded the fill, "steps": "16"
made 255 strips and "gradient": 3 made strips. They are now read with
switch_or, number_or and text_param, and such a value is an error that
names the param, before anything changes. Omitting a param or giving
null keeps its default.
2026-11-10 13:28:28 -08:00
dotCooCoo 73ada5181d Docs: the Copy and Cut paragraph follows the whole Clear description 2026-11-10 13:28:28 -08:00
BFlat a730f81e33 Merge pull request #6461 from dotCooCoo/fix/compound-member-copy-cut
Edit: Copy and Cut of a whole compound member take only that member
2026-11-11 04:17:12 +07:00
dotCooCoo a960ba0d08 PDF export: pages that exported before keep exporting
- PDF 1.3 and 1.4 files, PDF/X-1a, PDF/X-3, PDF/X-4 and PDF/A-2b at
  PDF 1.4 among them, write a page longer than 14,400 pt in points
  again, now with a warning that apps that keep to the limit cut it to
  200 in. Only a page that failed with
  "PDF writer error: Limit(TooLargeFloat)" gets the new error: one
  whose size or art needs a real number past 32,767, the most PDF 1.4
  holds. Whole numbers are written as integers, so a page of whole
  points past 32,767 is written as before.
- A page whose side is past 32,767 pt and not a whole number of points
  is refused before the thumbnails are drawn and the transparency is
  flattened.
- A PDF 1.5 file written as PDF 1.6 for a long page keeps PDF 1.5's
  encryption (128-bit RC4), which the Save PDF dialog shows.
- A long page whose short side would be under 3 units at its UserUnit
  (ISO 32000-1, Annex C.2), such as 50 m x 4 mm, gets a smaller
  UserUnit that keeps the short side at 3 units, with a warning.
- The warnings give a page's size rounded up, as the error does.

A page of 14,400 pt or less is written as before. The new warning has
rows in every complete catalog. Docs: docs/mcp.md,
docs/target-app-parity.md and the document.exportPdf params.
2026-11-10 12:31:53 -08:00
Sven Lafebre eadf64fbab Fix #6335: Color Settings are remembered across restarts
edit.colorSettings set only the process-wide colour settings, so the RGB and
CMYK working spaces, intent and black point compensation went back to the
defaults at every start, although the profiles color.loadProfile loads are
kept (#2168, #2174). The engine now writes them to a settings file when they
change (Session::attach_color_settings), and the desktop app and
vectorcraft-cli keep that file as `Color Settings.json` next to the
preferences, attached right after the profile store so a saved working space
may be a loaded profile. Saved settings that can't be used (a profile that is
gone, a damaged or oversized file) leave the defaults with a log record, and
the next change writes over them. Nothing is read or written with
VECTORCRAFT_NO_PREFS.
2026-11-10 21:28:07 +01:00
dotCooCoo 668b3fa3d7 Edit: a copied member keeps its compound's gradient, and Clear leaves no empty compound
A compound member copied or cut on its own now keeps the compound's
gradient fitted where it was: an unplaced gradient is pinned to the
compound's bounds, measured once per compound.

Clear that deletes every anchor or segment of every member of a compound
path now removes the compound too, as Cut does, instead of leaving an
empty compound in the layer.

The edit.copy and edit.clear descriptions, docs/mcp.md and the progress
line now say that selecting the compound copies it whole, that isolation
mode takes each member as itself, and how a compound of one and Paste in
Front with the copied member still selected behave.
2026-11-10 12:25:30 -08:00
BFlat 34d0227a61 Merge pull request #6454 from dotCooCoo/fix/js-identifier-tables
JavaScript: identifiers follow Unicode's ID_Start and ID_Continue properties
2026-11-11 03:05:32 +07:00
dotCooCoo 085609e398 Merge main into feat/plugin-call-commands 2026-11-10 12:01:07 -08:00
BFlat fa13af4b8f Merge pull request #6353 from Messhias/feat/g5-brush-lib-game-trails
G5: built-in Game Trails brush library
2026-11-11 02:53:07 +07:00
BFlat 6a83f3a268 Merge pull request #6452 from dotCooCoo/fix/glyph-bounds-width-keeps-font-size
Docs: with glyph bounds, the font size follows the vertical scale
2026-11-11 02:36:28 +07:00
dotCooCoo c6c57a80ef Merge main into feat/plugin-call-commands 2026-11-10 11:26:41 -08:00
dotCooCoo 1f8423c2a9 Edit: Copy and Cut of a whole compound member take only that member
A compound-path member selected on its own, whole with Direct Selection
or with Group Selection, is now copied as an ordinary path instead of
promoting the selection to its compound. Cut removes the same objects
Copy takes, so the other members stay a compound path, a compound of
one included. The compound is still taken whole when every member is
selected whole, or when the compound itself is selected.

A copied member or piece takes the compound's paint, opacity, blending
mode, opacity mask, pixel alignment and fill rule.

Tests that pinned the earlier rule from #786 now check the new one.
2026-11-10 11:26:35 -08:00
dotCooCoo 811c21e7c2 Plug-ins: calls need doc.read, and an edit in progress is kept before a calling run
A command's result describes the document, so a plug-in without doc.read
gets -6 for every call, whether or not the id names a command. A run that
calls commands commits an edit still in progress first and prepares its
input again when that changed the document or the selection.
2026-11-10 11:26:10 -08:00
BFlat 437794f033 Merge pull request #6450 from dotCooCoo/fix/3d-extrude-limits
3D: Extrude & Bevel and Inflate build detailed shapes they refused as too complex
2026-11-11 02:20:21 +07:00
dotCooCoo 36cd83cc40 Merge main into fix/js-identifier-tables 2026-11-10 11:06:55 -08:00
dotCooCoo b86497b1e4 JavaScript: identifiers take every Unicode ID_Start and ID_Continue character, and no others
is_id_start now accepts the Other_ID_Start characters (U+1885, U+1886,
U+2118, U+212E, U+309B, U+309C), and is_id_part the Other_ID_Continue
characters (U+00B7, U+0387, U+1369 to U+1371, U+19DA, U+30FB, U+FF65),
as Unicode's ID_Start and ID_Continue properties and the ECMAScript
Names and Keywords clause define them. Letters, marks, digits and
connectors that are Pattern_Syntax are refused, which replaces the
U+2E2F special case. Escaped identifier characters go through the same
check. A supplementary letter right after a number is now the
"identifier starts immediately after numeric literal" error.

Letter categories still come from Unicode 16.0, so characters assigned
in later versions are not identifier characters yet.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-10 11:06:32 -08:00
Fabio William Conceição 9dc15b8f1f G5: built-in Game Trails brush library
Add Speed Line, Dash Trail, Burst Ray and Zigzag as original art brushes so motion and impact strokes are one library click away.
2026-11-10 19:04:40 +00:00
dotCooCoo a5d09c13f0 Docs: with glyph bounds, the font size follows the vertical scale
docs/mcp.md and docs/target-app-parity.md said that a width or height
typed with Measure Type by Glyph Bounds on changes the font size by the
scale. The font size follows the vertical scale only: a width typed
alone, out of proportion, changes the horizontal scale and keeps the
font size, and a height typed alone changes the horizontal scale the
other way. A new test checks both.
2026-11-10 10:57:34 -08:00
dotCooCoo a900653c9c 3D: Inflate limits the work of filling its grid
Inflate's grid clipped every ring of the outline in each cell the
outline crosses and tested every edge for each cell's center, so its
work grew with the outline's points times the cells: a comb of 4,000
teeth (16,002 points) took 1.1 to 1.3 s and one of 16,000 teeth 8.8 to
9.1 s. Inflate now counts that work (the edge index's entries, the edges
its queries look at and the ring points its cells clip) and refuses the
shape with "The 3D surface is too complex; simplify the shape" once it
passes 268,435,456, VectorCraft's own value (about 0.65 s). The index
takes at most 16,777,216 entries (64 MiB). Each row's inside test reads
the sorted crossings of its line, and a cell clips only the rings whose
bounds meet it, so a 65,536-point circle inflates in 0.66 s instead of
1.0 to 1.2 s.

The effects test of a stroke past the limits uses 40,000 corners, so its
outline passes the 65,536 points a solid takes.

Docs: docs/three-d.md, docs/mcp.md.
2026-11-10 10:43:24 -08:00
dotCooCoo f51a9dc16d Merge main into feat/plugin-call-commands 2026-11-10 10:16:48 -08:00
dotCooCoo f921a6923d Plug-ins: an API level 2 plug-in calls the commands its manifest lists
A filter at plug-in API level 2 with the new `commands` permission names
the commands it may run in its manifest's `commandAllowlist` and runs
them with `env.vc_call`, reading each result with `env.vc_call_result`.
Each call runs through Session::execute on the run's document and sees
what earlier calls changed; the calls and the filter's output are one
undo step, and a run that fails, is cancelled or makes a failed call
leaves the documents, their history and the session state the commands
change as they were.

Commands that touch files, the clipboard, preferences, the view,
scripts, actions, plug-ins, open documents or the undo history are never
callable, and every other command must be listed as allowed in
cmd/plugin_call/reviewed.rs, so a new command is refused until placed.
Calls are capped at 1,000 a run, 8 MiB a call and 64 MiB a run, and each
costs instructions from the run's budget. plugin.install refuses a
manifest that lists a refused command and reports unknown ids;
plugin.inspect lists both, and the approval dialog lists the commands.

Refs #2186
2026-11-10 10:16:28 -08:00
dotCooCoo 6484e72dff 3D: Extrude & Bevel and Inflate build detailed shapes they refused as too complex
Each Extrude & Bevel and Inflate solid now takes up to 65,536 outline
points (was 2,048) and 163,840 faces (was 32,768), VectorCraft's own
limits, as Revolve's. Before any point is sampled, the outline's lines
and curves are counted with each curve's tolerance pieces, and the faces
the walls, bevels and caps (Extrude) or the sides (Inflate) need. When
they do not fit, every curve takes fewer pieces, down to 4; a shape that
does not fit at 4 is refused with the existing surface error before any
face is built. The subpath count is capped at the point limit too. The
error texts are unchanged.

A closed path of 2,000 curves now extrudes with a bevel and inflates,
and paths of 5,000 and 10,000 curves build at the default settings.

Docs: docs/three-d.md, docs/mcp.md, docs/target-app-parity.md.
2026-11-10 10:14:22 -08:00
HassanKhan 4a954a6a84 Edit Custom Dictionary: Done saves its deletes and adds together, all or none (part of #4936)
Done ran text.spelling.removeWord and text.spelling.addWord one word at a
time, each saving the file, so a save that failed after a delete was saved
left that word deleted even after Cancel. text.spelling.editDictionary
{remove, add} makes every change, saves once and takes all of them back when
the save fails; Done runs it once.
2026-11-10 21:48:25 +05:00
HassanKhan bc3d23bb50 Merge remote-tracking branch 'upstream/main' into feat-4936-edit-custom-dictionary
# Conflicts:
#	docs/gaps.md
#	docs/roadmap.md
#	docs/target-app-parity.md
#	docs/type-parity.md
2026-11-10 21:13:30 +05:00
BFlat e1137877ac Merge pull request #6424 from Messhias/feat/g5-style-lib-game-hud
G5: built-in Game HUD graphic style library
2026-11-10 22:19:35 +07:00
BFlat a991ec8dd6 Merge pull request #6432 from ruchirguitar/fix/3565-direct-select-type-path
Direct Selection shows and drags type on a path's direction handles (#3565)
2026-11-10 22:11:14 +07:00
Fabio William Conceição 710e14a33a G5: built-in Game HUD graphic style library 2026-11-10 14:26:37 +00:00
ruchirguitar 74ae6fdd05 #3565: Direct Selection shows and drags type on a path's direction handles
Direct Selection showed and dragged the anchors of type on a path's path
(#3980) but not their direction handles: handle_anchors read only a
path's own data, and the canvas draws only a path's handles.

- text.setPathHandle moves a handle of type on a path's path, in
  document space, as path.setHandle moves a path's; the brackets keep
  their fractions and the text reflows. One undo step.
- Direct Selection draws the handles of selected type on a path and
  drags them with it (Alt: one side, Shift: 45 degree steps).
2026-11-10 19:35:29 +05:30
BFlat 207091564e Merge pull request #6349 from juliusvaart/5421-line-arrowhead
Stroke: Line Arrow arrowhead (part of #5421)
2026-11-10 20:19:01 +07:00
BFlat d80e73b76e Merge pull request #6342 from christianlappin/codex/fix-6322-rotate-view-mcp
MCP: handle Rotate View gestures in the desktop canvas
2026-11-10 20:10:24 +07:00
HassanKhan 0437d987fb #4936: Edit › Edit Custom Dictionary… dialog
The custom dictionary's words in a list, with an Entry field and Add, Delete
and Change, applied on Done, as the public Check and correct spelling page
describes it. The menu item moves from the Spelling submenu to the Edit menu,
where the page puts it.
2026-11-10 15:09:55 +05:00
dotCooCoo d358eb0d90 Merge main into fix/3d-more-object-kinds 2026-11-10 01:00:01 -08:00
Julius van der Vaart 5b7325483a Merge branch 'main' of github.com:storytold/vectorcraft into 5421-line-arrowhead
# Conflicts:
#	docs/target-app-parity.md
2026-11-10 09:50:32 +01:00