Commit Graph
4974 Commits
Author SHA1 Message Date
Dylan M. Taylor e4035a75db DXF import: read the drawing with craft_dxf::model
craft_dxf::parse_recovering reads the tags (ASCII and binary, any code
page), model::Document::read the sections, tables, blocks, layouts and
entity followers, and Entity::read each entity. The pair parser, the
records, the header, layer, block and layout readers and the colour
palette are gone; what stays is the mapping onto VectorCraft art.

Binary DXF files now open instead of being refused. A damaged binary
file says so.
2026-11-14 00:56:01 +00:00
dotCooCoo 2bd3466de2 i18n: Traditional Chinese has a row for the messages the untranslated report lists
The Traditional Chinese catalog had no row for 1,852 of the status and
error messages that i18n::tests::untranslated_report finds in the
sources, so the status bar showed them in English.

- zh-hant.tsv gets 1,813 @msg rows under one comment line at the end of
  the file, written in Taiwan usage with the catalog's existing terms.
  Each row keeps the English key, its placeholders, doubled braces,
  parameter names, command ids and quoted values unchanged.
- The 38 rows that open #7211, #7116 and #7330 add, and the row #7214
  added, are left out, so the catalogs stay consistent.
- docs/localization-parity.md and docs/target-app-parity.md give the new
  counts: 3,438 @msg and 48 @msgplural rows, 40 messages still listed.

The rows for `{name} must be {lo}–{hi}{unit} (got {v})` and
`unknown parameter `{within}{key}`; {why}` are counted by the report, but
Template::parse does not load a template with two placeholders in a row,
so those two messages still show in English. The row for
`{k} has control characters{_1}` does not match the message for a
multi-line File Info field, where its last placeholder is empty.
2026-11-13 16:54:23 -08:00
dotCooCoo aef3acd51b Text Wrap: Offset in picas reads bare numbers as the other length fields do
In a document in picas, a bare number typed in Text Wrap Options › Offset
follows Preferences › Units › Numbers Without Units Are Points, as every
length field drawn by the shared unit field does: points while it is on
(the default), picas while it is off. A test covers both settings, and
the evidence line in docs/target-app-parity.md states the rule.
2026-11-13 16:44:37 -08:00
dotCooCoo be8d614b0c .ai import: straight compound paths whose guides reach past them keep the drawn look under Twist
A straight compound path with Twist was read live up to 180° whatever
guides it held, and the live Twist was measured from bounds that take in
the guide members. A straight compound path with Twist whose guide
members reach past its other members now opens as its drawn look
instead of live, and so does a compound path made only of guides.
Compound paths whose guides lie inside their other members, a Twist of
0°, and single paths keep opening live.

