1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
use super::prelude::*;
/// `align`: Configure the alignment along the layouting axes.
pub fn align(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
castable! {
Spec<Option<Align>>,
Expected: "1d or 2d alignment",
@align: Align => {
let mut aligns = Spec::default();
aligns.set(align.axis(), Some(*align));
aligns
},
@aligns: Spec<Align> => aligns.map(Some),
}
let aligns = args.expect::<Spec<_>>("alignment")?;
let body = args.expect::<Template>("body")?;
Ok(Value::Template(Template::from_block(move |style| {
let mut style = style.clone();
if let Some(x) = aligns.x {
style.par_mut().align = x;
}
body.pack(&style).aligned(aligns)
})))
}
/// A node that aligns its child.
#[derive(Debug, Hash)]
pub struct AlignNode {
/// How to align the node horizontally and vertically.
pub aligns: Spec<Option<Align>>,
/// The node to be aligned.
pub child: PackedNode,
}
impl Layout for AlignNode {
fn layout(
&self,
ctx: &mut LayoutContext,
regions: &Regions,
) -> Vec<Constrained<Rc<Frame>>> {
// The child only needs to expand along an axis if there's no alignment.
let mut pod = regions.clone();
pod.expand &= self.aligns.map_is_none();
// Layout the child.
let mut frames = self.child.layout(ctx, &pod);
for ((current, base), Constrained { item: frame, cts }) in
regions.iter().zip(&mut frames)
{
// Align in the target size. The target size depends on whether we
// should expand.
let target = regions.expand.select(current, frame.size);
let default = Spec::new(Align::Left, Align::Top);
let aligns = self.aligns.unwrap_or(default);
Rc::make_mut(frame).resize(target, aligns);
// Set constraints.
cts.expand = regions.expand;
cts.base = base.filter(cts.base.map_is_some());
cts.exact = current.filter(regions.expand | cts.exact.map_is_some());
}
frames
}
}
|