| # File src/library/grid/R/layout.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/ |
| |
| |
| is.layout <- function(l) { |
| inherits(l, "layout") |
| } |
| |
| # FIXME: The internal C code now does a lot of recycling of |
| # unit values, units, and data. Can some/most/all of the |
| # recycling stuff below be removed ? |
| valid.layout <- function(nrow, ncol, widths, heights, respect, just) { |
| nrow <- as.integer(nrow) |
| ncol <- as.integer(ncol) |
| # make sure we're dealing with a unit object |
| if (!is.logical(respect)) { |
| respect <- as.matrix(respect) |
| if (!is.matrix(respect) || any(dim(respect) != c(nrow, ncol))) |
| stop("'respect' must be logical or an 'nrow' by 'ncol' matrix") |
| } |
| if (is.matrix(respect)) { |
| respect.mat <- matrix(as.integer(respect), |
| dim(respect)[1L], |
| dim(respect)[2L]) |
| respect <- 2 |
| } |
| else respect.mat <- matrix(0L, nrow, ncol) |
| |
| valid.just <- valid.just(just) |
| l <- list(nrow = nrow, ncol = ncol, |
| widths = widths, heights = heights, |
| respect = respect, valid.respect=as.integer(respect), |
| respect.mat = respect.mat, |
| just=just, valid.just=valid.just) |
| class(l) <- "layout" |
| l |
| } |
| |
| layout.torture <- function() { |
| top.vp <- viewport(y=0, height=unit(1, "npc") - unit(1.5, "lines"), |
| just=c("centre", "bottom")) |
| do.label <- function(label) { |
| grid.rect(y=1, height=unit(1.5, "lines"), |
| just=c("center", "top")) |
| grid.text(label, |
| y=unit(1, "npc") - unit(1, "lines"), |
| gp=gpar(font=2)) |
| } |
| # 1 = all relative widths and heights |
| grid.show.layout(grid.layout(3,2), vp=top.vp) |
| do.label("All dimensions relative -- no respect") |
| # (1) with full respect |
| grid.show.layout(grid.layout(3,2, respect=TRUE), vp=top.vp) |
| do.label("All dimensions relative -- full respect") |
| # (1) with partial respect |
| grid.show.layout(grid.layout(3,2,respect=matrix(c(1,0,0,0,0,0), 3L, 2L, TRUE)), |
| vp=top.vp) |
| do.label("All dimensions relative -- only top-left cell respected") |
| # (1) with slightly weirder partial respect |
| grid.show.layout(grid.layout(3,2,respect=matrix(c(1,0,0,0,0,1), 3L, 2L, TRUE)), |
| vp=top.vp) |
| do.label("All relative -- top-left, bottom-right respected") |
| # 2 = combination of absolute and relative widths and heights |
| grid.show.layout(grid.layout(2, 3, |
| widths=unit(c(2,4,1), c("null", "cm", "null")), |
| heights=unit(c(6,4), c("cm", "null"))), |
| vp=top.vp) |
| do.label("Absolute and relative -- no respect") |
| # (2) with full respect |
| grid.show.layout(grid.layout(2, 3, |
| widths=unit(c(2,4,1), c("null", "cm", "null")), |
| heights=unit(c(6,4), c("cm", "null")), respect=TRUE), |
| vp=top.vp) |
| do.label("Absolute and relative -- full respect") |
| # (2) with partial respect |
| grid.show.layout(grid.layout(2, 3, |
| widths=unit(c(2,4,1), c("null", "cm", "null")), |
| heights=unit(c(6,4), c("cm", "null")), |
| respect=matrix(c(0,0,0,0,0,1), 2L, 3L, TRUE)), |
| vp=top.vp) |
| do.label("Absolute and relative -- bottom-right respected") |
| } |
| |
| # Return the region allocated by the layout of the current viewport |
| layoutRegion <- function(layout.pos.row=1, layout.pos.col=1) { |
| region <- grid.Call(C_layoutRegion, |
| # This conversion matches the vailidity check in |
| # valid.viewport() |
| if (is.null(layout.pos.row)) layout.pos.row |
| else as.integer(rep(layout.pos.row, length.out=2)), |
| if (is.null(layout.pos.col)) layout.pos.col |
| else as.integer(rep(layout.pos.col, length.out=2))) |
| list(left=unit(region[1L], "npc"), |
| bottom=unit(region[2L], "npc"), |
| width=unit(region[3L], "npc"), |
| height=unit(region[4L], "npc")) |
| } |
| |
| #################### |
| # Accessors |
| #################### |
| |
| layout.nrow <- function(lay) { |
| lay$nrow |
| } |
| |
| layout.ncol <- function(lay) { |
| lay$ncol |
| } |
| |
| layout.widths <- function(lay) { |
| lay$widths |
| } |
| |
| layout.heights <- function(lay) { |
| lay$heights |
| } |
| |
| layout.respect <- function(lay) { |
| switch(lay$respect + 1, |
| FALSE, |
| TRUE, |
| lay$respect.mat) |
| } |
| |
| #################### |
| # Public constructor function |
| #################### |
| grid.layout <- function (nrow = 1, ncol = 1, |
| widths = unit(rep_len(1, ncol), "null"), |
| heights = unit(rep_len(1, nrow), "null"), |
| default.units = "null", |
| respect = FALSE, |
| just="centre") |
| { |
| if (!is.unit(widths)) |
| widths <- unit(widths, default.units) |
| if (!is.unit(heights)) |
| heights <- unit(heights, default.units) |
| valid.layout(nrow, ncol, widths, heights, respect, just) |
| } |
| |
| #################### |
| # Utility Functions |
| #################### |
| |
| dim.layout <- function(x) { |
| c(x$nrow, x$ncol) |
| } |