The `.ai` writer keeps a graphic-style link only where the reader reads
the style live, so such an object is now written without the link, with
the existing style-link warning.
2026-11-13 16:35:37 -08:00
dotCooCoo ead3cd1ebd Variables: Import Data Sets reads UTF-16 CSV files without a byte-order mark
A CSV file that holds NUL bytes and has no byte-order mark was refused.
It is now read as UTF-16 when at least half of its two-byte units hold
a NUL byte, in the byte order that reads a line break. A file with fewer
NUL bytes (UTF-8 or Windows-1252 text with stray NUL bytes, or UTF-16
text made mostly of characters above U+00FF) is still refused, and so is
a file that reads a line break in both byte orders, has an odd length,
isn't valid UTF-16 in that order or holds a NUL character. Refused files
get the same message as before.
2026-11-13 16:34:43 -08:00
BFlat 92d9604726 Merge pull request #7264 from dotCooCoo/fix/confined-svg-export-script-paths
MCP: SVG export by a confined caller refuses script links outside its read roots
2026-11-14 07:34:26 +07:00
BFlat 02f8a5ce88 Merge pull request #7317 from dotCooCoo/fix/app-bar-button-layout
Title bar: the app bar places its window buttons by the desktop's button layout
2026-11-14 07:34:18 +07:00
BFlat f14aa09bbf Merge pull request #7226 from dotCooCoo/fix/legacy-ai-type-kerning
PDF/.ai import: legacy type keeps manual kerning, discretionary hyphens and language
2026-11-14 07:34:10 +07:00
BFlat c79a21c8b7 Merge pull request #7320 from dotCooCoo/fix/graph-design-art-appearance
Graphs: Appearance and effect commands leave a design's art in a series out
2026-11-14 07:33:59 +07:00
BFlat 0c976db26c Merge pull request #7319 from dotCooCoo/fix/ai-wrap-options-saved
.ai save: the editing copy keeps text wrap Offset and Invert Wrap
2026-11-14 07:33:50 +07:00
BFlat 8009ea8e6d Merge pull request #7313 from dotCooCoo/fix/background-document-bounds
Type: a document replaced in the back measures its type when it is replaced
2026-11-14 07:33:42 +07:00
BFlat c6d580af4b Merge pull request #7280 from dotCooCoo/fix/colored-solid-faces-one-order-limit
3D: solid-color fills and strokes under colored lights draw their faces in one depth order
2026-11-14 07:33:34 +07:00
BFlat 13abf355c6 Merge pull request #7323 from dotCooCoo/fix/trace-palette-flat-ground
Image Trace: a nearly flat dark ground keeps one color in a Limited palette
2026-11-14 07:33:05 +07:00
BFlat 239152b6c8 Merge pull request #7303 from dotCooCoo/fix/slanted-seam-tolerance
Area type: lines stop at a gap between slanted contours however narrow
2026-11-14 07:32:55 +07:00
dotCooCoo 40f69a1204 Docs: the Brushes panel lists the second brush of a repeated name in its own numbered row
Reading a brush library numbers the second brush of a repeated name, so
the panel's row of that name previews and drags the first brush, and the
second brush has a numbered row of its own.
2026-11-13 16:27:27 -08:00
dotCooCoo 09f5efad22 i18n: Ukrainian translates 1,811 more status and error messages
uk is in COMPLETE_MESSAGES, but the untranslated report listed status
and error messages with no Ukrainian row, so with the interface in
Ukrainian those messages showed in English.

- uk.tsv gains 1,811 `@msg` rows. The translations are VectorCraft's
  own, written from the English meaning with the catalog's terms and
  typography (« » around interface names, ’ inside words).
  Placeholders, backticked names, command ids, double-quoted values and
  bare true, false and null stay as the English writes them.
- The 41 rows that open #7211, #7214, #7116, #7330 and #817 add to
  uk.tsv are left out, so the catalog keeps one row per key when they
  merge (bundled_catalogs_are_consistent rejects a second row for a
  key).
- The Ukrainian row of docs/localization-parity.md gives the catalog's
  counts.
2026-11-13 16:25:25 -08:00
dotCooCoo c6211b35ab Docs: the Linux title bar paragraphs describe the frame the desktop draws
docs/control-protocol.md said the window has no OS decorations on
Windows and Linux. On Linux and the BSDs the app bar is the title bar by
default only on a Wayland session without server-side decorations, such
as GNOME, in a window not opened through XWayland; elsewhere the desktop
draws the frame unless VectorCraft Title Bar on Every Desktop or
VECTORCRAFT_TITLEBAR=app turns the app frame on. The paragraph now says
so.

docs/development.md said the custom title bar is the Linux default. It
now says where the app bar is the default title bar. The comment on
CUSTOM_TITLEBAR in apps/vectorcraft/src/titlebar.rs made the same
Windows and Linux claim and now names Windows only.
2026-11-13 16:24:44 -08:00
dotCooCoo d358baf9cc i18n: Brazilian Portuguese translates 1,812 of the status and error messages the untranslated report lists
pt-br is in COMPLETE_MESSAGES, but the untranslated report listed 1,851
status and error messages with no pt-br row, so with the interface in
Brazilian Portuguese those messages showed in English.

- pt-br.tsv gains 1,812 `@msg` rows. The translations are VectorCraft's
  own, written from the English meaning with the catalog's terms.
  Placeholders, backticked names, command ids, parameter names,
  double-quoted values and bare true, false and null stay as the English
  writes them.
