Skip to content

Lay lists out with ^FB field blocks - #57

Merged
PeteRichardson merged 1 commit into
mainfrom
Fix-I54-fb-field-block-layout
Aug 31, 2026
Merged

Lay lists out with ^FB field blocks#57
PeteRichardson merged 1 commit into
mainfrom
Fix-I54-fb-field-block-layout

Conversation

@PeteRichardson

Copy link
Copy Markdown
Owner

Fixes #54

A run of consecutive list items is now emitted as one ^FB field block — a single ^FO origin, items joined with \&, and the printer performing the line advance — instead of one host-computed ^FO/^FD pair per item.

Measured on a 19-line list (labelprint zpl, before vs after):

commands bytes computed ^FO
before 83 557 18
after 38 395 6

The remaining origins are the 3 headers and the 3 blocks between them.

^FB also fixes silent truncation

Text wider than ^PW was clipped at the right edge with no error. Inside a block the same text wraps. Verified against Labelary — a 74-character item now prints on two lines instead of losing its tail.

ZPLLengthEstimator learns ^FB first

This was the prerequisite: InjectLength would otherwise compute a wrong ^LL for any block label. The estimator now models the block width, its line-spacing parameter, its max-lines cap, and — the part that can't be had from counting \& separators — the wrapping the printer does inside the block.

It has no font metrics, so it charges each character a fixed fraction of the declared cell width. Font 0 is proportional and measures near 0.44 of its cell against Labelary; 0.6 is used for headroom, so ^LL runs a little long rather than short. Running long wastes a little media; running short clips the print.

Decisions worth review

Two things went differently from the issue's description, both verified against Labelary rather than assumed:

  1. zpl2png is worse than "renders \& as glyphs" — it renders a block's first line and silently drops the rest. Per the decision on the issue, labelprint preview and example-reminderlist preview now use LabelaryRenderer, which matches the ZD620. Those previews therefore need network access; printing is unaffected, and compare-renderers still shows the divergence.

  2. A literal \& in item text cannot be escaped. The printer applies ^FH substitution before scanning for line breaks, so _5C& becomes \& and breaks the line just the same (verified — I tried it). Such an item prints as two lines: layout is lost, content is not. Documented on escaped(_:) rather than papered over.

Tests

133 pass. New coverage: 6 estimator tests (block spacing, wrapping, word-boundary breaks, max-lines cap, per-field scope, zero font width) and 3 ListLayout tests (block grouping, header ending a run, ^LL covering wrapped lines). Existing tests that asserted the per-item ^FO form were updated to the block form — the same geometry facts, restated.

Consecutive list items were each emitted as their own ^FO/^FD pair with a
Y coordinate computed on the host. A run of items is now one ^FB field
block: a single origin, items joined with \&, and the printer performing
the line advance. For a 19-line list that is 83 -> 38 commands, 557 ->
395 bytes, and 18 -> 6 computed origins.

It also fixes silent truncation. Text wider than ^PW was clipped at the
right edge with no error; inside a block the same text wraps.

Teach ZPLLengthEstimator about ^FB first, since InjectLength would
otherwise compute a wrong ^LL for any block label. The estimator now
models the block width, its line-spacing parameter, its max-lines cap,
and the wrapping the printer will do inside it -- wrapping being the part
that cannot be had from counting \& separators.

Wrap estimation has no font metrics to work from, so it charges each
character a fixed fraction of the declared cell width. Font 0 is
proportional and measures near 0.44 of its cell against Labelary; 0.6 is
used for headroom, which leaves ^LL a little long rather than short,
because running long wastes media and running short clips the print.

The bundled zpl2png helper does not implement ^FB -- it renders a block's
first line and silently drops the rest -- so the list examples preview
via LabelaryRenderer, which matches the ZD620. This makes those previews
require network access; printing is unaffected.

A literal \& in item text is deliberately left unescaped because it
cannot be escaped: the printer applies ^FH substitution before scanning
for line breaks, so _5C& becomes \& and breaks the line just the same.
Such an item prints as two lines, losing layout but not content.

Fixes #54

@PeteRichardson PeteRichardson left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@PeteRichardson
PeteRichardson merged commit e7ac935 into main Aug 31, 2026
1 check passed
@PeteRichardson
PeteRichardson deleted the Fix-I54-fb-field-block-layout branch August 31, 2026 19:28
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.

Use ^FB field blocks for list layout instead of host-computed per-line coordinates

1 participant