summaryrefslogtreecommitdiff
path: root/src/library/align.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-11-17 17:09:19 +0100
committerLaurenz <laurmaedje@gmail.com>2021-11-17 17:09:19 +0100
commit89f2e71852e96062ea9b756bf92fbf4e894871b1 (patch)
tree836099ebd17adf30a24fc62464dfdd3d9c248480 /src/library/align.rs
parent9a800daa82833c57eee04e92c701ca9a05a67d3b (diff)
Align node
Diffstat (limited to 'src/library/align.rs')
-rw-r--r--src/library/align.rs106
1 files changed, 66 insertions, 40 deletions
diff --git a/src/library/align.rs b/src/library/align.rs
index c6f96a13..591a4085 100644
--- a/src/library/align.rs
+++ b/src/library/align.rs
@@ -1,51 +1,77 @@
use super::prelude::*;
/// `align`: Configure the alignment along the layouting axes.
-pub fn align(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
- let first = args.find::<Align>();
- let second = args.find::<Align>();
- let body = args.find::<Template>();
-
- let mut horizontal = args.named("horizontal")?;
- let mut vertical = args.named("vertical")?;
-
- for value in first.into_iter().chain(second) {
- match value.axis() {
- Some(SpecAxis::Horizontal) | None if horizontal.is_none() => {
- horizontal = Some(value);
- }
- Some(SpecAxis::Vertical) | None if vertical.is_none() => {
- vertical = Some(value);
- }
- _ => {}
+pub fn align(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
+ let mut x = args.named("horizontal")?;
+ let mut y = args.named("vertical")?;
+ for Spanned { v, span } in args.all::<Spanned<Align>>() {
+ match v.axis() {
+ None | Some(SpecAxis::Horizontal) if x.is_none() => x = Some(v),
+ None | Some(SpecAxis::Vertical) if y.is_none() => y = Some(v),
+ _ => bail!(span, "unexpected argument"),
}
}
- let realign = |template: &mut Template| {
- template.modify(move |style| {
- if let Some(horizontal) = horizontal {
- style.aligns.inline = horizontal;
- }
+ let body = args.expect::<Template>("body")?;
+
+ Ok(Value::Template(Template::from_block(move |style| {
+ let mut style = style.clone();
+ if let Some(x) = x {
+ style.par_mut().align = x;
+ }
+
+ body.pack(&style).aligned(x, y)
+ })))
+}
+
+/// A node that aligns its child.
+#[derive(Debug, Hash)]
+pub struct AlignNode {
+ /// The node to be aligned.
+ pub child: PackedNode,
+ /// How to align the node horizontally and vertically.
+ pub aligns: Spec<Option<Align>>,
+}
+
+impl Layout for AlignNode {
+ fn layout(
+ &self,
+ ctx: &mut LayoutContext,
+ regions: &Regions,
+ ) -> Vec<Constrained<Rc<Frame>>> {
+ // Along axes with specified alignment, the child doesn't need to expand.
+ let mut pod = regions.clone();
+ pod.expand.x &= self.aligns.x.is_none();
+ 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())
+ {
+ let canvas = Size::new(
+ if regions.expand.x { current.w } else { frame.size.w },
+ if regions.expand.y { current.h } else { frame.size.h },
+ );
- if let Some(vertical) = vertical {
- style.aligns.block = vertical;
+ let aligns = self.aligns.unwrap_or(Spec::new(Align::Left, Align::Top));
+ let offset = Point::new(
+ aligns.x.resolve(Length::zero() .. canvas.w - frame.size.w),
+ aligns.y.resolve(Length::zero() .. canvas.h - frame.size.h),
+ );
+
+ let frame = Rc::make_mut(frame);
+ frame.size = canvas;
+ frame.baseline += offset.y;
+
+ for (point, _) in &mut frame.elements {
+ *point += offset;
}
- });
- if vertical.is_some() {
- template.parbreak();
+ cts.expand = regions.expand;
+ cts.exact = current.to_spec().map(Some);
}
- };
-
- Ok(if let Some(body) = body {
- let mut template = Template::new();
- template.save();
- realign(&mut template);
- template += body;
- template.restore();
- Value::Template(template)
- } else {
- realign(&mut ctx.template);
- Value::None
- })
+
+ frames
+ }
}