- The 39 messages that open #7211, #7214, #7116 and #7330 add pt-br rows
  for are left out. bundled_catalogs_are_consistent rejects a second row
  for the same key.
- The Portuguese row of docs/localization-parity.md gives the catalog's
  counts: 9,260 rows, 3,445 of them `@msg` and 48 `@msgplural`.
2026-11-13 16:13:53 -08:00
dotCooCoo c0e70819f4 i18n: the untranslated report checks the effects, map_err messages and schema phrases
The untranslated report missed messages that reach the status bar:

- MESSAGE_CRATES now includes effects, color, render, three-d and pathops,
  whose errors the engine and the effects pass on (SVG filters, swatch
  libraries, raster sizes and encoders, 3D solids, path operations).
- The scan reads the messages a .map_err closure returns, from each if
  branch, match arm and the last expression of a block, the messages of
  a handler that .map_err(name) names (a closure bound with let, or a
  function), and the message given to a variant of an enum whose name
  ends in Fail (CompileFail::Syntax). The steps of a script result's
  path ([{i}]{place}, .{k}{place}) are not messages.
- The report and the VECTORCRAFT_I18N_DUMP_MESSAGES dump include the
  phrases a parameter schema's error builds at run time (SCHEMA_PHRASES).

Missing translations stay report-only. On main at 0b29b2b1f6 the report
lists 126 more messages, missing in all 23 languages that translate
every message: 43,084 missing rows before, 45,983 after.
2026-11-13 16:06:26 -08:00
dotCooCoo 187032fbb2 Path Precision Tools: Corner commands refuse unknown item keys
addon.pathtools.cornerSet and cornerRemove now refuse a key other than
id and anchors in an `items` member, with the standard unknown-parameter
error, instead of ignoring it. A misspelled `anchor` used to fall back
to the request's `anchors`, else the path's direct-selected anchors,
else every corner of the path. They also refuse `items` given together
with `ids`, which `items` replaces. Saved steps played with replay
still run as recorded.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-13 16:03:08 -08:00
dotCooCoo 9a355b1a75 i18n: German leaves out the rows #7211, #7214 and #7116 add
Open #7211, #7214 and #7116 add German rows for 38 of the messages this
branch translates. A second row for the same key fails
bundled_catalogs_are_consistent once both sides merge, so this branch
drops its 38 rows and leaves those messages to the other pull requests.
The German lines in docs/localization-parity.md and
docs/target-app-parity.md give the new counts.
2026-11-13 15:58:36 -08:00
dotCooCoo d30831bd5a Merge main into feat/live-paint-cursor-swatch-preview 2026-11-13 15:54:47 -08:00
dotCooCoo dd411ec6b4 Image Trace: a JPEG's 8 x 8 blocks no longer trace as staircase steps
A JPEG rounds each 8 x 8 block's tone on its own, which leaves a small
step at every block edge. Where a dark ground changes slowly, those steps
decided which of two palette colors a whole block got, and the trace
followed the block edges as a staircase.

The new deblock pass finds the block grid in the image: the mean step
between neighboring opaque pixels must peak at the same one of eight
positions at both block edges of a 16 px span, across and down. Cropped
JPEGs and JPEGs saved in another format are found the same way; pictures
of flat 8 x 8 cells are not. At each block edge, a stretch of eight lines
whose step is under the limit and whose pixels hold no edge has the step
spread over the eight pixels around the edge, as the deblocking filters
of ITU-T H.263 Annex J and MPEG-4 Part 2 Annex F.3.1 do. Larger steps are
kept. The limit, the edge guard and how much of each line's own step is
smoothed depend on the mode: Black and White smooths only the smallest
steps, and traces of more than 16 colors move every line of a stretch
by the same amount. The pass runs before the photo pre-filter and works
in strips of rows, so only its output is as large as the image.
2026-11-13 15:47:30 -08:00
dotCooCoo 76d99d6afb Merge main into fix/ai-graphs-keep-data 2026-11-13 15:46:07 -08:00
dotCooCoo d7da446cd7 Text Wrap: Offset is a distance in the document's units
Text Wrap Options showed Offset as a plain number in points. It is now a
distance field in the document's General unit: a bare number is in that
unit, a typed unit is read as typed, and OK sends points.

