mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Store core context in grid layouter
This commit is contained in:
parent
a3262af014
commit
204cad6bd6
@ -39,6 +39,7 @@ impl Layout for GridNode {
|
|||||||
) -> TypResult<Vec<Arc<Frame>>> {
|
) -> TypResult<Vec<Arc<Frame>>> {
|
||||||
// Prepare grid layout by unifying content and gutter tracks.
|
// Prepare grid layout by unifying content and gutter tracks.
|
||||||
let layouter = GridLayouter::new(
|
let layouter = GridLayouter::new(
|
||||||
|
ctx,
|
||||||
self.tracks.as_deref(),
|
self.tracks.as_deref(),
|
||||||
self.gutter.as_deref(),
|
self.gutter.as_deref(),
|
||||||
&self.cells,
|
&self.cells,
|
||||||
@ -47,7 +48,7 @@ impl Layout for GridNode {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Measure the columns and layout the grid row-by-row.
|
// Measure the columns and layout the grid row-by-row.
|
||||||
layouter.layout(ctx)
|
layouter.layout()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,6 +92,8 @@ castable! {
|
|||||||
|
|
||||||
/// Performs grid layout.
|
/// Performs grid layout.
|
||||||
pub struct GridLayouter<'a> {
|
pub struct GridLayouter<'a> {
|
||||||
|
/// The core context.
|
||||||
|
ctx: &'a mut Context,
|
||||||
/// The grid cells.
|
/// The grid cells.
|
||||||
cells: &'a [LayoutNode],
|
cells: &'a [LayoutNode],
|
||||||
/// The column tracks including gutter tracks.
|
/// The column tracks including gutter tracks.
|
||||||
@ -130,6 +133,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
///
|
///
|
||||||
/// This prepares grid layout by unifying content and gutter tracks.
|
/// This prepares grid layout by unifying content and gutter tracks.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
|
ctx: &'a mut Context,
|
||||||
tracks: Spec<&[TrackSizing]>,
|
tracks: Spec<&[TrackSizing]>,
|
||||||
gutter: Spec<&[TrackSizing]>,
|
gutter: Spec<&[TrackSizing]>,
|
||||||
cells: &'a [LayoutNode],
|
cells: &'a [LayoutNode],
|
||||||
@ -183,6 +187,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
regions.expand = Spec::new(true, false);
|
regions.expand = Spec::new(true, false);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
ctx,
|
||||||
cells,
|
cells,
|
||||||
cols,
|
cols,
|
||||||
rows,
|
rows,
|
||||||
@ -198,19 +203,19 @@ impl<'a> GridLayouter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Determines the columns sizes and then layouts the grid row-by-row.
|
/// Determines the columns sizes and then layouts the grid row-by-row.
|
||||||
pub fn layout(mut self, ctx: &mut Context) -> TypResult<Vec<Arc<Frame>>> {
|
pub fn layout(mut self) -> TypResult<Vec<Arc<Frame>>> {
|
||||||
self.measure_columns(ctx)?;
|
self.measure_columns()?;
|
||||||
|
|
||||||
for y in 0 .. self.rows.len() {
|
for y in 0 .. self.rows.len() {
|
||||||
// Skip to next region if current one is full, but only for content
|
// Skip to next region if current one is full, but only for content
|
||||||
// rows, not for gutter rows.
|
// rows, not for gutter rows.
|
||||||
if y % 2 == 0 && self.regions.is_full() {
|
if y % 2 == 0 && self.regions.is_full() {
|
||||||
self.finish_region(ctx)?;
|
self.finish_region()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.rows[y] {
|
match self.rows[y] {
|
||||||
TrackSizing::Auto => self.layout_auto_row(ctx, y)?,
|
TrackSizing::Auto => self.layout_auto_row(y)?,
|
||||||
TrackSizing::Relative(v) => self.layout_relative_row(ctx, v, y)?,
|
TrackSizing::Relative(v) => self.layout_relative_row(v, y)?,
|
||||||
TrackSizing::Fractional(v) => {
|
TrackSizing::Fractional(v) => {
|
||||||
self.lrows.push(Row::Fr(v, y));
|
self.lrows.push(Row::Fr(v, y));
|
||||||
self.fr += v;
|
self.fr += v;
|
||||||
@ -218,12 +223,12 @@ impl<'a> GridLayouter<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.finish_region(ctx)?;
|
self.finish_region()?;
|
||||||
Ok(self.finished)
|
Ok(self.finished)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine all column sizes.
|
/// Determine all column sizes.
|
||||||
fn measure_columns(&mut self, ctx: &mut Context) -> TypResult<()> {
|
fn measure_columns(&mut self) -> TypResult<()> {
|
||||||
// Sum of sizes of resolved relative tracks.
|
// Sum of sizes of resolved relative tracks.
|
||||||
let mut rel = Length::zero();
|
let mut rel = Length::zero();
|
||||||
|
|
||||||
@ -249,7 +254,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
let available = self.regions.first.x - rel;
|
let available = self.regions.first.x - rel;
|
||||||
if available >= Length::zero() {
|
if available >= Length::zero() {
|
||||||
// Determine size of auto columns.
|
// Determine size of auto columns.
|
||||||
let (auto, count) = self.measure_auto_columns(ctx, available)?;
|
let (auto, count) = self.measure_auto_columns(available)?;
|
||||||
|
|
||||||
// If there is remaining space, distribute it to fractional columns,
|
// If there is remaining space, distribute it to fractional columns,
|
||||||
// otherwise shrink auto columns.
|
// otherwise shrink auto columns.
|
||||||
@ -270,11 +275,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Measure the size that is available to auto columns.
|
/// Measure the size that is available to auto columns.
|
||||||
fn measure_auto_columns(
|
fn measure_auto_columns(&mut self, available: Length) -> TypResult<(Length, usize)> {
|
||||||
&mut self,
|
|
||||||
ctx: &mut Context,
|
|
||||||
available: Length,
|
|
||||||
) -> TypResult<(Length, usize)> {
|
|
||||||
let mut auto = Length::zero();
|
let mut auto = Length::zero();
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
|
|
||||||
@ -300,7 +301,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
v.resolve(self.styles).relative_to(self.regions.base.y);
|
v.resolve(self.styles).relative_to(self.regions.base.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
let frame = node.layout(ctx, &pod, self.styles)?.remove(0);
|
let frame = node.layout(self.ctx, &pod, self.styles)?.remove(0);
|
||||||
resolved.set_max(frame.size.x);
|
resolved.set_max(frame.size.x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -354,7 +355,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
|
|
||||||
/// Layout a row with automatic height. Such a row may break across multiple
|
/// Layout a row with automatic height. Such a row may break across multiple
|
||||||
/// regions.
|
/// regions.
|
||||||
fn layout_auto_row(&mut self, ctx: &mut Context, y: usize) -> TypResult<()> {
|
fn layout_auto_row(&mut self, y: usize) -> TypResult<()> {
|
||||||
let mut resolved: Vec<Length> = vec![];
|
let mut resolved: Vec<Length> = vec![];
|
||||||
|
|
||||||
// Determine the size for each region of the row.
|
// Determine the size for each region of the row.
|
||||||
@ -370,7 +371,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut sizes = node
|
let mut sizes = node
|
||||||
.layout(ctx, &pod, self.styles)?
|
.layout(self.ctx, &pod, self.styles)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|frame| frame.size.y);
|
.map(|frame| frame.size.y);
|
||||||
|
|
||||||
@ -393,7 +394,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
|
|
||||||
// Layout into a single region.
|
// Layout into a single region.
|
||||||
if let &[first] = resolved.as_slice() {
|
if let &[first] = resolved.as_slice() {
|
||||||
let frame = self.layout_single_row(ctx, first, y)?;
|
let frame = self.layout_single_row(first, y)?;
|
||||||
self.push_row(frame);
|
self.push_row(frame);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -408,12 +409,12 @@ impl<'a> GridLayouter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Layout into multiple regions.
|
// Layout into multiple regions.
|
||||||
let frames = self.layout_multi_row(ctx, &resolved, y)?;
|
let frames = self.layout_multi_row(&resolved, y)?;
|
||||||
let len = frames.len();
|
let len = frames.len();
|
||||||
for (i, frame) in frames.into_iter().enumerate() {
|
for (i, frame) in frames.into_iter().enumerate() {
|
||||||
self.push_row(frame);
|
self.push_row(frame);
|
||||||
if i + 1 < len {
|
if i + 1 < len {
|
||||||
self.finish_region(ctx)?;
|
self.finish_region()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -422,19 +423,14 @@ impl<'a> GridLayouter<'a> {
|
|||||||
|
|
||||||
/// Layout a row with relative height. Such a row cannot break across
|
/// Layout a row with relative height. Such a row cannot break across
|
||||||
/// multiple regions, but it may force a region break.
|
/// multiple regions, but it may force a region break.
|
||||||
fn layout_relative_row(
|
fn layout_relative_row(&mut self, v: Relative<RawLength>, y: usize) -> TypResult<()> {
|
||||||
&mut self,
|
|
||||||
ctx: &mut Context,
|
|
||||||
v: Relative<RawLength>,
|
|
||||||
y: usize,
|
|
||||||
) -> TypResult<()> {
|
|
||||||
let resolved = v.resolve(self.styles).relative_to(self.regions.base.y);
|
let resolved = v.resolve(self.styles).relative_to(self.regions.base.y);
|
||||||
let frame = self.layout_single_row(ctx, resolved, y)?;
|
let frame = self.layout_single_row(resolved, y)?;
|
||||||
|
|
||||||
// Skip to fitting region.
|
// Skip to fitting region.
|
||||||
let height = frame.size.y;
|
let height = frame.size.y;
|
||||||
while !self.regions.first.y.fits(height) && !self.regions.in_last() {
|
while !self.regions.first.y.fits(height) && !self.regions.in_last() {
|
||||||
self.finish_region(ctx)?;
|
self.finish_region()?;
|
||||||
|
|
||||||
// Don't skip multiple regions for gutter and don't push a row.
|
// Don't skip multiple regions for gutter and don't push a row.
|
||||||
if y % 2 == 1 {
|
if y % 2 == 1 {
|
||||||
@ -448,12 +444,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Layout a row with fixed height and return its frame.
|
/// Layout a row with fixed height and return its frame.
|
||||||
fn layout_single_row(
|
fn layout_single_row(&mut self, height: Length, y: usize) -> TypResult<Frame> {
|
||||||
&self,
|
|
||||||
ctx: &mut Context,
|
|
||||||
height: Length,
|
|
||||||
y: usize,
|
|
||||||
) -> TypResult<Frame> {
|
|
||||||
let mut output = Frame::new(Size::new(self.used.x, height));
|
let mut output = Frame::new(Size::new(self.used.x, height));
|
||||||
let mut pos = Point::zero();
|
let mut pos = Point::zero();
|
||||||
|
|
||||||
@ -468,7 +459,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
.select(self.regions.base, size);
|
.select(self.regions.base, size);
|
||||||
|
|
||||||
let pod = Regions::one(size, base, Spec::splat(true));
|
let pod = Regions::one(size, base, Spec::splat(true));
|
||||||
let frame = node.layout(ctx, &pod, self.styles)?.remove(0);
|
let frame = node.layout(self.ctx, &pod, self.styles)?.remove(0);
|
||||||
output.push_frame(pos, frame);
|
output.push_frame(pos, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -480,8 +471,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
|
|
||||||
/// Layout a row spanning multiple regions.
|
/// Layout a row spanning multiple regions.
|
||||||
fn layout_multi_row(
|
fn layout_multi_row(
|
||||||
&self,
|
&mut self,
|
||||||
ctx: &mut Context,
|
|
||||||
heights: &[Length],
|
heights: &[Length],
|
||||||
y: usize,
|
y: usize,
|
||||||
) -> TypResult<Vec<Frame>> {
|
) -> TypResult<Vec<Frame>> {
|
||||||
@ -509,7 +499,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Push the layouted frames into the individual output frames.
|
// Push the layouted frames into the individual output frames.
|
||||||
let frames = node.layout(ctx, &pod, self.styles)?;
|
let frames = node.layout(self.ctx, &pod, self.styles)?;
|
||||||
for (output, frame) in outputs.iter_mut().zip(frames) {
|
for (output, frame) in outputs.iter_mut().zip(frames) {
|
||||||
output.push_frame(pos, frame);
|
output.push_frame(pos, frame);
|
||||||
}
|
}
|
||||||
@ -529,7 +519,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Finish rows for one region.
|
/// Finish rows for one region.
|
||||||
fn finish_region(&mut self, ctx: &mut Context) -> TypResult<()> {
|
fn finish_region(&mut self) -> TypResult<()> {
|
||||||
// Determine the size of the grid in this region, expanding fully if
|
// Determine the size of the grid in this region, expanding fully if
|
||||||
// there are fr rows.
|
// there are fr rows.
|
||||||
let mut size = self.used;
|
let mut size = self.used;
|
||||||
@ -548,7 +538,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
Row::Fr(v, y) => {
|
Row::Fr(v, y) => {
|
||||||
let remaining = self.full - self.used.y;
|
let remaining = self.full - self.used.y;
|
||||||
let height = v.share(self.fr, remaining);
|
let height = v.share(self.fr, remaining);
|
||||||
self.layout_single_row(ctx, height, y)?
|
self.layout_single_row(height, y)?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user