/// [Pager] breaks a [Page] into smaller [page]s that will fit in the available
/// space.
///
+/// A [Page] always has the same headers as its [Table].
+///
/// # Rendered cells
///
-/// The horizontal cells rendered are the leftmost `h[X]`, then `r[X]`.
-/// The vertical cells rendered are the topmost `h[Y]`, then `r[Y]`.
-/// `n[i]` is the sum of `h[i]` and `r[i].len()`.
+/// - The columns rendered are the leftmost `self.table.h[X]`, then `r[X]`.
+/// - The rows rendered are the topmost `self.table.h[Y]`, then `r[Y]`.
#[derive(Debug)]
struct Page {
table: Arc<Table>,
- /// Size of the table in cells.
+ /// Table size in cells.
///
+ /// This is the sum of `self.table.h` and `self.r`.
n: CellPos,
- /// Header size. Cells `0..h[X]` are rendered horizontally, and `0..h[Y]` vertically.
- h: CellPos,
-
- /// Main region of cells to render.
+ /// The region of cells in `self.table` to render.
r: CellRect,
/// Mappings from [Page] positions to those in the underlying [Table].
/// reasonably, then [Break::next] will split a single row or column across
/// multiple [Page]s. This member indicates when this has happened:
///
- /// is_edge_cutoff[X][0] is true if pixels have been cut off the left side
- /// of the leftmost column in this page, and false otherwise.
+ /// - `is_edge_cutoff[Axis2::X][0]` is true if pixels have been cut off the
+ /// left side of the leftmost column in this page, and false otherwise.
///
- /// is_edge_cutoff[X][1] is true if pixels have been cut off the right side
- /// of the rightmost column in this page, and false otherwise.
+ /// - `is_edge_cutoff[Axis2::X][1]` is true if pixels have been cut off the
+ /// right side of the rightmost column in this page, and false otherwise.
///
- /// is_edge_cutoff[Y][0] and is_edge_cutoff[Y][1] are similar for the top
- /// and bottom of the table.
+ /// - `is_edge_cutoff[Axis2::Y][0]` and `is_edge_cutoff[Axis2::Y][1]` are
+ /// similar for the top and bottom of the table.
///
- /// The effect of is_edge_cutoff is to prevent rules along the edge in
- /// question from being rendered.
+ /// The effect is to prevent rules along the edge in question from being
+ /// rendered.
///
- /// When is_edge_cutoff is true for a given edge, the 'overflows' hmap will
- /// contain a node for each cell along that edge.
+ /// When `is_edge_cutoff` is true for a given edge, 'overflows' will contain
+ /// a node for each cell along that edge.
is_edge_cutoff: EnumMap<Axis2, [bool; 2]>,
}
Self {
table,
n,
- h,
r,
cp: Axis2::new_enum(cp_x, cp_y),
overflows: HashMap::new(),
}
}
+ /// A [Page] always has the same headers as its underlying [Table].
+ fn h(&self) -> CellPos {
+ self.table.h
+ }
+
fn use_row_widths(rows: &[isize], rules: &[isize]) -> Vec<isize> {
let mut vec = once(0)
.chain(interleave(rules, rows).copied())
/// Returns the width of the headers along `axis`.
fn headers_width(&self, axis: Axis2) -> isize {
- self.axis_width(axis, rule_ofs(0)..cell_ofs(self.h[axis]))
+ self.axis_width(axis, rule_ofs(0)..cell_ofs(self.h()[axis]))
}
/// Returns the width of rule `z` along `axis`.
/// Returns the width of the widest cell, excluding headers, along `axis`.
fn max_cell_width(&self, axis: Axis2) -> isize {
- (self.h[axis]..self.n[axis])
+ (self.h()[axis]..self.n[axis])
.map(|z| self.cell_width(axis, z))
.max()
.unwrap_or(0)
}
fn get_map(&self, axis: Axis2, z: usize) -> &Map {
- if z < self.h[axis] {
+ if z < self.h()[axis] {
&self.maps[axis][0]
} else {
&self.maps[axis][1]
/// cell `extent.end - 1`. (`pixel0` and `pixel1` are used to render cells
/// that are too large to fit on a single page.)
///
- /// The whole of axis `!axis` is included. (The caller may follow up with
- /// another call to select on `!axis`.)
+ /// The whole of axis `!a` is included. (The caller may follow up with
+ /// another call to select on `!a`.)
fn select(
self: &Arc<Self>,
a: Axis2,
let b = !a;
let z0 = extent.start;
let z1 = extent.end;
+ let h = self.h();
// If all of the page is selected, just make a copy.
- if z0 == self.h[a] && z1 == self.n[a] && pixel0 == 0 && pixel1 == 0 {
+ if z0 == h[a] && z1 == self.n[a] && pixel0 == 0 && pixel1 == 0 {
return self.clone();
}
// Figure out `n`, `h`, `r` for the subpage.
- let trim = [z0 - self.h[a], self.n[a] - z1];
+ let trim = [z0 - self.h()[a], self.n[a] - z1];
let mut n = self.n;
n[a] -= trim[0] + trim[1];
- let h = self.h;
let mut r = self.r.clone();
r[a].start += trim[0];
r[a].end -= trim[1];
p1: pixel1,
};
// Add overflows along the left side...
- if self.h[a] == 0 || z0 > self.h[a] || pixel0 > 0 {
+ if h[a] == 0 || z0 > h[a] || pixel0 > 0 {
let mut z = 0;
while z < self.n[b] {
let d = CellPos::for_axis((a, z0), z);
overflow[a][1] +=
pixel1 + self.axis_width(a, cell_ofs(z1)..cell_ofs(cell.rect[a].end));
}
- assert!(
- overflows
- .insert(s.coord_to_subpage(cell.rect.top_left()), overflow)
- .is_none()
- );
+ assert!(overflows.insert(s.coord_to_subpage(d), overflow).is_none());
}
z += cell.rect[b].len();
}
Arc::new(Self {
table: self.table.clone(),
n,
- h,
r,
maps,
cp,
let coord = self.map_coord(coord);
let border = self.table.get_rule(a, coord);
- if self.h[a] > 0 && coord[a] == self.h[a] {
+ let h = self.h();
+ if h[a] > 0 && coord[a] == h[a] {
let border2 = self
.table
- .get_rule(a, CellPos::for_axis((a, self.h[a]), coord[!a]));
+ .get_rule(a, CellPos::for_axis((a, h[a]), coord[!a]));
border.combine(border2)
} else {
border
/// Returns the coordinates of `coord` as it will appear in this subpage.
///
/// `coord` must be in the selected region or the results will not make
- /// sense.
+ /// sense (or will panic due to overflow).
fn coord_to_subpage(&self, coord: CellPos) -> CellPos {
let a = self.a;
let b = self.b;
let ha0 = self.h[a];
- CellPos::for_axis((a, max(coord[a] + ha0 - self.z0, ha0)), coord[b])
+ let z = coord[a];
+ let z_subpage = if (0..ha0).contains(&z) {
+ z
+ } else if (self.z0..self.z1).contains(&z) {
+ z - self.z0 + ha0
+ } else {
+ unreachable!("{z} is not in {:?} or {:?}", 0..ha0, self.z0..self.z1);
+ };
+ CellPos::for_axis((a, z_subpage), coord[b])
}
}
impl Break {
fn new(page: Arc<Page>, axis: Axis2) -> Self {
- let z = page.h[axis];
+ let z = page.h()[axis];
let hw = page.headers_width(axis);
Self {
page,
// Width of header not including its rightmost rule.
let mut size = self
.page
- .axis_width(self.axis, 0..rule_ofs(self.page.h[self.axis]));
+ .axis_width(self.axis, 0..rule_ofs(self.page.h()[self.axis]));
// If we have a pixel offset and there is no header, then we omit
// the leftmost rule of the body. Otherwise the rendering is deceptive
// rightmost rule in the header and the leftmost rule in the body. We
// assume that the width of a merged rule is the larger of the widths of
// either rule individually.
- if self.pixel == 0 || self.page.h[self.axis] > 0 {
+ if self.pixel == 0 || self.page.h()[self.axis] > 0 {
size += max(
- self.page.rule_width(self.axis, self.page.h[self.axis]),
+ self.page.rule_width(self.axis, self.page.h()[self.axis]),
self.page.rule_width(self.axis, self.z),
);
}