1use indexmap::IndexSet;
16use std::num::NonZero;
17use thunderdome::Index as NodeIndex;
18
19use crate::{Alignment, NodeCache, Rect, UiNode, UiTree};
20
21pub struct HEqual {
27 align: (Alignment, Alignment),
28 children: IndexSet<NodeIndex>,
29}
30
31impl HEqual {
32 pub fn new() -> Self {
36 Self {
37 align: (Alignment::Begin, Alignment::Begin),
38 children: IndexSet::new(),
39 }
40 }
41
42 pub fn with_child(mut self, index: NodeIndex) -> Self {
44 self.children.insert(index);
45 self
46 }
47
48 pub fn with_align(mut self, align: (Alignment, Alignment)) -> Self {
50 self.align = align;
51 self
52 }
53
54 pub fn add_child(&mut self, index: NodeIndex) {
56 self.children.insert(index);
57 }
58
59 pub fn len(&self) -> usize {
61 self.children.len()
62 }
63
64 pub fn is_empty(&self) -> bool {
68 self.children.is_empty()
69 }
70
71 pub fn remove_child(&mut self, index: usize, tree: &mut UiTree) -> bool {
75 let Some(ti) = self.children.shift_remove_index(index) else {
76 return false;
77 };
78
79 if tree.get_node(ti).is_none() {
80 return false;
81 }
82 tree.remove_node(ti);
83
84 true
85 }
86
87 pub fn set_child_position(&mut self, index: usize, position: usize) -> bool {
91 self.children.move_index(index, position);
92 true
93 }
94
95 pub fn get_child_index(&self, index: usize) -> Option<NodeIndex> {
97 self.children.get_index(index).copied()
98 }
99}
100
101impl Default for HEqual {
102 fn default() -> Self {
103 Self::new()
104 }
105}
106
107impl UiNode for HEqual {
108 fn get_align(&self) -> (Alignment, Alignment) {
109 self.align
110 }
111
112 fn get_align_mut(&mut self) -> (&mut Alignment, &mut Alignment) {
113 (&mut self.align.0, &mut self.align.1)
114 }
115
116 fn calculate_min_size(&self, tree: &UiTree) -> (f32, f32) {
117 if self.children.is_empty() {
118 return (0.0, 0.0);
119 }
120
121 let mut w = 0.0f32;
122 let mut h = 0.0f32;
123 for child in &self.children {
124 let child = tree.get_cache(*child).expect("Child not in cache");
125 let (cw, ch) = child.min_size;
126 w = w.max(cw);
127 h = h.max(ch);
128 }
129
130 (w * (self.len() as f32), h)
131 }
132
133 fn calculate_rects(&self, cache: &NodeCache, tree: &UiTree) -> Vec<Rect> {
134 if self.is_empty() {
135 return vec![];
136 }
137
138 let mut child_rects = Vec::with_capacity(self.children.len());
139
140 let w = cache.rect.w / (self.len() as f32);
141
142 let mut x = cache.rect.x;
143 for child in &self.children {
144 let child_min = tree.get_cache(*child).expect("Child not in cache").min_size;
145 let child = tree.get_node(*child).expect("Child not in arena");
146
147 let space =
148 Rect::new(x, cache.rect.y, w, cache.rect.h).align(child.get_align(), child_min);
149 child_rects.push(space);
150 x += w;
151 }
152
153 child_rects
154 }
155
156 fn get_children(&self) -> Vec<NodeIndex> {
157 self.children.iter().copied().collect()
158 }
159}
160
161pub struct VEqual {
167 align: (Alignment, Alignment),
168 children: IndexSet<NodeIndex>,
169}
170
171impl VEqual {
172 pub fn new() -> Self {
176 Self {
177 align: (Alignment::Begin, Alignment::Begin),
178 children: IndexSet::new(),
179 }
180 }
181
182 pub fn with_child(mut self, index: NodeIndex) -> Self {
184 self.children.insert(index);
185 self
186 }
187
188 pub fn with_align(mut self, align: (Alignment, Alignment)) -> Self {
190 self.align = align;
191 self
192 }
193
194 pub fn add_child(&mut self, index: NodeIndex) {
196 self.children.insert(index);
197 }
198
199 pub fn len(&self) -> usize {
201 self.children.len()
202 }
203
204 pub fn is_empty(&self) -> bool {
208 self.children.is_empty()
209 }
210
211 pub fn remove_child(&mut self, index: usize, tree: &mut UiTree) -> bool {
215 let Some(ti) = self.children.shift_remove_index(index) else {
216 return false;
217 };
218
219 if tree.get_node(ti).is_none() {
220 return false;
221 }
222 tree.remove_node(ti);
223
224 true
225 }
226
227 pub fn set_child_position(&mut self, index: usize, position: usize) -> bool {
231 self.children.move_index(index, position);
232 true
233 }
234
235 pub fn get_child_index(&self, index: usize) -> Option<NodeIndex> {
237 self.children.get_index(index).copied()
238 }
239}
240
241impl Default for VEqual {
242 fn default() -> Self {
243 Self::new()
244 }
245}
246
247impl UiNode for VEqual {
248 fn get_align(&self) -> (Alignment, Alignment) {
249 self.align
250 }
251
252 fn get_align_mut(&mut self) -> (&mut Alignment, &mut Alignment) {
253 (&mut self.align.0, &mut self.align.1)
254 }
255
256 fn calculate_min_size(&self, tree: &UiTree) -> (f32, f32) {
257 if self.children.is_empty() {
258 return (0.0, 0.0);
259 }
260
261 let mut w = 0.0f32;
262 let mut h = 0.0f32;
263 for child in &self.children {
264 let child = tree.get_cache(*child).expect("Child not in cache");
265 let (cw, ch) = child.min_size;
266 w = w.max(cw);
267 h = h.max(ch);
268 }
269
270 (w, h * (self.len() as f32))
271 }
272
273 fn calculate_rects(&self, cache: &NodeCache, tree: &UiTree) -> Vec<Rect> {
274 if self.is_empty() {
275 return vec![];
276 }
277
278 let mut child_rects = Vec::with_capacity(self.children.len());
279
280 let h = cache.rect.h / (self.len() as f32);
281
282 let mut y = cache.rect.y;
283 for child in &self.children {
284 let child_min = tree.get_cache(*child).expect("Child not in cache").min_size;
285 let child = tree.get_node(*child).expect("Child not in arena");
286
287 let space =
288 Rect::new(cache.rect.x, y, cache.rect.w, h).align(child.get_align(), child_min);
289 child_rects.push(space);
290 y += h;
291 }
292
293 child_rects
294 }
295
296 fn get_children(&self) -> Vec<NodeIndex> {
297 self.children.iter().copied().collect()
298 }
299}
300
301pub struct Grid {
303 pub num_cols: NonZero<usize>,
304
305 align: (Alignment, Alignment),
306 children: IndexSet<NodeIndex>,
307}
308
309impl Grid {
310 pub fn new(num_cols: NonZero<usize>) -> Self {
312 Self {
313 num_cols,
314 align: (Alignment::Full, Alignment::Full),
315 children: IndexSet::new(),
316 }
317 }
318
319 pub fn with_child(mut self, index: NodeIndex) -> Self {
321 self.children.insert(index);
322 self
323 }
324
325 pub fn with_align(mut self, align: (Alignment, Alignment)) -> Self {
327 self.align = align;
328 self
329 }
330
331 pub fn add_child(&mut self, index: NodeIndex) {
333 self.children.insert(index);
334 }
335
336 pub fn len(&self) -> usize {
338 self.children.len()
339 }
340
341 pub fn is_empty(&self) -> bool {
345 self.children.is_empty()
346 }
347
348 pub fn remove_child(&mut self, index: usize, tree: &mut UiTree) -> bool {
352 let Some(ti) = self.children.shift_remove_index(index) else {
353 return false;
354 };
355
356 if tree.get_node(ti).is_none() {
357 return false;
358 }
359 tree.remove_node(ti);
360
361 true
362 }
363
364 pub fn set_child_position(&mut self, index: usize, position: usize) -> bool {
368 self.children.move_index(index, position);
369 true
370 }
371
372 pub fn get_child_index(&self, index: usize) -> Option<NodeIndex> {
374 self.children.get_index(index).copied()
375 }
376}
377
378impl UiNode for Grid {
379 fn get_align(&self) -> (Alignment, Alignment) {
380 self.align
381 }
382
383 fn get_align_mut(&mut self) -> (&mut Alignment, &mut Alignment) {
384 (&mut self.align.0, &mut self.align.1)
385 }
386
387 fn calculate_min_size(&self, tree: &UiTree) -> (f32, f32) {
388 let mut w = 0.0f32;
389 let mut h = 0.0f32;
390 for child in &self.children {
391 let (cw, ch) = tree.get_cache(*child).expect("Child not in cache").min_size;
392 w = w.max(cw);
393 h = h.max(ch);
394 }
395
396 let num_rows = self.len().div_ceil(self.num_cols.get());
397
398 (w * self.num_cols.get() as f32, h * num_rows as f32)
399 }
400
401 fn calculate_rects(&self, cache: &NodeCache, tree: &UiTree) -> Vec<Rect> {
402 let mut child_rects = Vec::with_capacity(self.children.len());
403
404 let num_rows = self.len().div_ceil(self.num_cols.get());
405 let dx = cache.rect.w / (self.num_cols.get() as f32);
406 let dy = cache.rect.h / (num_rows as f32);
407
408 let mut col = 0;
409 let mut x = cache.rect.x;
410 let mut y = cache.rect.y;
411 for child in &self.children {
412 let child_min = tree.get_cache(*child).expect("Child not in cache").min_size;
413 let child = tree.get_node(*child).expect("Child not in arena");
414
415 let space = Rect::new(x, y, dx, dy).align(child.get_align(), child_min);
416 child_rects.push(space);
417
418 col += 1;
419 if col >= self.num_cols.get() {
420 col = 0;
421 x = cache.rect.x;
422 y += dy;
423 } else {
424 x += dx;
425 }
426 }
427
428 child_rects
429 }
430
431 fn get_children(&self) -> Vec<NodeIndex> {
432 self.children.iter().copied().collect()
433 }
434}