Drag the visible image in the print preview using paper-scaled egui points.
Switch Center to manual without moving the grab point, allow signed Top/Left
offsets, and retain the shared preview/PDF layout and mirrored behavior.
Add regression coverage for negative PDF placement, native HiDPI dragging,
centering, clipping, scaling, fit, mirroring and invalid geometry.
Validation: 25 engine print tests, 19 file-dialog unit tests, four print-dialog
integration tests and the adversarial-command test pass. Formatting,
all-target clippy, desktop check/build and layer checks pass.
Three existing socket-binding tests are sandbox-blocked and excluded from
the successful print-suite rerun. GUI capture and wasm checks remain limited
by the environment.
On Windows the Print dialog takes the paper and its orientation from the
printer driver, and had no way to change the orientation short of the
driver's own Print Settings… dialog. Photoshop has Layout buttons for it.
A print laid out landscape on portrait driver settings (from a script,
the CLI or another app) stopped with "the driver paper or orientation
differs from the print layout".
- The dialog has an Orientation row (Portrait, Landscape) under Print
Settings…. It turns the driver settings through file.print.page and
takes the paper from the driver again, so the paper and preview turn.
- file.print.page takes "orientation": "portrait|landscape" and returns
the turned settings as printerSettings, with the page they give.
- print_windows turns the settings (the given ones or the printer's
defaults) to the layout's orientation when the driver has the layout's
paper the other way round; another paper is still refused.
Turning sets dmOrientation and its dmFields bit in the DEVMODE and keeps
every other byte, the driver's private settings included; the driver
validates the result as it does settings from Print Settings…. No new
UI strings: "Orientation", "Portrait" and "Landscape" are in every
catalog.
Tests: the turned settings (orientation set, all else kept, with and
without private driver bytes), when a paper counts as turned, an unknown
orientation refused before any printer is asked, the dialog's reading of
the driver paper and its error path, and, run by hand on Windows, a
real "Microsoft Print to PDF" driver turning for a landscape layout.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main prints through craft-print, which runs `lp`; a Flatpak has no `lp`,
so File › Print fails there. This keeps craft-print as the route wherever
`lp` is on the path (and on Windows) and adds two more behind it:
- `photocraft-ipp`, a pure-Rust IPP client (CUPS-Get-Printers/Classes/
Default, Print-Job over HTTP/1.1) that talks to CUPS over its socket or
TCP; the Flatpak manifests grant --socket=cups for it. A `printServer`
named in the request always takes this route. `file.print.printers`
lists the queues.
- The XDG Print portal as the app's spooler (`Session::print_spooler`),
for a sandbox without the CUPS socket or a system without a printer:
the system print dialog, seeded with copies, paper and orientation.
PHOTOCRAFT_PRINT_PORTAL=1 prefers it, =0 removes it.
A route that exists but fails (unknown printer, refused job) is an error;
only a missing route moves on. Results gain `backend` (lp, windows, ipp,
portal). docs/printing.md describes the routes.