| # File src/library/grid/R/ls.R |
| # Part of the R package, https://www.R-project.org |
| # |
| # Copyright (C) 1995-2016 The R Core Team |
| # |
| # This program is free software; you can redistribute it and/or modify |
| # it under the terms of the GNU General Public License as published by |
| # the Free Software Foundation; either version 2 of the License, or |
| # (at your option) any later version. |
| # |
| # This program is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # |
| # A copy of the GNU General Public License is available at |
| # https://www.R-project.org/Licenses/ |
| |
| |
| # Code for listing objects in various grid "namespaces" |
| # (gTrees, vpTrees, and the grid display list) |
| |
| # Return a "gridListing" object, |
| # ... either ... |
| # "gridVectorListing", which is just character vector, |
| # "grobListing", or "vpListing", or "vpNameListing", or |
| # "vpPopListing", or "vpUpListing", |
| # ... or ... |
| # "gridListListing", which is list of "gridListing" objects, |
| # "grobListListing", or "vpListListing", ... |
| # ... or ... |
| # "gridTreeListing", which is list of parent "gridVectorListing" object |
| # plus children "gridListing" object, |
| # "gTreeListing", or "vpTreeListing", or "vpNameTreeListing" |
| # (vpStack or vpTree produces a "vpTreeListing"). |
| # (vpPath [depth > 1] produces a "vpNameTreeListing"). |
| # |
| # "vpListListing", and all "gridTreeListing" objects have a "depth" attribute |
| |
| # The print method will print these in some format, but by having |
| # a separate object, others can capture the result and format the |
| # printing themselves. |
| |
| grid.ls <- function(x=NULL, grobs=TRUE, viewports=FALSE, fullNames=FALSE, |
| recursive=TRUE, print=TRUE, flatten=TRUE, ...) { |
| # If 'x' is NULL, list the grobs on the DL |
| if (is.null(x)) { |
| listing <- gridListDL(grobs=grobs, viewports=viewports, |
| fullNames=fullNames, recursive=recursive) |
| } else { |
| listing <- gridList(x, grobs=grobs, viewports=viewports, |
| fullNames=fullNames, recursive=recursive) |
| } |
| if (flatten) { |
| listing <- flattenListing(listing) |
| } |
| if (is.logical(print)) { |
| if (print) { |
| print(listing) |
| } |
| } else if (is.function(print)) { |
| print(listing, ...) |
| } else { |
| stop("invalid 'print' argument") |
| } |
| invisible(listing) |
| } |
| |
| gridListDL <- function(x, grobs=TRUE, viewports=FALSE, |
| fullNames=FALSE, recursive=TRUE) { |
| if (is.null(dev.list())) { |
| result <- list(gridList(NULL)) |
| } else { |
| display.list <- grid.Call(C_getDisplayList) |
| dl.index <- grid.Call(C_getDLindex) |
| result <- lapply(display.list[1L:dl.index], gridList, |
| grobs=grobs, viewports=viewports, |
| fullNames=fullNames, recursive=recursive) |
| names(result) <- NULL |
| } |
| class(result) <- c("gridListListing", "gridListing") |
| result |
| } |
| |
| gridList <- function(x, ...) { |
| UseMethod("gridList") |
| } |
| |
| gridList.default <- function(x, grobs=TRUE, viewports=FALSE, |
| fullNames=FALSE, recursive=TRUE) { |
| if (is.null(x)) { |
| # This handles empty slots in the display list |
| result <- character() |
| class(result) <- "gridListing" |
| } else { |
| stop("invalid object in 'listing'") |
| } |
| result |
| } |
| |
| # Grob methods |
| gridList.grob <- function(x, grobs=TRUE, viewports=FALSE, |
| fullNames=FALSE, recursive=TRUE) { |
| if (grobs) { |
| if (fullNames) { |
| result <- as.character(x) |
| } else { |
| result <- x$name |
| } |
| class(result) <- c("grobListing", "gridVectorListing", "gridListing") |
| } else { |
| result <- character() |
| class(result) <- "gridListing" |
| } |
| if (viewports) { |
| # Call makeContext() to get x$vp at drawing time |
| x <- makeContext(x) |
| } |
| if (viewports && !is.null(x$vp)) { |
| # Bit dodgy this bit |
| # Emulates an "upViewport" on the DL |
| n <- depth(x$vp) |
| class(n) <- "up" |
| result <- list(gridList(x$vp, |
| grobs=grobs, viewports=viewports, |
| fullNames=fullNames, |
| recursive=recursive), |
| result, |
| gridList(n, |
| grobs=grobs, viewports=viewports, |
| fullNames=fullNames, |
| recursive=recursive)) |
| class(result) <- c("gridListListing", "gridListing") |
| } |
| result |
| } |
| |
| gridList.gList <- function(x, grobs=TRUE, viewports=FALSE, |
| fullNames=FALSE, recursive=TRUE) { |
| # Allow for grobs=FALSE but viewports=TRUE |
| if (grobs || viewports) { |
| if (length(x) == 0L) { |
| result <- character() |
| class(result) <- "gridListing" |
| } else { |
| result <- lapply(x, gridList, |
| grobs=grobs, viewports=viewports, |
| fullNames=fullNames, recursive=recursive) |
| class(result) <- c("gListListing", "gridListListing", |
| "gridListing") |
| } |
| } else { |
| result <- character() |
| class(result) <- "gridListing" |
| } |
| result |
| } |
| |
| gridList.gTree <- function(x, grobs=TRUE, viewports=FALSE, |
| fullNames=FALSE, recursive=TRUE) { |
| if (fullNames) { |
| name <- as.character(x) |
| } else { |
| name <- x$name |
| } |
| class(name) <- c("grobListing", "gridVectorListing", "gridListing") |
| if (viewports) { |
| # Call makeContext() to get x$vp and x$childrenvp at drawing time |
| x <- makeContext(x) |
| } |
| if (recursive) { |
| # Allow for grobs=FALSE but viewports=TRUE |
| result <- gridList(x$children[x$childrenOrder], |
| grobs=grobs, viewports=viewports, |
| fullNames=fullNames, recursive=recursive) |
| if (viewports && !is.null(x$childrenvp)) { |
| # Bit dodgy this bit |
| # Emulates an "upViewport" on the DL |
| n <- depth(x$childrenvp) |
| class(n) <- "up" |
| result <- list(gridList(x$childrenvp, |
| grobs=grobs, viewports=viewports, |
| fullNames=fullNames, |
| recursive=recursive), |
| gridList(n, |
| grobs=grobs, viewports=viewports, |
| fullNames=fullNames, |
| recursive=recursive), |
| result) |
| class(result) <- c("gridListListing", "gridListing") |
| } |
| if (grobs) { |
| result <- list(parent=name, |
| children=result) |
| class(result) <- c("gTreeListing", "gridTreeListing", |
| "gridListing") |
| } else if (!viewports) { |
| result <- character() |
| class(result) <- "gridListing" |
| } |
| } else { |
| if (grobs) { |
| result <- name |
| } else { |
| result <- character() |
| class(result) <- "gridListing" |
| } |
| } |
| if (viewports && !is.null(x$vp)) { |
| # Bit dodgy this bit |
| # Emulates an "upViewport" on the DL |
| n <- depth(x$vp) |
| class(n) <- "up" |
| result <- list(gridList(x$vp, |
| grobs=grobs, viewports=viewports, |
| fullNames=fullNames, |
| recursive=recursive), |
| result, |
| gridList(n, |
| grobs=grobs, viewports=viewports, |
| fullNames=fullNames, |
| recursive=recursive)) |
| class(result) <- c("gridListListing", "gridListing") |
| } |
| result |
| } |
| |
| # Viewport methods |
| gridList.viewport <- function(x, grobs=TRUE, viewports=FALSE, |
| fullNames=FALSE, recursive=TRUE) { |
| if (viewports) { |
| if (fullNames) { |
| result <- as.character(x) |
| } else { |
| result <- x$name |
| } |
| class(result) <- c("vpListing", "gridVectorListing", "gridListing") |
| } else { |
| result <- character() |
| class(result) <- "gridListing" |
| } |
| result |
| } |
| |
| # ... are arugments to gridList |
| listvpListElement <- function(x, ...) { |
| n <- depth(x) |
| class(n) <- "up" |
| result <- list(gridList(x, ...), |
| gridList(n, ...)) |
| class(result) <- c("gridListListing", "gridListing") |
| result |
| } |
| |
| gridList.vpList <- function(x, grobs=TRUE, viewports=FALSE, |
| fullNames=FALSE, recursive=TRUE) { |
| if (viewports) { |
| if (length(x) == 0L) { |
| result <- character() |
| class(result) <- "gridListing" |
| } else if (length(x) == 1L) { |
| result <- gridList(x[[1L]], |
| grobs=grobs, viewports=viewports, |
| fullNames=fullNames, |
| recursive=recursive) |
| } else { |
| result <- c(lapply(x[-length(x)], listvpListElement, |
| grobs=grobs, viewports=viewports, |
| fullNames=fullNames, |
| recursive=recursive), |
| list(gridList(x[[length(x)]], |
| grobs=grobs, viewports=viewports, |
| fullNames=fullNames, |
| recursive=recursive))) |
| attr(result, "depth") <- depth(x[[length(x)]]) |
| class(result) <- c("vpListListing", "gridListListing", |
| "gridListing") |
| } |
| } else { |
| result <- character() |
| class(result) <- "gridListing" |
| } |
| result |
| } |
| |
| gridList.vpStack <- function(x, grobs=TRUE, viewports=FALSE, |
| fullNames=FALSE, recursive=TRUE) { |
| if (viewports) { |
| if (length(x) == 0L) { |
| result <- character() |
| class(result) <- "gridListing" |
| } else if (length(x) == 1L || !recursive) { |
| result <- gridList(x[[1L]], |
| grobs=grobs, viewports=viewports, |
| fullNames=fullNames, recursive=recursive) |
| } else { |
| theRest <- x[-1L] |
| class(theRest) <- "vpStack" |
| result <- gridList(theRest, |
| grobs=grobs, viewports=viewports, |
| fullNames=fullNames, |
| recursive=recursive) |
| result <- list(parent=gridList(x[[1L]], |
| grobs=grobs, viewports=viewports, |
| fullNames=fullNames, |
| recursive=recursive), |
| children=result) |
| attr(result, "depth") <- depth(x) |
| class(result) <- c("vpTreeListing", "gridTreeListing", |
| "gridListing") |
| } |
| } else { |
| result <- character() |
| class(result) <- "gridListing" |
| } |
| result |
| } |
| |
| gridList.vpTree <- function(x, grobs=TRUE, viewports=FALSE, |
| fullNames=FALSE, recursive=TRUE) { |
| if (viewports) { |
| if (recursive) { |
| result <- gridList(x$children, |
| grobs=grobs, viewports=viewports, |
| fullNames=fullNames, recursive=recursive) |
| # Parent can only be a plain viewport |
| result <- list(parent=gridList(x$parent, |
| grobs=grobs, viewports=viewports, |
| fullNames=fullNames, |
| recursive=recursive), |
| children=result) |
| attr(result, "depth") <- depth(x$children) + 1 |
| class(result) <- c("vpTreeListing", "gridTreeListing", |
| "gridListing") |
| } else { |
| result <- gridList(x$parent, |
| grobs=grobs, viewports=viewports, |
| fullNames=fullNames, recursive=recursive) |
| } |
| } else { |
| result <- character() |
| class(result) <- "gridListing" |
| } |
| result |
| } |
| |
| # This handles downViewports in the display list |
| gridList.vpPath <- function(x, grobs=TRUE, viewports=FALSE, |
| fullNames=FALSE, recursive=TRUE) { |
| if (viewports) { |
| # Have to account for top-level downViewports that are |
| # non-strict (i.e., they could navigate down quite a long way) |
| # In particular, when the vpPath navigates down more |
| # levels than there are names in the vpPath |
| recordedDepth <- attr(x, "depth") |
| if (!is.null(recordedDepth) && recordedDepth != depth(x)) { |
| # In this case, need to prepend a fake path on the front |
| # so that subsequent upViewport()s will work |
| x <- vpPathFromVector(c(rep("...", recordedDepth - depth(x)), |
| explode(as.character(x)))) |
| } |
| # This would be simpler if paths were kept as vectors |
| # but that redesign is a bit of an undertaking |
| if (depth(x) == 1) { |
| if (fullNames) { |
| result <- paste0("downViewport[", x$name, "]") |
| } else { |
| result <- x$name |
| } |
| class(result) <- c("vpNameListing", "gridVectorListing", |
| "gridListing") |
| } else if (depth(x) == 2) { |
| result <- gridList(vpPath(x$name), |
| grobs=grobs, viewports=viewports, |
| fullNames=fullNames, |
| recursive=recursive) |
| result <- list(parent=gridList(vpPath(x$path), |
| grobs=grobs, viewports=viewports, |
| fullNames=fullNames, |
| recursive=recursive), |
| children=result) |
| attr(result, "depth") <- depth(x) |
| # Inherit updateVPDepth and updateVPPath methods |
| # from vpTreeListing |
| class(result) <- c("vpNameTreeListing", "vpTreeListing", |
| "gridTreeListing", "gridListing") |
| } else { |
| path <- explode(x$path) |
| result <- gridList(vpPathFromVector(c(path[-1L], x$name)), |
| grobs=grobs, viewports=viewports, |
| fullNames=fullNames, |
| recursive=recursive) |
| result <- list(parent=gridList(vpPath(path[1L]), |
| grobs=grobs, viewports=viewports, |
| fullNames=fullNames, |
| recursive=recursive), |
| children=result) |
| attr(result, "depth") <- depth(x) |
| # Inherit updateVPDepth and updateVPPath methods |
| # from vpTreeListing |
| class(result) <- c("vpNameTreeListing", "vpTreeListing", |
| "gridTreeListing", "gridListing") |
| } |
| } else { |
| result <- character() |
| class(result) <- "gridListing" |
| } |
| result |
| } |
| |
| # This handles popViewports in the display list |
| gridList.pop <- function(x, grobs=TRUE, viewports=FALSE, |
| fullNames=FALSE, recursive=TRUE) { |
| if (viewports) { |
| result <- as.character(x) |
| if (fullNames) { |
| result <- paste0("popViewport[", result, "]") |
| } |
| class(result) <- c("vpPopListing", "gridVectorListing", "gridListing") |
| } else { |
| result <- character() |
| class(result) <- "gridListing" |
| } |
| result |
| } |
| |
| # This handles upViewports in the display list |
| gridList.up <- function(x, grobs=TRUE, viewports=FALSE, |
| fullNames=FALSE, recursive=TRUE) { |
| if (viewports) { |
| result <- as.character(x) |
| if (fullNames) { |
| result <- paste0("upViewport[", result, "]") |
| } |
| class(result) <- c("vpUpListing", "gridVectorListing", "gridListing") |
| } else { |
| result <- character() |
| class(result) <- "gridListing" |
| } |
| result |
| } |
| |
| ###################### |
| # flatten methods for gridListing objects |
| ###################### |
| |
| incDepth <- function(depth, n=1) { |
| depth + n |
| } |
| |
| decrDepth <- function(depth, x) { |
| n <- as.numeric(gsub("^.+\\[", "", |
| gsub("\\]$", "", |
| as.character(x)))) |
| depth - n |
| } |
| |
| # updateDepth modifies depth from sibling to sibling |
| # (flatListing methods take care of parent to child updates of depth) |
| updateGDepth <- function(x, gdepth) { |
| UseMethod("updateGDepth") |
| } |
| |
| updateGDepth.default <- function(x, gdepth) { |
| gdepth |
| } |
| |
| updateVPDepth <- function(x, vpdepth) { |
| UseMethod("updateVPDepth") |
| } |
| |
| updateVPDepth.default <- function(x, vpdepth) { |
| vpdepth |
| } |
| |
| updateVPDepth.vpListing <- function(x, vpdepth) { |
| incDepth(vpdepth) |
| } |
| |
| updateVPDepth.vpNameListing <- function(x, vpdepth) { |
| incDepth(vpdepth) |
| } |
| |
| updateVPDepth.vpListListing <- function(x, vpdepth) { |
| incDepth(vpdepth, attr(x, "depth")) |
| } |
| |
| updateVPDepth.vpUpListing <- function(x, vpdepth) { |
| decrDepth(vpdepth, x) |
| } |
| |
| updateVPDepth.vpPopListing <- function(x, vpdepth) { |
| decrDepth(vpdepth, x) |
| } |
| |
| updateVPDepth.vpTreeListing <- function(x, vpdepth) { |
| incDepth(vpdepth, attr(x, "depth")) |
| } |
| |
| incPath <- function(oldpath, addition) { |
| if (nchar(oldpath) > 0) { |
| paste0(oldpath, .grid.pathSep, as.character(addition)) |
| } else { |
| as.character(addition) |
| } |
| } |
| |
| decrPath <- function(oldpath, x) { |
| bits <- strsplit(oldpath, .grid.pathSep)[[1L]] |
| n <- as.numeric(gsub("^.+\\[", "", |
| gsub("\\]$", "", |
| as.character(x)))) |
| if ((m <- (length(bits) - n)) == 0L) { |
| "" |
| } else { |
| paste(bits[seq_len(m)], collapse=.grid.pathSep) |
| } |
| } |
| |
| updateGPath <- function(x, gpath) { |
| UseMethod("updateGPath") |
| } |
| |
| updateGPath.default <- function(x, gpath) { |
| gpath |
| } |
| |
| updateVPPath <- function(x, vppath) { |
| UseMethod("updateVPPath") |
| } |
| |
| updateVPPath.default <- function(x, vppath) { |
| vppath |
| } |
| |
| updateVPPath.vpListing <- function(x, vppath) { |
| incPath(vppath, x) |
| } |
| |
| updateVPPath.vpNameListing <- function(x, vppath) { |
| incPath(vppath, x) |
| } |
| |
| updateVPPath.vpListListing <- function(x, vppath) { |
| incPath(vppath, x[[length(x)]]) |
| } |
| |
| updateVPPath.vpUpListing <- function(x, vppath) { |
| decrPath(vppath, x) |
| } |
| |
| updateVPPath.vpPopListing <- function(x, vppath) { |
| decrPath(vppath, x) |
| } |
| |
| updateVPPath.vpTreeListing <- function(x, vppath) { |
| incPath(vppath, |
| paste0(updateVPPath(x$parent, ""), .grid.pathSep, |
| updateVPPath(x$children, ""))) |
| } |
| |
| flatListing <- function(x, gDepth=0, vpDepth=0, gPath="", vpPath="") { |
| UseMethod("flatListing") |
| } |
| |
| flatListing.gridListing <- function(x, gDepth=0, vpDepth=0, |
| gPath="", vpPath="") { |
| if (length(x)) { |
| list(name=as.character(x), |
| gDepth=gDepth, |
| vpDepth=vpDepth, |
| gPath=gPath, |
| vpPath=vpPath, |
| type=class(x)[1L]) |
| } else { |
| list(name=character(), |
| gDepth=numeric(), |
| vpDepth=numeric(), |
| gPath=character(), |
| vpPath=character(), |
| type=character()) |
| } |
| } |
| |
| flatListing.gTreeListing <- function(x, gDepth=0, vpDepth=0, |
| gPath="", vpPath="") { |
| # Increase gDepth and gPath |
| flatChildren <- flatListing(x$children, incDepth(gDepth, 1), vpDepth, |
| incPath(gPath, x$parent), vpPath) |
| list(name=c(as.character(x$parent), flatChildren$name), |
| gDepth=c(gDepth, flatChildren$gDepth), |
| vpDepth=c(vpDepth, flatChildren$vpDepth), |
| gPath=c(gPath, flatChildren$gPath), |
| vpPath=c(vpPath, flatChildren$vpPath), |
| type=c(class(x)[1L], flatChildren$type)) |
| } |
| |
| OLDflatListing.vpTreeListing <- function(x, gDepth=0, vpDepth=0, |
| gPath="", vpPath="") { |
| # Increase vpDepth and vpPath |
| flatChildren <- flatListing(x$children, gDepth, incDepth(vpDepth, 1), |
| gPath, incPath(vpPath, x$parent)) |
| list(name=c(as.character(x$parent), flatChildren$name), |
| gDepth=c(gDepth, flatChildren$gDepth), |
| vpDepth=c(vpDepth, flatChildren$vpDepth), |
| gPath=c(gPath, flatChildren$gPath), |
| vpPath=c(vpPath, flatChildren$vpPath), |
| type=c(class(x)[1L], flatChildren$type)) |
| } |
| |
| flatListing.vpTreeListing <- function(x, gDepth=0, vpDepth=0, |
| gPath="", vpPath="") { |
| flatParent <- flatListing(x$parent, gDepth, vpDepth, |
| gPath, vpPath) |
| depth <- attr(x$parent, "depth") |
| if (is.null(depth)) { |
| depth <- 1 |
| } |
| # Increase vpDepth and vpPath |
| flatChildren <- flatListing(x$children, gDepth, incDepth(vpDepth, depth), |
| gPath, updateVPPath(x$parent, vpPath)) |
| list(name=c(flatParent$name, flatChildren$name), |
| gDepth=c(flatParent$gDepth, flatChildren$gDepth), |
| vpDepth=c(flatParent$vpDepth, flatChildren$vpDepth), |
| gPath=c(flatParent$gPath, flatChildren$gPath), |
| vpPath=c(flatParent$vpPath, flatChildren$vpPath), |
| type=c(flatParent$type, flatChildren$type)) |
| } |
| |
| flatListing.vpNameTreeListing <- function(x, gDepth=0, vpDepth=0, |
| gPath="", vpPath="") { |
| # Increase vpDepth and vpPath |
| flatChildren <- flatListing(x$children, gDepth, incDepth(vpDepth, 1), |
| gPath, incPath(vpPath, x$parent)) |
| list(name=c(as.character(x$parent), flatChildren$name), |
| gDepth=c(gDepth, flatChildren$gDepth), |
| vpDepth=c(vpDepth, flatChildren$vpDepth), |
| gPath=c(gPath, flatChildren$gPath), |
| vpPath=c(vpPath, flatChildren$vpPath), |
| type=c(class(x)[1L], flatChildren$type)) |
| } |
| |
| flatListing.gridListListing <- function(x, gDepth=0, vpDepth=0, |
| gPath="", vpPath="") { |
| n <- length(x) |
| listListing <- list(name=character(), |
| gDepth=numeric(), |
| vpDepth=numeric(), |
| gPath=character(), |
| vpPath=character(), |
| type=character()) |
| for (i in 1L:n) { |
| componentListing <- flatListing(x[[i]], gDepth, vpDepth, |
| gPath, vpPath) |
| listListing$name <- c(listListing$name, |
| componentListing$name) |
| listListing$gDepth <- c(listListing$gDepth, |
| componentListing$gDepth) |
| listListing$vpDepth <- c(listListing$vpDepth, |
| componentListing$vpDepth) |
| listListing$gPath <- c(listListing$gPath, |
| componentListing$gPath) |
| listListing$vpPath <- c(listListing$vpPath, |
| componentListing$vpPath) |
| listListing$type <- c(listListing$type, |
| componentListing$type) |
| gPath <- updateGPath(x[[i]], gPath) |
| vpPath <- updateVPPath(x[[i]], vpPath) |
| gDepth <- updateGDepth(x[[i]], gDepth) |
| vpDepth <- updateVPDepth(x[[i]], vpDepth) |
| } |
| listListing |
| } |
| |
| flattenListing <- function(x) { |
| listing <- flatListing(x) |
| class(listing) <- "flatGridListing" |
| listing |
| } |
| |
| print.flatGridListing <- function(x, ...) { |
| nestedListing(x, ...) |
| invisible(x) |
| } |
| |
| ###################### |
| # Print functions for flatGridListings |
| ###################### |
| |
| nestedListing <- function(x, gindent=" ", vpindent=gindent) { |
| |
| makePrefix <- function(indent, depth) { |
| indents <- rep(indent, length(depth)) |
| indents <- mapply(rep, indents, depth) |
| sapply(indents, paste, collapse="") |
| } |
| |
| if (!inherits(x, "flatGridListing")) |
| stop("invalid listing") |
| cat(paste0(makePrefix(gindent, x$gDepth), |
| makePrefix(vpindent, x$vpDepth), |
| x$name), |
| sep = "\n") |
| } |
| |
| pathListing <- function(x, gvpSep=" | ", gAlign=TRUE) { |
| |
| appendToPrefix <- function(path, name) { |
| emptyPath <- nchar(path) == 0 |
| ifelse(emptyPath, |
| name, |
| paste(path, name, sep = .grid.pathSep)) |
| } |
| |
| padPrefix <- function(path, maxLen) { |
| paste0(path, strrep(" ", maxLen - nchar(path))) |
| } |
| |
| if (!inherits(x, "flatGridListing")) |
| stop("invalid 'listing'") |
| vpListings <- seq_along(x$name) %in% grep("^vp", x$type) |
| paths <- x$vpPath |
| # Only if viewport listings |
| if (sum(vpListings) > 0) { |
| paths[vpListings] <- appendToPrefix(paths[vpListings], |
| x$name[vpListings]) |
| # If viewports are shown, then allow extra space before grobs |
| maxLen <- max(nchar(paths[vpListings])) |
| } |
| else |
| maxLen <- max(nchar(paths)) |
| |
| # Only if grob listings |
| if (sum(!vpListings) > 0) { |
| if (gAlign) { |
| paths[!vpListings] <- padPrefix(paths[!vpListings], maxLen) |
| } |
| paths[!vpListings] <- paste0(paths[!vpListings], |
| gvpSep, |
| appendToPrefix(x$gPath[!vpListings], |
| x$name[!vpListings])) |
| } |
| cat(paths, sep = "\n") |
| } |
| |
| grobPathListing <- function(x, ...) { |
| subset <- grep("^g", x$type) |
| if (length(subset)) { |
| cl <- class(x) |
| subListing <- lapply(x, "[", subset) |
| class(subListing) <- cl |
| pathListing(subListing, ...) |
| } |
| } |
| |
| # Tidy up the vpPath from grid.ls() to remove ROOT if it is there |
| clean <- function(paths) { |
| sapply(lapply(paths, |
| function(x) { |
| pieces <- explode(x) |
| if (length(pieces) && pieces[1] == "ROOT") |
| pieces <- pieces[-1] |
| pieces |
| }), |
| function(x) { |
| if (length(x)) |
| as.character(vpPath(x)) |
| else "" |
| }) |
| } |
| |
| # Given a gPath, return complete grob paths that match from the display list |
| grid.grep <- function(path, x = NULL, grobs = TRUE, viewports = FALSE, |
| strict = FALSE, grep = FALSE, global = FALSE, |
| no.match = character()) { |
| if (!inherits(path, "gPath")) |
| path <- gPath(path) |
| depth <- depth(path) |
| grep <- rep(grep, length.out = depth) |
| |
| # Get each piece of the path as a sequential char vector |
| pathPieces <- explode(path) |
| |
| if (is.null(x)) { |
| dl <- grid.ls( grobs=grobs, viewports=viewports, print = FALSE) |
| } else { |
| dl <- grid.ls(x, grobs=grobs, viewports=viewports, print = FALSE) |
| } |
| if (!length(dl$name)) |
| return(no.match) |
| # Only keep vpListing and grobListing |
| names <- names(dl) |
| dl <- lapply(dl, |
| function(x) { |
| x[dl$type == "vpListing" | dl$type == "grobListing" | |
| dl$type == "gTreeListing"] |
| }) |
| names(dl) <- names |
| # "depth" is vpDepth for vpListing and gDepth for grobListing |
| # "path" is gPath for vpListing and vpPath for grobListing |
| if (is.null(x)) { |
| # (remove "ROOT" from path and depth) |
| dl$depth <- ifelse(dl$type == "vpListing", dl$vpDepth - 1, dl$gDepth) |
| dl$path <- ifelse(dl$type == "vpListing", clean(dl$vpPath), dl$gPath) |
| } else { |
| dl$depth <- ifelse(dl$type == "vpListing", dl$vpDepth, dl$gDepth) |
| dl$path <- ifelse(dl$type == "vpListing", dl$vpPath, dl$gPath) |
| } |
| # Limit our search only to grobs whose depth matches ours |
| # For not strict, we're only looking at the grob names, so all |
| # depths apply. |
| matchingDepths <- if (! strict) which((dl$depth + 1) >= depth) |
| else which((dl$depth + 1) == depth) |
| if (!length(matchingDepths)) |
| return(no.match) |
| |
| nMatches <- 0 |
| searchMatches <- vector("list", length(matchingDepths)) |
| # For each name of the correct path length |
| for (i in matchingDepths) { |
| dlPathPieces <- |
| if (dl$depth[i] > 0) |
| c(explode(dl$path[i]), dl$name[i]) |
| else |
| dl$name[i] |
| matches <- logical(depth) |
| if (!strict) { |
| # NOTE that we already know that the dlPath is AT LEAST as long |
| # as the path |
| depthOffset <- 0 |
| while (depthOffset + depth <= dl$depth[i] + 1 && |
| !all(matches)) { |
| for (j in 1:depth) { |
| matches[j] <- |
| if (grep[j]) |
| grepl(pathPieces[j], dlPathPieces[depthOffset + j]) |
| else |
| pathPieces[j] == dlPathPieces[depthOffset + j] |
| } |
| depthOffset <- depthOffset + 1 |
| } |
| } else { |
| # Check whether we need to grep this level or not, attempt match |
| # NOTE that we already know that path and dlPath are same length |
| for (j in 1:depth) { |
| matches[j] <- |
| if (grep[j]) |
| grepl(pathPieces[j], dlPathPieces[j]) |
| else |
| pathPieces[j] == dlPathPieces[j] |
| } |
| } |
| # We have found a grob |
| if (all(matches)) { |
| if (!global) { |
| # Returning early to avoid further searching |
| if (dl$type[i] == "vpListing") { |
| result <- do.call("vpPath", list(dlPathPieces)) |
| } else { |
| result <- do.call("gPath", list(dlPathPieces)) |
| attr(result, "vpPath") <- clean(dl$vpPath[i]) |
| } |
| return(result) |
| } else { |
| nMatches <- nMatches + 1 |
| if (dl$type[i] == "vpListing") { |
| result <- do.call("vpPath", |
| list(dlPathPieces)) |
| } else { |
| result <- do.call("gPath", |
| list(dlPathPieces)) |
| attr(result, "vpPath") <- clean(dl$vpPath[i]) |
| } |
| searchMatches[[nMatches]] <- result |
| } |
| } |
| } |
| |
| if (!nMatches) |
| return(no.match) |
| |
| # We may have allocated a list too large earlier, |
| # subset to only matching results |
| searchMatches <- searchMatches[1:nMatches] |
| |
| return(searchMatches) |
| } |