summaryrefslogtreecommitdiff
path: root/src/library/layout/align.rs
blob: 2a4d039eaba0d50a10e95614ead3e5908c47b929 (plain) (blame)
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
use crate::library::prelude::*;
use crate::library::text::{HorizontalAlign, ParNode};

/// Align a node along the layouting axes.
#[derive(Debug, Hash)]
pub struct AlignNode {
    /// How to align the node horizontally and vertically.
    pub aligns: Spec<Option<RawAlign>>,
    /// The node to be aligned.
    pub child: LayoutNode,
}

#[node]
impl AlignNode {
    fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
        let aligns: Spec<_> = args.find()?.unwrap_or_default();
        let body: LayoutNode = args.expect("body")?;
        Ok(Content::block(body.aligned(aligns)))
    }
}

impl Layout for AlignNode {
    fn layout(
        &self,
        ctx: &mut Context,
        regions: &Regions,
        styles: StyleChain,
    ) -> TypResult<Vec<Arc<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();

        // Align paragraphs inside the child.
        let mut passed = StyleMap::new();
        if let Some(align) = self.aligns.x {
            passed.set(ParNode::ALIGN, HorizontalAlign(align));
        }

        // Layout the child.
        let mut frames = self.child.layout(ctx, &pod, passed.chain(&styles))?;
        for (region, frame) 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(region, frame.size);
            let aligns = self
                .aligns
                .map(|align| align.resolve(styles))
                .unwrap_or(Spec::new(Align::Left, Align::Top));

            Arc::make_mut(frame).resize(target, aligns);
        }

        Ok(frames)
    }
}