diff options
Diffstat (limited to 'src/layout')
| -rw-r--r-- | src/layout/fixed.rs | 6 | ||||
| -rw-r--r-- | src/layout/mod.rs | 63 | ||||
| -rw-r--r-- | src/layout/pad.rs | 6 | ||||
| -rw-r--r-- | src/layout/par.rs | 21 | ||||
| -rw-r--r-- | src/layout/stack.rs | 21 |
5 files changed, 58 insertions, 59 deletions
diff --git a/src/layout/fixed.rs b/src/layout/fixed.rs index cb69b178..60dbe4d6 100644 --- a/src/layout/fixed.rs +++ b/src/layout/fixed.rs @@ -14,10 +14,10 @@ pub struct NodeFixed { impl Layout for NodeFixed { fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Layouted { - let Area { rem, full } = areas.current; + let Areas { current, full, .. } = areas; let size = Size::new( - self.width.map(|w| w.resolve(full.width)).unwrap_or(rem.width), - self.height.map(|h| h.resolve(full.height)).unwrap_or(rem.height), + self.width.map(|w| w.resolve(full.width)).unwrap_or(current.width), + self.height.map(|h| h.resolve(full.height)).unwrap_or(current.height), ); let areas = Areas::once(size); diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 30026b9f..714bac4b 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -71,27 +71,13 @@ pub struct LayoutContext { pub env: SharedEnv, } -/// An area into which content can be laid out. -#[derive(Debug, Copy, Clone, PartialEq)] -pub struct Area { - /// The remaining size of this area. - pub rem: Size, - /// The full size this area once had (used for relative sizing). - pub full: Size, -} - -impl Area { - /// Create a new area. - pub fn new(size: Size) -> Self { - Self { rem: size, full: size } - } -} - /// A collection of areas to layout into. #[derive(Debug, Clone, PartialEq)] pub struct Areas { - /// The current area. - pub current: Area, + /// The remaining size of the current area. + pub current: Size, + /// The full size the current area once had (used for relative sizing). + pub full: Size, /// A stack of followup areas (the next area is the last element). pub backlog: Vec<Size>, /// The final area that is repeated when the backlog is empty. @@ -102,7 +88,8 @@ impl Areas { /// Create a new length-1 sequence of areas with just one `area`. pub fn once(size: Size) -> Self { Self { - current: Area::new(size), + current: size, + full: size, backlog: vec![], last: None, } @@ -111,7 +98,8 @@ impl Areas { /// Create a new sequence of areas that repeats `area` indefinitely. pub fn repeat(size: Size) -> Self { Self { - current: Area::new(size), + current: size, + full: size, backlog: vec![], last: Some(size), } @@ -120,7 +108,8 @@ impl Areas { /// Advance to the next area if there is any. pub fn next(&mut self) { if let Some(size) = self.backlog.pop().or(self.last) { - self.current = Area::new(size); + self.current = size; + self.full = size; } } @@ -130,11 +119,32 @@ impl Areas { pub fn in_full_last(&self) -> bool { self.backlog.is_empty() && self.last.map_or(true, |size| { - self.current.rem.is_nan() || size.is_nan() || self.current.rem == size + self.current.is_nan() || size.is_nan() || self.current == size }) } } +/// Whether to expand or shrink a node along an axis. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum Expansion { + /// Fit the content. + Fit, + /// Fill the available space. + Fill, +} + +impl Expansion { + /// Resolve the expansion to either the `fit` or `fill` length. + /// + /// Prefers `fit` if `fill` is infinite. + pub fn resolve(self, fit: Length, fill: Length) -> Length { + match self { + Self::Fill if fill.is_finite() => fill, + _ => fit, + } + } +} + /// The result of layouting a node. #[derive(Debug, Clone, PartialEq)] pub enum Layouted { @@ -158,15 +168,6 @@ impl Layouted { } } -/// Whether to expand or shrink a node along an axis. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum Expansion { - /// Fit the content. - Fit, - /// Fill the available space. - Fill, -} - /// A finished layout with elements at fixed positions. #[derive(Debug, Clone, PartialEq)] pub struct Frame { diff --git a/src/layout/pad.rs b/src/layout/pad.rs index 9e2718c3..f8a623e3 100644 --- a/src/layout/pad.rs +++ b/src/layout/pad.rs @@ -39,10 +39,8 @@ impl From<NodePad> for NodeAny { fn shrink(areas: &Areas, padding: Sides<Linear>) -> Areas { let shrink = |size| size - padding.resolve(size).size(); Areas { - current: Area { - rem: shrink(areas.current.rem), - full: shrink(areas.current.full), - }, + current: shrink(areas.current), + full: shrink(areas.full), backlog: areas.backlog.iter().copied().map(shrink).collect(), last: areas.last.map(shrink), } diff --git a/src/layout/par.rs b/src/layout/par.rs index 7b2e4e92..2a1ad941 100644 --- a/src/layout/par.rs +++ b/src/layout/par.rs @@ -74,7 +74,7 @@ impl<'a> ParLayouter<'a> { } fn push_spacing(&mut self, amount: Length) { - let cross_max = self.areas.current.rem.get(self.cross); + let cross_max = self.areas.current.get(self.cross); self.run_size.cross = (self.run_size.cross + amount).min(cross_max); } @@ -84,7 +84,7 @@ impl<'a> ParLayouter<'a> { } let fits = { - let mut usable = self.areas.current.rem; + let mut usable = self.areas.current; *usable.get_mut(self.cross) -= self.run_size.cross; usable.fits(frame.size) }; @@ -92,7 +92,7 @@ impl<'a> ParLayouter<'a> { if !fits { self.finish_run(); - while !self.areas.current.rem.fits(frame.size) { + while !self.areas.current.fits(frame.size) { if self.areas.in_full_last() { // TODO: Diagnose once the necessary spans exist. let _ = warning!("cannot fit frame into any area"); @@ -112,10 +112,15 @@ impl<'a> ParLayouter<'a> { } fn finish_run(&mut self) { - let full_size = Gen::new(self.run_size.main, match self.par.cross_expansion { - Expansion::Fill => self.areas.current.full.get(self.cross), - Expansion::Fit => self.run_size.cross, - }); + let full_size = { + let full = self.areas.full.switch(self.dirs); + Gen::new( + self.run_size.main, + self.par + .cross_expansion + .resolve(self.run_size.cross.min(full.cross), full.cross), + ) + }; let mut output = Frame::new(full_size.switch(self.dirs).to_size()); @@ -139,7 +144,7 @@ impl<'a> ParLayouter<'a> { self.lines.push((self.lines_size.main, output, self.run_ruler)); let main_offset = full_size.main + self.par.line_spacing; - *self.areas.current.rem.get_mut(self.main) -= main_offset; + *self.areas.current.get_mut(self.main) -= main_offset; self.lines_size.main += main_offset; self.lines_size.cross = self.lines_size.cross.max(full_size.cross); diff --git a/src/layout/stack.rs b/src/layout/stack.rs index eac631d9..bfb93a94 100644 --- a/src/layout/stack.rs +++ b/src/layout/stack.rs @@ -11,7 +11,7 @@ pub struct NodeStack { /// How to align this stack in _its_ parent. pub align: ChildAlign, /// Whether to expand the axes to fill the area or to fit the content. - pub expansion: Gen<Expansion>, + pub expand: Spec<Expansion>, /// The nodes to be stacked. pub children: Vec<Node>, } @@ -66,7 +66,7 @@ impl<'a> StackLayouter<'a> { } fn push_spacing(&mut self, amount: Length) { - let main_rest = self.areas.current.rem.get_mut(self.main); + let main_rest = self.areas.current.get_mut(self.main); let capped = amount.min(*main_rest); *main_rest -= capped; self.used.main += capped; @@ -77,7 +77,7 @@ impl<'a> StackLayouter<'a> { self.finish_area(); } - while !self.areas.current.rem.fits(frame.size) { + while !self.areas.current.fits(frame.size) { if self.areas.in_full_last() { // TODO: Diagnose once the necessary spans exist. let _ = warning!("cannot fit frame into any area"); @@ -90,7 +90,7 @@ impl<'a> StackLayouter<'a> { let size = frame.size.switch(self.dirs); self.frames.push((self.used.main, frame, align)); - *self.areas.current.rem.get_mut(self.main) -= size.main; + *self.areas.current.get_mut(self.main) -= size.main; self.used.main += size.main; self.used.cross = self.used.cross.max(size.cross); self.ruler = align.main; @@ -98,16 +98,11 @@ impl<'a> StackLayouter<'a> { fn finish_area(&mut self) { let full_size = { - let full = self.areas.current.full.switch(self.dirs); + let expand = self.stack.expand.switch(self.dirs); + let full = self.areas.full.switch(self.dirs); Gen::new( - match self.stack.expansion.main { - Expansion::Fill => full.main, - Expansion::Fit => self.used.main.min(full.main), - }, - match self.stack.expansion.cross { - Expansion::Fill => full.cross, - Expansion::Fit => self.used.cross.min(full.cross), - }, + expand.main.resolve(self.used.main.min(full.main), full.main), + expand.cross.resolve(self.used.cross.min(full.cross), full.cross), ) }; |
