Bug fix release.
split() then reported the
whole block as fitting (head = <block>, tail = NULL) and .place_block()
went on to measure the NULL tail ("attempt to apply non-function").
.place_block() now (a) treats a block as fitting when its height exceeds the
remaining space by less than 1e-9 pt, matching the tolerance the split()
methods already use, and (b) stops cleanly when a split returns no tail,
instead of starting a page for it. Affected block_para(), block_pre() and
block_table() alike; nmw worked around it. Regression-tested in
inst/tinytest/test_flow.R..block_seq() (used by block_table()/block_matrix()) now returns
tail = NULL rather than an empty sequence block when a split consumes every
sub-block, which also removes a spurious trailing blank page.Documentation-only release for the CRAN resubmission (no code changes).
\value sections to all exported functions' help pages
(CRAN review): flow_run(), flow_add(), remaining(),
running_header()/running_footer(), block_keep(), block_spacer(),
block_rule(), frame_set(), sp_page(), sp_close(), sp_trace().\value sections to describe the structure (class)
and meaning of every return value, e.g. what a "block" is (a list with
measure/draw/keep/split components consumed by the flow engine)
and that document-handle returns are environments updated in place.First working slice of the device-based report engine (see PLAN-simPDF.md).
sp_new() opens a pdf()/cairo_pdf() device with a
point coordinate system; sp_page(), sp_close(), frame_set().sp_width() / sp_height(). AFM-exact for the core fonts and
linear in size for fractional sizes too (measured at a reference size and
scaled, working around the pdf() device's integer font-size rounding in
strwidth).flow_run() / flow_add() place measured blocks, advancing
the cursor by real height and paginating automatically; block_keep()
(keep-together), block_spacer(), block_rule(), remaining(),
running_header() / running_footer().block_para() (word-wrapped, aligned) and block_pre()
(monospace capture.output() dumps, auto-shrunk to fit the frame width).sp_trace() / sp_overlaps() record and detect overlapping text
bounding boxes. Tests in inst/tinytest/ assert a 200+ line synthetic report
renders with zero overlap across multiple pages.This removes the dead-reckoned-coordinate overlap of the nmw diagnostic
reports (see inst/examples/nmw_params.R).
block_table(): renders a data.frame/matrix with column widths measured
from the content, numeric columns right-aligned, a header that repeats on
every page, a rule under the header, and automatic row-boundary page
splitting. If the natural width exceeds the frame, the font shrinks uniformly
to fit. Row names become a leading label column.block_matrix(): renders a wide matrix by splitting its data columns into
groups that each fit the page width (row labels repeated in every group),
stacked vertically -- replacing hand-placed column loops such as
PrinTxt(row, i * 8, ...) that overflow for many columns.inst/tinytest/test_table.R covers a 200-row split table (header
repeated once per page) and a 20-column matrix split into groups, both with
zero overlap.block_table/block_matrix shrink-to-fit now scales the cell padding by
the same factor as the font and column widths. Previously only font and widths
were scaled, so at strong shrink (tot > 2 * frameW) the last column's text
spilled past the frame's right edge (and a right-aligned first column past the
left). Regression-tested..tabularize preserves the column count when there are no rows,
and .natural_widths guards the empty-column max() so header = FALSE
0-row input no longer warns. Regression-tested.block_plot(expr, height): evaluates a base-R plotting expression (scatter,
histogram, QQ, ...) inside a reserved band of the flowing page via par(fig),
then restores the text canvas. Plots sit inline with measured text, are kept
with their headings via block_keep, and participate in pagination. The
expression is captured unevaluated and run at draw time in the caller's
environment.block_image(img, height): embeds a raster, array/matrix, or PNG/JPEG file
(png/jpeg in Suggests) via rasterImage.par(op) alone (no extra plot.new()), so a page break after a
block_plot advances the physical PDF page in lock-step with doc$page_no.
Regression-tested by comparing doc$page_no to the physical /Type /Page
count. See inst/examples/nmw_diagnostics.R.For downstream packages that build reports on simPDF:
block_authorship() and block_signature(): a "Prepared by" metadata
block and visible approval/signature lines (role caption + dated line). The
signing rectangles are recorded on doc$sig.sp_add_sig_fields(): a finishing pass that inserts interactive Adobe
Acrobat digital-signature fields (AcroForm /Sig) into the written PDF via a
pure base-R incremental update (no external tools) -- generalised from
NonCompart::addSigFieldNCA, and driven by the doc$sig rectangles so the
clickable fields land exactly on the visible lines. The result is
one-click-signable in the free Acrobat Reader and passes qpdf --check.block_flow_diagram(): a model-development flow diagram where each node is
a box measured to its text, laid out as a tidy tree (children centred under
parents) and scaled uniformly to fit the frame -- so more models shrink the
diagram instead of cluttering it (unlike the dead-reckoned legacy Outline).All 8 nmw diagnostic reports now have simPDF implementations (S2-Parameters
plus the remaining seven: S1-OFV, S3-Predictions, S4-Residuals, S5-EBE,
SA-Input, SB-Output, SC-IndiPK). Each keeps the parsing/statistics verbatim and
replaces the dead-reckoned pdf()+PrinTxt/split.screen layout with a
blocks list + flow_run() (text/tables) and sp_figure_page() (per-subject /
per-eta plot pages). Validated on the bundled 2006 example (all 8 generate)
and across real runs (97/98 report generations on 14 models); the
S3-Predictions "zero-length labels" crash on subjects with no observations is
fixed (was 11/18, now 14/14). These functions live with the nmw package
(which gains simPDF in Imports); simPDF gained sp_figure_page() to host the
full-page multi-panel diagnostic pages.
report_* functions in nmw (replace bodies, drop the old
PrepPDF/PrinTxt/AddPage/PrinMTxt/ClosePDF from pdf_report.R).