summaryrefslogtreecommitdiff
path: root/src/library/boxed.rs
blob: da06a371e458e48dedd89db764b7a46df25f6be0 (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
56
57
use smallvec::smallvec;

use crate::func::prelude::*;
use super::maps::ExtentMap;


function! {
    /// `box`: Layouts content into a box.
    #[derive(Debug, PartialEq)]
    pub struct BoxFunc {
        body: SyntaxTree,
        map: ExtentMap<PSize>,
        debug: Option<bool>,
    }

    parse(args, body, ctx) {
        BoxFunc {
            body: parse!(optional: body, ctx).unwrap_or(SyntaxTree::new()),
            map: ExtentMap::new(&mut args, false)?,
            debug: args.get_key_opt::<bool>("debug")?,
        }
    }

    layout(self, mut ctx) {
        ctx.repeat = false;

        if let Some(debug) = self.debug {
            ctx.debug = debug;
        }

        let map = self.map.dedup(ctx.axes)?;

        // Try to layout this box in all spaces until it fits into some space.
        let mut error = None;
        for &(mut space) in &ctx.spaces {
            let mut ctx = ctx.clone();

            for &axis in &[Horizontal, Vertical] {
                if let Some(psize) = map.get(axis) {
                    let size = psize.scaled(ctx.base.get(axis));
                    *ctx.base.get_mut(axis) = size;
                    *space.dimensions.get_mut(axis) = size;
                    *space.expansion.get_mut(axis) = true;
                }
            }

            ctx.spaces = smallvec![space];

            match layout(&self.body, ctx).await {
                Ok(layouts) => return Ok(vec![AddMultiple(layouts)]),
                Err(err) => error = Some(err),
            }
        }

        return Err(error.expect("expected at least one space"));
    }
}