summaryrefslogtreecommitdiff
path: root/src/layout
diff options
context:
space:
mode:
Diffstat (limited to 'src/layout')
-rw-r--r--src/layout/fixed.rs6
-rw-r--r--src/layout/mod.rs63
-rw-r--r--src/layout/pad.rs6
-rw-r--r--src/layout/par.rs21
-rw-r--r--src/layout/stack.rs21
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),
)
};