Commit Graph
301 Commits
Author SHA1 Message Date
aiongg b6952941b3 Web: show a status line when a dropped file can't be read 2026-11-14 06:11:51 +00:00
aiongg 62f70cc03c Merge branch 'pr-2309' into multi-place 2026-11-14 05:49:14 +00:00
aiongg 2ee301bd4b Merge pr-2302 (place cursor queue) into multi-place 2026-11-14 05:49:14 +00:00
aiongg 55a0c7da3d DES-10 T2: port asset byte users to AssetData
Export, import, links, preflight, alpha wrap and the UI read bytes with
AssetData::load; every asset is still embedded.
2026-11-14 05:15:03 +00:00
Dylan M. Taylor 32274e843a Merge codex/designcraft-craft-libs into origin/main: cut over document formats and codecs to craft-libs 2026-11-14 02:13:28 +00:00
Dylan M. Taylor 32c239cacc Use shared image codecs for CLI previews 2026-11-13 01:59:00 -05:00
Dylan M. Taylor 44fd4aec60 Route CLI format dispatch through shared registry 2026-11-13 01:42:51 -05:00
dotCooCoo 630b5dfc43 Paste: images on the system clipboard paste as embedded images (#2204)
Paste ignored a bitmap on the system clipboard: a screenshot or an image
copied in a browser had to be saved and placed. Paste now places it.

- edit.pasteImage {base64, name?, spread?, at?} embeds the image in the
  selected empty frame, or in a new frame centered on `at` at its stored
  resolution (72 ppi when none) and at most 60% of the page width, as
  File > Place sizes it. Save and reopen and IDML export keep the pixels.
  Images over 64 million pixels and names without an image extension are
  refused.
- Ctrl/Cmd+V pastes the image egui delivers with no text, and Edit >
  Paste reads the clipboard's bitmap, or the first image file of a copied
  file list, when there is no text or the text is only an address.
- The menu read waits at most 1.5 s on its own thread, with one read in
  flight at a time.
- With a native menu, objects copied here still paste as objects until
  the pasteboard's change count shows a newer copy.
- ui.paste takes {image} for the control channel.
2026-11-11 20:50:24 -08:00
texjer 39d8469b1f Merge remote-tracking branch 'upstream/main' into HEAD
# Conflicts:
#	crates/engine/src/cmd/file/place.rs
2026-11-10 18:29:09 -05:00
texjer 969eaa0aaf Merge remote-tracking branch 'upstream/main' into HEAD
# Conflicts:
#	crates/ui-egui/src/app/files.rs
#	crates/ui-egui/src/tests.rs
2026-11-09 13:51:45 -05:00
aiongg 49f6b85cb9 Merge pull request #2037 from r31lin/fix/gpu-largest-buffer
Ask the graphics device for the adapter's largest buffer
2026-11-08 16:10:35 -05:00
texjer 37cbfceaaa Merge remote-tracking branch 'upstream/main' into feat/drop-loads-place-cursor
# Conflicts:
#	crates/ui-egui/src/app/file_dialogs.rs
2026-11-05 11:59:37 -05:00
texjer aca5c8b84a Merge remote-tracking branch 'upstream/main' into feat/place-cursor-queue
# Conflicts:
#	crates/ui-egui/src/app/file_dialogs.rs
2026-11-05 11:59:37 -05:00
.CooCoo e16785ea50 Fix CLI build warnings on Windows (#2356) 2026-11-05 09:53:17 -05:00
texjer b458bec4c5 Merge branch 'feat/place-cursor-queue' into feat/drop-loads-place-cursor
# Conflicts:
#	ROADMAP.md
#	crates/ui-egui/src/app/files.rs
2026-11-04 19:56:22 -05:00
texjer ad611c1b6f Merge remote-tracking branch 'upstream/main' into feat/place-cursor-queue
# Conflicts:
#	ROADMAP.md
2026-11-04 19:03:47 -05:00
texjer 93f18aa086 Merge branch 'feat/finder-drop-pointer' into feat/drop-loads-place-cursor
# Conflicts:
#	crates/ui-egui/src/app/input.rs
2026-11-04 13:20:02 -05:00
texjer f02e13318b Place: a drop without pointer events keeps the system pointer of its own input
Review fixes for #2304:
- Each pointer-less drop asks the system where the pointer is when its raw input arrives, and
  converts it with that input's window rect and the UI scale, instead of one sample taken at the
  later UI pass for the whole batch. Drops with pointer events keep their own pointer, and the
  system is still only asked when a drop brought none.
- system_pointer is cfg'd off on wasm with its only caller; Services::pointer's docs say a drop
  without a pointer lands in the middle of the view.
- pointer.rs: the AppKit flip is a pure function with a test, documenting why it flips against
  the main display only (winit's window positions use the same origin).
- Test: a filled compound path takes a dropped image through its ring, not its hole.
2026-11-04 12:06:17 -05:00
aiongg fb630909c4 Merge pull request #2304 from texjer/feat/finder-drop-pointer
Place: a file dragged in from the Finder fills the frame it was dropped on
2026-11-04 11:19:45 -05:00
texjer a10e288a58 Place: dropped images load the place cursor, in the order they came
Split out of #2073. Port of #1307's drops and #1666.

- Several images dropped together load the place cursor in the order they
  came, each run of them where it comes among the other files, after the
  images it already holds; click to place them one by one.
- One image dropped off a frame that takes it loads the place cursor instead
  of being placed at once; on such a frame it still fills it.
- A drop is handled in its order, each file at its own pointer, and a dialog
  (a multi-page PDF's Import Options, an alert) cancels the rest.
- On the web, files dropped together are read as one batch (none if one
  can't be read), and a single dropped image loads the place cursor.
2026-11-03 23:05:47 -05:00
Dylan M. Taylor c4ed9b2210 fix: write screenshots, signing certificates and benchmark files in private temp folders (#2219) 2026-11-03 22:16:28 -05:00
Dylan M. Taylor bcc74f29c9 fix(app): log message line breaks continue the record instead of starting another (#2220) 2026-11-03 22:16:06 -05:00
texjer 4d34f83926 Merge branch 'feat/finder-drop-pointer' into feat/drop-loads-place-cursor
# Conflicts:
#	ROADMAP.md
2026-11-03 21:50:19 -05:00
texjer 8815ef7350 Place: a file dragged in from the Finder fills the frame it was dropped on
Split out of #2073. winit sends no pointer events during a drag from another
application on macOS, so a Finder drop had no pointer and never found the frame
under it. The host now gives the pointer's place on the screen
(`Services::pointer`, `PointerFn`: the system's points before the UI scale,
from `NSEvent.mouseLocation`), and `take_pending_drops` uses it for the files
that came without a pointer, divided by egui's zoom factor and made relative
to the window.
2026-11-03 21:50:08 -05:00
texjer d890289a92 Place: several images load the place cursor, with a thumbnail, count and grid
Split out of #2073. Port of #1307, #1392 (grid) and #1432 (thumbnail and count).

- File › Place takes several files; images load the place cursor in the
  order chosen (`place.load` `files`, `append`), after the ones it holds.
  A multi-page PDF or an alert stops the batch, and a file that can't be
  placed returns its error to `app.placeDialog`.
- Each click places the next image; arrow keys while dragging lay out a
  grid (`place.grid`) and are handled even at a limit; Escape unloads the
  rest (`place.cancel`). Undo of a loaded image's asset cancels the queue.
- The cursor shows how many images are loaded.
- On the web, Place picks several files and the inbox loads consecutive
  images for the same document as one batch.
2026-11-03 21:43:44 -05:00
aiongg b749251694 Merge pull request #1478 from Hamza0101/fix/cli-argument-handling
cli: the three argument bugs photocraft#7071 lists are live here too
2026-11-03 17:01:34 -05:00
aiongg 65c4db30e1 Apply review fixes
- apps/designcraft-cli/src/main.rs
2026-11-03 21:48:08 +00:00
aiongg 61ed22140a Apply review fixes
- apps/designcraft-cli/src/main.rs
2026-11-03 19:41:27 +00:00
aiongg 35a7410481 Merge pull request #2192 2026-11-03 19:07:42 +00:00
aiongg a2d745db00 Apply review fixes
- apps/designcraft/src/main.rs
2026-11-03 13:40:17 +00:00
Hamza 54df0d21b3 Merge remote-tracking branch 'origin/main' into fix/cli-argument-handling
# Conflicts:
#	apps/designcraft-cli/src/main.rs
#	apps/designcraft-cli/tests/it/cli.rs
2026-11-03 13:50:15 +05:00
Brandon Thomas 1bca5db25b Merge pull request #1792 from marcoarnulfo/feat/thumbnailer
Linux: file managers show a .designcraft file's first page through a freedesktop thumbnailer (#1782)
2026-11-02 23:24:25 -05:00
Brandon Thomas 3a40dc7577 Merge pull request #2158 from Silvertree2010/fix/2116-graphics-fallback-marks-a-workin
Keep the graphics backend when the window closes before its first frame
2026-11-02 23:23:50 -05:00
JonRC 41c59708eb cli: script --export prints the export's warnings, as run does (#2191)
The script command threw away the result of each export, so a PDF with
a drop shadow came out with nothing on stderr, while run --export
printed "warning: 1 object(s) with soft effects ... exported as images".
Each warning an export returns now goes to stderr as "warning: ...".
The JSON report on stdout is unchanged.
2026-11-03 01:05:17 -03:00
FredApps fc47f3156e Merge current main into fix/gnome-window-decorations 2026-11-02 19:10:33 +01:00
NetterSilverandClaude Opus 5.5 a207f13f73 Keep the graphics backend when the window closes before its first frame
Fixes #2116

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 15:47:11 +01:00
Hamza 133e9098e8 cli: validate-pdf's help names --standard
`validate_pdf` accepts `--standard x4|x1a`, and both its own usage string and the
module docs say so, but the line in the global `USAGE` left it off -- and that
line is exactly what `validate-pdf --help` slices out. So the option was
documented everywhere except the one place a user would look (noted in review).

`subcommand_help_names_the_options_that_subcommand_takes` asserts it, checks the
parser and the help agree by refusing an unknown standard, and does the same for
`run --cmd` and `mcp --automation-read-root` so this is about subcommand help
rather than one line.
2026-11-02 17:39:55 +05:00
Hamza 4c9e5277f7 cli: subcommand help is for subcommands that exist
`<sub> --help` answered about that subcommand without first asking whether the
subcommand was one, so `designcraft-cli typo --help` printed the whole usage and
succeeded. `typo` on its own was an error and `typo --help` was not, which is
backwards: a script checking the exit status carried straight past a misspelled
command (noted in review).

`is_subcommand` reads the names out of `USAGE` rather than listing them again,
so one added to the usage text cannot be missing here, and `usage_for` now uses
the same line parser instead of its own copy. An unknown name falls through to
the dispatch and fails there, as it already did without `--help`.

Measured over every name the usage lists -- run, commands, describe, script,
app, mcp, perf, bench, validate-pdf, links -- each still answers on stdout and
exits 0, while `typo` and `nonsense` exit 1. The test asserts both halves, so
the check cannot quietly become a block on subcommand help.
2026-11-02 16:00:15 +05:00
aiongg cc3c70d4be Windows: keep the custom title bar window borderless (#2139)
winit 0.30 gives an undecorated window WS_CAPTION and WS_BORDER; on some systems the compositor
reserves that frame, so the content is drawn offset (black bars at the top and left) while the
pointer keeps the client coordinates. A per-frame guard strips the styles again after every
winit flag change and keeps a maximized window clear of the taskbar. Fixes #1295.
2026-11-01 20:39:44 -05:00
NetterSilverandClaude Opus 5.5 52232fc2c7 Read PDF/X output intent and Info as parsed objects in validate-pdf
Fixes #2050

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 11:47:33 +01:00
MarekSpodBiedry 759ab3ba7c Separate the CJK commands from Insert Math Expression in the Type menu (#2043) 2026-10-30 16:39:22 +01:00
r31linandClaude Opus 5.5 d9a55d19d6 Ask the graphics device for the adapter's largest buffer
egui-wgpu doubles its vertex buffer when a frame outgrows it, and wgpu's
default largest buffer is 256 MiB. Opening a 160-page InDesign catalogue
produced a frame with 137 MB of vertices; egui-wgpu asked for a 275 MB
buffer, the device refused it and the app stopped. The device now takes
the adapter's own largest buffer, as it already did for the texture side
(2047 MiB on DirectX 12 here), and the log says both limits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 11:52:42 +01:00
Dylan M. Taylor 15d13dde20 Update prompt shows the app icon and accent color instead of a letter (#2023)
UPDATE_APP (native builds; craft-update is a native-only dependency) carries our 128 px icon and accent (#7bb51c, 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/engine/src/cmd/export/text_tests.rs
- crates/pdf/src/gradient_inks.rs
2026-10-30 01:28:06 -04:00
Marco Arnulfo 8e8865bba1 thumbnail: refuse an output that names the input document (#1782)
designcraft-cli thumbnail a.designcraft a.designcraft replaced the
document with PNG bytes. The output is now refused before anything is
read or written when it is the input by the same path, through a
symlink, or on Unix as a hard link (same device and inode).
2026-10-30 03:08:39 +01:00
Marco Arnulfo ec059c042b Linux: file managers show a .designcraft file's first page through a freedesktop thumbnailer (#1782) 2026-10-30 03:00:29 +01:00
Hamza f11f5f3b11 cli: a missing value is found before anything runs
Review caught a consequence of the previous commit. Standing the order check
aside so a missing value could be reported meant the value was reported
later -- after the exports before it had already been written. `run --export
first.png --scale --export second.png` wrote first.png and only then failed,
so an invocation that fails could overwrite a file that was already there.

`values_present` checks every option that takes a value before the order
check and before any export, so the line is refused as a whole. The test
writes a file at the export path first and asserts its bytes are unchanged.
2026-10-29 13:51:49 +05:00
aiongg 855d606325 Show file and message dialogs without blocking the frame (fixes macOS crash) (#1961)
* Show file and message dialogs without blocking the frame

A blocking rfd dialog inside the egui frame runs AppKit's modal loop; a
file dragged from Finder and held over the window then re-enters winit's
handler and aborts the app. Dialogs now go through craft-dialogs: a
command without a path asks with a continuation and returns, the host
shows the dialog at the end of the frame, and the continuation runs with
the answer on a later frame, in the document it was asked for. Commands
given a path stay synchronous. The replace-file question is a message
box from the same queue. Quit and Close wait for a Save As dialog's
answer. clippy.toml disallows rfd::FileDialog and rfd::MessageDialog.

* Raise the open file panel when File > Open is chosen again

* Repin craft-dialogs to the craft-libs PR head

* Queue dialogs asked by different code or documents; hold answers behind newer dialogs

Two asks for the same file dialog were treated as one, so Place for one
document and then Choose Image, or Place again for another document, ran
the first ask's action. An ask is now skipped (and the open panel
raised) only when the same code asked for the same dialog for the same
document. An answer that would replace an egui dialog opened since the
asking (an unsaved-changes question, Preferences) waits until it closes;
Quit counts it as pending.

* Repin craft-dialogs to the craft-libs PR head

* Allow the file dialogs' existence checks in the file guard

* Repin craft-dialogs to storytold/craft-libs main
2026-10-28 17:13:45 -04:00
Hamza 434e269691 cli: the three argument bugs photocraft#7071 lists are live here too
- An option took the next token whatever it was, so `--export --scale` wrote a
  file called `--scale` in the working directory. A token that cannot be a
  value is refused, and where the value is a path the message offers the
  shell's own way out (`./-name`). A negative number can still be a value, and
  `-inf`/`-nan` still reach the check that reports them.
- An argument that is not UTF-8 panicked inside `std::env::args`. It is a
  usage error now, named, since such a path cannot reach the engine anyway.
- `<sub> --help` was read as an unknown option by every parser but `script`'s.
  It answers from the usage block, on stdout, and nothing else happens.

Rebased onto the post-split main, where the fix had to grow one part. Upstream
has since added a check that an export option sits before its `--export`, and
it consumed the following token whatever it was, so `--scale --export out.png`
was reported as the *order* of the options -- advice to move an option that is
already where it belongs -- when what is wrong is that `--scale` has no value.
That check now skips a value only where the next token can be one, and stands
aside entirely when a value is missing so the value error speaks. Its own test,
`run_export_options_come_before_their_export`, still passes.

The CLI's tests moved to tests/it/cli.rs, so the test additions went there.
2026-10-28 18:34:12 +05:00
Dylan M. Taylor 251dabb2b5 Refactor designcraft-cli for strict Clippy checks 2026-10-28 11:39:26 +00:00
NetterSilverandClaude Opus 5.5 1db1635a88 Ask the composition cache once per story and page in PDF export
The PDF exporter called Cache::get twice for every text frame it drew.
Each call rebuilds the cache signature of the whole story, which looks up
every frame of the story with Document::find (a linear walk over all
spreads), and the anchored-frame placements walk them again. For a story
threaded through many frames this is O(frames^2 x items) per export.

The document doesn't change during an export, so the exporter now keeps
the composition it got for each (story, page) and reuses it. The cache
still decides what to compose; the output is byte-identical.

Add examples/pdf_export.rs to designcraft-cli: File > Export PDF through
a headless session on the `designcraft-cli perf` stress document (200
pages, 1M characters in 40 threaded stories, 500 placed images). The
stress document generator moves unchanged from src/perf.rs to a small
library module (src/stress.rs) that the binary and the example share.

Ryzen 16 threads, Linux, 12 runs each, interleaved:
  main     median 3485 ms, min 3427 ms
  patched  median 2016 ms, min 1656 ms  (-42 % median, -52 % min)
The exported PDF is byte-identical (12,075,744 bytes).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 16:47:25 +01:00