The field's range is the one object.textWrap.options keeps an Offset to,
-1000 to 1000 pt, read from the engine's TEXT_WRAP_OFFSET_RANGE. A value
typed outside it, or text that doesn't read, is refused: the field
flashes and the dialog stays open. The ends as the field shows them in
another unit (352.7778 mm for 1000 pt) read back as the ends.

In the dialogs drawn by the shared dialog window, a click on OK no
longer confirms the dialog when the field it takes the focus from
refuses its text, as Enter already did not. OK pressed from the keyboard
after such a click still confirms.
2026-11-13 15:39:15 -08:00
dotCooCoo c477db87ba Live Paint: an edit that changes nothing records no undo step
A Live Paint Bucket click or drag over faces that already have the
fill, a stroke on an edge that already has the paint and width, Gap
Options with the options the groups have and no gap to close, and Make
or Merge given one Live Paint group alone now leave the document, the
undo and redo steps and the saved state as they are, and reply as
usual. Such a fill or stroke also leaves the recent colors as they are.

Gap Options with Close Gaps With Paths makes a group's faces again only
when it adds a path or what paint stops at changes, so the faces keep
their ids otherwise.
2026-11-13 15:39:04 -08:00
dotCooCoo a8a0316da7 Type: Create Outlines keeps the type object's own fills and strokes
Type > Create Outlines dropped the fills and strokes of the type object
itself (the items around the Appearance panel's Characters row), so the
outlines no longer drew what the type drew. On type without effects of
its own, Object > Expand outlines the type with the same command, so it
lost them before Fill or Stroke could expand them.

- Create Outlines puts those items on paths of the type's whole outline:
  the items below the Characters row on one path under the glyph paths,
  the others on one path over them, in their order. Unplaced gradients
  are fixed to the type's layout box, as the canvas paints them.
- object.expand.info reports the type object's own strokes, pattern
  fills and gradient fills, measuring a gradient on the whole outline.
  It counts them only when the type has an outline: type of only spaces
  reports none of them.
- The stroke flag of object.expand.info counts every stroke Outline
  Stroke outlines, not only the topmost one, for paths as well as type.
  Expand skipped Stroke for a visible stroke under a stroke with no
  paint.

Create Outlines still does not carry over the type object's own effects.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-13 15:39:04 -08:00
dotCooCoo 3429bbc76a Save, Export for Screens: warnings name an option the file doesn't read
The save commands' warnings now follow an export's .ai rules: a legacy
.ai file (aiVersion "7") reads only its own options, and the other .ai
and .ait files don't read outlineText, hiddenObjects, transparentImages
or preserveEditing. They name any option given beside the path that the
file doesn't read, not only compress, version, preview and precision,
and any such key in options. The bytes a save writes don't change.

The Save Options dialog sends a .ai save only the options the chosen
version reads, so a save from the dialog gets none of these warnings.
When the document's own file is already a .ai, the .ai options that a
save doesn't give and its file doesn't read keep their remembered
values, so the dialog still shows them; the save doesn't write them, and
a retry in another folder doesn't send them.

Export for Screens and Export Assets already accepted a key in a format
row or in a format's settings that only another format takes. Their
warnings now name it as given (formats[0].quality, settings.png.quality).
A key in a format's settings is named only when no row of that format,
as the export writes it, reads it. The options of an exportPreset, and
for assets.export the settings the document keeps, get no warning.

Docs: params text of document.save, document.exportForScreens and
assets.export; docs/mcp.md; docs/target-app-parity.md.
2026-11-13 15:34:25 -08:00
dotCooCoo 71fab5bd81 Merge main into fix/it-message-rows 2026-11-13 15:30:48 -08:00
dotCooCoo 9594d39bd5 Edit Colors: no undo step when a recolor changes nothing
Invert Colors, the Convert to commands, Saturate, Adjust Color Balance,
the Blend commands and Recolor Artwork recorded an undo step even when
they changed no color, for example Invert Colors with fills and strokes
off, Saturate at 0 or a second Blend Front to Back. The empty step also
cleared the redo steps. paint.invert and paint.complement on whole
objects, Apply as Filter (addon.color.filter) and Apply Nearest Swatch
run the same pass and did the same.

These commands now run on a copy of the document and record the step
only when something changed. Convert to Indexed Color uses the same
helper. Recolor Artwork also compares the documents when it counted no
recolored paint, so rewriting a color group's swatches still records
its step.
2026-11-13 15:29:04 -08:00
BFlat 0b29b2b1f6 Merge pull request #7267 from dotCooCoo/fix/doc-info-values-translated
Document Info: values show in the interface language
2026-11-14 06:27:27 +07:00
BFlat 4a0f4b924e Merge pull request #7305 from dotCooCoo/fix/one-anchor-edit-no-remeasure
Path: anchor edits on a long selected path skip measuring it for the canvas check
2026-11-14 06:27:14 +07:00
BFlat f6e84df143 Merge pull request #7306 from dotCooCoo/fix/path-type-rtl-fit
Type on a path: overflowing right-to-left type shows the longest start that fits
2026-11-14 06:26:48 +07:00
BFlat efba8bfd89 Merge pull request #7295 from dotCooCoo/fix/negative-wrap-offset
Text Wrap: a negative Offset lets text run into the wrap object
2026-11-14 06:26:39 +07:00
BFlat be1810e0c9 Merge pull request #7263 from dotCooCoo/feat/smooth-free-end-tangent
Smooth tool: an open path's end turns with the smoothing when a drag reaches it
2026-11-14 06:26:31 +07:00
BFlat 6fa41d4f76 Merge pull request #7304 from dotCooCoo/fix/graph-series-object-opacity-other-commands
Graphs: Global Edit, Randomize Opacity and Sort Objects keep what they give a series
2026-11-14 06:26:22 +07:00
BFlat 2beda0487e Merge pull request #7251 from ncic/snap-labels
Snap to Point draws no Smart Guides labels or lines with Smart Guides off
2026-11-14 06:26:14 +07:00
dotCooCoo 96833747dc Merge main into fix/de-message-rows 2026-11-13 15:18:54 -08:00
dotCooCoo 0fc37a0ddf Merge main into fix/slanted-seam-tolerance 2026-11-13 15:17:12 -08:00
dotCooCoo 9d3717b0c0 Merge main into fix/colored-solid-faces-one-order-limit 2026-11-13 15:16:25 -08:00
dotCooCoo aab26c2b31 Image Trace: a nearly flat dark ground keeps one color in a Limited palette
The Limited palette's median cut ranks cuts by pixel-weighted gain. A
large near-black ground with faint noise therefore took two colors less
than 0.02 apart in Oklab, and the trace drew blotches of one over the
other.

With 9 to 16 colors, a cut whose two sides both have a dark gray mean
(Oklab lightness under 0.30, chroma under 0.03) and lie less than 0.03
apart now has its gain scaled by (distance / 0.03)^2 while the cut is
chosen. The ground keeps one color, and the color it would have taken
goes to another cut. Document Library without swatches follows Limited.
Other color counts, Full Tone and Automatic choose the same cuts as
before.
2026-11-13 15:13:54 -08:00
dotCooCoo 5d543c906a Merge main into fix/item-4459 2026-11-13 15:13:10 -08:00
dotCooCoo 11ecbe4e9a Merge main into fix/legacy-ai-type-kerning 2026-11-13 15:00:02 -08:00
dotCooCoo 0d26724a7c Graphs: Appearance and effect commands leave a design's art in a series out
A graph draws the art of a column or marker design inside a series again
from the stored design. Rows, effects and graphic styles that a command
gave that art were lost the next time the graph's data, type or size
changed. The paint commands already left the art out.

- The appearance.* row and whole-appearance commands, effect.apply,
  appearance.addEffect and the effect.* commands that edit, move or
  remove an effect, threeD.mapGraphic, graphicStyle.apply,
  graphicStyle.addFromLibrary with apply, transparency.set with a fill
  or stroke item, and appearance.copyFrom (as the target) leave out any
  object inside a series group other than a path directly in it, given
  by id, selected or reached through target: "contents". They edit the
  other objects given, and a command whose objects are all design art
  is an error.
- appearance.transfer with design art as its target, or as its source
  without copy, is an error.
- A Pathfinder effect no longer groups selected design art.
- The paint commands given a design's copy with a fill or stroke item
  leave it out as well.

docs/mcp.md states the rule, and the Graphs line in
docs/target-app-parity.md names it.
2026-11-13 14:51:31 -08:00
dotCooCoo aa5d142bd8 .ai save: the editing copy keeps text wrap Offset and Invert Wrap
A PDF-compatible .ai saved with Include Editing Data for Other Apps
wrote no text wrap options, so a wrap object opened from the file no
longer wrapped type. An object with only wrap options got no
dictionary at all.

The writer now writes each wrap object's options in its dictionary as
`AI11TextWrapOffset` (`/Real`) and `AI11TextWrapInvert` (`/Bool`, 1 or
0), the entries `text_wrap` in crates/eps/src/import/ai/read/document.rs
reads, beside the object's name, variables and opacity mask.

- The offset is the one in the art's space, so on a large canvas it is
  written at 1/10 and read back at its size. An offset that is not
  finite is written as the default 6 pt, and one past the -1000 to
  1000 pt the reader keeps as the nearer end of that range.
- Art the writer draws for an object (a blend's steps, a symbol
  instance written as its art, a brushed stroke's pieces, pattern
  tiles, an object's drawn look) is written without the options of the
  objects it is made from. The object itself and a symbol's own art
  keep theirs.
- A clipping path written as its fills and its strokes has its options
  once.

Docs: docs/file-format-parity.md, docs/target-app-parity.md.
2026-11-13 14:48:16 -08:00
dotCooCoo ccc9c6b341 Title bar: the app bar places its window buttons by the desktop's button layout
On Linux and the BSDs, craft-window reads the desktop's window-button
layout (`button-layout` in `org.gnome.desktop.wm.preferences`) into
`Frame::App` when the desktop leaves the window's frame to the app, but
the app bar ignored it and always drew Minimize, Maximize and Close at
its right end.

- `CaptionLayout` lists the buttons at each end of the bar;
  `caption_buttons` draws them there in the listed order, first one
  leftmost, and the bar's other controls keep clear of both groups.
- The desktop app copies the layout of an app frame the desktop left to
  it. An app frame turned on by `VECTORCRAFT_TITLEBAR=app` or by
  VectorCraft Title Bar on Every Desktop, a window opened through
  XWayland, macOS and Windows keep all three at the right.

Docs: docs/control-protocol.md, docs/target-app-parity.md.
2026-11-13 14:45:12 -08:00
BFlat 28bd9c9292 Merge pull request #7298 from dotCooCoo/fix/hi-message-rows
i18n: Hindi rows no longer keep English words or garble their sentences
2026-11-14 05:42:51 +07:00
BFlat 517b725be5 Merge pull request #7089 from dotCooCoo/fix/smooth-fidelity-screen-pixels
Smooth: Fidelity is in screen pixels, so a drag smooths as much at any zoom
2026-11-14 05:42:42 +07:00
BFlat 64c6387b84 Merge pull request #7260 from dotCooCoo/fix/tool-options-refuse-invalid
Live Paint and Shape Builder: tool.setOption refuses invalid options
2026-11-14 05:42:33 +07:00
BFlat 0899d4026a Merge pull request #7302 from dotCooCoo/fix/plugin-before-item-3d-context
Effects: a plug-in before a fill's or stroke's own 3D effect is told its fill or stroke
2026-11-14 05:42:24 +07:00