Store core context in grid layouter

This commit is contained in:
Laurenz 2022-05-16 15:39:08 +02:00
parent a3262af014
commit 204cad6bd6

View File

@ -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)?
} }
}; };