summaryrefslogtreecommitdiff
path: root/src/library/maps/padding.rs
blob: 4bbbb754fdc44acbab729f2866103ffef4f05b27 (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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
use super::*;
use AxisKey::*;
use AlignmentKey::*;
use PaddingKey::*;


/// An argument key which identifies a margin or padding target.
///
/// A is the used axis type.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum PaddingKey<A> {
    /// All four sides should have the specified padding.
    All,
    /// Both sides of the given axis should have the specified padding.
    Both(A),
    /// Only the given side of the given axis should have the specified padding.
    Side(A, AlignmentKey),
}

key!(PaddingKey<AxisKey>, "axis or side",
    "horizontal" | "h" => Both(Specific(Horizontal)),
    "vertical"   | "v" => Both(Specific(Vertical)),
    "primary"    | "p" => Both(Generic(Primary)),
    "secondary"  | "s" => Both(Generic(Secondary)),

    "left"   => Side(Specific(Horizontal), Left),
    "right"  => Side(Specific(Horizontal), Right),
    "top"    => Side(Specific(Vertical),   Top),
    "bottom" => Side(Specific(Vertical),   Bottom),

    "primary-origin"    => Side(Generic(Primary),     Align(Origin)),
    "primary-end"       => Side(Generic(Primary),     Align(End)),
    "secondary-origin"  => Side(Generic(Secondary),   Align(Origin)),
    "secondary-end"     => Side(Generic(Secondary),   Align(End)),
    "horizontal-origin" => Side(Specific(Horizontal), Align(Origin)),
    "horizontal-end"    => Side(Specific(Horizontal), Align(End)),
    "vertical-origin"   => Side(Specific(Vertical),   Align(Origin)),
    "vertical-end"      => Side(Specific(Vertical),   Align(End)),
);

/// A map for storing padding at sides.
#[derive(Debug, Clone, PartialEq)]
pub struct PaddingMap(ConsistentMap<PaddingKey<AxisKey>, Option<PSize>>);

impl PaddingMap {
    /// Parse a padding map from the function args.
    pub fn new(args: &mut FuncArgs) -> ParseResult<PaddingMap> {
        let mut map = ConsistentMap::new();
        map.add_opt(PaddingKey::All, args.get_pos_opt::<Option<PSize>>()?)?;

        for arg in args.keys() {
            let key = PaddingKey::from_ident(&arg.v.key)?;
            let size = Option::<PSize>::from_expr(arg.v.value)?;
            map.add(key, size)?;
        }

        Ok(PaddingMap(map))
    }

    /// Apply the specified padding on the size box.
    pub fn apply(&self, axes: LayoutAxes, padding: &mut ValueBox<Option<PSize>>)
    -> LayoutResult<()> {
        use PaddingKey::*;

        let map = self.0.dedup(|key, &val| {
            Ok((match key {
                All => All,
                Both(axis) => Both(axis.to_specific(axes)),
                Side(axis, alignment) => {
                    let axis = axis.to_specific(axes);
                    Side(axis, alignment.to_specific(axes, axis))
                }
            }, val))
        })?;

        map.with(All, |&val| padding.set_all(val));
        map.with(Both(Horizontal), |&val| padding.set_horizontal(val));
        map.with(Both(Vertical), |&val| padding.set_vertical(val));

        for (key, &val) in map.iter() {
            if let Side(_, alignment) = key {
                match alignment {
                    AlignmentKey::Left => padding.left = val,
                    AlignmentKey::Right => padding.right = val,
                    AlignmentKey::Top => padding.top = val,
                    AlignmentKey::Bottom => padding.bottom = val,
                    _ => {},
                }
            }
        }

        Ok(())
    }
}