196 Commits
Author SHA1 Message Date
Helen Kwok f9bf685cbd vectorcraft-web: window.vectorcraft takes its request functions from craft-web-api
request, execute, commands and screenshot move onto the shared crate (storytold/craft-libs#413): a timeout on every call, the screenshot's PNG also in data, and docInspect and uiInspect beside them. A call the page gave up on gives up its request if the app has not started it, so the app skips it. openFile, captureDownloads, files, readFile and inspect stay VectorCraft's own, on the same object.
2026-11-07 09:18:00 +07:00
Kushagra Kumar 316f0d6213 SVG import: clip path on clipPath children clips child silhouettes before union (#5841)
Squashed from #5855 onto main.
2026-11-06 07:23:31 +07:00
dotCooCoo b8155698b5 Remove temporary test files after failures 2026-11-05 23:25:05 +07:00
BFlat 15670ca9f3 Merge pull request #4968 from dotCooCoo/feat/ai-editing-data 2026-11-04 11:41:38 +07:00
Don Omondi 4f60ee47e8 Fix #2920: an open path in a PDF-compatible .ai opens as drawn
Squashed from #4616 onto main.
2026-11-04 10:25:55 +07:00
dotCooCoo d2c5ea127a Merge commit 'refs/check/4968-main' into feat/ai-editing-data 2026-11-03 13:05:54 -08:00
dotCooCoo b751dce8e3 SVG import preserves selector matches while retaining metadata 2026-11-03 21:09:57 +07:00
dependabot[bot] 0fa627c6df chore(deps): bump wat from 1.262.0 to 1.263.0
Bumps [wat](https://github.com/bytecodealliance/wasm-tools) from 1.262.0 to 1.263.0.
- [Release notes](https://github.com/bytecodealliance/wasm-tools/releases)
- [Commits](https://github.com/bytecodealliance/wasm-tools/compare/v1.262.0...v1.263.0)

---
updated-dependencies:
- dependency-name: wat
  dependency-version: 1.263.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-11-03 20:07:58 +07:00
dotCooCoo 6228446e9e Fix #4559: shortcuts can use the ISO key next to left Shift
Squashed from #5276 onto main.
2026-11-03 16:03:38 +07:00
dotCooCoo f8095edf0d Merge commit 'refs/check/4968-main' into feat/ai-editing-data
# Conflicts:
#	crates/eps/src/lib.rs
#	crates/pdf/src/lib.rs
#	docs/file-format-parity.md
2026-11-02 18:47:39 -08:00
Brandon ThomasandClaude Opus 5.5 11862f6119 Release 0.21.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 19:27:35 -05:00
dotCooCoo b30f7ad34c Fix #3118: PDF export writes CMYK inks, gray and spot tints as the document holds them
Squashed from #5080 onto main.
2026-11-02 15:22:38 +07:00
NetterSilverandClaude Sonnet 5.5 88d8a7839e fix: validate parse_date calendar dates with chrono
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-02 14:36:06 +07:00
dotCooCoo 4e409af54a Merge main into feat/ai-editing-data 2026-11-01 21:29:58 -08:00
.CooCoo 890c27ccb2 Native format: take the .vectorcraft envelope from craft-vectorcraft-format (#5146)
* Native format: the .vectorcraft envelope comes from craft-vectorcraft-format

vectorcraft-format reads and writes the file's envelope through the
craft-vectorcraft-format crate in craft-libs: Head and Image, the version
and size constants, the format and version check, Tail for the data after
the JSON, split_tail and entry, and base64. The constants, is_compressed,
json_part, base64_encode and base64_decode are re-exported from
vectorcraft_format, so callers do not change. load_file reads the members
it uses with Image entries and skips the preview and PDF data. The
document, its migrations, the version 1 writer, gzip writing, sniff and
the limits on decompression stay here.

A preview or pdf member of the wrong shape now reads as missing on its
own, so pdf_content still returns a file's PDF when its preview is
damaged.

A new test saves a document in every version, compressed and pretty,
with a preview, profiles and a PDF, reads it back, saves it again and
compares the bytes; it also reads each uncompressed file as the crate's
File. Another reads the PDF of a file whose preview is damaged.

* Native format: sniff from craft-vectorcraft-format, pinned at #408's head

- craft-vectorcraft-format moves to craft-libs 0fd7e75fe6, the head of
  storytold/craft-libs#408.
- `sniff` is the crate's: a file is native when its top-level `format`
  member, within the first 256 bytes after decompression, is
  `vectorcraft` or `drawcraft`, read with JSON escapes decoded. The word
  elsewhere in the head no longer counts. All 192 corpus files and
  their resaved copies get the same answer as before.
- Envelope errors other than the format and the version keep the
  crate's message instead of reading as a compressed file that unpacks
  to too much.
- A test checks that a repeated `generator`, `preview` or `pdf` opens
  and any other repeated member is refused, by `load_file` and by the
  crate's `Contents` alike.

* Native format: read through the crate's Contents and Entries

Pins craft-vectorcraft-format at 420a27f18f, the current head of
craft-libs#408, and replaces VectorCraft's own copies with the crate's:

- load_file reads the JSON through Contents::read, which also refuses
  another format or a newer version. Opened is removed. Messages are
  those of main: serde names the struct File, as main's reader did.
- In-memory data after the JSON (uncompressed files, and compressed
  files unpacked whole) is read through the crate's Entries.
  entries_within keeps its streaming reader for compressed files, whose
  data is unpacked entry by entry and is never one slice in memory.
- The streaming reader finds the marker through the crate's marker_at.
- MAX_BLOB is the crate's MAX_ENTRY (1 GiB).

save_to still writes the envelope member by member: it streams the
document into the output and looks for the images it uses as it
writes, and File would need the images before the document. A new test
checks that its output, compact, pretty and compressed, for versions 1
to 4, equals serde_json::to_vec or to_vec_pretty of the crate's File
holding the same members followed by the crate's Tail, so a change to
either side fails.

* Native format: pin craft-vectorcraft-format at craft-libs main

craft-libs#408 merged as 14d5dbb50c; the crate is unchanged from
420a27f18f. A test checks that the crate's sniff takes every layout
VectorCraft has written: the version 1 and 2 files from before the
rename, compact and pretty, and each version save_with writes.
2026-11-01 23:30:54 -05:00
dotCooCoo 0823672c82 Merge main into feat/ai-editing-data 2026-11-01 15:57:03 -08:00
Brandon ThomasandClaude Opus 5.5 5628de96f8 Release 0.20.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 13:59:17 -05:00
dotCooCoo e7cb16b66d Merge main into feat/ai-editing-data 2026-10-31 20:20:39 -07:00
dotCooCoo 5fdccdf602 Place: Word 97-2003 .doc files place as area type with their formatting
File > Place reads a Word 97-2003 document (a compound file named .doc,
or one that holds a WordDocument stream) and sets its main text as area
type, as it does for .rtf and .docx files. The text comes from the
piece table, in 16-bit Unicode or compressed 8-bit pieces. Formatting
is resolved from the style sheet's default font, the paragraph style,
the character style and the direct character and paragraph properties,
and keeps the same properties the .docx reader maps.

Table cells are separated by tabs and each row is a paragraph, and a
field places as its result. Hidden and deleted text, pictures, headers,
footers, notes, comments and text boxes are left out, and the reply's
warnings name each kind of content left out or changed once. Word 6.0
and Word 95 documents, encrypted documents and documents last saved
with fast save are refused, and so are structures that lie outside
their streams.

The compound file is read with the cfb crate (MIT), which adds one
package to Cargo.lock.
2026-11-01 07:16:29 +07:00
dotCooCoo 23005d4816 Merge main into feat/ai-editing-data 2026-10-31 11:41:40 -07:00
dotCooCoo 777ad6765c File formats: JPEG 2000 images open and place
File › Open and File › Place read JP2 files and raw JPEG 2000
codestreams (.jpf, .jpx, .jp2, .j2k, .j2c, .jpc) through hayro-jpeg2000,
and store the pixels as PNG. Gray, RGB, CMYK and ICC-tagged images, with
or without alpha, are converted to RGBA. Several codestreams, JPX
composition or layers, other color spaces, inconsistent or oversize
palettes, inconsistent channel definitions, oversize tile grids and
images past the pixel allowance are refused with a message before the
pixels are decoded.

The capture and display resolution boxes size the image: the box that
comes last sets each axis, and an axis without a usable value uses
72 ppi.

IccProfile::to_srgb_into converts a pixel with the cached transform and
no heap allocation.
2026-11-01 01:22:05 +07:00
dotCooCoo 22610af58c Merge main into feat/ai-editing-data 2026-10-31 10:51:17 -07:00
dotCooCoo 034a327f5b Eyedropper: bound the work of one color sample
A sample now shares one work limit, counted in objects looked at, across
hit tests, pattern tiles and the tile or symbol art it places for hit
testing, and gives no color when the limit runs out. Objects that give
no color are skipped by id instead of cloning the document for each
retry, each nesting level reuses one scratch document that holds only
the symbols, and patterns and images are looked up in the sampled
document. The sample runs on a deep stack and follows art inside art at
most 16 levels deep.

A symbol instance is now sampled as it draws: its art is stained by the
instance's fill and placed by the instance's transform without moving
the patterns in it or scaling its strokes. Between the shapes of its art
the sample shows what lies below instead of the stain, and a pattern
tile holding an instance is sampled wherever the symbol's art reaches.
2026-11-01 00:36:32 +07:00
dotCooCoo bb6cbfb2b4 Images: SVG and EPS export write colorized grayscale and 1-bit images in their fill color
SVG export ignored an image's colorize paint and wrote the image's own
black, white and gray pixels. EPS export flattened every colorized image
into a process-color raster, so a spot color lost its plate. Both now
write the image in the fill color, with the coverage the canvas and PDF
export use (darkness times alpha), so white and transparent pixels take
no color.

- SVG writes a coverage PNG as a mask over a rectangle in the color,
  shared between repeated images while each keeps its own color. Linked
  mode writes the coverage PNG as a file, and SVG Tiny 1.2 writes a PNG
  in the color. A colorized image whose pixels are missing, or whose
  grayscale pixels can't be decoded, is left out with a warning.
- EPS writes fully covered or uncovered pixels as an imagemask in the
  color's process or Separation ink (Registration on every plate), and a
  grayscale image as ink samples scaled by coverage. Level 3 masks its
  uncovered pixels out and Level 2 writes them white; gray midtones are
  written over white, with the existing warnings.
- EPS flattening no longer counts a solid colorize paint on a grayscale
  or 1-bit image as transparency by itself. Opacity, blending modes,
  opacity masks, effects and overlapping transparent art still flatten
  it, and so does a colorize paint the writer can't draw.

The svg crate's tests turn on resvg's raster-images feature to render
the embedded PNGs.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-01 00:35:27 +07:00
Don Omondi 1679318034 Type: lam-alef highlight follow-up: optional features, all marks, exact ligature test (#394)
Highlight Alternate Glyphs no longer drops a lam-alef cluster's glyphs
outright: the ligature is clear when required shaping, or shaping with
liga left on (older fonts), gives it, so an optional feature such as
salt that changes it is highlighted again. is_lam_alef takes any
combining mark by Unicode general category (Arabic Extended-A/B/C
included) instead of a partial list. The test font maps the fatha to a
mark and skips marks in its ligature, so the mark-spanning test checks
the exact ligature glyph and cluster; it gains a salt lookup and test.

Also a one-line equivalent nonminimal_bool repair in pathops'
pathtools that strict Clippy needs on main.
2026-10-31 19:43:17 +07:00
dotCooCoo 4e785b40ce Part of #4516: Windows renders start workers only for the cores the process may use
The renderer sized its worker pool from available_parallelism, which on
Windows counts every processor in the machine, also when the process's
affinity mask allows fewer. A process allowed one core started 8 workers,
and the renderer's flush spun on that core while the workers got no time,
so renders crawled or stalled.

The desktop app and vectorcraft-cli now read the affinity mask at startup
(src/windows_cores.rs, shared) and pass the count to the renderer with
vectorcraft_render::set_usable_cores. With one usable core the renderer
renders on the calling thread.
2026-10-31 18:44:55 +07:00
aiongg 91e97c92dd updates: show check results with craft-update's CheckResultDialog 2026-10-31 04:42:43 +00:00
Brandon ThomasandClaude Opus 5.5 bcebabe3f8 Release 0.19.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 23:26:38 -04:00
dependabot[bot] 414aad10bd chore(deps): bump the cargo-patch group across 2 directories with 4 updates
Bumps the cargo-patch group with 3 updates in the / directory: [rustix](https://github.com/bytecodealliance/rustix), [clipboard-win](https://github.com/DoumanAsh/clipboard-win) and [smallvec](https://github.com/servo/rust-smallvec).
Bumps the cargo-patch group with 1 update in the /crates/plugins/example directory: [serde_json](https://github.com/serde-rs/json).


Updates `rustix` from 1.1.5 to 1.1.6
- [Release notes](https://github.com/bytecodealliance/rustix/releases)
- [Changelog](https://github.com/bytecodealliance/rustix/blob/main/CHANGES.md)
- [Commits](https://github.com/bytecodealliance/rustix/compare/v1.1.5...v1.1.6)

Updates `clipboard-win` from 5.4.1 to 5.4.3
- [Commits](https://github.com/DoumanAsh/clipboard-win/commits)

Updates `smallvec` from 1.16.3 to 1.16.4
- [Release notes](https://github.com/servo/rust-smallvec/releases)
- [Commits](https://github.com/servo/rust-smallvec/compare/v1.16.3...v1.16.4)

Updates `serde_json` from 1.0.151 to 1.0.154
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.151...v1.0.154)

Updates `serde_json` from 1.0.151 to 1.0.154
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.151...v1.0.154)

---
updated-dependencies:
- dependency-name: clipboard-win
  dependency-version: 5.4.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: cargo-patch
- dependency-name: rustix
  dependency-version: 1.1.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: cargo-patch
- dependency-name: serde_json
  dependency-version: 1.0.154
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: cargo-patch
- dependency-name: serde_json
  dependency-version: 1.0.154
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: cargo-patch
- dependency-name: smallvec
  dependency-version: 1.16.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: cargo-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-10-31 02:23:04 +07:00
wjrichardsandClaude Opus 5.5 dd934dfd4e Linux clipboard: copy text through the core Wayland protocol
Where arboard can't open (GNOME has no data-control protocol, and the Flatpak on a
Wayland session has no X11), Copy and Paste use the compositor's core data-device
protocol on the window's own connection through smithay-clipboard, already in the
build through egui-winit: text only, a copy's text or its SVG markup. A bitmap-only
copy reports that this clipboard carries text only and leaves it as it was.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 17:12:17 +07:00
Dylan M. Taylor 45be6f47bf UPD.1: honor app pretend versions in update checks (#4677) 2026-10-30 03:07:22 -04:00
Dylan M. Taylor a24d811c7b Update prompt shows the app icon and accent color instead of a letter (#4671)
UPDATE_APP (native builds; craft-update is a native-only dependency) carries our 128 px icon and accent (#e8573f, its colour in ArtCraft Launcher). The updater, the self-update
helper and craft-update's startup prompt all get them through crate::UPDATE_APP; the
prompt draws the icon, the accent and "by ArtCraft" (craft-update's default developer).

craft-update is pinned to storytold/craft-libs main at 1065653e7 (#434).
Clippy fixes for Rust 1.99 in untouched code (same logic):
- crates/svg/src/import/fx.rs
- crates/tools/src/text/tool.rs
2026-10-30 01:27:35 -04:00
Dylan M. Taylor 39bb862420 deps: bump tar, zip, roxmltree, rustls-webpki and symphonia to their latest versions (#4662)
- `roxmltree`: 0.20.0, 0.21.1 → 0.20.0, 0.21.2
- `zip`: 9.1.0 → 9.1.3

Lockfile only.
2026-10-29 22:32:34 -04:00
dotCooCoo f55cbf313c Fix #2249: macOS converts the canvas from sRGB to the display's profile
The window's CAMetalLayer had no color space: wgpu 30.0.1 sets it to
nil for an sRGB surface each time it configures the surface, and Core
Animation does not color-match a layer without one. On a wide-gamut
display #FF0000 showed as the display's own red, (255, 0, 0) in a
capture where Preview shows the same sRGB red as (234, 51, 35).

A paint callback that draws nothing runs after egui configures the
surface and before the frame is presented. It sets sRGB on each
window's Metal layer that has no color space and leaves any other color
space as it is. wgpu's own fix (gfx-rs/wgpu#10286) is in no release yet.

Fixes #3161.
2026-10-29 14:36:37 +07:00
NetterSilverandClaude Opus 5.5 4c4113096c Seed PDF encryption keys from the OS random source
Fixes #3605

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 08:44:36 +07:00
dotCooCoo f33617142c Save As .ai: carry editing data that other apps open as layers and paths
A PDF-compatible .ai now also carries, on its first page's PieceInfo, an
editing copy of the art in the form VectorCraft's own .ai reader reads:
AIPrivateData streams of 64 KiB holding the program compressed with
Zstandard after %AI24_ZStandard_Data, an AIMetaData stream of its header
comments, and the ContainerVersion, CreatorVersion, NumBlock,
RoundtripStreamType and RoundtripVersion entries.

The program holds the header comments, the color swatches and color
groups, every artboard, layers and sublayers (name, order, visibility,
lock, color, printing, dimming), groups, paths, fills and strokes (width,
caps, joins, miter limit, dashes, overprint, fill rule), process, spot and
global colors, guides, hidden and locked objects and object names. Type,
gradients, patterns, images, symbols, live objects, brushes, clipping
groups and compound paths are written as plain filled and stroked paths,
each with a warning; transparency and effects other than geometry effects
are left out.

The .ai option editingData (on by default, Include Editing Data for Other
Apps in Save As) turns it off. The legacy version 7 writer is unchanged;
the path, guide and line style operators both writers write move to
eps/src/ai_ops.rs. LoadOptions::native off opens a file from its editing
copy or pages instead of the VectorCraft document it carries.
2026-10-28 16:55:41 -07:00
Dylan M. Taylor 50bb4acf4e Update Cargo.lock: eframe no longer needs glow without the windows7 feature 2026-10-28 18:35:07 -04:00
Brandon ThomasandClaude Opus 5.5 68b68a30ac Release 0.18.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 12:09:18 -04:00
aiongg 13d837363d Dropdowns: menus grow back after a search with no matches (#4337)
* chore(deps): pin craft-libs to 62bb0e1d (shared combo box)

* fix(ui-egui): dropdown menus grow back after their contents shrink

Every combo box is craft_ui::ComboBox, whose menu follows its contents'
height while it is open (egui#5225); clippy.toml bans egui::ComboBox.

The font family menu is a craft_ui::combo::Menu under its field, with the
search field and filters in its header and the family rows scrolling under
them, still laid out only in view. The menu keeps to the room on its side
of the field, so the list's minimum height and the popup's room are gone.

* fix(ui-egui): the shortcut import's target picker grows back after a search

Its search field, "No equivalent" and the row's choices are the header of
a craft_ui::combo::Menu, and Keyboard Shortcuts' entries scroll under
them. That was the last menu on the popup path that capped itself at the
room left, so that path and combo's `searchable` flag are gone.

* chore(deps): craft-libs 60d60d48 (dropdown fixes)

* chore(deps): craft-libs 4d7b82f7 (dropdown fixes)

* chore(deps): craft-libs 92d392cf (#387 merged)

* chore(xtask): pdf-deps expects craft-libs 92d392cf
2026-10-27 10:36:58 -04:00
dotCooCoo 6ed4608d82 Images: an image past the 2 GiB decode allowance draws at reduced size instead of a crossed box
A PNG, JPEG, GIF or WebP image that takes more than the decode
allowance as RGBA (2 GiB, 512 MiB in the web app), such as a 24000 ×
24000 JPEG, was placed with the warning "too large to draw" and then
drew as a crossed gray box on the canvas and was left out of raster
exports. A 16-bit PNG whose decoded samples were past the allowance
was shown the same way, with the same warning, although its RGBA fits.

The renderer now decodes such an image at the largest size, keeping its
proportions, that fits the allowance as RGBA. Each pixel of the result
is the mean of the image's pixels it covers. A PNG that isn't
interlaced is read a row at a time; other images are decoded whole when
their decoded samples fit the allowance. A 16-bit PNG that isn't
interlaced and whose RGBA fits is read a row at a time at its own size.
An image of more pixels than the allowance has bytes still draws as the
crossed box, and so does one whose decoded samples are past the
allowance, other than a PNG that isn't interlaced. The renderer
decodes an image at reduced size only while the result and the memory
reading it takes (the image decoded whole, or the PNG reader's row
buffers) fit beside the images being painted; otherwise the image is
not decoded on that render (on the canvas it draws as the crossed box)
and is tried again on the next render. The document keeps the whole
file for saving and export. A placed document's saved preview past the
allowance is decoded the same way, at the size it is drawn at or at the
reduced size when that is smaller.

Open, Place and the Links panel say "an image of W × H pixels is shown
at reduced size" for an image drawn smaller. They say nothing for an
image drawn at its own size, and they say "too large to draw" for one
that is not drawn at reduced size.

Docs: docs/mcp.md, docs/target-app-parity.md (the crossed box's line
now names an image over the allowance that can't be drawn at reduced
size).
2026-10-26 21:41:42 +07:00
dotCooCoo 16205440e2 Render: the decoded-image cache sizes from installed memory on Windows, macOS and FreeBSD
The renderers share decoded images within a budget of an eighth of the
installed memory, at most 1 GiB. The installed memory was read only on
Linux, so on Windows, macOS and FreeBSD the budget was always 1 GiB,
also on machines with less than 8 GiB.

The installed memory is now read with GlobalMemoryStatusEx on Windows
(through winsafe, which vectorcraft-cli already uses), sysctl
hw.memsize on macOS and sysctl hw.physmem on FreeBSD. The budget rule
is unchanged: an eighth of the installed memory, at most 1 GiB, 1 GiB
where the memory can't be read, and 256 MiB in the web build.
2026-10-26 20:18:33 +07:00
skylar taylor-barrick 4ddd0332cf chore(deps): refresh muda, webbrowser and weezl (#4189)
* chore(deps): bump muda to 0.21.2 and webbrowser to 1.2.5

* chore(deps): bump weezl to 0.2 in render and pdf
2026-10-25 19:31:19 -04:00
Dylan M. Taylor 3f8d7a0c5a build: pin craft-update to craft-libs main (495e597) (#4183)
Picks up the startup prompt without the glyphs a font may lack (storytold/craft-libs#343, #344): the close mark is painted and the version pill is ASCII, so apps that panic on a missing glyph no longer take the prompt down.

Part of tracking issue storytold/craft-libs#319
2026-10-25 17:55:25 -04:00
Dylan M. Taylor caef923806 feat: startup update prompt modal and direct self-updating (#4138)
* feat: startup update prompt modal and direct self-updating

The update flow (check at start or on request, the startup prompt, the self-update worker) is craft-update's Updater; the app only supplies the suite, its close path and its status window. The check at start is opt-in for the desktop app, and the Windows update helper runs before argument parsing.

Ref: storytold/craft-libs#319

* refactor(updates): hold the install back while documents are unsaved

* fix(updates): drop the manual window's custom id; pin craft-update to craft-libs main (db19c37)

* fix(updates): address review feedback

Wake the UI when a manual check is queued from a menu callback; the update prompt owns the keyboard while it is open (LightCraft); Download opens through the desktop URL hook (FilmCraft); the Help menu dispatches through menus::invoke (FigCraft); print jobs and comment drafts hold an install back (WordCraft); Check for Updates is a registered command (GridCraft); an install holds back while documents are unsaved.

* fix(updates): localize the update status messages

* build: resolve the craft-update pin after rebasing
2026-10-25 16:22:52 -04:00
aiongg 714434527e Docking: panels on craft-ui's shared docking, floating panels in OS windows (#4135)
* Build: craft-libs at 2869b8cc

Pin craft-pdf, craft-print, craft-docpath, craft-ui, craft-keymap,
craft-window and the patched hayro/krilla backends to craft-libs
2869b8cc1077530bd07a7e192fb2b0e1304a1354, with the pdf-deps gate,
NOTICE, ASSETS.md and docs/pdf-backend.md at the same revision.

PDF: no modification date beyond the creation date, DeviceN images
are not JPEG-encoded, and clipping text draws nothing (its outlines
arrive as a clip path).

* Docking: compile against craft-ui at 2869b8cc

Floating windows are trees of groups: window_panels and window_active
read one as a flat group, and windows rebuilt from the legacy groups
keep their ids. Unknown dock actions are rejected, the new ones are
checked like the old, and every panel a close action removes keeps its
return location.

* Docking: panels and canvas on craft-ui's docking area

* Docking: tests for the dock area, flyouts, floating panels and the Tools panel

* Docking: catalogs without the old dock's strings

* Build: craft-libs at 8a503cfe

* Docking: floating panels in OS windows of their own on the desktop

* Docking: modal dialogs block panel windows; their keys and dropped files reach the main window

* Docking: art dragged onto a panel in its own window drops there

* Docking: module doc names the OS windows

* Build: craft-libs at a042cf26

* Docking: onto, above, below, collapsed, icon and column places on Float and Dock Panel; ui.docking

* Docking: command descriptions of Float, Dock, Move and Collapse Panel for the craft-ui layout

* Docking: control protocol describes the craft-ui layout, its commands and ui.docking

* Docking: rustfmt

* Docking: layouts saved before the canvas joined convert on load

Saved ui.json files and workspaces from before the shared layout held the
canvas (a dock-only tree plus floating_panels, docking_icons,
docking_collapsed, dock_collapsed and dock_width) convert into one layout:
the dock tree's groups in the main column, the icon column with the panels
dropped on it, floating groups and sets, sets docked as columns, collapsed
groups, the dock width and the places of closed panels. The legacy fields
are read, never written. A ui.json read only in part is copied to
ui.unreadable.json before anything saves over it.

* Docking: catalogs without the old collapse message

* Docking: converted floating sets start at most 720 points tall

* Docking: closed icon panels convert into the icon column; old floating rects, set heights and a copy of the file before conversion

* Build: craft-libs at 27e60765

* Docking: dock column places and icon count from the icon column; a docked column moves to a later place

* Build: craft-libs at d24e4bcc

* Build: craft-libs at 5bbe9f62

* Docs: floating panels in OS windows of their own close the other-monitor gap

* Docking: keys forwarded from a floating panel's OS window run shortcuts while the main window is unfocused
2026-10-25 15:25:35 -04:00
Dylan M. Taylor 6e7854967d Merge pull request #4113 from storytold/codex/egui-037-vectorcraft-20261023
Migrate VectorCraft input, text and capture to egui 0.37
2026-10-25 14:09:31 -04:00
Brandon ThomasandClaude Opus 5.5 43313f9451 Release 0.17.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 09:26:31 -04:00
skylartaylor 340e3495d8 egui037: migrate VectorCraft UI and reconcile current main 2026-10-25 03:27:29 +01:00
aiongg 8bf090b253 Shortcuts: use the shared craft-keymap crate for the catalogue, overrides, dispatch and .kys import (#3119)
* Shortcuts: the keymap, overrides and dispatch come from craft-keymap

The editor's catalogue (commands, UI commands, panels, tools; one tool
group per tool; show/hide commands marked as toggles) builds a
craft-keymap Keymap. UiState::shortcut_overrides is a craft_keymap
Overrides stored through keymap::stored, which writes the same map of
entry key -> one string as before, with panel: keys and VectorCraft's
spellings, so earlier versions read the file; a value that is not text
drops that entry instead of every preference.

Key presses run through craft_keymap's Dispatcher with accept filters:
keys that type text go to the one-key text path, and while the Type
tool edits only command-key chords run. Held keys repeat. Conflicts
and assignment use the crate's conflicts and set_bindings. Extra Shift
no longer falls back to the chord without it.

* Shortcuts: .kys import matches and applies through craft-keymap

The review proposes targets with craft_keymap's namematch, and Apply
hands the ready rows to craft_keymap::plan as one set, each row's
target passed as the remembered answer for its entry. The later row
takes a chord, and commands outside the set lose the chords the set
gives. Rows with one name in one block keep their own targets.
The engine's own namematch module is removed.

* Shortcuts: Cmd+, beside other hits, web Mac platform, cached dialog view

- Pin craft-keymap at 362eb59f.
- Cmd+, opens Settings on a Mac after the frame's other shortcuts run, with the
  Mac read from egui's OS; drop settings_chord, which dispatch no longer used.
- The web build follows the browser's OS, so Ctrl stays Ctrl on a Mac.
- The Keyboard Shortcuts dialog keeps its keymap, row texts and conflict count
  between frames while the working set is unchanged.
- Every default shortcut text becomes its entry's binding (test).
- craft-keymap counts as a UI crate for the layer check.
- Translate "too many changed shortcuts"; the parse error reuses the existing
  "can't parse shortcut `{c}`" message.

* Shortcuts: the chords the operating system takes can't be assigned

The keymap reserves craft_keymap::reserved::system for its platform:
window switching and closing, and the virtual consoles off the Mac.
The Keyboard Shortcuts dialog and shortcuts.set refuse them with
"<chord> is reserved by the system", and a saved override on one keeps
the entry's default. No default shortcut uses a reserved chord.

* Shortcuts: craft-keymap at craft-libs 2eca9b3a

craft-keymap comes from storytold/craft-libs (craft-libs #164 and #186), at the rev craft-pdf
already uses. The web build keeps the browser's full platform, so Windows browsers get Windows'
reserved chords, and each platform caches its own default keymap.
2026-10-24 15:01:26 -04:00
Dylan M. TaylorandClaude Opus 5.5 03d2f0e83c Security: file authority for stored paths, linked files, placed documents, font folders, recovery areas and atomic saves
CodeRabbit findings #7, #72, #92, #94, #95, #99, #100, #140, #158, #174:

- Link search hashes at most the size it looked at (a growing file no longer matches).
- Resolving links reads, decodes and previews each linked file once, shared by every key.
- Placed documents read inside one another resolve links at most 8 deep, never one already
  being read.
- A data set's image path and the placed-document rereader follow stored paths through
  `document_path` (no other computer's share).
- The Links panel looks at a linked file within the roots of the automation caller that
  opened the document.
- A fonts folder set by a confined caller is scanned without following links out of it.
- Recovery refuses an area folder that is a link or another account's.
- Atomic saves keep the replaced file's group and Linux access ACL, or make the replacement
  owner-only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 17:19:59 +07:00