diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-02-03 15:25:47 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-02-03 15:25:47 +0100 |
| commit | bdc7127adfdb52a79459f13a37c93d367241f434 (patch) | |
| tree | 6a2cd121155b00bd4b43c15fffe7060f890a2375 /src/library/grid.rs | |
| parent | f9d380249295280ebf84900d726c3baca565d511 (diff) | |
Refactor flow, stack and grid layouters a bit
Diffstat (limited to 'src/library/grid.rs')
| -rw-r--r-- | src/library/grid.rs | 102 |
1 files changed, 58 insertions, 44 deletions
diff --git a/src/library/grid.rs b/src/library/grid.rs index d681ae7d..59fe8486 100644 --- a/src/library/grid.rs +++ b/src/library/grid.rs @@ -40,12 +40,15 @@ impl Layout for GridNode { styles: StyleChain, ) -> Vec<Constrained<Arc<Frame>>> { // Prepare grid layout by unifying content and gutter tracks. - let mut layouter = GridLayouter::new(self, regions.clone(), styles); - - // Determine all column sizes. - layouter.measure_columns(ctx); + let layouter = GridLayouter::new( + self.tracks.as_deref(), + self.gutter.as_deref(), + &self.children, + regions, + styles, + ); - // Layout the grid row-by-row. + // Measure the columsna nd layout the grid row-by-row. layouter.layout(ctx) } } @@ -87,9 +90,9 @@ castable! { } /// Performs grid layout. -struct GridLayouter<'a> { - /// The children of the grid. - children: &'a [PackedNode], +pub struct GridLayouter<'a> { + /// The grid cells. + cells: &'a [PackedNode], /// The column tracks including gutter tracks. cols: Vec<TrackSizing>, /// The row tracks including gutter tracks. @@ -102,7 +105,7 @@ struct GridLayouter<'a> { rcols: Vec<Length>, /// Rows in the current region. lrows: Vec<Row>, - /// Whether the grid should expand to fill the region. + /// Whether the grid itself should expand to fill the region. expand: Spec<bool>, /// The full height of the current region. full: Length, @@ -127,19 +130,27 @@ enum Row { } impl<'a> GridLayouter<'a> { - /// Prepare grid layout by unifying content and gutter tracks. - fn new(grid: &'a GridNode, mut regions: Regions, styles: StyleChain<'a>) -> Self { + /// Create a new grid layouter. + /// + /// This prepares grid layout by unifying content and gutter tracks. + pub fn new( + tracks: Spec<&[TrackSizing]>, + gutter: Spec<&[TrackSizing]>, + cells: &'a [PackedNode], + regions: &Regions, + styles: StyleChain<'a>, + ) -> Self { let mut cols = vec![]; let mut rows = vec![]; // Number of content columns: Always at least one. - let c = grid.tracks.x.len().max(1); + let c = tracks.x.len().max(1); // Number of content rows: At least as many as given, but also at least // as many as needed to place each item. let r = { - let len = grid.children.len(); - let given = grid.tracks.y.len(); + let len = cells.len(); + let given = tracks.y.len(); let needed = len / c + (len % c).clamp(0, 1); given.max(needed) }; @@ -152,14 +163,14 @@ impl<'a> GridLayouter<'a> { // Collect content and gutter columns. for x in 0 .. c { - cols.push(get_or(&grid.tracks.x, x, auto)); - cols.push(get_or(&grid.gutter.x, x, zero)); + cols.push(get_or(tracks.x, x, auto)); + cols.push(get_or(gutter.x, x, zero)); } // Collect content and gutter rows. for y in 0 .. r { - rows.push(get_or(&grid.tracks.y, y, auto)); - rows.push(get_or(&grid.gutter.y, y, zero)); + rows.push(get_or(tracks.y, y, auto)); + rows.push(get_or(gutter.y, y, zero)); } // Remove superfluous gutter tracks. @@ -173,10 +184,11 @@ impl<'a> GridLayouter<'a> { // We use the regions for auto row measurement. Since at that moment, // columns are already sized, we can enable horizontal expansion. + let mut regions = regions.clone(); regions.expand = Spec::new(true, false); Self { - children: &grid.children, + cells, cols, rows, regions, @@ -192,6 +204,32 @@ impl<'a> GridLayouter<'a> { } } + /// Determines the columns sizes and then layouts the grid row-by-row. + pub fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Arc<Frame>>> { + self.measure_columns(ctx); + + for y in 0 .. self.rows.len() { + // Skip to next region if current one is full, but only for content + // rows, not for gutter rows. + if y % 2 == 0 && self.regions.is_full() { + self.finish_region(ctx); + } + + match self.rows[y] { + TrackSizing::Auto => self.layout_auto_row(ctx, y), + TrackSizing::Linear(v) => self.layout_linear_row(ctx, v, y), + TrackSizing::Fractional(v) => { + self.cts.exact.y = Some(self.full); + self.lrows.push(Row::Fr(v, y)); + self.fr += v; + } + } + } + + self.finish_region(ctx); + self.finished + } + /// Determine all column sizes. fn measure_columns(&mut self, ctx: &mut LayoutContext) { enum Case { @@ -354,30 +392,6 @@ impl<'a> GridLayouter<'a> { } } - /// Layout the grid row-by-row. - fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Arc<Frame>>> { - for y in 0 .. self.rows.len() { - // Skip to next region if current one is full, but only for content - // rows, not for gutter rows. - if y % 2 == 0 && self.regions.is_full() { - self.finish_region(ctx); - } - - match self.rows[y] { - TrackSizing::Auto => self.layout_auto_row(ctx, y), - TrackSizing::Linear(v) => self.layout_linear_row(ctx, v, y), - TrackSizing::Fractional(v) => { - self.cts.exact.y = Some(self.full); - self.lrows.push(Row::Fr(v, y)); - self.fr += v; - } - } - } - - self.finish_region(ctx); - self.finished - } - /// Layout a row with automatic height. Such a row may break across multiple /// regions. fn layout_auto_row(&mut self, ctx: &mut LayoutContext, y: usize) { @@ -599,7 +613,7 @@ impl<'a> GridLayouter<'a> { // Even columns and rows are children, odd ones are gutter. if x % 2 == 0 && y % 2 == 0 { let c = 1 + self.cols.len() / 2; - self.children.get((y / 2) * c + x / 2) + self.cells.get((y / 2) * c + x / 2) } else { None } |
