summaryrefslogtreecommitdiff
path: root/src/library
diff options
context:
space:
mode:
Diffstat (limited to 'src/library')
-rw-r--r--src/library/align.rs6
-rw-r--r--src/library/flow.rs2
-rw-r--r--src/library/grid.rs28
-rw-r--r--src/library/pad.rs94
-rw-r--r--src/library/shape.rs7
-rw-r--r--src/library/stack.rs2
-rw-r--r--src/library/transform.rs8
7 files changed, 80 insertions, 67 deletions
diff --git a/src/library/align.rs b/src/library/align.rs
index 19c52f98..5aeef543 100644
--- a/src/library/align.rs
+++ b/src/library/align.rs
@@ -49,7 +49,6 @@ impl Layout for AlignNode {
pod.expand.y &= self.aligns.y.is_none();
let mut frames = self.child.layout(ctx, &pod);
-
for (Constrained { item: frame, cts }, (current, _)) in
frames.iter_mut().zip(regions.iter())
{
@@ -67,10 +66,7 @@ impl Layout for AlignNode {
let frame = Rc::make_mut(frame);
frame.size = canvas;
frame.baseline += offset.y;
-
- for (point, _) in &mut frame.elements {
- *point += offset;
- }
+ frame.translate(offset);
cts.expand = regions.expand;
cts.exact = current.to_spec().map(Some);
diff --git a/src/library/flow.rs b/src/library/flow.rs
index 185e60bb..5271eca9 100644
--- a/src/library/flow.rs
+++ b/src/library/flow.rs
@@ -61,7 +61,7 @@ impl Layout for FlowNode {
pub enum FlowChild {
/// Vertical spacing between other children.
Spacing(Spacing),
- /// A node and how to align it in the flow.
+ /// An arbitrary node.
Node(PackedNode),
}
diff --git a/src/library/grid.rs b/src/library/grid.rs
index 347132e1..6bd72388 100644
--- a/src/library/grid.rs
+++ b/src/library/grid.rs
@@ -288,17 +288,17 @@ impl<'a> GridLayouter<'a> {
for y in 0 .. self.rows.len() {
if let Some(node) = self.cell(x, y) {
let size = Size::new(available, self.regions.base.h);
- let mut regions =
+ let mut pod =
Regions::one(size, self.regions.base, Spec::splat(false));
// For linear rows, we can already resolve the correct
// base, for auto it's already correct and for fr we could
// only guess anyway.
if let TrackSizing::Linear(v) = self.rows[y] {
- regions.base.h = v.resolve(self.regions.base.h);
+ pod.base.h = v.resolve(self.regions.base.h);
}
- let frame = node.layout(ctx, &regions).remove(0).item;
+ let frame = node.layout(ctx, &pod).remove(0).item;
resolved.set_max(frame.size.w);
}
}
@@ -376,17 +376,17 @@ 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) {
- let mut regions = self.regions.clone();
- regions.mutate(|size| size.w = rcol);
+ let mut pod = self.regions.clone();
+ pod.mutate(|size| size.w = rcol);
// Set the horizontal base back to the parent region's base for
// auto columns.
if self.cols[x] == TrackSizing::Auto {
- regions.base.w = self.regions.base.w;
+ pod.base.w = self.regions.base.w;
}
let mut sizes =
- node.layout(ctx, &regions).into_iter().map(|frame| frame.item.size.h);
+ node.layout(ctx, &pod).into_iter().map(|frame| frame.item.size.h);
for (target, size) in resolved.iter_mut().zip(&mut sizes) {
target.set_max(size);
@@ -475,8 +475,8 @@ impl<'a> GridLayouter<'a> {
base.h = size.h;
}
- let regions = Regions::one(size, base, Spec::splat(true));
- let frame = node.layout(ctx, &regions).remove(0);
+ let pod = Regions::one(size, base, Spec::splat(true));
+ let frame = node.layout(ctx, &pod).remove(0);
output.push_frame(pos, frame.item);
}
@@ -501,8 +501,8 @@ impl<'a> GridLayouter<'a> {
// Prepare regions.
let size = Size::new(self.used.w, resolved[0]);
- let mut regions = Regions::one(size, self.regions.base, Spec::splat(true));
- regions.backlog = resolved[1 ..]
+ let mut pod = Regions::one(size, self.regions.base, Spec::splat(true));
+ pod.backlog = resolved[1 ..]
.iter()
.map(|&h| Size::new(self.used.w, h))
.collect::<Vec<_>>()
@@ -512,16 +512,16 @@ impl<'a> GridLayouter<'a> {
let mut pos = Point::zero();
for (x, &rcol) in self.rcols.iter().enumerate() {
if let Some(node) = self.cell(x, y) {
- regions.mutate(|size| size.w = rcol);
+ pod.mutate(|size| size.w = rcol);
// Set the horizontal base back to the parent region's base for
// auto columns.
if self.cols[x] == TrackSizing::Auto {
- regions.base.w = self.regions.base.w;
+ pod.base.w = self.regions.base.w;
}
// Push the layouted frames into the individual output frames.
- let frames = node.layout(ctx, &regions);
+ let frames = node.layout(ctx, &pod);
for (output, frame) in outputs.iter_mut().zip(frames) {
output.push_frame(pos, frame.item);
}
diff --git a/src/library/pad.rs b/src/library/pad.rs
index a1c8c6f9..829272cc 100644
--- a/src/library/pad.rs
+++ b/src/library/pad.rs
@@ -8,7 +8,6 @@ pub fn pad(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
let right = args.named("right")?;
let bottom = args.named("bottom")?;
let body: Template = args.expect("body")?;
-
let padding = Sides::new(
left.or(all).unwrap_or_default(),
top.or(all).unwrap_or_default(),
@@ -17,17 +16,17 @@ pub fn pad(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
);
Ok(Value::Template(Template::from_inline(move |style| {
- PadNode { padding, child: body.pack(style) }
+ body.pack(style).padded(padding)
})))
}
/// A node that adds padding to its child.
#[derive(Debug, Hash)]
pub struct PadNode {
- /// The amount of padding.
- pub padding: Sides<Linear>,
/// The child node whose sides to pad.
pub child: PackedNode,
+ /// The amount of padding.
+ pub padding: Sides<Linear>,
}
impl Layout for PadNode {
@@ -37,43 +36,23 @@ impl Layout for PadNode {
regions: &Regions,
) -> Vec<Constrained<Rc<Frame>>> {
// Layout child into padded regions.
- let mut frames = self.child.layout(
- ctx,
- &regions.map(|size| size - self.padding.resolve(size).size()),
- );
+ let pod = regions.map(|size| shrink(size, self.padding));
+ let mut frames = self.child.layout(ctx, &pod);
for (Constrained { item: frame, cts }, (current, base)) in
frames.iter_mut().zip(regions.iter())
{
- fn solve_axis(length: Length, padding: Linear) -> Length {
- (length + padding.abs).safe_div(1.0 - padding.rel.get())
- }
-
- // Solve for the size `padded` that satisfies (approximately):
- // `padded - padding.resolve(padded).size() == size`
- let padded = Size::new(
- solve_axis(frame.size.w, self.padding.left + self.padding.right),
- solve_axis(frame.size.h, self.padding.top + self.padding.bottom),
- );
-
+ // Apply the padding inversely such that the grown size padded
+ // yields the frame's size.
+ let padded = grow(frame.size, self.padding);
let padding = self.padding.resolve(padded);
- let origin = Point::new(padding.left, padding.top);
-
- // Create a new larger frame and place the child's frame inside it.
- let empty = Frame::new(padded, frame.baseline + origin.y);
- let prev = std::mem::replace(frame, Rc::new(empty));
- let new = Rc::make_mut(frame);
- new.push_frame(origin, prev);
+ let offset = Point::new(padding.left, padding.top);
- // Inflate min and max contraints by the padding.
- for spec in [&mut cts.min, &mut cts.max] {
- if let Some(x) = spec.x.as_mut() {
- *x += padding.size().w;
- }
- if let Some(y) = spec.y.as_mut() {
- *y += padding.size().h;
- }
- }
+ // Grow the frame and translate everything in the frame inwards.
+ let frame = Rc::make_mut(frame);
+ frame.size = padded;
+ frame.baseline += offset.y;
+ frame.translate(offset);
// Set exact and base constraints if the child had them.
cts.exact.x.and_set(Some(current.w));
@@ -89,8 +68,53 @@ impl Layout for PadNode {
if self.padding.top.is_relative() || self.padding.bottom.is_relative() {
cts.base.y = Some(base.h);
}
+
+ // Inflate min and max contraints by the padding.
+ for spec in [&mut cts.min, &mut cts.max] {
+ if let Some(x) = spec.x.as_mut() {
+ *x += padding.size().w;
+ }
+ if let Some(y) = spec.y.as_mut() {
+ *y += padding.size().h;
+ }
+ }
}
frames
}
}
+
+/// Shrink a size by padding relative to the size itself.
+fn shrink(size: Size, padding: Sides<Linear>) -> Size {
+ size - padding.resolve(size).size()
+}
+
+/// Grow a size by padding relative to the grown size.
+/// This is the inverse operation to `shrink()`.
+///
+/// For the horizontal axis the derivation looks as follows.
+/// (Vertical axis is analogous.)
+///
+/// Let w be the grown target width,
+/// s be given width,
+/// l be the left padding,
+/// r be the right padding,
+/// p = l + r.
+///
+/// We want that: w - l.resolve(w) - r.resolve(w) = s
+///
+/// Thus: w - l.resolve(w) - r.resolve(w) = s
+/// <=> w - p.resolve(w) = s
+/// <=> w - p.rel * w - p.abs = s
+/// <=> (1 - p.rel) * w = s + p.abs
+/// <=> w = (s + p.abs) / (1 - p.rel)
+fn grow(size: Size, padding: Sides<Linear>) -> Size {
+ fn solve_axis(length: Length, padding: Linear) -> Length {
+ (length + padding.abs).safe_div(1.0 - padding.rel.get())
+ }
+
+ Size::new(
+ solve_axis(size.w, padding.left + padding.right),
+ solve_axis(size.h, padding.top + padding.bottom),
+ )
+}
diff --git a/src/library/shape.rs b/src/library/shape.rs
index 5d9b4152..7c543958 100644
--- a/src/library/shape.rs
+++ b/src/library/shape.rs
@@ -1,7 +1,6 @@
use std::f64::consts::SQRT_2;
use super::prelude::*;
-use super::PadNode;
use crate::util::RcExt;
/// `rect`: A rectangle with optional content.
@@ -113,10 +112,8 @@ impl Layout for ShapeNode {
if matches!(self.kind, ShapeKind::Circle | ShapeKind::Ellipse) {
// Padding with this ratio ensures that a rectangular child fits
// perfectly into a circle / an ellipse.
- storage = PadNode {
- padding: Sides::splat(Relative::new(0.5 - SQRT_2 / 4.0).into()),
- child: child.clone(),
- };
+ let ratio = Relative::new(0.5 - SQRT_2 / 4.0);
+ storage = child.clone().padded(Sides::splat(ratio.into()));
node = &storage;
}
diff --git a/src/library/stack.rs b/src/library/stack.rs
index cc02592f..3d91bec7 100644
--- a/src/library/stack.rs
+++ b/src/library/stack.rs
@@ -75,7 +75,7 @@ impl Layout for StackNode {
pub enum StackChild {
/// Spacing between other nodes.
Spacing(Spacing),
- /// Any block node and how to align it in the stack.
+ /// An arbitrary node.
Node(PackedNode),
}
diff --git a/src/library/transform.rs b/src/library/transform.rs
index ef9caf2e..10752358 100644
--- a/src/library/transform.rs
+++ b/src/library/transform.rs
@@ -30,14 +30,10 @@ impl Layout for MoveNode {
for (Constrained { item: frame, .. }, (_, base)) in
frames.iter_mut().zip(regions.iter())
{
- let offset = Point::new(
+ Rc::make_mut(frame).translate(Point::new(
self.offset.x.map(|x| x.resolve(base.w)).unwrap_or_default(),
self.offset.y.map(|y| y.resolve(base.h)).unwrap_or_default(),
- );
-
- for (point, _) in &mut Rc::make_mut(frame).elements {
- *point += offset;
- }
+ ));
}
frames