diff options
Diffstat (limited to 'src/layout/grid.rs')
| -rw-r--r-- | src/layout/grid.rs | 746 |
1 files changed, 343 insertions, 403 deletions
diff --git a/src/layout/grid.rs b/src/layout/grid.rs index 6ea99476..52e07d0d 100644 --- a/src/layout/grid.rs +++ b/src/layout/grid.rs @@ -16,9 +16,27 @@ pub struct GridNode { pub children: Vec<AnyNode>, } +/// Defines how to size a grid cell along an axis. +#[derive(Debug, Copy, Clone, PartialEq, Hash)] +pub enum TrackSizing { + /// Fit the cell to its contents. + Auto, + /// A length stated in absolute values and fractions of the parent's size. + Linear(Linear), + /// A length that is the fraction of the remaining free space in the parent. + Fractional(Fractional), +} + impl Layout for GridNode { fn layout(&self, ctx: &mut LayoutContext, regions: &Regions) -> Vec<Frame> { - GridLayouter::new(self, regions.clone()).layout(ctx) + // Prepare grid layout by unifying content and gutter tracks. + let mut layouter = GridLayouter::new(self, regions.clone()); + + // Determine all column sizes. + layouter.measure_columns(ctx); + + // Layout the grid row-by-row. + layouter.layout(ctx) } } @@ -28,125 +46,123 @@ impl From<GridNode> for AnyNode { } } -#[derive(Debug)] +/// Performs grid layout. struct GridLayouter<'a> { + /// The axis of the cross direction. cross: SpecAxis, + /// The axis of the main direction. main: SpecAxis, + /// The column tracks including gutter tracks. cols: Vec<TrackSizing>, + /// The row tracks including gutter tracks. rows: Vec<TrackSizing>, - cells: Vec<Cell<'a>>, + /// The children of the grid. + children: &'a [AnyNode], + /// The region to layout into. regions: Regions, + /// Resolved column sizes. rcols: Vec<Length>, - rrows: Vec<(usize, Option<Length>, Option<Vec<Option<Frame>>>)>, + /// The full main size of the current region. + full: Length, + /// The used-up size of the current region. The cross size is determined + /// once after columns are resolved and not touched again. + used: Gen<Length>, + /// The sum of fractional ratios in the current region. + fr: Fractional, + /// Rows in the current region. + lrows: Vec<Row>, + /// Frames for finished regions. finished: Vec<Frame>, } -#[derive(Debug)] -enum Cell<'a> { - Node(&'a AnyNode), - Gutter, +/// Produced by initial row layout, auto and linear rows are already finished, +/// fractional rows not yet. +enum Row { + /// Finished row frame of auto or linear row. + Frame(Frame), + /// Ratio of a fractional row and y index of the track. + Fr(Fractional, usize), } impl<'a> GridLayouter<'a> { - fn new(grid: &'a GridNode, regions: Regions) -> Self { - let cross = grid.dirs.cross.axis(); - let main = grid.dirs.main.axis(); - + /// Prepare grid layout by unifying content and gutter tracks. + fn new(grid: &'a GridNode, mut regions: Regions) -> Self { let mut cols = vec![]; let mut rows = vec![]; - let mut cells = vec![]; - // A grid always needs to have at least one column. - let content_cols = grid.tracks.cross.len().max(1); + // Number of content columns: Always at least one. + let c = grid.tracks.cross.len().max(1); - // Create at least as many rows as specified and also at least as many - // as necessary to place each item. - let content_rows = { + // 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 specified = grid.tracks.main.len(); - let necessary = len / content_cols + (len % content_cols).clamp(0, 1); - specified.max(necessary) + let given = grid.tracks.main.len(); + let needed = len / c + (len % c).clamp(0, 1); + given.max(needed) }; - // Collect the track sizing for all columns, including gutter columns. - for i in 0 .. content_cols { - cols.push(grid.tracks.cross.get_or_last(i)); - if i < content_cols - 1 { - cols.push(grid.gutter.cross.get_or_last(i)); - } - } + let auto = TrackSizing::Auto; + let zero = TrackSizing::Linear(Linear::zero()); + let get_or = |tracks: &[_], idx, default| { + tracks.get(idx).or(tracks.last()).copied().unwrap_or(default) + }; - // Collect the track sizing for all rows, including gutter rows. - for i in 0 .. content_rows { - rows.push(grid.tracks.main.get_or_last(i)); - if i < content_rows - 1 { - rows.push(grid.gutter.main.get_or_last(i)); - } + // Collect content and gutter columns. + for x in 0 .. c { + cols.push(get_or(&grid.tracks.cross, x, auto)); + cols.push(get_or(&grid.gutter.cross, x, zero)); } - // Build up the matrix of cells, including gutter cells. - for (i, item) in grid.children.iter().enumerate() { - cells.push(Cell::Node(item)); - - let row = i / content_cols; - let col = i % content_cols; - - if col < content_cols - 1 { - // Push gutter after each child. - cells.push(Cell::Gutter); - } else if row < content_rows - 1 { - // Except for the last child of each row. - // There we push a gutter row. - for _ in 0 .. cols.len() { - cells.push(Cell::Gutter); - } - } + // Collect content and gutter rows. + for y in 0 .. r { + rows.push(get_or(&grid.tracks.main, y, auto)); + rows.push(get_or(&grid.gutter.main, y, zero)); } - // Fill the thing up. - while cells.len() < cols.len() * rows.len() { - cells.push(Cell::Gutter); - } + // Remove superfluous gutter tracks. + cols.pop(); + rows.pop(); + + let cross = grid.dirs.cross.axis(); + let main = grid.dirs.main.axis(); + let full = regions.current.get(main); + let rcols = vec![Length::zero(); cols.len()]; + + // We use the regions only for auto row measurement. + regions.expand = Gen::new(true, false).to_spec(main); Self { cross, main, cols, rows, - cells, + children: &grid.children, regions, - rcols: vec![], - rrows: vec![], + rcols, + lrows: vec![], + full, + used: Gen::zero(), + fr: Fractional::zero(), finished: vec![], } } - fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Frame> { - self.rcols = self.resolve_columns(ctx); - self.layout_rows(ctx); - self.finished - } + /// Determine all column sizes. + fn measure_columns(&mut self, ctx: &mut LayoutContext) { + // Sum of sizes of resolved linear tracks. + let mut linear = Length::zero(); - /// Determine the size of all columns. - fn resolve_columns(&self, ctx: &mut LayoutContext) -> Vec<Length> { + // Sum of fractions of all fractional tracks. + let mut fr = Fractional::zero(); + + // Generic version of current and base size. let current = self.regions.current.to_gen(self.main); let base = self.regions.base.to_gen(self.main); - // Prepare vector for resolved column lengths. - let mut rcols = vec![Length::zero(); self.cols.len()]; - - // - Sum of sizes of resolved linear tracks, - // - Sum of fractions of all fractional tracks, - // - Sum of sizes of resolved (through layouting) auto tracks, - // - Number of auto tracks. - let mut linear = Length::zero(); - let mut fr = Fractional::zero(); - let mut auto = Length::zero(); - let mut auto_count = 0; - - // Resolve size of linear columns and compute the sum of all fractional - // tracks. - for (&col, rcol) in self.cols.iter().zip(&mut rcols) { + // Resolve the size of all linear columns and compute the sum of all + // fractional tracks. + for (&col, rcol) in self.cols.iter().zip(&mut self.rcols) { match col { TrackSizing::Auto => {} TrackSizing::Linear(v) => { @@ -158,379 +174,303 @@ impl<'a> GridLayouter<'a> { } } - // Size available to auto columns (not used by fixed-size columns). + // Size that is not used by fixed-size columns. let available = current.cross - linear; - if available <= Length::zero() { - return rcols; + if available >= Length::zero() { + // Determine size of auto columns. + let (auto, count) = self.measure_auto_columns(ctx, available); + + // If there is remaining space, distribute it to fractional columns, + // otherwise shrink auto columns. + let remaining = available - auto; + if remaining >= Length::zero() { + self.grow_fractional_columns(remaining, fr); + } else { + self.shrink_auto_columns(available, count); + } } - // Resolve size of auto columns by laying out all cells in those + self.used.cross = self.rcols.iter().sum(); + } + + /// Measure the size that is available to auto columns. + fn measure_auto_columns( + &mut self, + ctx: &mut LayoutContext, + available: Length, + ) -> (Length, usize) { + let mut auto = Length::zero(); + let mut count = 0; + + // Determine size of auto columns by laying out all cells in those // columns, measuring them and finding the largest one. - for (x, (&col, rcol)) in self.cols.iter().zip(&mut rcols).enumerate() { - if col == TrackSizing::Auto { - let mut resolved = Length::zero(); - - for (y, &row) in self.rows.iter().enumerate() { - if let Cell::Node(node) = self.get(x, y) { - // Set the correct main size if the row is fixed-size. - let main = match row { - TrackSizing::Linear(v) => v.resolve(base.main), - _ => current.main, - }; - - let size = Gen::new(available, main).to_size(self.main); - let regions = Regions::one(size, Spec::splat(false)); - let frame = node.layout(ctx, ®ions).remove(0); - resolved = resolved.max(frame.size.get(self.cross)) - } - } + for (x, &col) in self.cols.iter().enumerate() { + if col != TrackSizing::Auto { + continue; + } - *rcol = resolved; - auto += resolved; - auto_count += 1; + let mut resolved = Length::zero(); + for node in (0 .. self.rows.len()).filter_map(|y| self.cell(x, y)) { + let size = Gen::new(available, Length::inf()).to_size(self.main); + let regions = Regions::one(size, Spec::splat(false)); + let frame = node.layout(ctx, ®ions).remove(0); + resolved.set_max(frame.size.get(self.cross)); } + + self.rcols[x] = resolved; + auto += resolved; + count += 1; } - // If there is remaining space, distribute it to fractional columns, - // otherwise shrink auto columns. - let remaining = available - auto; - if remaining >= Length::zero() { - for (&col, rcol) in self.cols.iter().zip(&mut rcols) { - if let TrackSizing::Fractional(v) = col { - let ratio = v / fr; - if ratio.is_finite() { - *rcol = ratio * remaining; - } - } - } - } else { - // The fair share each auto column may have. - let fair = available / auto_count as f64; - - // The number of overlarge auto columns and the space that will be - // equally redistributed to them. - let mut overlarge: usize = 0; - let mut redistribute = available; - - for (&col, rcol) in self.cols.iter().zip(&mut rcols) { - if col == TrackSizing::Auto { - if *rcol > fair { - overlarge += 1; - } else { - redistribute -= *rcol; - } + (auto, count) + } + + /// Distribute remaining space to fractional columns. + fn grow_fractional_columns(&mut self, remaining: Length, fr: Fractional) { + for (&col, rcol) in self.cols.iter().zip(&mut self.rcols) { + if let TrackSizing::Fractional(v) = col { + let ratio = v / fr; + if ratio.is_finite() { + *rcol = ratio * remaining; } } + } + } - // Redistribute the space equally. - let share = redistribute / overlarge as f64; - if overlarge > 0 { - for (&col, rcol) in self.cols.iter().zip(&mut rcols) { - if col == TrackSizing::Auto && *rcol > fair { - *rcol = share; - } + /// Redistribute space to auto columns so that each gets a fair share. + fn shrink_auto_columns(&mut self, available: Length, count: usize) { + // The fair share each auto column may have. + let fair = available / count as f64; + + // The number of overlarge auto columns and the space that will be + // equally redistributed to them. + let mut overlarge: usize = 0; + let mut redistribute = available; + + // Find out the number of and space used by overlarge auto columns. + for (&col, rcol) in self.cols.iter().zip(&mut self.rcols) { + if col == TrackSizing::Auto { + if *rcol > fair { + overlarge += 1; + } else { + redistribute -= *rcol; } } } - rcols + // Redistribute the space equally. + let share = redistribute / overlarge as f64; + for (&col, rcol) in self.cols.iter().zip(&mut self.rcols) { + if col == TrackSizing::Auto && *rcol > fair { + *rcol = share; + } + } } - fn layout_rows(&mut self, ctx: &mut LayoutContext) { - // Determine non-`fr` row heights - let mut total_frs = 0.0; - let mut current = self.regions.current.get(self.main); - + /// Layout the grid row-by-row. + fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Frame> { for y in 0 .. self.rows.len() { - let resolved = match self.rows[y] { - TrackSizing::Linear(l) => { - (Some(l.resolve(self.regions.base.get(self.main))), None) - } + match self.rows[y] { TrackSizing::Auto => { - let mut max = Length::zero(); - let mut local_max = max; - let mut multi_region = false; - let mut last_size = vec![]; - for (x, &col_size) in self.rcols.iter().enumerate() { - if let Cell::Node(node) = self.get(x, y) { - let colsize = Gen::new(col_size, current).to_size(self.main); - - let mut regions = self.regions.map(|mut s| { - *s.get_mut(self.cross) = col_size; - s - }); - - regions.base = colsize; - regions.current = colsize; - regions.expand = Spec::splat(false); - - let mut frames = node.layout(ctx, ®ions); - multi_region |= frames.len() > 1; - last_size.push(( - frames.len() - 1, - frames.last().unwrap().size.get(self.main), - )); - let frame = frames.remove(0); - local_max = local_max.max(frame.size.get(self.main)); - - if !multi_region { - max = local_max; - } - } else { - last_size.push((0, Length::zero())) - } - } - - let overshoot = if multi_region { - self.rrows.push((y, Some(local_max), None)); - let res = self.finish_region(ctx, total_frs, Some(last_size)); - max = if let Some(overflow) = res.as_ref() { - overflow - .iter() - .filter_map(|x| x.as_ref()) - .map(|x| x.size.get(self.main)) - .max() - .unwrap_or(Length::zero()) - } else { - local_max - }; - - current = self.regions.current.get(self.main); - total_frs = 0.0; - if res.is_none() { - continue; - } - - res - } else { - None - }; - - // If multi-region results: finish_regions, returning - // the last non-set frames. - (Some(max), overshoot) + self.layout_auto_row(ctx, y); } - TrackSizing::Fractional(f) => { - total_frs += f.get(); - (None, None) + TrackSizing::Linear(v) => { + let base = self.regions.base.get(self.main); + let resolved = v.resolve(base); + let frame = self.layout_single_row(ctx, resolved, y); + self.push_row(ctx, frame); } - }; - - if let (Some(resolved), _) = resolved { - while !current.fits(resolved) && !self.regions.in_full_last() { - self.finish_region(ctx, total_frs, None); - current = self.regions.current.get(self.main); - total_frs = 0.0; + TrackSizing::Fractional(v) => { + self.fr += v; + self.lrows.push(Row::Fr(v, y)); } - current -= resolved; } - - self.rrows.push((y, resolved.0, resolved.1)); } - self.finish_region(ctx, total_frs, None); + self.finish_region(ctx); + self.finished } - fn finish_region( - &mut self, - ctx: &mut LayoutContext, - total_frs: f64, - multiregion_sizing: Option<Vec<(usize, Length)>>, - ) -> Option<Vec<Option<Frame>>> { - if self.rrows.is_empty() { - return None; + /// Layout a row with automatic size along the main axis. Such a row may + /// break across multiple regions. + fn layout_auto_row(&mut self, ctx: &mut LayoutContext, y: usize) { + let mut first = Length::zero(); + let mut rest: Vec<Length> = vec![]; + + // Determine the size for each region of the row. + for (x, &rcol) in self.rcols.iter().enumerate() { + if let Some(node) = self.cell(x, y) { + let cross = self.cross; + self.regions.mutate(|size| *size.get_mut(cross) = rcol); + + let mut sizes = node + .layout(ctx, &self.regions) + .into_iter() + .map(|frame| frame.size.get(self.main)); + + if let Some(size) = sizes.next() { + first.set_max(size); + } + + for (resolved, size) in rest.iter_mut().zip(&mut sizes) { + resolved.set_max(size); + } + + rest.extend(sizes); + } } - let mut pos = Gen::splat(Length::zero()); - let frame = Frame::new(Size::zero(), Length::zero()); - let mut total_cross = Length::zero(); - let mut total_main = Length::zero(); - let mut max_regions = 0; - let mut collected_frames = if multiregion_sizing.is_some() { - Some(vec![None; self.rcols.len()]) + // Layout the row. + if rest.is_empty() { + let frame = self.layout_single_row(ctx, first, y); + self.push_row(ctx, frame); } else { - None - }; + let frames = self.layout_multi_row(ctx, first, &rest, y); + for frame in frames { + self.push_row(ctx, frame); + } + } + } - self.finished.push(frame); + /// Layout a row with a fixed size along the main axis. + fn layout_single_row( + &self, + ctx: &mut LayoutContext, + length: Length, + y: usize, + ) -> Frame { + let size = self.to_size(length); + let mut output = Frame::new(size, size.height); + let mut pos = Gen::zero(); + + for (x, &rcol) in self.rcols.iter().enumerate() { + if let Some(node) = self.cell(x, y) { + let size = Gen::new(rcol, length).to_size(self.main); + let regions = Regions::one(size, Spec::splat(true)); + let frame = node.layout(ctx, ®ions).remove(0); + output.push_frame(pos.to_point(self.main), frame); + } - let frame_len = self.finished.len(); + pos.cross += rcol; + } - let total_row_height: Length = self.rrows.iter().filter_map(|(_, x, _)| *x).sum(); + output + } - for &(y, h, ref layouted) in self.rrows.iter().as_ref() { - let last = self.rrows.last().map_or(false, |(o, _, _)| &y == o); - let available = self.regions.current.get(self.main) - total_row_height; - let h = if let Some(len) = h { - len - } else if let TrackSizing::Fractional(f) = self.rows[y] { - if total_frs > 0.0 { - let res = available * (f.get() / total_frs); - if res.is_finite() { res } else { Length::zero() } - } else { - Length::zero() - } - } else { - unreachable!("non-fractional tracks are already resolved"); - }; - total_main += h; - - if let Some(layouted) = layouted { - for (col_index, frame) in layouted.into_iter().enumerate() { - if let Some(frame) = frame { - self.finished - .get_mut(frame_len - 1) - .unwrap() - .push_frame(pos.to_point(self.main), frame.clone()); - } - pos.cross += self.rcols[col_index]; + /// Layout a row spanning multiple regions. + fn layout_multi_row( + &self, + ctx: &mut LayoutContext, + first: Length, + rest: &[Length], + y: usize, + ) -> Vec<Frame> { + // Prepare frames. + let mut outputs: Vec<_> = std::iter::once(first) + .chain(rest.iter().copied()) + .map(|v| self.to_size(v)) + .map(|size| Frame::new(size, size.height)) + .collect(); + + // Prepare regions. + let mut regions = Regions::one(self.to_size(first), Spec::splat(true)); + regions.backlog = rest.iter().rev().map(|&v| self.to_size(v)).collect(); + + // Layout the row. + let mut pos = Gen::zero(); + for (x, &rcol) in self.rcols.iter().enumerate() { + if let Some(node) = self.cell(x, y) { + regions.mutate(|size| *size.get_mut(self.cross) = rcol); + + // Push the layouted frames into the individual output frames. + let frames = node.layout(ctx, ®ions); + for (output, frame) in outputs.iter_mut().zip(frames) { + output.push_frame(pos.to_point(self.main), frame); } - } else { - let mut overshoot_columns = vec![]; - for (x, &w) in self.rcols.iter().enumerate() { - let element = self.get(x, y); - - if y == 0 { - total_cross += w; - } + } - if let Cell::Node(n) = element { - let region_size = Gen::new(w, h).to_size(self.main); - let regions = if last { - if let Some(last_sizes) = multiregion_sizing.as_ref() { - let mut regions = self.regions.map(|mut s| { - *s.get_mut(self.cross) = w; - s - }); - - regions.base = region_size; - regions.current = region_size; - regions.expand = Spec::splat(true); - - let (last_region, last_size) = last_sizes[x]; - regions.unique_regions(last_region + 1); - *regions - .nth_mut(last_region) - .unwrap() - .get_mut(self.main) = last_size; - regions - } else { - Regions::one(region_size, Spec::splat(true)) - } - } else { - Regions::one(region_size, Spec::splat(true)) - }; - let mut items = n.layout(ctx, ®ions); - let item = items.remove(0); - - if last && multiregion_sizing.is_some() { - max_regions = max_regions.max(items.len()); - overshoot_columns.push((x, items)); - } else { - assert_eq!(items.len(), 0); - } - - self.finished - .get_mut(frame_len - 1) - .unwrap() - .push_frame(pos.to_point(self.main), item); - } + pos.cross += rcol; + } - pos.cross += w; - } + outputs + } - if overshoot_columns.iter().any(|(_, items)| !items.is_empty()) { - for (x, col) in overshoot_columns { - let mut cross_offset = Length::zero(); - for col in 0 .. x { - cross_offset += self.rcols[col]; - } - - - let collected_frames = collected_frames.as_mut().unwrap(); - *collected_frames.get_mut(x).unwrap() = - col.get(max_regions - 1).cloned(); - - for (cell_index, subcell) in col.into_iter().enumerate() { - if cell_index >= max_regions - 1 { - continue; - } - let frame = if let Some(frame) = - self.finished.get_mut(frame_len + cell_index) - { - frame - } else { - let frame = Frame::new(Size::zero(), Length::zero()); - // The previous frame always exists: either the - // last iteration created it or it is the normal - // frame. - self.finished.push(frame); - self.finished.last_mut().unwrap() - }; - let pos = Gen::new(cross_offset, Length::zero()); - frame - .size - .get_mut(self.cross) - .set_max(pos.cross + subcell.size.get(self.cross)); - frame - .size - .get_mut(self.main) - .set_max(subcell.size.get(self.main)); - frame.baseline = frame.size.height; - frame.push_frame(pos.to_point(self.main), subcell); - } - } - } - } + /// Push a row frame into the current or next fitting region, finishing + /// regions (including layouting fractional rows) if necessary. + fn push_row(&mut self, ctx: &mut LayoutContext, frame: Frame) { + let length = frame.size.get(self.main); - pos.cross = Length::zero(); - pos.main += h; + // Skip to fitting region. + while !self.regions.current.get(self.main).fits(length) + && !self.regions.in_full_last() + { + self.finish_region(ctx); } - let frame = self.finished.get_mut(frame_len - 1).unwrap(); - frame.size = Gen::new(total_cross, total_main).to_size(self.main); - frame.baseline = frame.size.height; + *self.regions.current.get_mut(self.main) -= length; + self.used.main += length; + self.lrows.push(Row::Frame(frame)); + } - self.rrows.clear(); - for _ in 0 .. (max_regions.max(1)) { - self.regions.next(); - } + /// Finish rows for one region. + fn finish_region(&mut self, ctx: &mut LayoutContext) { + // Determine the size of the region. + let length = if self.fr.is_zero() { self.used.main } else { self.full }; + let size = self.to_size(length); + + // The frame for the region. + let mut output = Frame::new(size, size.height); + let mut pos = Gen::zero(); + + // Determine the remaining size for fractional rows. + let remaining = self.full - self.used.main; + + // Place finished rows and layout fractional rows. + for row in std::mem::take(&mut self.lrows) { + let frame = match row { + Row::Frame(frame) => frame, + Row::Fr(v, y) => { + let ratio = v / self.fr; + if remaining > Length::zero() && ratio.is_finite() { + let resolved = ratio * remaining; + self.layout_single_row(ctx, resolved, y) + } else { + continue; + } + } + }; - if let Some(frames) = collected_frames.as_ref() { - if frames.iter().all(|i| i.is_none()) { - collected_frames = None; - } + let main = frame.size.get(self.main); + output.push_frame(pos.to_point(self.main), frame); + pos.main += main; } - collected_frames + self.regions.next(); + self.full = self.regions.current.get(self.main); + self.used.main = Length::zero(); + self.fr = Fractional::zero(); + self.finished.push(output); } - fn get(&self, x: usize, y: usize) -> &Cell<'a> { + /// Get the node in the cell in column `x` and row `y`. + /// + /// Returns `None` if it's a gutter cell. + fn cell(&self, x: usize, y: usize) -> Option<&'a AnyNode> { assert!(x < self.cols.len()); assert!(y < self.rows.len()); - self.cells.get(y * self.cols.len() + x).unwrap() - } -} - -trait TracksExt { - /// Get the sizing for the track at the given `idx` or fallback to the - /// last defined track or `auto`. - fn get_or_last(&self, idx: usize) -> TrackSizing; -} -impl TracksExt for Vec<TrackSizing> { - fn get_or_last(&self, idx: usize) -> TrackSizing { - self.get(idx).or(self.last()).copied().unwrap_or(TrackSizing::Auto) + // 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) + } else { + None + } } -} -/// Defines how to size a grid cell along an axis. -#[derive(Debug, Copy, Clone, PartialEq, Hash)] -pub enum TrackSizing { - /// Fit the cell to its contents. - Auto, - /// A length stated in absolute values and fractions of the parent's size. - Linear(Linear), - /// A length that is the fraction of the remaining free space in the parent. - Fractional(Fractional), + /// Return a size where the cross axis spans the whole grid and the main + /// axis the given length. + fn to_size(&self, main_size: Length) -> Size { + Gen::new(self.used.cross, main_size).to_size(self.main) + } } |
