Skip to content

Commit 63ffa4b

Browse files
billdenneyclaude
andauthored
Phase 3: page setup and printing (#121)
* Add xl_page_setup() with the scalar print options xl_sheet(page =) takes an xl_page_setup() describing how the sheet prints: orientation, paper size, margins, scaling, fit-to-pages, centring, starting page number, page-layout view, and the print options (across, black and white, row and column headings). None of it touches the cells. paper accepts friendly names mapped to Excel's numeric types, and a raw index for the envelope and specialist sizes not worth naming; the range is capped at libxlsxwriter's real 0-118, since outside it worksheet_set_paper() warns and ignores the value, which from R would be a silent no-op. worksheet_set_start_page() is the one setter in libxlsxwriter that does not raise page_setup_changed, so a first_page on its own emitted no <pageSetup> element and was silently dropped. worksheet_set_paper() does raise it, and paper size 0 writes no attribute, so it is called alongside first_page as a harmless way to mark the sheet as having a page setup. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Add page headers and footers xl_page_setup() gains header, footer, header_margin and footer_margin, reaching worksheet_set_header/_opt and worksheet_set_footer/_opt. Excel's own &-codes are passed through untouched; the plain setter is used when no margin is given and the _opt form only when one is. Two libxlsxwriter behaviours are surfaced in R rather than left to fail obscurely. A margin is applied only when greater than zero, so a zero would be silently ignored and is now an error naming Excel's 0.3 default. An &G or &[Picture] placeholder needs a matching image, which writexl cannot supply until images land, so it is rejected with a message that says so instead of libxlsxwriter's opaque parameter-validation error. The 255-character cap is enforced in R, counting characters rather than bytes as lxw_utf8_strlen() does. Header and footer images are deliberately deferred: lxw_header_footer_options carries image_left/center/right, and those belong with the rest of the image handling rather than being built twice. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Add print area, repeat rows/columns, and page breaks xl_page_setup() gains print_area, repeat_rows, repeat_cols, h_breaks and v_breaks, completing the page-setup surface. print_area goes through the Phase 0 range resolver, so it takes an A1 string or a list(rows =, cols =) spec like every other range argument. repeat_rows and repeat_cols take either a count or a range string, and count *sheet* rows with the header included rather than data rows -- repeating the header row is the usual reason to reach for them, and data-row numbering could not name it. Page breaks are given as 1-based positions where a new page starts, matching how Excel describes them, and converted to libxlsxwriter's 0-based form. A break at position 1 is refused: libxlsxwriter terminates its break array with a 0, so a 0-based break of 0 would silently discard every break rather than merely doing nothing. Breaks are sorted and deduplicated, and capped at Excel's limit of 1023. Setting breaks together with fit_to warns, since Excel ignores manual breaks when fit-to-page is on. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Document page setup in the vignette and NEWS Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent d9af39d commit 63ffa4b

22 files changed

Lines changed: 1062 additions & 4 deletions

NAMESPACE

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ S3method(length,xl_cell_general)
99
S3method(print,xl_cell_general)
1010
S3method(print,xl_comment)
1111
S3method(print,xl_format)
12+
S3method(print,xl_page_setup)
1213
S3method(print,xl_properties)
1314
S3method(print,xl_rich_run)
1415
S3method(print,xl_rich_string)
@@ -33,6 +34,7 @@ export(xl_formula)
3334
export(xl_hyperlink)
3435
export(xl_hyperlink_cell)
3536
export(xl_num_format)
37+
export(xl_page_setup)
3638
export(xl_properties)
3739
export(xl_protection)
3840
export(xl_rich_run)

NEWS.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@
2424
* **Rich strings** — one cell whose text is split into differently formatted
2525
runs — via `xl_rich_string()` and `xl_rich_run()`.
2626

27+
* **Page setup and printing** via `xl_sheet(page = xl_page_setup(...))`:
28+
orientation, paper size, margins, scaling and fit-to-pages, centring, headers
29+
and footers, print area, repeating heading rows/columns, manual page breaks,
30+
and the print options.
31+
2732
* `xl_properties(hyperlink_format = NULL)` writes hyperlinks with no styling at
2833
all, which was previously impossible.
2934

R/xl_page_setup.R

Lines changed: 341 additions & 0 deletions
Large diffs are not rendered by default.

R/xl_sheet.R

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@ xl_row_spec <- function(rows, height = NA, hidden = NA, level = NA,
141141
#' per-comment `author` overrides it).
142142
#' @param show_comments If `TRUE`, all comments on the sheet are initially
143143
#' shown (individual comments can still be forced via `xl_comment(visible=)`).
144+
#' @param page An [xl_page_setup()] describing how the sheet prints
145+
#' (orientation, paper size, margins, scaling, header and footer). Affects
146+
#' printing only, never the cell data.
144147
#' @return An `xl_sheet` object.
145148
#' @family writexl
146149
#' @seealso [xl_col_spec], [xl_row_spec], [write_xlsx]
@@ -158,7 +161,8 @@ xl_sheet <- function(data, cols = NULL, rows = NULL, freeze = NULL,
158161
gridlines = NA, tab_color = NA, zoom = NA,
159162
default_row_height = NA, auto_colwidth = FALSE,
160163
autofilter = FALSE, protect = FALSE,
161-
comment_author = NA, show_comments = FALSE) {
164+
comment_author = NA, show_comments = FALSE,
165+
page = NULL) {
162166
if (!is.data.frame(data))
163167
stop("`data` must be a data frame", call. = FALSE)
164168
if (!is.logical(auto_colwidth) || length(auto_colwidth) != 1L || is.na(auto_colwidth))
@@ -184,7 +188,8 @@ xl_sheet <- function(data, cols = NULL, rows = NULL, freeze = NULL,
184188
autofilter = autofilter,
185189
protect = protect,
186190
comment_author = comment_author,
187-
show_comments = show_comments
191+
show_comments = show_comments,
192+
page = page
188193
),
189194
class = "xl_sheet"
190195
)
@@ -368,6 +373,7 @@ print.xl_sheet <- function(x, ...) {
368373
# author overrides the sheet default
369374
comment_author <- NA_character_
370375
show_comments <- FALSE
376+
page_payload <- NULL
371377

372378
if (inherits(el, "xl_sheet")) {
373379
# column specs
@@ -410,6 +416,7 @@ print.xl_sheet <- function(x, ...) {
410416
}
411417
overlay <- c(overlay, .as_overlay_list(el$overlay))
412418
protect <- .resolve_protect(el$protect)
419+
page_payload <- .page_setup_payload(el$page, df, header_offset)
413420
comment_author <- el$comment_author
414421
show_comments <- isTRUE(el$show_comments)
415422
# auto column widths (for columns the user did not size explicitly)
@@ -435,6 +442,7 @@ print.xl_sheet <- function(x, ...) {
435442
overlay = overlay, protect = protect$flag,
436443
protect_password = protect$password, protect_options = protect$options,
437444
comment_author = as.character(comment_author),
438-
show_comments = as.integer(show_comments)
445+
show_comments = as.integer(show_comments),
446+
page = page_payload
439447
)
440448
}

man/is_xl_comment.Rd

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/is_xl_format.Rd

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/xl_cell_general.Rd

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/xl_color.Rd

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/xl_colrow_spec.Rd

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/xl_comment.Rd

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)