summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-02-02 15:25:43 +0100
committerLaurenz <laurmaedje@gmail.com>2022-02-02 15:25:43 +0100
commit0a1916c1e4259aff1306b26c06d4edcf0f190a3b (patch)
tree8ab81f034dd8b392b368691a2d55349f5c798d85 /src
parentbdb1c008f2cee7c3929b671d9407d2b578182199 (diff)
Remove width from backlog and last region
Diffstat (limited to 'src')
-rw-r--r--src/layout/mod.rs9
-rw-r--r--src/layout/regions.rs58
-rw-r--r--src/library/columns.rs69
-rw-r--r--src/library/grid.rs14
4 files changed, 70 insertions, 80 deletions
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index 147e8c9d..ebdfba0e 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -200,6 +200,7 @@ impl PackedNode {
}
impl Layout for PackedNode {
+ #[track_caller]
fn layout(
&self,
ctx: &mut LayoutContext,
@@ -219,8 +220,12 @@ impl Layout for PackedNode {
state.finish()
};
+ // This is not written with `unwrap_or_else`, because then the
+ // #[track_caller] annotation doesn't work.
#[cfg(feature = "layout-cache")]
- ctx.layout_cache.get(hash, regions).unwrap_or_else(|| {
+ if let Some(frames) = ctx.layout_cache.get(hash, regions) {
+ frames
+ } else {
ctx.level += 1;
let frames = self.node.layout(ctx, regions, styles);
ctx.level -= 1;
@@ -240,7 +245,7 @@ impl Layout for PackedNode {
ctx.layout_cache.insert(hash, entry);
frames
- })
+ }
}
fn pack(self) -> PackedNode {
diff --git a/src/layout/regions.rs b/src/layout/regions.rs
index 66e6da17..3f8b6d25 100644
--- a/src/layout/regions.rs
+++ b/src/layout/regions.rs
@@ -7,10 +7,11 @@ pub struct Regions {
pub current: Size,
/// The base size for relative sizing.
pub base: Size,
- /// An iterator of followup regions.
- pub backlog: std::vec::IntoIter<Size>,
- /// The final region that is repeated once the backlog is drained.
- pub last: Option<Size>,
+ /// The height of followup regions. The width is the same for all regions.
+ pub backlog: std::vec::IntoIter<Length>,
+ /// The height of the final region that is repeated once the backlog is
+ /// drained. The width is the same for all regions.
+ pub last: Option<Length>,
/// Whether nodes should expand to fill the regions instead of shrinking to
/// fit the content.
pub expand: Spec<bool>,
@@ -34,19 +35,33 @@ impl Regions {
current: size,
base,
backlog: vec![].into_iter(),
- last: Some(size),
+ last: Some(size.y),
expand,
}
}
/// Create new regions where all sizes are mapped with `f`.
+ ///
+ /// Note that since all regions must have the same width, the width returned
+ /// by `f` is ignored for the backlog and the final region.
pub fn map<F>(&self, mut f: F) -> Self
where
F: FnMut(Size) -> Size,
{
- let mut regions = self.clone();
- regions.mutate(|s| *s = f(*s));
- regions
+ let x = self.current.x;
+ Self {
+ current: f(self.current),
+ base: f(self.base),
+ backlog: self
+ .backlog
+ .as_slice()
+ .iter()
+ .map(|&y| f(Size::new(x, y)).y)
+ .collect::<Vec<_>>()
+ .into_iter(),
+ last: self.last.map(|y| f(Size::new(x, y)).y),
+ expand: self.expand,
+ }
}
/// Whether the current region is full and a region break is called for.
@@ -58,14 +73,15 @@ impl Regions {
///
/// If this is true, calling `next()` will have no effect.
pub fn in_last(&self) -> bool {
- self.backlog.len() == 0 && self.last.map_or(true, |size| self.current == size)
+ self.backlog.len() == 0
+ && self.last.map_or(true, |height| self.current.y == height)
}
/// Advance to the next region if there is any.
pub fn next(&mut self) {
- if let Some(size) = self.backlog.next().or(self.last) {
- self.current = size;
- self.base = size;
+ if let Some(height) = self.backlog.next().or(self.last) {
+ self.current.y = height;
+ self.base.y = height;
}
}
@@ -76,17 +92,11 @@ impl Regions {
let first = std::iter::once((self.current, self.base));
let backlog = self.backlog.as_slice().iter();
let last = self.last.iter().cycle();
- first.chain(backlog.chain(last).map(|&s| (s, s)))
- }
-
- /// Mutate all contained sizes in place.
- pub fn mutate<F>(&mut self, mut f: F)
- where
- F: FnMut(&mut Size),
- {
- f(&mut self.current);
- f(&mut self.base);
- self.last.as_mut().map(|x| f(x));
- self.backlog.as_mut_slice().iter_mut().for_each(f);
+ first.chain(backlog.chain(last).map(|&height| {
+ (
+ Size::new(self.current.x, height),
+ Size::new(self.base.x, height),
+ )
+ }))
}
}
diff --git a/src/library/columns.rs b/src/library/columns.rs
index 149da755..5ea76973 100644
--- a/src/library/columns.rs
+++ b/src/library/columns.rs
@@ -38,63 +38,40 @@ impl Layout for ColumnsNode {
regions: &Regions,
styles: StyleChain,
) -> Vec<Constrained<Arc<Frame>>> {
- let columns = self.columns.get();
-
// Separating the infinite space into infinite columns does not make
- // much sense. Note that this line assumes that no infinitely wide
- // region will follow if the first region's width is finite.
+ // much sense.
if regions.current.x.is_infinite() {
return self.child.layout(ctx, regions, styles);
}
- // Gutter width for each region. (Can be different because the relative
- // component is calculated seperately for each region.)
- let mut gutters = vec![];
-
- // Sizes of all columns resulting from `region.current`,
- // `region.backlog` and `regions.last`.
- let mut sizes = vec![];
-
- for (current, base) in regions
- .iter()
- .take(1 + regions.backlog.len() + regions.last.iter().len())
- {
- let gutter = styles.get(Self::GUTTER).resolve(base.x);
- let width = (current.x - gutter * (columns - 1) as f64) / columns as f64;
- let size = Size::new(width, current.y);
- gutters.push(gutter);
- sizes.extend(std::iter::repeat(size).take(columns));
- }
-
- let first = sizes.remove(0);
- let mut pod = Regions::one(
- first,
- Size::new(first.x, regions.base.y),
- Spec::new(true, regions.expand.y),
- );
-
- // Retrieve elements for the last region from the vectors.
- let last_gutter = regions.last.map(|_| {
- let gutter = gutters.pop().unwrap();
- let size = sizes.drain(sizes.len() - columns ..).next().unwrap();
- pod.last = Some(size);
- gutter
- });
-
- pod.backlog = sizes.into_iter();
-
- let mut finished = vec![];
+ // Determine the width of the gutter and each column.
+ let columns = self.columns.get();
+ let gutter = styles.get(Self::GUTTER).resolve(regions.base.x);
+ let width = (regions.current.x - gutter * (columns - 1) as f64) / columns as f64;
+
+ // Create the pod regions.
+ let pod = Regions {
+ current: Size::new(width, regions.current.y),
+ base: Size::new(width, regions.base.y),
+ backlog: std::iter::once(&regions.current.y)
+ .chain(regions.backlog.as_slice())
+ .flat_map(|&height| std::iter::repeat(height).take(columns))
+ .skip(1)
+ .collect::<Vec<_>>()
+ .into_iter(),
+ last: regions.last,
+ expand: Spec::new(true, regions.expand.y),
+ };
+
+ // Layout the children.
let mut frames = self.child.layout(ctx, &pod, styles).into_iter();
let dir = styles.get(ParNode::DIR);
let total_regions = (frames.len() as f32 / columns as f32).ceil() as usize;
+ let mut finished = vec![];
// Stitch together the columns for each region.
- for ((current, base), gutter) in regions
- .iter()
- .take(total_regions)
- .zip(gutters.into_iter().chain(last_gutter.into_iter().cycle()))
- {
+ for (current, base) in regions.iter().take(total_regions) {
// The height should be the parent height if the node shall expand.
// Otherwise its the maximum column height for the frame. In that
// case, the frame is first created with zero height and then
diff --git a/src/library/grid.rs b/src/library/grid.rs
index c49ac84f..6a9b790a 100644
--- a/src/library/grid.rs
+++ b/src/library/grid.rs
@@ -386,9 +386,10 @@ impl<'a> GridLayouter<'a> {
// 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) {
- // All widths should be `rcol` except the base for auto columns.
let mut pod = self.regions.clone();
- pod.mutate(|size| size.x = rcol);
+ pod.current.x = rcol;
+
+ // All widths should be `rcol` except the base for auto columns.
if self.cols[x] == TrackSizing::Auto {
pod.base.x = self.regions.base.x;
}
@@ -513,18 +514,15 @@ impl<'a> GridLayouter<'a> {
// Prepare regions.
let size = Size::new(self.used.x, heights[0]);
let mut pod = Regions::one(size, self.regions.base, Spec::splat(true));
- pod.backlog = heights[1 ..]
- .iter()
- .map(|&h| Size::new(self.used.x, h))
- .collect::<Vec<_>>()
- .into_iter();
+ pod.backlog = heights[1 ..].to_vec().into_iter();
// Layout the row.
let mut pos = Point::zero();
for (x, &rcol) in self.rcols.iter().enumerate() {
if let Some(node) = self.cell(x, y) {
+ pod.current.x = rcol;
+
// All widths should be `rcol` except the base for auto columns.
- pod.mutate(|size| size.x = rcol);
if self.cols[x] == TrackSizing::Auto {
pod.base.x = self.regions.base.x;
}