Skip to content

feat: label sheet layouts for office printers (multi-up PDF export) - #10

Merged
glenntosco merged 9 commits into
mainfrom
claude/project-thread-5e0lug-sheet-layouts
Oct 24, 2026
Merged

glenntosco merged 9 commits into
mainfrom
claude/project-thread-5e0lug-sheet-layouts

Conversation

@glenntosco

Copy link
Copy Markdown
Collaborator

Requested by Glenn · project thread

What changed and why

Assessment item 17 (on the roadmap). Last in the stack, on the ^PO preview PR. Merge in order.

Print labels on laser or inkjet label sheets. File > Export > Label sheets (PDF), or Label sheets in the Print dialog, opens a dialog to pick a generic sheet template or type a custom layout, see where each label goes, start at any position on a partly used sheet, add crop marks or outlines, and save a multi-page PDF at the sheet's real size with every label at its physical size. Data merge records, copies and serial numbers behave exactly as when printing. The layout is saved with the label.

  • Core (Rotula.Core.Sheets): SheetLayout (paper Letter/A4/Legal/custom, margins, label size, grid, pitch, in mm) with Issue.Sheet.* validation keys; SheetTemplates (16 generic Letter/A4 layouts named only by dimensions; a sheet stock from the stock library opens on its matching template without showing a brand); SheetImposition (lazy fill, row or column order, start position).
  • Same iteration as printing: MergeBatch.Labels now carries resolved Values and Copies; LabelPrintRun.LabelValues() gives one set per copy so each copy gets its own serial; LabelDocumentAdapter.ToRenderLabelResolved draws those values without re-running counters.
  • Rendering: SheetExporter.SavePdf, one page per sheet, labels centred and clipped to their position, text and barcodes stay vector, temp file then move, an empty run writes nothing.
  • Files: optional root sheet section; older builds ignore it, so no format version bump. Start position is deliberately not saved.
  • App: SheetLayoutViewModel / SheetLayoutWindow (light theme), click a position to set the start, mm/in units. Serial numbers are reserved before the PDF is written and confirmed only when the file is complete.
  • 66 strings in en, es, pt-BR and fr-CA; CHANGELOG, README (en/es; item removed from the roadmap), docs/printing.md, decisions, stock-catalog.

How it was tested

  • SheetLayoutTests: positions in mm and points (Letter 30-up, A4 24-up, 21-up), column order, centred grid, every template valid, stock matching, every validation key, start position, page breaks, merge records carrying serials and copies across sheets, LabelValues confirm/cancel, PDF page count and size (Letter exactly 612 × 792 pt), placement and physical size, empty run, temp file, serializer round trip.
  • AppSheetLayoutTests: template suggestion, custom edits, validation blocking export, units, start position, single-label and merge exports with serials used once, nothing ticked, layout saved and reopened, Print dialog button, translated texts.
  • Solution builds with 0 warnings; Core/Rendering/Files tests also ran in a Linux scratch harness, and one PDF was rasterised and checked visually. App tests run on Windows CI.

Checklist

  • Build passes; tests run on Windows CI
  • New behavior has tests
  • New text in all four resx files
  • No network calls or telemetry; light theme only
  • No new dependencies
  • CHANGELOG.md updated
  • Hygiene check passes

Notes

  • PDF only: no direct printing to a Windows printer, because driver margins and fit-to-page scaling would move the labels. Users print the PDF at 100 %; documented.
  • Template margins are standard published layouts, not checked against suppliers, so the UI and docs say to print a test page on plain paper first.
  • A design that doesn't match the sheet's label size only gets a warning; it is printed at its own size, centred and clipped.
  • At most 100,000 labels per PDF.

Generated by Claude Code

A UI-free model of label sheets for office printers (paper, margins, label
size, grid, pitch), validation with message keys, a small set of generic
Letter and A4 templates described by their dimensions, and the imposition
that fills sheets in order with a start position.
MergeBatch labels and LabelPrintRun now expose the resolved values of
every label (same record iteration and serial numbers as the ZPL), and the
renderer can draw a label from those values without resolving counters
again. SheetExporter places the labels on sheets at their physical size
and writes one PDF page per sheet, with optional crop marks or outlines.
An optional root "sheet" object; older builds ignore it, so it does not
raise the format version. A section that makes no sense is dropped.
File > Export > Label sheets (PDF) and a button in the Print dialog open a
dialog to pick a generic sheet template or type a custom layout, see the
positions, start at a later position on a partly used sheet and save the
labels (or the ticked records) as a PDF at the sheet's real size. Serial
numbers are reserved and confirmed as for printing; the chosen layout is
saved with the label. English and Spanish texts.
pt-BR and fr-CA for the 66 keys of the Label sheets dialog, its enums
and its layout checks.
The main window applies the saved language when it opens, which put the test
back in English before the sheet dialog built its template names.
@glenntosco
glenntosco force-pushed the claude/project-thread-5e0lug-sheet-layouts branch from a31abde to d2a5ed4 Compare October 24, 2026 14:15
@glenntosco
glenntosco force-pushed the claude/project-thread-5e0lug-print-orientation branch from c90ef3a to 759552b Compare October 24, 2026 14:15
@glenntosco
glenntosco changed the base branch from claude/project-thread-5e0lug-print-orientation to main October 24, 2026 14:43
@glenntosco
glenntosco merged commit 7353c9a into main Oct 24, 2026
6 checks passed
glenntosco added a commit that referenced this pull request Oct 27, 2026
feat: label sheet layouts for office printers (multi-up PDF export)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants