summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--library/src/layout/grid.rs61
-rw-r--r--library/src/layout/table.rs86
-rw-r--r--tests/ref/bugs/grid-1.pngbin928 -> 923 bytes
-rw-r--r--tests/ref/compiler/break-continue.pngbin7268 -> 7263 bytes
-rw-r--r--tests/ref/compute/data.pngbin8602 -> 8606 bytes
-rw-r--r--tests/ref/layout/grid-auto-shrink.pngbin7796 -> 7799 bytes
-rw-r--r--tests/ref/layout/grid-rtl.pngbin1725 -> 1702 bytes
-rw-r--r--tests/ref/layout/par.pngbin25788 -> 25793 bytes
-rw-r--r--tests/ref/layout/table.pngbin4295 -> 4325 bytes
-rw-r--r--tests/ref/math/content.pngbin7871 -> 7869 bytes
-rw-r--r--tests/ref/text/shift.pngbin7781 -> 7781 bytes
-rw-r--r--tests/typ/layout/grid-rtl.typ2
12 files changed, 116 insertions, 33 deletions
diff --git a/library/src/layout/grid.rs b/library/src/layout/grid.rs
index 92bf19d1..c5bbe9e5 100644
--- a/library/src/layout/grid.rs
+++ b/library/src/layout/grid.rs
@@ -139,7 +139,7 @@ impl Layout for GridNode {
);
// Measure the columns and layout the grid row-by-row.
- layouter.layout()
+ Ok(layouter.layout()?.fragment)
}
}
@@ -165,7 +165,7 @@ castable! {
}
/// Performs grid layout.
-struct GridLayouter<'a, 'v> {
+pub struct GridLayouter<'a, 'v> {
/// The core context.
vt: &'a mut Vt<'v>,
/// The grid cells.
@@ -184,6 +184,8 @@ struct GridLayouter<'a, 'v> {
styles: StyleChain<'a>,
/// Resolved column sizes.
rcols: Vec<Abs>,
+ /// Resolve row sizes, by region.
+ rrows: Vec<Vec<RowPiece>>,
/// Rows in the current region.
lrows: Vec<Row>,
/// The used-up size of the current region. The horizontal size is
@@ -195,11 +197,31 @@ struct GridLayouter<'a, 'v> {
finished: Vec<Frame>,
}
+/// The resulting sizes of columns and rows in a grid.
+#[derive(Debug)]
+pub struct GridLayout {
+ /// The fragment.
+ pub fragment: Fragment,
+ /// The column widths.
+ pub cols: Vec<Abs>,
+ /// The heights of the resulting rows segments, by region.
+ pub rows: Vec<Vec<RowPiece>>,
+}
+
+/// Details about a resulting row piece.
+#[derive(Debug)]
+pub struct RowPiece {
+ /// The height of the segment.
+ pub height: Abs,
+ /// The index of the row.
+ pub y: usize,
+}
+
/// Produced by initial row layout, auto and relative rows are already finished,
/// fractional rows not yet.
enum Row {
- /// Finished row frame of auto or relative row.
- Frame(Frame),
+ /// Finished row frame of auto or relative row with y index.
+ Frame(Frame, usize),
/// Fractional row with y index.
Fr(Fr, usize),
}
@@ -208,7 +230,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
/// Create a new grid layouter.
///
/// This prepares grid layout by unifying content and gutter tracks.
- fn new(
+ pub fn new(
vt: &'a mut Vt<'v>,
tracks: Axes<&[Sizing]>,
gutter: Axes<&[Sizing]>,
@@ -284,6 +306,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
regions,
styles,
rcols,
+ rrows: vec![],
lrows,
used: Size::zero(),
fr: Fr::zero(),
@@ -292,7 +315,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
}
/// Determines the columns sizes and then layouts the grid row-by-row.
- fn layout(mut self) -> SourceResult<Fragment> {
+ pub fn layout(mut self) -> SourceResult<GridLayout> {
self.measure_columns()?;
for y in 0..self.rows.len() {
@@ -313,7 +336,12 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
}
self.finish_region()?;
- Ok(Fragment::frames(self.finished))
+
+ Ok(GridLayout {
+ fragment: Fragment::frames(self.finished),
+ cols: self.rcols,
+ rows: self.rrows,
+ })
}
/// Determine all column sizes.
@@ -485,7 +513,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
// Layout into a single region.
if let &[first] = resolved.as_slice() {
let frame = self.layout_single_row(first, y)?;
- self.push_row(frame);
+ self.push_row(frame, y);
return Ok(());
}
@@ -508,7 +536,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
let fragment = self.layout_multi_row(&resolved, y)?;
let len = fragment.len();
for (i, frame) in fragment.into_iter().enumerate() {
- self.push_row(frame);
+ self.push_row(frame, y);
if i + 1 < len {
self.finish_region()?;
}
@@ -534,7 +562,7 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
}
}
- self.push_row(frame);
+ self.push_row(frame, y);
Ok(())
}
@@ -595,10 +623,10 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
}
/// Push a row frame into the current region.
- fn push_row(&mut self, frame: Frame) {
+ fn push_row(&mut self, frame: Frame, y: usize) {
self.regions.size.y -= frame.height();
self.used.y += frame.height();
- self.lrows.push(Row::Frame(frame));
+ self.lrows.push(Row::Frame(frame, y));
}
/// Finish rows for one region.
@@ -613,25 +641,28 @@ impl<'a, 'v> GridLayouter<'a, 'v> {
// The frame for the region.
let mut output = Frame::new(size);
let mut pos = Point::zero();
+ let mut rrows = vec![];
// Place finished rows and layout fractional rows.
for row in std::mem::take(&mut self.lrows) {
- let frame = match row {
- Row::Frame(frame) => frame,
+ let (frame, y) = match row {
+ Row::Frame(frame, y) => (frame, y),
Row::Fr(v, y) => {
let remaining = self.regions.full - self.used.y;
let height = v.share(self.fr, remaining);
- self.layout_single_row(height, y)?
+ (self.layout_single_row(height, y)?, y)
}
};
let height = frame.height();
output.push_frame(pos, frame);
+ rrows.push(RowPiece { height, y });
pos.y += height;
}
self.finished.push(output);
self.regions.next();
+ self.rrows.push(rrows);
self.used.y = Abs::zero();
self.fr = Fr::zero();
diff --git a/library/src/layout/table.rs b/library/src/layout/table.rs
index 1ceea9b9..3084c3d4 100644
--- a/library/src/layout/table.rs
+++ b/library/src/layout/table.rs
@@ -1,4 +1,4 @@
-use crate::layout::{AlignNode, GridNode, Sizing, TrackSizings};
+use crate::layout::{AlignNode, GridLayouter, Sizing, TrackSizings};
use crate::prelude::*;
/// # Table
@@ -153,13 +153,11 @@ impl Layout for TableNode {
styles: StyleChain,
regions: Regions,
) -> SourceResult<Fragment> {
- let fill = styles.get(Self::FILL);
- let stroke = styles.get(Self::STROKE).map(PartialStroke::unwrap_or_default);
let inset = styles.get(Self::INSET);
let align = styles.get(Self::ALIGN);
let cols = self.tracks.x.len().max(1);
- let cells = self
+ let cells: Vec<_> = self
.cells
.iter()
.cloned()
@@ -173,27 +171,81 @@ impl Layout for TableNode {
child = child.styled(AlignNode::ALIGNS, alignment)
}
- if let Some(stroke) = stroke {
- child = child.stroked(stroke);
- }
-
- if let Some(fill) = fill.resolve(vt, x, y)? {
- child = child.filled(fill);
- }
-
Ok(child)
})
.collect::<SourceResult<_>>()?;
- GridNode {
- tracks: self.tracks.clone(),
- gutter: self.gutter.clone(),
- cells,
+ let fill = styles.get(Self::FILL);
+ let stroke = styles.get(Self::STROKE).map(PartialStroke::unwrap_or_default);
+
+ // Prepare grid layout by unifying content and gutter tracks.
+ let layouter = GridLayouter::new(
+ vt,
+ self.tracks.as_deref(),
+ self.gutter.as_deref(),
+ &cells,
+ regions,
+ styles,
+ );
+
+ // Measure the columns and layout the grid row-by-row.
+ let mut layout = layouter.layout()?;
+
+ // Add lines and backgrounds.
+ for (frame, rows) in layout.fragment.iter_mut().zip(&layout.rows) {
+ // Render table lines.
+ if let Some(stroke) = stroke {
+ let thickness = stroke.thickness;
+ let half = thickness / 2.0;
+
+ // Render horizontal lines.
+ for offset in points(rows.iter().map(|piece| piece.height)) {
+ let target = Point::with_x(frame.width() + thickness);
+ let hline = Geometry::Line(target).stroked(stroke);
+ frame.prepend(Point::new(-half, offset), Element::Shape(hline));
+ }
+
+ // Render vertical lines.
+ for offset in points(layout.cols.iter().copied()) {
+ let target = Point::with_y(frame.height() + thickness);
+ let vline = Geometry::Line(target).stroked(stroke);
+ frame.prepend(Point::new(offset, -half), Element::Shape(vline));
+ }
+ }
+
+ // Render cell backgrounds.
+ let mut dx = Abs::zero();
+ for (x, &col) in layout.cols.iter().enumerate() {
+ let mut dy = Abs::zero();
+ for row in rows {
+ if let Some(fill) = fill.resolve(vt, x, row.y)? {
+ let pos = Point::new(dx, dy);
+ let size = Size::new(col, row.height);
+ let rect = Geometry::Rect(size).filled(fill);
+ frame.prepend(pos, Element::Shape(rect));
+ }
+ dy += row.height;
+ }
+ dx += col;
+ }
}
- .layout(vt, styles, regions)
+
+ Ok(layout.fragment)
}
}
+/// Turn an iterator extents into an iterator of offsets before, in between, and
+/// after the extents, e.g. [10mm, 5mm] -> [0mm, 10mm, 15mm].
+fn points(extents: impl IntoIterator<Item = Abs>) -> impl Iterator<Item = Abs> {
+ let mut offset = Abs::zero();
+ std::iter::once(Abs::zero())
+ .chain(extents.into_iter())
+ .map(move |extent| {
+ offset += extent;
+ offset
+ })
+}
+
/// A value that can be configured per cell.
#[derive(Debug, Clone, PartialEq, Hash)]
pub enum Celled<T> {
diff --git a/tests/ref/bugs/grid-1.png b/tests/ref/bugs/grid-1.png
index 6fd950ad..1ed227e9 100644
--- a/tests/ref/bugs/grid-1.png
+++ b/tests/ref/bugs/grid-1.png
Binary files differ
diff --git a/tests/ref/compiler/break-continue.png b/tests/ref/compiler/break-continue.png
index 401b3940..e81c29fd 100644
--- a/tests/ref/compiler/break-continue.png
+++ b/tests/ref/compiler/break-continue.png
Binary files differ
diff --git a/tests/ref/compute/data.png b/tests/ref/compute/data.png
index 678a1fd1..5b232083 100644
--- a/tests/ref/compute/data.png
+++ b/tests/ref/compute/data.png
Binary files differ
diff --git a/tests/ref/layout/grid-auto-shrink.png b/tests/ref/layout/grid-auto-shrink.png
index 851e8b7e..64b14f63 100644
--- a/tests/ref/layout/grid-auto-shrink.png
+++ b/tests/ref/layout/grid-auto-shrink.png
Binary files differ
diff --git a/tests/ref/layout/grid-rtl.png b/tests/ref/layout/grid-rtl.png
index 8b838480..d0cdb16e 100644
--- a/tests/ref/layout/grid-rtl.png
+++ b/tests/ref/layout/grid-rtl.png
Binary files differ
diff --git a/tests/ref/layout/par.png b/tests/ref/layout/par.png
index 199c8919..2c19ffcf 100644
--- a/tests/ref/layout/par.png
+++ b/tests/ref/layout/par.png
Binary files differ
diff --git a/tests/ref/layout/table.png b/tests/ref/layout/table.png
index f50f613b..9c91b892 100644
--- a/tests/ref/layout/table.png
+++ b/tests/ref/layout/table.png
Binary files differ
diff --git a/tests/ref/math/content.png b/tests/ref/math/content.png
index 46d5ef9b..728e1a1e 100644
--- a/tests/ref/math/content.png
+++ b/tests/ref/math/content.png
Binary files differ
diff --git a/tests/ref/text/shift.png b/tests/ref/text/shift.png
index 7e8d99a9..1316fb77 100644
--- a/tests/ref/text/shift.png
+++ b/tests/ref/text/shift.png
Binary files differ
diff --git a/tests/typ/layout/grid-rtl.typ b/tests/typ/layout/grid-rtl.typ
index 31015097..9c871424 100644
--- a/tests/typ/layout/grid-rtl.typ
+++ b/tests/typ/layout/grid-rtl.typ
@@ -6,4 +6,4 @@
---
#set text(dir: rtl)
-#table(columns: 2, gutter: 5pt)[A][B][C][D]
+#table(columns: 2)[A][B][C][D]