85 Commits

Author SHA1 Message Date
Marcos Paulo 9c470aa935 feat(ui): material (solid/acrylic surfaces) and controls (checkbox, toggle, select)
Moved from PaperCraft so other Craft apps can share them. Controls take a
ControlStyle built from the app's tokens and paint through material.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 00:14:37 -03:00
Marcos Paulo 7fcee66b8e feat(ui): Catppuccin palettes (Latte, Frappé, Macchiato, Mocha)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 20:53:00 -03:00
Marcos Paulo 3e6869e88c chore: debrand ArtCraft references
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 20:52:59 -03:00
skylar taylor-barrick f03ec27ab2 Merge pull request #28 from jcl-bit/claude/print-native-windows-73c826
Print spooler / print (macos-latest) (push) Has been cancelled
Print spooler / print (ubuntu-latest) (push) Has been cancelled
Print spooler / print (windows-latest) (push) Has been cancelled
Shared UI / UI (macos-latest) (push) Has been cancelled
Shared UI / UI (ubuntu-latest) (push) Has been cancelled
Shared UI / UI (windows-latest) (push) Has been cancelled
Shared UI / UI WASM (push) Has been cancelled
craft-print: print on Windows in-process, without PowerShell
2026-10-12 17:19:38 -06:00
skylartaylor eb49a247a3 Gate Unix-only atomic test imports by platform 2026-10-13 00:29:22 +02:00
skylar taylor-barrick 79e89dc129 Merge remote-tracking branch 'origin/main' into codex/craft-print-fix-merge-20261012T210558Z
# Conflicts:
#	Cargo.lock
2026-10-12 23:49:49 +02:00
Alejandro Londono 6006abb757 feat(settings): add shared config storage for Craft apps
Add shared config.toml storage while keeping settings types, defaults and UI policy in each app.

Includes isolated in-memory operation, configurable portable paths, atomic saves with private backups, damaged-file preservation, schema migrations, and documented best-effort handling of external edits.

Validation: native macOS formatting, strict workspace clippy, 172 workspace tests and the craft-settings WASM check. Independent backup-permission and failed external-migration repros fail before the fixes and pass afterward.

Hosted CI: all seven UI and printing jobs pass across macOS, Linux, Windows and UI WASM.

