1use serde::{Deserialize, Serialize};
2
3use super::{divrem, remainderless_division, split, Rect, Rotation};
4
5#[derive(PartialEq, Eq, Clone, Copy, Serialize, Deserialize, Debug)]
12pub enum Split {
13 Horizontal,
25
26 Vertical,
38
39 Grid,
52
53 Fibonacci,
65
66 Dwindle,
79}
80
81pub fn vertical(rect: &Rect, amount: usize) -> Vec<Rect> {
82 let mut from_left = rect.x;
83 remainderless_division(rect.w as usize, amount)
84 .iter()
85 .map(|width| {
86 let rect = Rect::new(from_left, rect.y, *width as u32, rect.h);
87 from_left += *width as i32;
88 rect
89 })
90 .collect()
91}
92
93pub fn horizontal(rect: &Rect, amount: usize) -> Vec<Rect> {
94 let mut from_top = rect.y;
95 remainderless_division(rect.h as usize, amount)
96 .iter()
97 .map(|height| {
98 let rect = Rect::new(rect.x, from_top, rect.w, *height as u32);
99 from_top += *height as i32;
100 rect
101 })
102 .collect()
103}
104
105pub fn grid(rect: &Rect, amount: usize) -> Vec<Rect> {
106 let cols = (amount as f64).sqrt().ceil() as usize;
107 let col_tiles = vertical(rect, cols);
108 let min_rows = (amount as f64 / cols as f64).floor() as usize;
110 let min_row_amount = col_tiles.len() - divrem(amount, cols).1;
112
113 col_tiles
114 .iter()
115 .enumerate()
116 .flat_map(|(i, col_tile)| {
117 let rows = if i < min_row_amount {
118 min_rows
119 } else {
120 min_rows + 1
121 };
122 horizontal(col_tile, rows)
123 })
124 .collect()
125}
126
127pub fn fibonacci(rect: &Rect, amount: usize) -> Vec<Rect> {
128 let tiles: &mut Vec<Rect> = &mut Vec::new();
129 let mut remaining_tile = *rect;
130 let mut direction = Rotation::East;
131 for i in 0..amount {
132 let has_next = i < amount - 1;
133 direction = direction.clockwise();
134 if has_next {
135 let split_axis = match direction {
136 Rotation::North | Rotation::South => Split::Horizontal,
137 Rotation::East | Rotation::West => Split::Vertical,
138 };
139 let backwards = match direction {
140 Rotation::East | Rotation::South => false,
141 Rotation::West | Rotation::North => true,
142 };
143 let splitted_tiles = split(&remaining_tile, 2, Some(split_axis));
144 if backwards {
145 tiles.push(splitted_tiles[1]);
146 remaining_tile = splitted_tiles[0];
147 } else {
148 tiles.push(splitted_tiles[0]);
149 remaining_tile = splitted_tiles[1];
150 }
151 } else {
152 tiles.push(remaining_tile);
153 }
154 }
155 tiles.clone()
156}
157
158pub fn dwindle(rect: &Rect, amount: usize) -> Vec<Rect> {
159 let tiles: &mut Vec<Rect> = &mut Vec::new();
160 let mut remaining_tile = *rect;
161 let mut last_axis = Split::Vertical;
162 for i in 0..amount {
163 let has_next = i < amount - 1;
164 last_axis = if last_axis == Split::Vertical {
165 Split::Horizontal
166 } else {
167 Split::Vertical
168 };
169 if has_next {
170 let splitted_tiles = split(&remaining_tile, 2, Some(last_axis));
171 tiles.push(splitted_tiles[0]);
172 remaining_tile = splitted_tiles[1];
173 } else {
174 tiles.push(remaining_tile);
175 }
176 }
177 tiles.clone()
178}
179
180#[cfg(test)]
181mod tests {
182 use crate::geometry::{
183 split::{dwindle, fibonacci, grid, horizontal, vertical},
184 Rect,
185 };
186
187 const CONTAINER: Rect = Rect {
188 x: 0,
189 y: 0,
190 w: 400,
191 h: 200,
192 };
193
194 #[test]
195 fn split_vertical_two_windows() {
196 let rects = vertical(&CONTAINER, 2);
197 assert_eq!(rects.len(), 2);
198 let expected_first = Rect::new(0, 0, 200, 200);
199 let expected_second = Rect::new(200, 0, 200, 200);
200 assert!(rects[0].eq(&expected_first));
201 assert!(rects[1].eq(&expected_second));
202 }
203
204 #[test]
205 fn split_vertical_three_windows() {
206 let rects = vertical(&CONTAINER, 3);
207 assert_eq!(rects.len(), 3);
208 let expected_first = Rect::new(0, 0, 134, 200);
210 let expected_second = Rect::new(134, 0, 133, 200);
211 let expected_third = Rect::new(267, 0, 133, 200);
212 assert!(rects[0].eq(&expected_first));
213 assert!(rects[1].eq(&expected_second));
214 assert!(rects[2].eq(&expected_third));
215 }
216
217 #[test]
218 fn split_horizontal_two_windows() {
219 let rects = horizontal(&CONTAINER, 2);
220 assert_eq!(rects.len(), 2);
221 let expected_first = Rect::new(0, 0, 400, 100);
222 let expected_second = Rect::new(0, 100, 400, 100);
223 assert!(rects[0].eq(&expected_first));
224 assert!(rects[1].eq(&expected_second));
225 }
226
227 #[test]
228 fn split_horizontal_three_windows() {
229 let rects = horizontal(&CONTAINER, 3);
230 assert_eq!(rects.len(), 3);
231 let expected_first = Rect::new(0, 0, 400, 67);
233 let expected_second = Rect::new(0, 67, 400, 67);
234 let expected_third = Rect::new(0, 134, 400, 66);
235 assert!(rects[0].eq(&expected_first));
236 assert!(rects[1].eq(&expected_second));
237 assert!(rects[2].eq(&expected_third));
238 }
239
240 #[test]
241 fn split_grid_three_windows() {
242 let rects = grid(&CONTAINER, 3);
243 assert_eq!(rects.len(), 3);
244 let expected_first = Rect::new(0, 0, 200, 200);
245 let expected_second = Rect::new(200, 0, 200, 100);
246 let expected_third = Rect::new(200, 100, 200, 100);
247 assert!(rects[0].eq(&expected_first));
248 assert!(rects[1].eq(&expected_second));
249 assert!(rects[2].eq(&expected_third));
250 }
251
252 #[test]
253 fn split_grid_four_windows() {
254 let rects = grid(&CONTAINER, 4);
255 assert_eq!(rects.len(), 4);
256 let expected_first = Rect::new(0, 0, 200, 100);
257 let expected_second = Rect::new(0, 100, 200, 100);
258 let expected_third = Rect::new(200, 0, 200, 100);
259 let expected_fourth = Rect::new(200, 100, 200, 100);
260 assert!(rects[0].eq(&expected_first));
261 assert!(rects[1].eq(&expected_second));
262 assert!(rects[2].eq(&expected_third));
263 assert!(rects[3].eq(&expected_fourth));
264 }
265
266 #[test]
267 fn split_fibonacci_four_windows() {
268 let rects = fibonacci(&CONTAINER, 4);
269 assert_eq!(rects.len(), 4);
270 let expected_first = Rect::new(0, 0, 400, 100);
271 let expected_second = Rect::new(200, 100, 200, 100);
272 let expected_third = Rect::new(0, 150, 200, 50);
273 let expected_fourth = Rect::new(0, 100, 200, 50);
274 assert!(rects[0].eq(&expected_first));
275 assert!(rects[1].eq(&expected_second));
276 assert!(rects[2].eq(&expected_third));
277 assert!(rects[3].eq(&expected_fourth));
278 }
279
280 #[test]
281 fn split_fibonacci_five_windows() {
282 let rects = fibonacci(&CONTAINER, 5);
283 assert_eq!(rects.len(), 5);
284 let expected_first = Rect::new(0, 0, 400, 100);
285 let expected_second = Rect::new(200, 100, 200, 100);
286 let expected_third = Rect::new(0, 150, 200, 50);
287 let expected_fourth = Rect::new(0, 100, 100, 50);
288 let expected_fifth = Rect::new(100, 100, 100, 50);
289 assert!(rects[0].eq(&expected_first));
290 assert!(rects[1].eq(&expected_second));
291 assert!(rects[2].eq(&expected_third));
292 assert!(rects[3].eq(&expected_fourth));
293 assert!(rects[4].eq(&expected_fifth));
294 }
295
296 #[test]
297 fn split_dwindle_four_windows() {
298 let rects = dwindle(&CONTAINER, 4);
299 assert_eq!(rects.len(), 4);
300 let expected_first = Rect::new(0, 0, 400, 100);
301 let expected_second = Rect::new(0, 100, 200, 100);
302 let expected_third = Rect::new(200, 100, 200, 50);
303 let expected_fourth = Rect::new(200, 150, 200, 50);
304 assert!(rects[0].eq(&expected_first));
305 assert!(rects[1].eq(&expected_second));
306 assert!(rects[2].eq(&expected_third));
307 assert!(rects[3].eq(&expected_fourth));
308 }
309
310 #[test]
311 fn split_dwindle_five_windows() {
312 let rects = dwindle(&CONTAINER, 5);
313 assert_eq!(rects.len(), 5);
314 let expected_first = Rect::new(0, 0, 400, 100);
315 let expected_second = Rect::new(0, 100, 200, 100);
316 let expected_third = Rect::new(200, 100, 200, 50);
317 let expected_fourth = Rect::new(200, 150, 100, 50);
318 let expected_fifth = Rect::new(300, 150, 100, 50);
319 assert!(rects[0].eq(&expected_first));
320 assert!(rects[1].eq(&expected_second));
321 assert!(rects[2].eq(&expected_third));
322 assert!(rects[3].eq(&expected_fourth));
323 assert!(rects[4].eq(&expected_fifth));
324 }
325}