ori_core/layout/
justify.rs

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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
use core::slice;

/// The alignment of items along the cross axis.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Align {
    /// Items are packed toward the start of the stack.
    Start,

    /// Items are packed toward the end of the stack.
    End,

    /// Items are packed toward the center of the stack.
    Center,

    /// Items are stretched to all have the same size.
    Stretch,

    /// Items are stretched to fill the available space.
    Fill,
}

impl Align {
    /// Aligns an item within the given space.
    pub fn align(self, available: f32, size: f32) -> f32 {
        match self {
            Self::Start => 0.0,
            Self::End => available - size,
            Self::Center => (available - size) / 2.0,
            Self::Stretch => 0.0,
            Self::Fill => 0.0,
        }
    }
}

impl Default for Align {
    fn default() -> Self {
        Self::Start
    }
}

impl From<&str> for Align {
    fn from(value: &str) -> Self {
        match value {
            "start" => Self::Start,
            "end" => Self::End,
            "center" => Self::Center,
            "stretch" => Self::Stretch,
            "fill" => Self::Fill,
            _ => Self::Start,
        }
    }
}

impl From<String> for Align {
    fn from(value: String) -> Self {
        Align::from(value.as_str())
    }
}

/// The justify content of a stack container.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Justify {
    /// Items are packed toward the start of the stack.
    Start,

    /// Items are packed toward the end of the stack.
    End,

    /// Items are packed toward the center of the stack.
    Center,

    /// Items are evenly distributed in the stack, with equal-size spaces between them.
    SpaceBetween,

    /// Items are evenly distributed in the stack, with half-size spaces on either end.
    SpaceAround,

    /// Items are evenly distributed in the stack.
    SpaceEvenly,
}

impl Justify {
    /// Layout the items in a stack container.
    pub fn layout(self, sizes: &[f32], size: f32, gap: f32) -> JustifyIterator {
        let count = sizes.len() as f32;

        let total_gap = gap * (count - 1.0);
        let total_size = sizes.iter().sum::<f32>() + total_gap;

        let gap = match self {
            Self::Start | Self::End | Self::Center => gap,
            Self::SpaceBetween => (size - (total_size - total_gap)) / (count - 1.0),
            Self::SpaceAround => (size - (total_size - total_gap)) / count,
            Self::SpaceEvenly => (size - (total_size - total_gap)) / (count + 1.0),
        };

        let position = match self {
            Self::Start | Self::SpaceBetween => 0.0,
            Self::Center => (size - total_size) / 2.0,
            Self::End => size - total_size,
            Self::SpaceAround => gap / 2.0,
            Self::SpaceEvenly => gap,
        };

        JustifyIterator {
            sizes: sizes.iter(),
            position,
            gap,
        }
    }
}

impl Default for Justify {
    fn default() -> Self {
        Self::Start
    }
}

impl From<&str> for Justify {
    fn from(value: &str) -> Self {
        match value {
            "start" => Self::Start,
            "end" => Self::End,
            "center" => Self::Center,
            "space-between" => Self::SpaceBetween,
            "space-around" => Self::SpaceAround,
            "space-evenly" => Self::SpaceEvenly,
            _ => Self::Start,
        }
    }
}

impl From<String> for Justify {
    fn from(value: String) -> Self {
        Justify::from(value.as_str())
    }
}

/// An iterator over the positions of items in a stack container.
pub struct JustifyIterator<'a> {
    sizes: slice::Iter<'a, f32>,
    position: f32,
    gap: f32,
}

impl Iterator for JustifyIterator<'_> {
    type Item = f32;

    fn next(&mut self) -> Option<Self::Item> {
        let position = self.position;
        self.position += *self.sizes.next()? + self.gap;
        Some(position)
    }
}