Refs #12
2026-10-12 15:40:50 -06:00
skylar taylor-barrick 697b473c0b Stop PDF work immediately after a parser budget is exhausted 2026-10-12 23:27:53 +02:00
skylar taylor-barrick c22935270b Parse duplicate PDF dictionary keys in linear time 2026-10-12 23:22:05 +02:00
skylar taylor-barrick 85ef8b92ac Bound PDF parsing and preserve indirect page content arrays 2026-10-12 23:14:06 +02:00
skylar taylor-barrick 02d08fe9cc fix(print): pin native completion repair and document bounded PDF handling 2026-10-12 23:12:41 +02:00
skylar taylor-barrick a7e3c76c2f Merge remote-tracking branch 'origin/main' into codex/craft-print-fix-merge-20261012T210558Z 2026-10-12 23:05:59 +02:00
James Locke 36ce57c929 Merge remote-tracking branch 'origin/main' into claude/print-native-windows-73c826
# Conflicts:
#	Cargo.lock
2026-10-12 11:33:06 -07:00
skylar taylor-barrick f58bc1a3df Merge pull request #16 from zachshallbetter/feat/craft-atomic
Add craft-atomic: crash-safe atomic write and document replacement
2026-10-12 12:25:33 -06:00
skylar taylor-barrick 811558a3ad Create Unix atomic-write staging files with private permissions 2026-10-12 20:23:17 +02:00
Zach Shallbetter 5b273dd82f Clarify application recovery sweep responsibility and hardware durability limits 2026-10-12 20:23:17 +02:00
Zach Shallbetter d4a38f90ee Clarify user-space cleanup semantics and best-effort directory sync in craft-atomic 2026-10-12 20:23:17 +02:00
Zach Shallbetter 1c9baae1bf Lock tempfile and fastrand dependencies for workspace 2026-10-12 20:23:17 +02:00
Zach Shallbetter f75e9c9bc8 Document atomicity vs durability guarantees and add sequence verification test 2026-10-12 20:23:17 +02:00
aiongg 6bcd350d49 README: credit PhotoCraft only, document what a replace does not keep
The crate holds PhotoCraft's engine, and unsafe code is forbidden by the
workspace lint rather than in lib.rs.
2026-10-12 20:23:17 +02:00
aiongg 33b393bd88 Remove the unused proptest dev-dependency 2026-10-12 20:23:17 +02:00
aiongg 9d422a18b1 Retry Windows sharing and lock violations, with a capped backoff
retry_rename also retries ERROR_SHARING_VIOLATION (32) and
ERROR_LOCK_VIOLATION (33), which a rename can report while a scanner
holds the file, and caps each pause at 200 ms.
2026-10-12 20:23:17 +02:00
aiongg 253fd775f0 Set the replaced file's permissions on the open temporary file
The original's permissions are applied to the temporary file before it
is flushed, and a failure fails the save instead of being ignored.
2026-10-12 20:23:17 +02:00
aiongg d78b352004 Refuse to replace a file the user cannot write (Unix)
A rename needs only a writable folder, so a read-only file would be
replaced where writing it in place would fail. Before staging, the
existing file is opened for writing without truncating; when that fails
the save fails with a read-only error.
2026-10-12 20:23:17 +02:00
aiongg 658ca37c8e Follow symbolic links without canonicalize
The target is found by reading links one hop at a time, resolving
relative links against the link's folder. A dangling link writes the
file it names and stays a link, and a loop of links is an error.
2026-10-12 20:23:17 +02:00
aiongg fb26a9f90f Report a missing folder instead of creating it
A save into a folder that does not exist fails with an error naming the
folder, so a save to an unmounted network share does not create a local
folder in its place.
2026-10-12 20:23:17 +02:00
aiongg 9e160690fc Never replace an existing file in write_new
write_new_with gives the staged file its name with a hard link on every
platform. Where hard links fail for any reason other than an existing
target (FAT/exFAT, some SMB and FUSE volumes), it copies the staged
content into a file opened with create_new. It shares the temporary-file
retry, error context and folder flush with the replace path, and its
errors only mention an original file when there is one.
2026-10-12 20:23:17 +02:00
aiongg 818c0c0753 Share one replace path between the byte and streaming writers
atomic_write, atomic_write_with and atomic_write_custom all run through
one internal function that takes the AtomicFs, the RenameRetry and a
writer callback, so fault injection also covers streaming writes.
AtomicFs creates and flushes the temporary file (create_new, sync)
instead of writing a byte slice.
2026-10-12 20:23:17 +02:00
Zach Shallbetter 8df3d87d8b Add craft-atomic: crash-safe atomic write and document replacement (refs #2, fixes #14) 2026-10-12 20:23:17 +02:00
skylar taylor-barrick 4a4ec8c1ca Merge pull request #21 from jmacek/quit-app-menu
craft-quit: macOS app menu whose Quit asks the app first
2026-10-12 12:22:49 -06:00
skylar taylor-barrick c68d145c9f docs: list craft-quit in the library catalog 2026-10-12 20:21:37 +02:00
skylar taylor-barrick 8e9e437e78 craft-quit: route menu Quit to the root viewport 2026-10-12 20:18:18 +02:00
Jake Macek f0ae2b3f13 craft-quit: return the app menu install error to the app
install_app_menu printed the error and carried on, so an app could not
tell that ⌘Q had fallen back to winit's Quit, which skips the prompt.
It now returns the error; the app decides whether it is fatal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 20:18:18 +02:00
Jake Macek 673c14439b craft-quit: Quit menu id and handler for apps with their own menu
Apps that build their own muda app menu can't use install_app_menu: it
replaces the whole menu and sets muda's process-wide event handler.
QUIT_MENU_ID and on_menu_event(ctx, id) let them give their own Quit
item the id and route its event through the app's close handling.
Neither needs muda, so any muda version works. install_app_menu now
uses both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 20:18:18 +02:00
Jake Macek ebf3f552cd craft-quit: macOS app menu whose Quit asks the app first
winit's default app menu sends Quit (Cmd+Q) straight to
-[NSApplication terminate:] and winit doesn't implement
applicationShouldTerminate:, so a Craft app quits without its
unsaved-changes prompt. The new opt-in `menu` feature adds
`install_app_menu(ctx, app_name)`, which replaces that menu with a
muda-built copy whose Quit sends ViewportCommand::Close. The app's own
close handling then runs, as for the close button, and
on_close_request quits.

muda is a macOS-only, optional dependency; no unsafe code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 20:18:18 +02:00
skylar taylor-barrick f207cdd016 Merge pull request #5 from mjohnson7cd/macos-quit-terminate
Add craft-quit: quit macOS apps through NSApplication terminate:
2026-10-12 12:17:38 -06:00
skylar taylor-barrick bafeec6b7d Merge remote-tracking branch 'origin/main' into fix-quit5-20261012 2026-10-12 20:15:22 +02:00
skylar taylor-barrick c6a847b7d0 craft-quit: document logic-based close handling for hidden windows 2026-10-12 20:11:55 +02:00
skylar taylor-barrick 3c9702725d Merge pull request #26 from storytold/codex/craft-print-settings
Share printer settings and asynchronous print feedback
2026-10-12 08:25:02 -06:00
James Locke 754f4d70e0 Print on Windows in-process, without PowerShell
craft-print's Windows backend ran an embedded PowerShell script for the printer list and every
job. Under App Control for Business or AppLocker script enforcement that script runs in
Constrained Language Mode and every job fails (storytold/pdfcraft#1107). The backend now runs
in this process and starts no program:

- Printers come from EnumPrinters and the default from GetDefaultPrinter; Printer::two_sided
  from each driver's PrintCapabilities. The list is sorted, each name once.
- A job is drawn as vectors by the in-box Windows.Data.Pdf with Direct2D into the XPS print
  API (winprint). Copies, collation, duplex (left out for duplex: None), colour, orientation
  and the driver's own paper option go in a PrintTicket the driver validates; a ticket the
  driver changed (paper, orientation, scaling) is refused before anything is sent. The driver
  paper named like the standard size is preferred (pdfcraft#599).
- A job has one ticket, so one paper shape. A small lenient reader (sheets.rs) reads the
  print-ready PDF's sheets and, when needed, appends an incremental update: /Rotate for sheets
  of the other orientation, and for Scaling::ShrinkToFit a reframe onto the driver's matching
  or default paper (shrunk inside its widest hardware margin, never enlarged, centred).
  Exact size refuses mixed paper sizes and paper the driver lacks.
- command_preview describes the in-process job on Windows ("xps-print", key=value options).
- windows_print.ps1 and the PowerShell helpers are gone. open_printer_preferences (rundll32)
  and the CUPS path are unchanged, as is the public API.

The end-to-end test puts a paused Generic / Text Only printer on LPT1: (no port to remove
afterwards; a paused FILE: queue never takes the job) and checks a mixed-orientation exact job
and a shrink-to-fit job each land as one job with all sheets. The reader is tested on every
platform with classic and compressed cross-references and thousands of truncated and corrupted
files. Windows-only dependencies: winprint =0.2.1 (default features off), winsafe 0.0.29,
roxmltree 0.20, miniz_oxide 0.8.

Ported from PdfCraft's native printing branch (pdfcraft#1132), which carries #599's approach.

Co-authored-by: durtyrobbin <76844303+durtyrobbin@users.noreply.github.com>
Co-authored-by: Dimitar Klaturov <7221384+bulgariamitko@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 18:03:54 -07:00
skylar taylor-barrick 5d41e29e46 Install software Vulkan for shared UI rendering tests 2026-10-12 02:41:42 +02:00
skylar taylor-barrick 4cae45dbe8 Handle texture deltas in print control tests 2026-10-12 02:37:47 +02:00
skylar taylor-barrick d27646a5f7 Preserve accessible print control labels and narrow layout 2026-10-12 02:34:53 +02:00
skylar taylor-barrick b700ae753f Add shared printer settings and asynchronous job feedback 2026-10-12 02:32:49 +02:00
skylar taylor-barrick 1aa81a773a Expose Windows printer duplex capability (#25)
Expose Windows printer duplex capability
2026-10-11 17:20:15 -06:00
skylar taylor-barrick d991bf6792 Report Windows driver duplex capability to print callers 2026-10-12 01:04:26 +02:00
Mara Johnson 9d6610afd1 craft-quit: document calling on_close_request last in the frame
eframe calls logic before ui, so on_close_request goes after all of the
app's own close handling, at the end of ui when the app handles closes
there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 18:47:11 -04:00
Mara Johnson 0549f672a3 Add craft-quit: quit macOS apps through NSApplication terminate:
Closing an eframe window on macOS can crash in AppKit's Touch Bar finder
after eframe drops the window while the run loop is still running (#3).
craft-quit routes a window close through -[NSApplication terminate:],
the path Cmd+Q already takes, so the process ends before another display
cycle runs.

- quit(): schedules terminate: on the main queue on macOS, no-op elsewhere
- on_close_request() (feature "egui"): cancels the root window's close
  and quits through the platform path instead

Also commits Cargo.lock and ignores .idea/.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 18:47:11 -04:00
skylar taylor-barrick d26682a58a Launch the print spooler through system PowerShell (#23)
Launch the print spooler through system PowerShell
2026-10-11 14:10:44 -06:00
skylar taylor-barrick 32bcac12db Launch Windows PowerShell from its system path 2026-10-11 22:09:14 +02:00