Skip to content

Commit

Permalink
feat: hide slides
Browse files Browse the repository at this point in the history
* Add `slide_visible()`: gets and sets the visibility of slides (#622).
  • Loading branch information
markheckmann authored Jan 2, 2025
1 parent c79f2c0 commit 1660aec
Show file tree
Hide file tree
Showing 13 changed files with 410 additions and 3 deletions.
1 change: 1 addition & 0 deletions .github/workflows/R-CMD-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
pull_request:
branches:
- master
workflow_dispatch:

name: R-CMD-check

Expand Down
48 changes: 47 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Type: Package
Package: officer
Title: Manipulation of Microsoft Word and PowerPoint Documents
Version: 0.6.8.003
Version: 0.6.8.004
Authors@R: c(
person("David", "Gohel", , "[email protected]", role = c("aut", "cre")),
person("Stefan", "Moog", , "[email protected]", role = "aut"),
Expand Down Expand Up @@ -65,3 +65,49 @@ Suggests:
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.2
Collate:
'core_properties.R'
'custom_properties.R'
'defunct.R'
'dev-utils.R'
'docx_add.R'
'docx_comments.R'
'docx_cursor.R'
'docx_part.R'
'docx_replace.R'
'docx_section.R'
'docx_settings.R'
'empty_content.R'
'formatting_properties.R'
'fortify_docx.R'
'fortify_pptx.R'
'knitr_utils.R'
'officer.R'
'ooxml.R'
'ooxml_block_objects.R'
'ooxml_run_objects.R'
'openxml_content_type.R'
'openxml_document.R'
'pack_folder.R'
'ph_location.R'
'post-proc.R'
'ppt_class_dir_collection.R'
'ppt_classes.R'
'ppt_notes.R'
'ppt_ph_dedupe_layout.R'
'ppt_ph_manipulate.R'
'ppt_ph_rename_layout.R'
'ppt_ph_with_methods.R'
'pptx_informations.R'
'pptx_layout_helper.R'
'pptx_matrix.R'
'utils.R'
'pptx_slide_manip.R'
'read_docx.R'
'read_docx_styles.R'
'read_pptx.R'
'read_xlsx.R'
'relationship.R'
'rtf.R'
'shape_properties.R'
'shorcuts.R'
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ S3method(update,fpar)
S3method(update,sp_line)
S3method(update,sp_lineend)
export("layout_rename_ph_labels<-")
export("slide_visible<-")
export(add_sheet)
export(add_slide)
export(annotate_base)
Expand Down Expand Up @@ -301,6 +302,7 @@ export(sheet_select)
export(shortcuts)
export(slide_size)
export(slide_summary)
export(slide_visible)
export(slip_in_column_break)
export(slip_in_footnote)
export(slip_in_seqfield)
Expand Down
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Issues

- Add `slide_visible()` to get and set the visibility of slides (#622).
- debug selector for `ph_remove()` (see #625) that was not working
for rvg outputs.

Expand Down
82 changes: 82 additions & 0 deletions R/pptx_slide_manip.R
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

#' @export
#' @title Add a slide
#' @description Add a slide into a pptx presentation.
Expand Down Expand Up @@ -255,3 +256,84 @@ ensure_slide_index_exists <- function(x, slide_idx) {
)
}
}


# internal workhorse get/set slide visibility
# x : rpptx object
# slide_idx: id of slide
# value: Use TRUE / FALSE to set visibility.
.slide_visible <- function(x, slide_idx, value = NULL) {
stop_if_not_rpptx(x)
slide <- x$slide$get_slide(slide_idx)
slide_xml <- slide$get()
node <- xml2::xml_find_first(slide_xml, "/p:sld")
if (is.null(value)) {
value <- xml2::xml_attr(node, "show")
value <- as.logical(as.numeric(value))
ifelse(is.na(value), TRUE, value) # if show is not set, the slide is shown
} else {
stop_if_not_class(value, "logical", arg = "value")
xml2::xml_set_attr(node, "show", value = as.numeric(value))
slide$save()
invisible(x)
}
}


#' Get or set slide visibility
#'
#' PPTX slides can be visible or hidden. This function gets or sets the visibility of slides.
#' @param x An `rpptx` object.
#' @param value Boolean vector with slide visibilities.
#' @rdname slide-visible
#' @export
#' @example inst/examples/example_slide_visible.R
#' @return Boolean vector with slide visibilities or `rpptx` object if changes are made to the object.
`slide_visible<-` <- function(x, value) {
stop_if_not_rpptx(x)
stop_if_not_class(value, "logical", arg = "value")
n_vals <- length(value)
n_slides <- length(x)
if (n_vals > n_slides) {
cli::cli_abort("More values ({.val {n_vals}}) than slides ({.val {n_slides}})")
}
if (n_vals != 1 && n_vals != n_slides) {
cli::cli_warn("Value is not length 1 or same length as number of slides ({.val {n_slides}}). Recycling values.")
}
value <- rep(value, length.out = n_slides)
for (i in seq_along(value)) {
.slide_visible(x, i, value[i])
}
invisible(x)
}


#' @param hide,show Indexes of slides to hide or show.
#' @rdname slide-visible
#' @export
slide_visible <- function(x, hide = NULL, show = NULL) {
stop_if_not_rpptx(x)
idx_in_both <- intersect(as.integer(hide), as.integer(show))
if (length(idx_in_both) > 1) {
cli::cli_abort(
"Overlap between indexes in {.arg hide} and {.arg show}: {.val {idx_in_both}}",
"x" = "Indexes must be mutually exclusive.")
}
if (!is.null(hide)) {
stop_if_not_integerish(hide, "hide")
stop_if_not_in_slide_range(x, hide, arg = "hide")
slide_visible(x)[hide] <- FALSE
}
if (!is.null(show)) {
stop_if_not_integerish(show, "show")
stop_if_not_in_slide_range(x, show, arg = "show")
slide_visible(x)[show] <- TRUE
}
n_slides <- length(x)
res <- vapply(seq_len(n_slides), function(idx) .slide_visible(x, idx), logical(1))
if (is.null(hide) && is.null(show)) {
res
} else {
x
}
}
53 changes: 53 additions & 0 deletions R/utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,49 @@ stop_if_not_rpptx <- function(x, arg = NULL) {
stop_if_not_class(x, "rpptx", arg)
}


stop_if_not_integerish <- function(x, arg = NULL) {
check <- is_integerish(x)
if (!check) {
msg_arg <- ifelse(is.null(arg), "Incorrect input.", "Incorrect input for {.arg {arg}}")
cli::cli_abort(c(
msg_arg,
"x" = "Expected integerish values but got {.cls {class(x)[1]}}"
), call = NULL)
}
}


#' Ensure valid slide indexes
#'
#' @param x An `rpptx` object.
#' @param idx Slide indexes.
#' @param arg Name of argument to use in error message (optional).
#' @param call Environment to display in error message. Defaults to caller env.
#' Set `NULL` to suppress (see [cli::cli_abort]).
#' @keywords internal
stop_if_not_in_slide_range <- function(x, idx, arg = NULL, call = parent.frame()) {
stop_if_not_rpptx(x)
stop_if_not_integerish(idx)

n_slides <- length(x)
idx_available <- seq_len(n_slides)
idx_outside <- setdiff(idx, idx_available)
n_outside <- length(idx_outside)

if (n_outside == 0) {
return(invisible(NULL))
}
argname <- ifelse(is.null(arg), "", "of {.arg {arg}} ")
part_1 <- paste0("{n_outside} index{?es} ", argname, "outside slide range: {.val {idx_outside}}")
part_2 <- ifelse(n_slides == 0,
"Presentation has no slides!",
"Slide indexes must be in the range [{min(idx_available)}..{max(idx_available)}]"
)
cli::cli_abort(c(part_1, "x" = part_2), call = call)
}


check_unit <- function(unit, choices, several.ok = FALSE) {
if (!several.ok && length(unit) != 1) {
cli::cli_abort(
Expand Down Expand Up @@ -429,3 +472,13 @@ is_named <- function(x) {
detect_void_name <- function(x) {
x == "" | is.na(x)
}


# is_integerish(1)
# is_integerish(1.0)
# is_integerish(c(1.0, 2.0))
is_integerish <- function(x) {
ii <- all(is.numeric(x) | is.integer(x))
jj <- all(x == as.integer(x))
ii && jj
}
17 changes: 17 additions & 0 deletions inst/examples/example_slide_visible.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
path <- system.file("doc_examples/example.pptx", package = "officer")
x <- read_pptx(path)

slide_visible(x) # get slide visibilities

x <- slide_visible(x, hide = 1:2) # hide slides 1 and 2
x <- slide_visible(x, show = 1:2) # make slides 1 and 2 visible
x <- slide_visible(x, show = 1:2, hide = 3)

slide_visible(x) <- FALSE # hide all slides
slide_visible(x) <- c(TRUE, FALSE, TRUE) # set each slide separately
slide_visible(x) <- c(TRUE, FALSE) # warns that rhs values are recycled

slide_visible(x)[2] <- TRUE # set 2nd slide to visible
slide_visible(x)[c(1, 3)] <- FALSE # 1st and 3rd slide
slide_visible(x)[c(1, 3)] <- c(FALSE, FALSE) # identical

43 changes: 43 additions & 0 deletions man/slide-visible.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions man/stop_if_not_in_slide_range.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion officer.Rproj
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
Version: 1.0
ProjectId: cf684f77-79cc-4641-8f83-6d6abc3f30bd

RestoreWorkspace: No
SaveWorkspace: No
AlwaysSaveHistory: Default
AlwaysSaveHistory: No

EnableCodeIndexing: Yes
UseSpacesForTab: Yes
Expand Down
Binary file added tests/testthat/docs_dir/test-slides-visible.pptx
Binary file not shown.
Loading

0 comments on commit 1660aec

Please sign in to comment.