flexbox/
flexbox.rs

1#[derive(Clone, Debug)]
2pub struct FlexBox {
3    reverse: bool,
4    vertical: bool,
5    size_i: usize,
6    pos_i: usize,
7    size2_i: usize,
8    pos2_i: usize,
9    grows: usize,
10    shrinks: usize,
11}
12#[derive(Clone, Debug)]
13pub struct FlexItem {
14    width: usize,
15    height: usize,
16    direction: Direction,
17    children: Vec<Box<FlexItem>>,
18    frame: Vec<usize>,
19    grow: usize,
20    shrink: usize,
21    align_self: Align,
22    align_items: Align,
23    basis: usize,
24    justify_content: Align,
25}
26#[derive(Clone, Debug)]
27pub enum Direction {
28    Row,
29    RowReverse,
30    Column,
31    ColumnReverse,
32}
33
34#[derive(Clone, Debug, PartialEq)]
35pub enum Align {
36    Auto,
37    Center,
38    FlexStart,
39    FlexEnd,
40    Stretch,
41    Between,
42    Around,
43}
44
45impl FlexBox {
46    pub fn new() -> FlexBox {
47        FlexBox {
48            reverse: false,
49            vertical: false,
50            grows: 0,
51            shrinks: 0,
52            pos_i: 0,
53            size_i: 0,
54            size2_i: 0,
55            pos2_i: 0,
56        }
57    }
58
59    pub fn layout(&mut self, item: &mut FlexItem) {
60        let mut flex_dim = 0;
61        let mut align_dim = 0;
62        let mut size = 0;
63
64        match &item.direction {
65            Direction::Row => {
66                flex_dim = item.width;
67                align_dim = item.height;
68                self.pos_i = 0;
69                self.pos2_i = 1;
70                self.size_i = 2;
71                self.size2_i = 3;
72            }
73            Direction::RowReverse => {
74                self.reverse = true;
75            }
76            Direction::Column => {
77                flex_dim = item.height;
78                align_dim = item.width;
79                self.pos_i = 1;
80                self.pos2_i = 0;
81                self.size_i = 3;
82                self.size2_i = 2;
83            }
84            Direction::ColumnReverse => self.reverse = false,
85        }
86
87        let mut pos = if self.reverse { flex_dim } else { 0 };
88
89        for child in item.children.iter_mut() {
90            child.frame[0] = 0;
91            child.frame[1] = 0;
92            child.frame[2] = child.width;
93            child.frame[3] = child.height;
94
95            flex_dim -= child.frame[self.size_i];
96
97            self.grows += child.grow;
98            self.shrinks += child.shrink;
99
100            if child.basis > 0 {
101                child.frame[self.size_i] = child.basis;
102            }
103        }
104
105        for child in item.children.iter_mut() {
106            if flex_dim > 0 {
107                if child.grow != 0 {
108                    size = (flex_dim / (self.grows as usize)) * child.grow as usize;
109                }
110            } else {
111                if child.shrink != 0 {
112                    size = (flex_dim / (self.shrinks as usize)) * (child.shrink as usize);
113                }
114            }
115
116            child.frame[self.size_i] += size;
117            let mut spacing = 0;
118            match child.justify_content {
119                Align::FlexEnd => {
120                    pos = flex_dim;
121                }
122                Align::Center => {
123                    pos = flex_dim / 2;
124                }
125                Align::Between => {
126                    if child.children.len() > 0 {
127                        spacing = flex_dim / (child.children.len() - 1);
128                    }
129                }
130                Align::Around => {
131                    if child.children.len() > 0 {
132                        spacing = flex_dim / child.children.len();
133                        pos = spacing / 2;
134                    }
135                }
136                _ => {}
137            }
138
139            let a_pos = child.frame[self.size_i] + spacing;
140
141            if self.reverse {
142                pos -= a_pos;
143                child.frame[self.pos_i] = pos;
144            } else {
145                child.frame[self.pos_i] = pos;
146                pos += a_pos;
147            }
148
149            let mut align = 0;
150            let mut align_type = &child.align_self;
151
152            if align_type == &Align::Auto {
153                align_type = &child.align_items;
154            }
155            match align_type {
156                Align::Auto => {}
157                Align::FlexStart => {}
158                Align::Center => {
159                    align = (align_dim / 2) - (child.frame[self.size2_i] / 2);
160                }
161                Align::FlexEnd => {
162                    align = align_dim - child.frame[self.size2_i];
163                }
164                Align::Stretch => {
165                    align = 0;
166                    child.frame[self.size2_i] = align_dim;
167                }
168                _ => {}
169            }
170            child.frame[self.pos2_i] = align;
171        }
172    }
173
174    pub fn flex_layout(&mut self, root: &mut FlexItem) {
175        self.layout(root)
176    }
177}
178
179impl FlexItem {
180    pub fn add(&mut self, child: FlexItem) {
181        self.children.push(Box::new(child))
182    }
183
184    pub fn delete(&mut self, index: usize) {
185        self.children.remove(index);
186        ()
187    }
188
189    pub fn new(width: usize, height: usize) -> FlexItem {
190        FlexItem {
191            width,
192            height,
193            direction: Direction::Row,
194            children: vec![],
195            frame: vec![0, 0, 0, 0],
196            grow: 0,
197            shrink: 0,
198            basis: 0,
199            align_self: Align::Auto,
200            align_items: Align::Auto,
201            justify_content: Align::Auto,
202        }
203    }
204
205    pub fn default() -> FlexItem {
206        FlexItem {
207            width: 0,
208            height: 0,
209            direction: Direction::Row,
210            children: vec![],
211            frame: vec![0, 0, 0, 0],
212            grow: 0,
213            shrink: 0,
214            basis: 0,
215            align_self: Align::Auto,
216            align_items: Align::Auto,
217            justify_content: Align::Auto,
218        }
219    }
220
221    pub fn set_width(&mut self, width: usize) {
222        self.width = width;
223    }
224
225    pub fn set_height(&mut self, height: usize) {
226        self.height = height;
227    }
228
229    pub fn set_grow(&mut self, grow: usize) {
230        self.grow = grow;
231    }
232
233    pub fn set_direction(&mut self, direction: Direction) {
234        self.direction = direction;
235    }
236
237    pub fn set_align_self(&mut self, align: &str) {
238        let align_type = match align {
239            "center" => Align::Center,
240            "flex-start" => Align::FlexStart,
241            "flex-end" => Align::FlexEnd,
242            "stretch" => Align::Stretch,
243            _ => Align::Auto,
244        };
245        self.align_self = align_type
246    }
247
248    pub fn set_align_items(&mut self, align: &str) {
249        let align_type = match align {
250            "center" => Align::Center,
251            "flex-start" => Align::FlexStart,
252            "flex-end" => Align::FlexEnd,
253            "stretch" => Align::Stretch,
254            _ => Align::Auto,
255        };
256        self.align_items = align_type
257    }
258}