hyperchad_transformer/layout/
calc.rs

1use bumpalo::Bump;
2use paste::paste;
3
4use crate::Container;
5
6use super::{Calc, font::FontMetrics};
7
8#[derive(Debug, Clone, Copy)]
9pub struct CalculatorDefaults {
10    pub font_size: f32,
11    pub font_margin_top: f32,
12    pub font_margin_bottom: f32,
13    pub h1_font_size: f32,
14    pub h1_font_margin_top: f32,
15    pub h1_font_margin_bottom: f32,
16    pub h2_font_size: f32,
17    pub h2_font_margin_top: f32,
18    pub h2_font_margin_bottom: f32,
19    pub h3_font_size: f32,
20    pub h3_font_margin_top: f32,
21    pub h3_font_margin_bottom: f32,
22    pub h4_font_size: f32,
23    pub h4_font_margin_top: f32,
24    pub h4_font_margin_bottom: f32,
25    pub h5_font_size: f32,
26    pub h5_font_margin_top: f32,
27    pub h5_font_margin_bottom: f32,
28    pub h6_font_size: f32,
29    pub h6_font_margin_top: f32,
30    pub h6_font_margin_bottom: f32,
31}
32
33pub struct Calculator<F: FontMetrics> {
34    font_metrics: F,
35    defaults: CalculatorDefaults,
36}
37
38impl<F: FontMetrics> Calculator<F> {
39    pub const fn new(font_metrics: F, defaults: CalculatorDefaults) -> Self {
40        Self {
41            font_metrics,
42            defaults,
43        }
44    }
45}
46
47#[cfg(feature = "benchmark")]
48macro_rules! time {
49    ($label:tt, $expr:expr $(,)?) => {{
50        let before = gimbal_time::now();
51        let ret = $expr;
52        let duration = gimbal_time::now().duration_since(before).unwrap();
53        log::info!("{}: took {}µs", $label, duration.as_micros());
54        ret
55    }};
56}
57
58#[cfg(not(feature = "benchmark"))]
59macro_rules! time {
60    ($label:tt, $expr:expr $(,)?) => {
61        $expr
62    };
63}
64
65macro_rules! update_changed {
66    ($changed:ident, $($reason:tt)+) => {{
67        if std::option_env!("LOG_ON_CHANGED") == Some("1") {
68            let reason = format!($($reason)*);
69            log::info!("change triggered because {reason}");
70        }
71        $changed = true;
72    }};
73}
74
75#[cfg_attr(feature = "profiling", profiling::all_functions)]
76impl<F: FontMetrics> Calc for Calculator<F> {
77    #[allow(clippy::let_and_return, clippy::cognitive_complexity)]
78    fn calc(&self, container: &mut Container) -> bool {
79        log::trace!("calc: container={container}");
80
81        time!("calc", {
82            let arena = time!("arena", Bump::new());
83            let context = arena.alloc(Container::default());
84            let bfs = time!("bfs", container.bfs());
85            time!("calc_widths", self.calc_widths(&bfs, container));
86            time!(
87                "calc_margin_and_padding",
88                self.calc_margin_and_padding(&bfs, container)
89            );
90            time!("flex_width", self.flex_width(&bfs, container));
91            time!("wrap_horizontal", self.wrap_horizontal(&bfs, container));
92            time!("calc_heights", self.calc_heights(&bfs, container));
93            time!("flex_height", self.flex_height(&bfs, container));
94            time!(
95                "position_elements",
96                self.position_elements(&arena, &bfs, container, context)
97            )
98        })
99    }
100}
101
102macro_rules! calc_size_on_axis {
103    (
104        $label:tt,
105        $self:ident,
106        $bfs:ident,
107        $container:ident,
108        $size:ident,
109        $axis:ident,
110        $cross_axis:ident,
111        $x:ident,
112        $y:ident,
113        $unit:ident,
114        $each_parent:expr,
115        $each_child:expr
116        $(,)?
117    ) => {{
118        use paste::paste;
119
120        use crate::{LayoutDirection, LayoutOverflow, Position, float_eq};
121
122        const LABEL: &str = $label;
123
124        log::trace!("{LABEL}:\n{}", $container);
125
126        let root_id = $container.id;
127        let defaults = $self.defaults;
128        let view_width = $container.calculated_width.expect("Missing view_width");
129        let view_height = $container.calculated_height.expect("Missing view_height");
130
131        $bfs.traverse_rev_with_parents_ref_mut(
132            true,
133            Container::default(),
134            $container,
135            |parent, mut context| {
136                if parent.id == root_id {
137                    context.calculated_font_size = Some(defaults.font_size);
138                    context.calculated_margin_top = Some(defaults.font_margin_top);
139                    context.calculated_margin_bottom = Some(defaults.font_margin_bottom);
140                }
141
142                $each_parent(&mut *parent, view_width, view_height, &context, defaults);
143
144                macro_rules! set_prop_to_context {
145                    ($prop:ident) => {
146                        if let Some(value) = paste!(parent.[<calculated_ $prop>]) {
147                            paste!(context.[<calculated_ $prop>]) = Some(value);
148                        }
149                    };
150                }
151
152                set_prop_to_context!(font_size);
153                set_prop_to_context!(margin_top);
154                set_prop_to_context!(margin_bottom);
155
156                context
157            },
158            |parent, context| {
159                let mut min_size = 0.0;
160                let mut preferred_size = 0.0;
161
162                if let Some(gap) = paste!(parent.[<$cross_axis:lower _gap>]).as_ref().and_then(crate::Number::as_fixed) {
163                    let gap = gap.calc(0.0, view_width, view_height);
164                    log::trace!("{LABEL}: setting gap={gap}");
165                    paste!(parent.[<calculated_ $cross_axis:lower _gap>]) = Some(gap);
166                }
167
168                let direction = parent.direction;
169                let overflow = paste!(parent.[<overflow_ $unit>]);
170
171                for child in &mut parent.children {
172                    log::trace!("{LABEL}: container:\n{child}");
173
174                    $each_child(&mut *child, view_width, view_height, context, defaults);
175
176                    if let Some(max) = paste!(child.[<max_ $size>]).as_ref().and_then(crate::Number::as_fixed) {
177                        let size = max.calc(0.0, view_width, view_height);
178                        log::trace!("{LABEL}: calculated_max_size={size}");
179                        paste!(child.[<calculated_max_ $size>]) = Some(size);
180                    }
181                    if let Some(min) = paste!(child.[<min_ $size>]).as_ref().and_then(crate::Number::as_fixed) {
182                        let size = min.calc(0.0, view_width, view_height);
183                        log::trace!("{LABEL}: calculated_min_size={size}");
184                        paste!(child.[<calculated_min_ $size>]) = Some(size);
185                    }
186
187                    let (mut min, mut preferred) = if let Some(size) = child.$size.as_ref().and_then(Number::as_fixed) {
188                        let new_size = size.calc(0.0, view_width, view_height);
189
190                        paste!(child.[<calculated_ $size>]) = Some(new_size);
191                        (Some(new_size), new_size)
192                    } else if let (LayoutDirection::Row, crate::Element::Raw { value }) = (LayoutDirection::$axis, &child.element) {
193                        log::trace!("{LABEL}: measuring text={value}");
194                        let bounds = $self.font_metrics.measure_text(
195                            value,
196                            context.calculated_font_size.expect("Missing calculated_font_size"),
197                            f32::INFINITY
198                        );
199                        log::trace!("{LABEL}: measured bounds={bounds:?}");
200                        let width = bounds.width();
201                        let height = bounds.height();
202
203                        child.calculated_width = Some(width);
204                        child.calculated_height = Some(height);
205                        child.calculated_preferred_height = Some(height);
206
207                        (None, width)
208                    } else if let Some(size) = paste!(child.[<calculated_preferred_ $size>]) {
209                        paste!(child.[<calculated_ $size>]) = Some(size);
210                        (paste!(child.[<calculated_child_min_ $size>]), size)
211                    } else if let Some(size) = paste!(child.[<calculated_child_min_ $size>]) {
212                        paste!(child.[<calculated_ $size>]) = Some(size);
213                        (Some(size), size)
214                    } else {
215                        paste!(child.[<calculated_ $size>]) = Some(0.0);
216                        (None, 0.0)
217                    };
218
219                    if let Some(calculated_max) = paste!(child.[<calculated_max_ $size>]) {
220                        if let Some(existing) = &mut paste!(child.[<calculated_ $size>]) {
221                            if *existing > calculated_max {
222                                *existing = calculated_max;
223                                preferred = calculated_max;
224                            }
225                        } else {
226                            paste!(child.[<calculated_ $size>]) = Some(calculated_max);
227                            preferred = calculated_max;
228                        }
229                    }
230                    if let Some(calculated_min) = paste!(child.[<calculated_min_ $size>]) {
231                        if let Some(existing) = &mut paste!(child.[<calculated_ $size>]) {
232                            if *existing < calculated_min {
233                                *existing = calculated_min;
234                                preferred = calculated_min;
235                            }
236                        } else {
237                            paste!(child.[<calculated_ $size>]) = Some(calculated_min);
238                            preferred = calculated_min;
239                        }
240                    }
241
242                    if let Some(margin) = paste!(child.[<margin_ $x>]).as_ref().and_then(crate::Number::as_fixed) {
243                        let size = margin.calc(0.0, view_width, view_height);
244                        paste!(child.[<calculated_margin_ $x>]) = Some(size);
245                        preferred += size;
246                        crate::layout::increase_opt(&mut min, size);
247                    }
248                    if let Some(margin) = paste!(child.[<margin_ $y>]).as_ref().and_then(crate::Number::as_fixed) {
249                        let size = margin.calc(0.0, view_width, view_height);
250                        paste!(child.[<calculated_margin_ $y>]) = Some(size);
251                        preferred += size;
252                        crate::layout::increase_opt(&mut min, size);
253                    }
254                    if let Some(padding) = paste!(child.[<padding_ $x>]).as_ref().and_then(crate::Number::as_fixed) {
255                        let size = padding.calc(0.0, view_width, view_height);
256                        paste!(child.[<calculated_padding_ $x>]) = Some(size);
257                        preferred += size;
258                        crate::layout::increase_opt(&mut min, size);
259                    }
260                    if let Some(padding) = paste!(child.[<padding_ $y>]).as_ref().and_then(crate::Number::as_fixed) {
261                        let size = padding.calc(0.0, view_width, view_height);
262                        paste!(child.[<calculated_padding_ $y>]) = Some(size);
263                        preferred += size;
264                        crate::layout::increase_opt(&mut min, size);
265                    }
266                    if let Some((&color, size)) = paste!(child.[<border_ $x>])
267                        .as_ref()
268                        .and_then(|(color, size)| size.as_fixed().map(|size| (color, size)))
269                    {
270                        let size = size.calc(0.0, view_width, view_height);
271                        if let Some(calculated) = &mut paste!(child.[<calculated_border_ $x>]) {
272                            if calculated.0 != color {
273                                calculated.0 = color;
274                            }
275                            if !float_eq!(calculated.1, size) {
276                                calculated.1 = size;
277                            }
278                        } else {
279                            paste!(child.[<calculated_border_ $x>]) = Some((color, size));
280                        }
281                    }
282                    if let Some((&color, size)) = paste!(child.[<border_ $y>])
283                        .as_ref()
284                        .and_then(|(color, size)| size.as_fixed().map(|size| (color, size)))
285                    {
286                        let size = size.calc(0.0, view_width, view_height);
287                        if let Some(calculated) = &mut paste!(child.[<calculated_border_ $y>]) {
288                            if calculated.0 != color {
289                                calculated.0 = color;
290                            }
291                            if !float_eq!(calculated.1, size) {
292                                calculated.1 = size;
293                            }
294                        } else {
295                            paste!(child.[<calculated_border_ $y>]) = Some((color, size));
296                        }
297                    }
298
299                    macro_rules! handle_auto_sizing {
300                        ($value:ident, $output:ident) => {{
301                            match child.position.unwrap_or_default() {
302                                Position::Static | Position::Relative | Position::Sticky => match overflow {
303                                    LayoutOverflow::Auto
304                                    | LayoutOverflow::Scroll
305                                    | LayoutOverflow::Expand
306                                    | LayoutOverflow::Squash => {
307                                        match direction {
308                                            LayoutDirection::$axis => $output += $value,
309                                            LayoutDirection::$cross_axis => if $value > $output {
310                                                $output = $value;
311                                            },
312                                        }
313                                    }
314                                    LayoutOverflow::Wrap { .. } => {
315                                        if $value > $output {
316                                            $output = $value;
317                                        }
318                                    }
319                                    LayoutOverflow::Hidden => {}
320                                },
321                                Position::Absolute | Position::Fixed => {}
322                            }
323                        }};
324                    }
325
326                    paste!(child.[<calculated_preferred_ $size>]) = Some(preferred);
327                    handle_auto_sizing!(preferred, preferred_size);
328
329                    if let Some(size) = min {
330                        paste!(child.[<calculated_child_min_ $size>]) = Some(size);
331                        handle_auto_sizing!(size, min_size);
332                    }
333                }
334
335                paste!(parent.[<calculated_child_min_ $size>]) = Some(min_size);
336                paste!(parent.[<calculated_preferred_ $size>]) = Some(preferred_size);
337            });
338    }};
339}
340
341macro_rules! flex_on_axis {
342    (
343        $label:tt,
344        $bfs:ident,
345        $container:ident,
346        $size:ident,
347        $axis:ident,
348        $cross_axis:ident,
349        $cell:ident,
350        $x:ident,
351        $y:ident,
352        $unit:ident
353        $(,)?
354    ) => {{
355        use paste::paste;
356
357        use crate::{Element, LayoutOverflow, float_eq, float_gt};
358
359        const LABEL: &str = $label;
360
361        log::trace!("{LABEL}:\n{}", $container);
362
363        let root_id = $container.id;
364        let view_width = $container.calculated_width.expect("Missing view_width");
365        let view_height = $container.calculated_height.expect("Missing view_height");
366        let mut rect = crate::layout::Rect::default();
367
368        #[allow(clippy::cognitive_complexity)]
369        $bfs.traverse_with_parents_ref_mut(
370            true,
371            &mut rect,
372            $container,
373            |parent, relative_container| {
374                if parent.id == root_id {
375                    relative_container.x = 0.0;
376                    relative_container.y = 0.0;
377                    relative_container.width = view_width;
378                    relative_container.height = view_height;
379                } else if parent.position == Some(Position::Relative) {
380                    relative_container.x = 0.0;
381                    relative_container.y = 0.0;
382                    relative_container.width = view_width;
383                    relative_container.height = view_height;
384                    paste!(relative_container.[<$size>] = parent.[<calculated_ $size>].expect("Missing parent calculated size"));
385                }
386            },
387            |parent, relative_container| {
388                let direction = parent.direction;
389                let container_size = paste!(parent.[<calculated_ $size>]).expect("Missing container size");
390
391                if let Some(gap) = paste!(parent.[<$cross_axis:lower _gap>]).as_ref().and_then(crate::Number::as_dynamic) {
392                    paste!(parent.[<calculated_ $cross_axis:lower _gap>]) =
393                        Some(gap.calc(container_size, view_width, view_height));
394                }
395
396                for child in &mut parent.children {
397                    log::trace!("{LABEL}: processing child\n{child}");
398                    let calculated_size = paste!(child.[<calculated_ $size>]).as_mut().expect("Missing calculated size");
399                    if let Some(min) = paste!(child.[<min_ $size>]).as_ref().and_then(crate::Number::as_dynamic) {
400                        let size = min.calc(container_size, view_width, view_height);
401                        log::trace!("{LABEL}: calculated_min_size={size}");
402                        paste!(child.[<calculated_min_ $size>]) = Some(size);
403                    }
404                    if let Some(max) = paste!(child.[<max_ $size>]).as_ref().and_then(crate::Number::as_dynamic) {
405                        let size = max.calc(container_size, view_width, view_height);
406                        log::trace!("{LABEL}: calculated_max_size={size}");
407                        paste!(child.[<calculated_max_ $size>]) = Some(size);
408
409                        if size < *calculated_size {
410                            *calculated_size = size;
411                        }
412                    }
413                    if let Some(min) = paste!(child.[<calculated_min_ $size>]) {
414                        if min > *calculated_size {
415                            log::trace!("{LABEL}: setting size from={calculated_size} to min_size={min}");
416                            *calculated_size = min;
417                        }
418                    }
419
420                    if matches!(paste!(child.[<overflow_ $unit>]), LayoutOverflow::Auto | LayoutOverflow::Scroll) {
421                        if let Some(min) = &mut paste!(child.[<calculated_min_ $size>]).or(paste!(child.[<calculated_child_min_ $size>])) {
422                            log::trace!("{LABEL}: checking if min={min} > container_size={container_size}");
423                            if *min > container_size {
424                                *min = container_size;
425                                paste!(child.[<calculated_ $size>]) = Some(container_size);
426                            }
427                        }
428                    }
429
430                    if let Some((&color, size)) = paste!(child.[<border_ $x>])
431                        .as_ref()
432                        .and_then(|(color, size)| size.as_dynamic().map(|size| (color, size)))
433                    {
434                        let size = size.calc(0.0, view_width, view_height);
435                        if let Some(calculated) = &mut paste!(child.[<calculated_border_ $x>]) {
436                            if calculated.0 != color {
437                                calculated.0 = color;
438                            }
439                            if !float_eq!(calculated.1, size) {
440                                calculated.1 = size;
441                            }
442                        } else {
443                            paste!(child.[<calculated_border_ $x>]) = Some((color, size));
444                        }
445                    }
446                    if let Some((&color, size)) = paste!(child.[<border_ $y>])
447                        .as_ref()
448                        .and_then(|(color, size)| size.as_dynamic().map(|size| (color, size)))
449                    {
450                        let size = size.calc(0.0, view_width, view_height);
451                        if let Some(calculated) = &mut paste!(child.[<calculated_border_ $y>]) {
452                            if calculated.0 != color {
453                                calculated.0 = color;
454                            }
455                            if !float_eq!(calculated.1, size) {
456                                calculated.1 = size;
457                            }
458                        } else {
459                            paste!(child.[<calculated_border_ $y>]) = Some((color, size));
460                        }
461                    }
462                }
463
464                if parent.relative_positioned_elements().any(|x| x.$size.as_ref().is_none_or(crate::Number::is_dynamic)) {
465                    let mut remaining_container_size = container_size;
466
467                    // Remove margins & padding from remaining_container_size
468                    for child in parent.relative_positioned_elements() {
469                        match direction {
470                            LayoutDirection::$axis => {
471                                if let Some(size) = paste!(child.[<margin_ $unit>]()) {
472                                    log::trace!(
473                                        "{LABEL}: removing margin size={size} from remaining_container_size={remaining_container_size} ({})",
474                                        remaining_container_size - size
475                                    );
476                                    remaining_container_size -= size;
477                                }
478                                if let Some(size) = paste!(child.[<padding_ $unit>]()) {
479                                    log::trace!(
480                                        "{LABEL}: removing padding size={size} from remaining_container_size={remaining_container_size} ({})",
481                                        remaining_container_size - size
482                                    );
483                                    remaining_container_size -= size;
484                                }
485                            }
486                            LayoutDirection::$cross_axis => {}
487                        }
488                    }
489
490                    log::trace!("{LABEL}: container_size={container_size} remaining_container_size={remaining_container_size}");
491                    let container_size = remaining_container_size;
492
493                    // Calculate relative positioned children dynamic sizes
494                    for child in parent.relative_positioned_elements_mut() {
495                        if let Some(size) = child.$size.as_ref().and_then(crate::Number::as_dynamic) {
496                            let container_size = match direction {
497                                LayoutDirection::$axis => container_size,
498                                LayoutDirection::$cross_axis => {
499                                    container_size
500                                        - paste!(child.[<margin_ $unit>]()).unwrap_or_default()
501                                        - paste!(child.[<padding_ $unit>]()).unwrap_or_default()
502                                }
503                            };
504                            log::trace!("{LABEL}: calculating dynamic size={size:?}");
505                            let size = size.calc(container_size, view_width, view_height);
506                            log::trace!("{LABEL}: calculated dynamic size={size}");
507                            paste!(child.[<calculated_ $size>]) = Some(size);
508                        }
509                    }
510
511                    // Fit all unsized children
512                    if parent.relative_positioned_elements().any(|x| x.$size.is_none()) {
513                        let mut remaining_size = container_size;
514                        let mut last_cell = 0;
515                        let mut max_cell_size = 0.0;
516
517                        // Remove sized children sizes from remaining_size
518                        for child in parent.relative_positioned_elements() {
519                            log::trace!("{LABEL}: calculating remaining size:\n{child}");
520
521                            match direction {
522                                LayoutDirection::$axis => {
523                                    if let Some(size) = paste!(child.[<calculated_ $size>]) {
524                                        log::trace!(
525                                            "{LABEL}: removing size={size} from remaining_size={remaining_size} ({})",
526                                            remaining_size - size
527                                        );
528                                        remaining_size -= size;
529                                    }
530                                }
531                                LayoutDirection::$cross_axis => {
532                                    if let Some(LayoutPosition::Wrap { $cell: cell, .. }) = child.calculated_position {
533                                        if cell != last_cell {
534                                            moosicbox_assert::assert!(cell > last_cell);
535                                            remaining_size -= max_cell_size;
536                                            max_cell_size = paste!(child.[<calculated_ $size>]).unwrap_or_default();
537                                        }
538                                        last_cell = cell;
539                                    }
540                                }
541                            }
542                        }
543
544                        let cell_count = last_cell + 1;
545                        remaining_size -= max_cell_size;
546
547                        if remaining_size < 0.0 {
548                            remaining_size = 0.0;
549                        }
550
551                        log::trace!("{LABEL}: remaining_size={remaining_size}\n{parent}");
552
553                        // Fit all unsized children to remaining_size
554                        match direction {
555                            LayoutDirection::$axis => {
556                                if parent.is_flex_container() {
557                                    if float_gt!(remaining_size, 0.0)
558                                        && parent
559                                            .relative_positioned_elements()
560                                            .any(|x| x.$size.is_none() && x.is_expandable(parent))
561                                    {
562                                        loop {
563                                            let mut smallest = f32::INFINITY;
564                                            let mut target = f32::INFINITY;
565                                            let mut smallest_count = 0_u16;
566
567                                            for size in parent
568                                                .relative_positioned_elements()
569                                                .filter(|x| x.$size.is_none() && x.is_expandable(parent))
570                                                .filter_map(|x| paste!(x.[<calculated_ $size>]))
571                                            {
572                                                if smallest > size {
573                                                    target = smallest;
574                                                    smallest = size;
575                                                    smallest_count = 1;
576                                                } else if float_eq!(smallest, size) {
577                                                    smallest_count += 1;
578                                                } else if size < target {
579                                                    target = size;
580                                                }
581                                            }
582
583                                            moosicbox_assert::assert!(smallest_count > 0, "expected at least one smallest item");
584                                            moosicbox_assert::assert!(smallest.is_finite(), "expected smallest to be finite");
585
586                                            let smallest_countf = f32::from(smallest_count);
587
588                                            let last_iteration = if target.is_infinite() {
589                                                log::trace!("{LABEL}: last iteration remaining_size={remaining_size}");
590                                                target = smallest + if smallest_count == 1 {
591                                                    remaining_size
592                                                } else {
593                                                    remaining_size / smallest_countf
594                                                };
595                                                remaining_size = 0.0;
596                                                true
597                                            } else if target > remaining_size {
598                                                log::trace!("{LABEL}: target={target} > remaining_size={remaining_size}");
599                                                target = if smallest_count == 1 {
600                                                    remaining_size
601                                                } else {
602                                                    remaining_size / smallest_countf
603                                                };
604                                                remaining_size = 0.0;
605                                                true
606                                            } else {
607                                                remaining_size -= (target - smallest) * smallest_countf;
608                                                float_eq!(remaining_size, 0.0)
609                                            };
610
611                                            log::trace!("{LABEL}: target={target} smallest={smallest} smallest_count={smallest_count} remaining_size={remaining_size} container_size={container_size}");
612
613                                            moosicbox_assert::assert!(target.is_finite(), "expected target to be finite");
614
615                                            let mut dynamic_child_size = false;
616
617                                            for child in parent
618                                                .relative_positioned_elements_mut()
619                                                .filter(|x| x.$size.is_none())
620                                                .filter(|x| paste!(x.[<calculated_ $size>]).is_some_and(|x| float_eq!(x, smallest)))
621                                            {
622                                                let mut clipped = false;
623                                                let mut target = target;
624
625                                                if let Some(min) = paste!(child.[<calculated_min_ $size>]) {
626                                                    log::trace!("{LABEL}: calculated_min={min}");
627                                                    let min = min - paste!(child.[<padding_ $unit>]()).unwrap_or_default() - paste!(child.[<margin_ $unit>]()).unwrap_or_default();
628                                                    log::trace!("{LABEL}: calculated_min={min} without padding/margins");
629                                                    if target < min {
630                                                        remaining_size -= min - target;
631                                                        target = min;
632                                                    }
633                                                }
634                                                if direction == LayoutDirection::Row && child.is_raw() {
635                                                    if let Some(preferred) = paste!(child.[<calculated_preferred_ $size>]) {
636                                                        log::trace!("{LABEL}: calculated_preferred={preferred}");
637                                                        let preferred = preferred - paste!(child.[<padding_ $unit>]()).unwrap_or_default() - paste!(child.[<margin_ $unit>]()).unwrap_or_default();
638                                                        log::trace!("{LABEL}: calculated_preferred={preferred} without padding/margins");
639                                                        if target > preferred {
640                                                            remaining_size += target - preferred;
641                                                            target = preferred;
642                                                            clipped = true;
643                                                        }
644                                                    }
645                                                }
646
647                                                if !clipped {
648                                                    dynamic_child_size = true;
649                                                }
650
651                                                let prev = paste!(child.[<calculated_ $size>]).unwrap();
652                                                paste!(child.[<calculated_ $size>]) = Some(target);
653                                                log::trace!("{LABEL}: increasing child size prev={prev} to target={target}:\n{child}");
654                                            }
655
656                                            if last_iteration || !dynamic_child_size {
657                                                break;
658                                            }
659                                        }
660                                    }
661                                }
662                            }
663                            LayoutDirection::$cross_axis => {
664                                log::trace!("{LABEL}: size_cross_axis\n{parent}");
665
666                                let align_items = parent.align_items;
667
668                                for child in parent.relative_positioned_elements_mut() {
669                                    if matches!(child.element, Element::Raw { .. }) {
670                                        continue;
671                                    }
672
673                                    if float_gt!(paste!(child.[<calculated_ $size>]).expect("Missing calculated_size"), container_size) {
674                                        set_float(
675                                            &mut paste!(child.[<calculated_ $size>]),
676                                            paste!(child.[<calculated_min_ $size>]).unwrap_or(container_size)
677                                        );
678                                    }
679
680                                    if align_items.is_none() {
681                                        log::trace!("{LABEL}: setting size to remaining_size={remaining_size}:\n{child}");
682                                        let mut remaining_container_size = remaining_size;
683
684                                        if let Some(size) = paste!(child.[<margin_ $unit>]()) {
685                                            log::trace!(
686                                                "{LABEL}: removing margin size={size} from remaining_container_size={remaining_container_size} ({})",
687                                                remaining_container_size - size
688                                            );
689                                            remaining_container_size -= size;
690                                        }
691                                        if let Some(size) = paste!(child.[<padding_ $unit>]()) {
692                                            log::trace!(
693                                                "{LABEL}: removing padding size={size} from remaining_container_size={remaining_container_size} ({})",
694                                                remaining_container_size - size
695                                            );
696                                            remaining_container_size -= size;
697                                        }
698
699                                        #[allow(clippy::cast_precision_loss)]
700                                        let mut new_size = remaining_container_size / (cell_count as f32);
701
702                                        if let Some(max) = paste!(child.[<calculated_max_ $size>]) {
703                                            if new_size > max {
704                                                log::trace!("{LABEL}: setting size to calculated_max={max}");
705                                                new_size = max;
706                                            }
707                                        }
708                                        if let Some(min) = paste!(child.[<calculated_min_ $size>]) {
709                                            if new_size < min {
710                                                log::trace!("{LABEL}: setting size to calculated_min={min}");
711                                                new_size = min;
712                                            }
713                                        } else if let Some(min) = paste!(child.[<calculated_child_min_ $size>]) {
714                                            if new_size < min
715                                                && paste!(child.[<calculated_max_ $size>]).is_none_or(|x| min < x)
716                                                && paste!(child.[<calculated_min_ $size>]).is_none_or(|x| min > x)
717                                            {
718                                                log::trace!("{LABEL}: setting size to calculated_child_min={min}");
719                                                new_size = min;
720                                            }
721                                        }
722
723                                        if new_size < 0.0 {
724                                            log::trace!("{LABEL}: clamping size to 0.0");
725                                            new_size = 0.0;
726                                        }
727
728                                        if child.$size.is_none() {
729                                            paste!(child.[<calculated_ $size>]) = Some(new_size);
730                                        }
731                                    }
732                                }
733                            }
734                        }
735                    }
736                }
737
738                // absolute positioned
739
740                let crate::layout::Rect { $size: relative_size, .. } = relative_container;
741
742                for child in parent.absolute_positioned_elements_mut() {
743                    let mut remaining_container_size = *relative_size;
744
745                    if let Some(size) = paste!(child.[<margin_ $unit>]()) {
746                        log::trace!(
747                            "{LABEL}: absolute removing margin size={size} from remaining_container_size={remaining_container_size} ({})",
748                            remaining_container_size - size
749                        );
750                        remaining_container_size -= size;
751                    }
752                    if let Some(size) = paste!(child.[<padding_ $unit>]()) {
753                        log::trace!(
754                            "{LABEL}: absolute removing padding size={size} from remaining_container_size={remaining_container_size} ({})",
755                            remaining_container_size - size
756                        );
757                        remaining_container_size -= size;
758                    }
759
760                    if let Some(size) = &child.$size {
761                        log::trace!("{LABEL}: calculating absolute child size={size:?}");
762                        let size = size.calc(remaining_container_size, view_width, view_height);
763                        log::trace!("{LABEL}: calculated absolute child size={size}");
764                        paste!(child.[<calculated_ $size>]) = Some(size);
765                    } else {
766                        paste!(child.[<calculated_ $size>]) = Some(remaining_container_size);
767                    }
768                }
769
770                for child in parent.fixed_positioned_elements_mut() {
771                    let mut remaining_container_size = *relative_size;
772
773                    if let Some(size) = paste!(child.[<margin_ $unit>]()) {
774                        log::trace!(
775                            "{LABEL}: fixed removing margin size={size} from remaining_container_size={remaining_container_size} ({})",
776                            remaining_container_size - size
777                        );
778                        remaining_container_size -= size;
779                    }
780                    if let Some(size) = paste!(child.[<padding_ $unit>]()) {
781                        log::trace!(
782                            "{LABEL}: fixed removing padding size={size} from remaining_container_size={remaining_container_size} ({})",
783                            remaining_container_size - size
784                        );
785                        remaining_container_size -= size;
786                    }
787
788                    if let Some(size) = &child.$size {
789                        log::trace!("{LABEL}: calculating fixed child size={size:?}");
790                        let size = size.calc(remaining_container_size, view_width, view_height);
791                        log::trace!("{LABEL}: calculated fixed child size={size}");
792                        paste!(child.[<calculated_ $size>]) = Some(size);
793                    }
794                }
795            });
796    }};
797}
798
799macro_rules! wrap_on_axis {
800    (
801        $label:tt,
802        $axis:ident,
803        $bfs:ident,
804        $container:ident,
805        $size:ident,
806        $overflow:ident,
807        $gap:ident,
808        $each_child:expr
809        $(,)?
810    ) => {{
811        use paste::paste;
812
813        use crate::models::{LayoutDirection, LayoutOverflow, LayoutPosition};
814
815        paste! {
816            const LABEL: &str = $label;
817
818            log::trace!("{LABEL}:\n{}", $container);
819
820            let view_width = $container.calculated_width.expect("Missing view_width");
821            let view_height = $container.calculated_height.expect("Missing view_height");
822
823            $bfs.traverse_mut($container, |parent| {
824                let container_width = parent.calculated_width.expect("Missing parent calculated_width");
825
826                for child in &mut parent.children {
827                    $each_child(child, container_width, view_width, view_height);
828                }
829
830                if !matches!(parent.$overflow, LayoutOverflow::Wrap { .. }) {
831                    return;
832                }
833
834                let container_size = paste!(parent.[<calculated_ $size>]).expect("Missing parent container_size");
835
836                let direction = parent.direction;
837                let mut pos = 0.0;
838                let mut row = 0;
839                let mut col = 0;
840                let gap = paste!(parent.[<calculated_ $gap>]);
841
842                for child in parent.relative_positioned_elements_mut() {
843                    let child_size = paste!(child.[<bounding_calculated_ $size>]()).expect("Missing child calculated bounding size");
844
845                    let mut position = LayoutPosition::Wrap { row, col };
846
847                    if direction == LayoutDirection::$axis {
848                        pos += child_size;
849
850                        if pos > container_size {
851                            log::trace!("{LABEL}: wrapping to next row");
852                            pos = child_size + gap.unwrap_or_default();
853                            col = 0;
854                            row += 1;
855                            position = LayoutPosition::Wrap { row, col };
856                        } else if let Some(gap) = gap {
857                            pos += gap;
858                        }
859
860                        col += 1;
861                    }
862
863                    if let LayoutPosition::Wrap { row, col } = position {
864                        log::trace!("{LABEL}: positioning child ({row}, {col}) pos={pos} container_size={container_size}:\n{child}");
865                    }
866
867                    set_value(&mut child.calculated_position, position);
868                }
869            });
870        }
871    }};
872}
873
874/// # Pass 1: Widths
875///
876/// This pass traverses the `Container` children in reverse BFS (Breadth-First Search)
877/// and calculates the widths required for each of the `Container`s.
878mod pass_widths {
879    use paste::paste;
880
881    use crate::{
882        BfsPaths, Container, Element, HeaderSize, Number,
883        layout::{
884            calc::{Calculator, CalculatorDefaults},
885            font::FontMetrics,
886            set_float,
887        },
888    };
889
890    #[cfg_attr(feature = "profiling", profiling::all_functions)]
891    impl Container {
892        fn calculate_font_size(
893            &mut self,
894            view_width: f32,
895            view_height: f32,
896            context: &Self,
897            defaults: CalculatorDefaults,
898        ) {
899            if self.calculated_font_size.is_some() {
900                return;
901            }
902
903            macro_rules! default_heading_prop {
904                ($size:expr, $prop:ident $(,)?) => {
905                    match $size {
906                        HeaderSize::H1 => paste!(defaults.[<h1_ $prop>]),
907                        HeaderSize::H2 => paste!(defaults.[<h2_ $prop>]),
908                        HeaderSize::H3 => paste!(defaults.[<h3_ $prop>]),
909                        HeaderSize::H4 => paste!(defaults.[<h4_ $prop>]),
910                        HeaderSize::H5 => paste!(defaults.[<h5_ $prop>]),
911                        HeaderSize::H6 => paste!(defaults.[<h6_ $prop>]),
912                    }
913                };
914            }
915
916            self.calculated_font_size = self.font_size.as_ref().map_or_else(
917                || {
918                    match self.element {
919                        Element::Heading { size } => {
920                            Some(default_heading_prop!(size, font_size))
921                        }
922                        _ => {
923                            context.calculated_font_size
924                        }
925                    }
926                },
927                |font_size| {
928                    let calculated_font_size = font_size.calc(
929                        context
930                            .calculated_font_size
931                            .expect("Missing calculated_font_size"),
932                        view_width,
933                        view_height,
934                    );
935                    log::trace!("calculate_font_size: setting font_size={font_size} to calculated_font_size={calculated_font_size}");
936
937                    Some(calculated_font_size)
938                },
939            );
940
941            if self.margin_top.is_none() {
942                if let Element::Heading { size } = self.element {
943                    self.calculated_margin_top = Some(default_heading_prop!(size, font_margin_top));
944                }
945            }
946
947            if self.margin_bottom.is_none() {
948                if let Element::Heading { size } = self.element {
949                    self.calculated_margin_bottom =
950                        Some(default_heading_prop!(size, font_margin_bottom));
951                }
952            }
953        }
954
955        fn calc_fixed_properties(&mut self, view_width: f32, view_height: f32) -> bool {
956            macro_rules! update_prop {
957                ($value:expr, $prop:ident, $basis:expr $(,)?) => {{
958                    let value = $value;
959                    let size = value.calc($basis, view_width, view_height);
960                    if set_float(&mut paste!(self.[<calculated_ $prop>]), size).is_some() {
961                        log::trace!("calc_fixed_properties: updated from={value} to calculated_{}={size}", stringify!($prop));
962                    }
963                }};
964            }
965
966            macro_rules! update_fixed_prop {
967                ($prop:ident, $basis:expr $(,)?) => {
968                    if let Some(value) = self.$prop.as_ref().and_then(crate::Number::as_fixed) {
969                        update_prop!(value, $prop, $basis);
970                    }
971                };
972            }
973
974            if let Some(value) = &self.opacity {
975                update_prop!(value, opacity, 1.0);
976            }
977            update_fixed_prop!(border_top_left_radius, 0.0);
978            update_fixed_prop!(border_top_right_radius, 0.0);
979            update_fixed_prop!(border_bottom_left_radius, 0.0);
980            update_fixed_prop!(border_bottom_right_radius, 0.0);
981
982            false
983        }
984    }
985
986    impl<F: FontMetrics> Calculator<F> {
987        #[cfg_attr(feature = "profiling", profiling::function)]
988        pub fn calc_widths(&self, bfs: &BfsPaths, container: &mut Container) {
989            let each_parent = |container: &mut Container,
990                               view_width,
991                               view_height,
992                               context: &Container,
993                               defaults| {
994                container.calculate_font_size(view_width, view_height, context, defaults);
995            };
996            let each_child = |container: &mut Container,
997                              view_width,
998                              view_height,
999                              context: &Container,
1000                              defaults| {
1001                container.calculate_font_size(view_width, view_height, context, defaults);
1002
1003                container.calc_fixed_properties(view_width, view_height);
1004            };
1005
1006            calc_size_on_axis!(
1007                "calc_widths",
1008                self,
1009                bfs,
1010                container,
1011                width,
1012                Row,
1013                Column,
1014                left,
1015                right,
1016                x,
1017                each_parent,
1018                each_child,
1019            );
1020        }
1021    }
1022}
1023
1024mod pass_margin_and_padding {
1025    use paste::paste;
1026
1027    use crate::{
1028        BfsPaths, Container,
1029        layout::{calc::Calculator, font::FontMetrics, set_float},
1030    };
1031
1032    impl<F: FontMetrics> Calculator<F> {
1033        /// # Panics
1034        ///
1035        /// * If any of the required container properties are missing
1036        #[cfg_attr(feature = "profiling", profiling::function)]
1037        #[allow(clippy::too_many_lines)]
1038        pub fn calc_margin_and_padding(&self, bfs: &BfsPaths, container: &mut Container) {
1039            log::trace!("calc_margin_and_padding:\n{container}");
1040
1041            let view_width = container.calculated_width.expect("Missing view_width");
1042            let view_height = container.calculated_height.expect("Missing view_height");
1043
1044            #[allow(clippy::cognitive_complexity)]
1045            bfs.traverse_mut(container, |parent| {
1046                let container_width = parent.calculated_width.expect("Missing container_width");
1047
1048                if let Some(gap) = parent
1049                    .column_gap
1050                    .as_ref()
1051                    .and_then(crate::Number::as_dynamic)
1052                {
1053                    parent.calculated_column_gap =
1054                        Some(gap.calc(container_width, view_width, view_height));
1055                }
1056
1057                for child in &mut parent.children {
1058                    macro_rules! update_dynamic_prop {
1059                        ($prop:ident $(,)?) => {
1060                            if let Some(value) =
1061                                child.$prop.as_ref().and_then(crate::Number::as_dynamic)
1062                            {
1063                                let size = value.calc(container_width, view_width, view_height);
1064                                if set_float(&mut paste!(child.[<calculated_ $prop>]), size).is_some() {
1065                                    log::trace!("calc_margin_and_padding: updated from={value} to calculated_{}={size}", stringify!($prop));
1066                                }
1067                            }
1068                        };
1069                    }
1070
1071                    update_dynamic_prop!(border_top_left_radius);
1072                    update_dynamic_prop!(border_top_right_radius);
1073                    update_dynamic_prop!(border_bottom_left_radius);
1074                    update_dynamic_prop!(border_bottom_right_radius);
1075
1076                    update_dynamic_prop!(margin_left);
1077                    update_dynamic_prop!(margin_right);
1078                    update_dynamic_prop!(margin_top);
1079                    update_dynamic_prop!(margin_bottom);
1080
1081                    update_dynamic_prop!(padding_left);
1082                    update_dynamic_prop!(padding_right);
1083                    update_dynamic_prop!(padding_top);
1084                    update_dynamic_prop!(padding_bottom);
1085                }
1086            });
1087        }
1088    }
1089}
1090
1091mod pass_flex_width {
1092    use hyperchad_transformer_models::{LayoutDirection, LayoutPosition, Position};
1093
1094    use crate::{
1095        BfsPaths, Container,
1096        layout::{calc::Calculator, font::FontMetrics, set_float},
1097    };
1098
1099    impl<F: FontMetrics> Calculator<F> {
1100        #[cfg_attr(feature = "profiling", profiling::function)]
1101        pub fn flex_width(&self, bfs: &BfsPaths, container: &mut Container) {
1102            flex_on_axis!(
1103                "flex_width",
1104                bfs,
1105                container,
1106                width,
1107                Row,
1108                Column,
1109                col,
1110                left,
1111                right,
1112                x,
1113            );
1114        }
1115    }
1116}
1117
1118mod pass_wrap_horizontal {
1119    use crate::{
1120        BfsPaths, Container, Element, float_lte,
1121        layout::{calc::Calculator, font::FontMetrics, set_value},
1122    };
1123
1124    impl<F: FontMetrics> Calculator<F> {
1125        /// # Panics
1126        ///
1127        /// * If any of the required container properties are missing
1128        #[cfg_attr(feature = "profiling", profiling::function)]
1129        pub fn wrap_horizontal(&self, bfs: &BfsPaths, container: &mut Container) {
1130            let each_child =
1131                |container: &mut Container, container_width, _view_width, _view_height| {
1132                    let Element::Raw { value } = &container.element else {
1133                        return;
1134                    };
1135                    if float_lte!(
1136                        container
1137                            .calculated_width
1138                            .expect("Missing calculated_width"),
1139                        container_width
1140                    ) {
1141                        return;
1142                    }
1143
1144                    let font_size = container.calculated_font_size.expect("Missing font_size");
1145
1146                    log::trace!(
1147                        "wrap_horizontal: measuring text={value} container_width={container_width}"
1148                    );
1149                    let bounds = self
1150                        .font_metrics
1151                        .measure_text(value, font_size, container_width);
1152                    log::trace!("wrap_horizontal: measured bounds={bounds:?}");
1153                    let new_width = bounds.width();
1154                    let new_height = bounds.height();
1155                    log::trace!("wrap_horizontal: measured width={new_width} height={new_height}");
1156
1157                    container.calculated_preferred_width = Some(new_width);
1158                    container.calculated_width = Some(new_width);
1159                    container.calculated_preferred_height = Some(new_height);
1160                    container.calculated_height = Some(new_height);
1161                };
1162
1163            wrap_on_axis!(
1164                "wrap", Row, bfs, container, width, overflow_x, column_gap, each_child,
1165            );
1166        }
1167    }
1168}
1169
1170mod pass_heights {
1171    use crate::{
1172        BfsPaths, Container, Number,
1173        layout::{calc::Calculator, font::FontMetrics},
1174    };
1175
1176    impl<F: FontMetrics> Calculator<F> {
1177        #[cfg_attr(feature = "profiling", profiling::function)]
1178        pub fn calc_heights(&self, bfs: &BfsPaths, container: &mut Container) {
1179            calc_size_on_axis!(
1180                "calc_heights",
1181                self,
1182                bfs,
1183                container,
1184                height,
1185                Column,
1186                Row,
1187                top,
1188                bottom,
1189                y,
1190                (|_, _, _, _, _| {}),
1191                (|_, _, _, _, _| {}),
1192            );
1193        }
1194    }
1195}
1196
1197mod pass_flex_height {
1198    use hyperchad_transformer_models::{LayoutDirection, LayoutPosition, Position};
1199
1200    use crate::{
1201        BfsPaths, Container,
1202        layout::{calc::Calculator, font::FontMetrics, set_float},
1203    };
1204
1205    impl<F: FontMetrics> Calculator<F> {
1206        #[cfg_attr(feature = "profiling", profiling::function)]
1207        pub fn flex_height(&self, bfs: &BfsPaths, container: &mut Container) {
1208            flex_on_axis!(
1209                "flex_height",
1210                bfs,
1211                container,
1212                height,
1213                Column,
1214                Row,
1215                row,
1216                top,
1217                bottom,
1218                y,
1219            );
1220        }
1221    }
1222}
1223
1224mod pass_positioning {
1225    use bumpalo::Bump;
1226    use hyperchad_transformer_models::{
1227        AlignItems, JustifyContent, LayoutDirection, LayoutOverflow, LayoutPosition, Position,
1228        TextAlign, Visibility,
1229    };
1230
1231    use crate::{
1232        BfsPaths, Container, Element, float_lte,
1233        layout::{calc::Calculator, font::FontMetrics, set_float},
1234    };
1235
1236    impl<F: FontMetrics> Calculator<F> {
1237        /// # Panics
1238        ///
1239        /// * If any of the required container properties are missing
1240        #[allow(clippy::too_many_lines)]
1241        #[cfg_attr(feature = "profiling", profiling::function)]
1242        pub fn position_elements(
1243            &self,
1244            arena: &Bump,
1245            bfs: &BfsPaths,
1246            container: &mut Container,
1247            context: &mut Container,
1248        ) -> bool {
1249            log::trace!("position_elements:\n{container}");
1250
1251            let root_id = container.id;
1252            let root_text_align = container.text_align;
1253            let view_width = container.calculated_width.expect("Missing view_width");
1254            let view_height = container.calculated_height.expect("Missing view_height");
1255
1256            let mut changed = false;
1257
1258            #[allow(clippy::cognitive_complexity)]
1259            bfs.traverse_with_parents_ref_mut(
1260                true,
1261                context,
1262                container,
1263                |parent, relative_container| {
1264                    if parent.id == root_id {
1265                        relative_container.calculated_x = Some(0.0);
1266                        relative_container.calculated_y = Some(0.0);
1267                        relative_container.calculated_width = Some(view_width);
1268                        relative_container.calculated_height = Some(view_height);
1269                        relative_container.text_align = root_text_align;
1270                    } else if parent.position == Some(Position::Relative) {
1271                        relative_container.calculated_x =
1272                            Some(parent.calculated_x.expect("Missing calculated_x"));
1273                        relative_container.calculated_y =
1274                            Some(parent.calculated_y.expect("Missing calculated_y"));
1275                        relative_container.calculated_width =
1276                            Some(parent.calculated_width.expect("Missing calculated_width"));
1277                        relative_container.calculated_height =
1278                            Some(parent.calculated_height.expect("Missing calculated_height"));
1279                    }
1280
1281                    if let Some(align) = parent.text_align {
1282                        relative_container.text_align = Some(align);
1283                    }
1284                },
1285                |parent, relative_container| {
1286                    let is_top_level = parent.id == root_id;
1287                    let direction = parent.direction;
1288                    let justify_content = parent.justify_content.unwrap_or_default();
1289                    let align_items = parent.align_items.unwrap_or_default();
1290                    let container_width = parent
1291                        .calculated_width
1292                        .expect("Missing parent calculated_width");
1293                    let container_height = parent
1294                        .calculated_height
1295                        .expect("Missing parent calculated_height");
1296
1297                    if let LayoutOverflow::Wrap { grid } = parent.overflow_x {
1298                        let mut last_row = 0;
1299                        let mut col_count = 0;
1300                        let mut max_col_count = 0;
1301                        let mut row_width = 0.0;
1302                        let gaps = &mut bumpalo::collections::Vec::new_in(arena);
1303                        let grid_cell_size = parent
1304                            .grid_cell_size
1305                            .as_ref()
1306                            .map(|x| x.calc(container_width, view_width, view_height));
1307                        let row_gap = parent.calculated_row_gap.unwrap_or_default();
1308                        let column_gap = parent.calculated_column_gap.unwrap_or_default();
1309
1310                        #[allow(clippy::cast_precision_loss)]
1311                        let mut add_gap = |row_width, col_count| {
1312                            let mut col_count = col_count;
1313                            let remainder = container_width - grid_cell_size.map_or(
1314                                row_width,
1315                                |cell_size| {
1316                                    col_count = 1;
1317                                    let mut size = cell_size + column_gap;
1318
1319                                    while float_lte!(size + cell_size, container_width) {
1320                                        col_count += 1;
1321                                        size += cell_size + column_gap;
1322                                    }
1323
1324                                    column_gap.mul_add(-(col_count as f32), size)
1325                                }
1326                            );
1327
1328                            let gap = match justify_content {
1329                                JustifyContent::Start
1330                                | JustifyContent::Center
1331                                | JustifyContent::End => column_gap,
1332                                JustifyContent::SpaceBetween => {
1333                                    remainder / ((col_count - 1) as f32)
1334                                }
1335                                JustifyContent::SpaceEvenly => {
1336                                    remainder / ((col_count + 1) as f32)
1337                                }
1338                            };
1339
1340                            gaps.push(gap);
1341
1342                            gap
1343                        };
1344
1345                        for child in parent.relative_positioned_elements_mut().filter(|x| x.visibility != Some(Visibility::Hidden)) {
1346                            let Some(LayoutPosition::Wrap { row, col }) = child.calculated_position
1347                            else {
1348                                continue;
1349                            };
1350                            log::trace!("position_elements: wrap calculating gaps (r{row}, c{col})");
1351
1352                            if row != last_row {
1353                                moosicbox_assert::assert!(row > last_row);
1354
1355                                let gap = add_gap(row_width, col_count);
1356                                log::trace!("position_elements: (r{row}, c{col}) gap={gap}");
1357
1358                                if grid && col_count > max_col_count {
1359                                    max_col_count = col_count;
1360                                }
1361
1362                                row_width = 0.0;
1363                                col_count = 0;
1364                                last_row = row;
1365                            }
1366
1367                            row_width += grid_cell_size.unwrap_or_else(|| {
1368                                child
1369                                    .calculated_width
1370                                    .expect("Child missing calculated_width")
1371                            });
1372                            col_count += 1;
1373                        }
1374
1375                        add_gap(row_width, col_count);
1376
1377                        #[allow(unused_assignments)]
1378                        if col_count > max_col_count {
1379                            max_col_count = col_count;
1380                        }
1381
1382                        let mut gap = gaps.first().copied().unwrap_or_default();
1383
1384                        let first_gap = |gap| match justify_content {
1385                            JustifyContent::Start
1386                            | JustifyContent::Center
1387                            | JustifyContent::End
1388                            | JustifyContent::SpaceBetween => 0.0,
1389                            JustifyContent::SpaceEvenly => gap,
1390                        };
1391
1392                        let mut x = first_gap(gap);
1393                        let mut y = 0.0;
1394
1395                        let mut max_height = 0.0;
1396                        last_row = 0;
1397
1398                        for child in parent.relative_positioned_elements_mut().filter(|x| x.visibility != Some(Visibility::Hidden)) {
1399                            let Some(LayoutPosition::Wrap { row, col }) = child.calculated_position
1400                            else {
1401                                continue;
1402                            };
1403                            log::trace!("position_elements: (r{row}, c{col}) gap={gap} row_gap={row_gap} last_row={last_row} ({x}, {y})");
1404
1405                            let child_width = child.bounding_calculated_width().unwrap();
1406                            let child_height = child.bounding_calculated_height().unwrap();
1407
1408                            if row != last_row {
1409                                moosicbox_assert::assert!(row > last_row);
1410
1411                                if !grid {
1412                                    gap = gaps.get(row as usize).copied().unwrap_or_default();
1413                                }
1414
1415                                x = first_gap(gap);
1416                                y += max_height + row_gap;
1417                                max_height = 0.0;
1418                                last_row = row;
1419                                #[cfg(feature = "layout-offset")]
1420                                {
1421                                    child.calculated_offset_x = Some(x);
1422                                }
1423                            }
1424
1425                            #[cfg(feature = "layout-offset")]
1426                            {
1427                                child.calculated_offset_x = Some(if col > 0 { gap } else { x });
1428                                child.calculated_offset_y = Some(if row > 0 { row_gap } else { 0.0 });
1429                            }
1430
1431                            if child_height > max_height {
1432                                max_height = child_height;
1433                            }
1434
1435                            log::trace!(
1436                                "position_elements: setting wrapped position ({x}, {y}):\n{child}"
1437                            );
1438                            if set_float(&mut child.calculated_x, x).is_some() && is_top_level {
1439                                update_changed!(changed, "wrapped calculated_x changed to {x}");
1440                            }
1441                            if set_float(&mut child.calculated_y, y).is_some() && is_top_level {
1442                                update_changed!(changed, "wrapped calculated_y changed to {y}");
1443                            }
1444
1445                            x += child_width + gap;
1446                        }
1447                    } else {
1448                        let mut x = 0.0;
1449                        let mut y = 0.0;
1450                        let mut col_gap = parent.calculated_column_gap.unwrap_or_default();
1451                        let row_gap = parent.calculated_row_gap.unwrap_or_default();
1452                        let axis_gap = match direction {
1453                            LayoutDirection::Row => col_gap,
1454                            LayoutDirection::Column => row_gap,
1455                        };
1456
1457                        macro_rules! visible_elements {
1458                            () => {{
1459                                parent
1460                                    .relative_positioned_elements()
1461                                    .filter(|x| x.visibility != Some(Visibility::Hidden))
1462                            }};
1463                        }
1464
1465                        macro_rules! visible_elements_mut {
1466                            () => {{
1467                                parent
1468                                    .relative_positioned_elements_mut()
1469                                    .filter(|x| x.visibility != Some(Visibility::Hidden))
1470                            }};
1471                        }
1472
1473                        macro_rules! sizes_on_axis {
1474                            ($direction:expr) => {{
1475                                visible_elements!().filter_map(|x| match $direction {
1476                                    LayoutDirection::Row => x.bounding_calculated_width(),
1477                                    LayoutDirection::Column => x.bounding_calculated_height(),
1478                                })
1479                            }};
1480                        }
1481
1482                        match justify_content {
1483                            JustifyContent::Start => {}
1484                            JustifyContent::Center => {
1485                                let count = visible_elements!().count();
1486                                let size: f32 = sizes_on_axis!(direction).sum();
1487                                #[allow(clippy::cast_precision_loss)]
1488                                let gap_offset = (count - 1) as f32 * axis_gap;
1489
1490                                match direction {
1491                                    LayoutDirection::Row => x += (container_width - size - gap_offset) / 2.0,
1492                                    LayoutDirection::Column => y += (container_height - size - gap_offset) / 2.0,
1493                                }
1494                            }
1495                            JustifyContent::End => {
1496                                let count = visible_elements!().count();
1497                                let size: f32 = sizes_on_axis!(direction).sum();
1498                                #[allow(clippy::cast_precision_loss)]
1499                                let gap_offset = (count - 1) as f32 * axis_gap;
1500
1501                                match direction {
1502                                    LayoutDirection::Row => x += container_width - size - gap_offset,
1503                                    LayoutDirection::Column => y += container_height - size - gap_offset,
1504                                }
1505                            }
1506                            JustifyContent::SpaceBetween => {
1507                                let count = visible_elements!().count();
1508                                let size: f32 = sizes_on_axis!(direction).sum();
1509
1510                                #[allow(clippy::cast_precision_loss)]
1511                                match direction {
1512                                    LayoutDirection::Row => {
1513                                        col_gap = (container_width - size) / ((count - 1) as f32);
1514                                    }
1515                                    LayoutDirection::Column => {
1516                                        col_gap = (container_height - size) / ((count - 1) as f32);
1517                                    }
1518                                }
1519                            }
1520                            JustifyContent::SpaceEvenly => {
1521                                let count = visible_elements!().count();
1522                                let size: f32 = sizes_on_axis!(direction).sum();
1523
1524                                #[allow(clippy::cast_precision_loss)]
1525                                match direction {
1526                                    LayoutDirection::Row => {
1527                                        col_gap = (container_width - size) / ((count + 1) as f32);
1528                                    }
1529                                    LayoutDirection::Column => {
1530                                        col_gap = (container_height - size) / ((count + 1) as f32);
1531                                    }
1532                                }
1533
1534                                x += col_gap;
1535                            }
1536                        }
1537
1538                        if let Some(text_align) = relative_container.text_align {
1539                            if visible_elements!().all(|x| matches!(x.element, Element::Raw { .. }))
1540                            {
1541                                match text_align {
1542                                    TextAlign::Start => {}
1543                                    TextAlign::Center => {
1544                                        let size: f32 = sizes_on_axis!(LayoutDirection::Row).sum();
1545
1546                                        log::trace!("position_elements: TextAlign::{text_align:?} container_width={container_width} container_height={container_height} size={size}");
1547
1548                                        x += (container_width - size) / 2.0;
1549                                    }
1550                                    TextAlign::End => {
1551                                        let size: f32 = sizes_on_axis!(LayoutDirection::Row).sum();
1552
1553                                        log::trace!("position_elements: TextAlign::{text_align:?} container_width={container_width} container_height={container_height} size={size}");
1554
1555                                        x += container_width - size;
1556                                    }
1557                                    TextAlign::Justify => {
1558                                        // TODO:
1559                                        // https://github.com/emilk/egui/issues/1724
1560                                        // https://docs.rs/egui/latest/egui/text/struct.LayoutJob.html
1561                                        todo!();
1562                                    }
1563                                }
1564                            }
1565                        }
1566
1567                        for (i, child) in visible_elements_mut!().enumerate()
1568                        {
1569                            let start_x = x;
1570                            let start_y = y;
1571
1572                            match align_items {
1573                                AlignItems::Start => {}
1574                                AlignItems::Center | AlignItems::End => {
1575                                    let size = match direction {
1576                                        LayoutDirection::Row => child.bounding_calculated_height(),
1577                                        LayoutDirection::Column => child.bounding_calculated_width(),
1578                                    }.unwrap_or_default();
1579
1580                                    log::trace!("position_elements: AlignItems::{align_items:?} container_width={container_width} container_height={container_height} size={size}:\n{child}");
1581
1582                                    match align_items {
1583                                        AlignItems::Start => unreachable!(),
1584                                        AlignItems::Center => match direction {
1585                                            LayoutDirection::Row => y += (container_height - size) / 2.0,
1586                                            LayoutDirection::Column => x += (container_width - size) / 2.0,
1587                                        },
1588                                        AlignItems::End => match direction {
1589                                            LayoutDirection::Row => y += container_height - size,
1590                                            LayoutDirection::Column => x += container_width - size,
1591                                        },
1592                                    }
1593                                }
1594                            }
1595
1596                            log::trace!("position_elements: setting position ({x}, {y}) i={i}:\n{child}");
1597                            if set_float(&mut child.calculated_x, x).is_some() && is_top_level {
1598                                update_changed!(changed, "calculated_x changed to {x}");
1599                            }
1600                            if set_float(&mut child.calculated_y, y).is_some() && is_top_level {
1601                                update_changed!(changed, "calculated_y changed to {y}");
1602                            }
1603
1604                            match direction {
1605                                LayoutDirection::Row => {
1606                                    #[cfg(feature = "layout-offset")]
1607                                    {
1608                                        child.calculated_offset_x = Some(if i == 0 { start_x } else { col_gap });
1609                                        child.calculated_offset_y = Some(y);
1610                                    }
1611                                    x += child.bounding_calculated_width().unwrap() + col_gap;
1612                                    y = start_y;
1613                                }
1614                                LayoutDirection::Column => {
1615                                    #[cfg(feature = "layout-offset")]
1616                                    {
1617                                        child.calculated_offset_x = Some(x);
1618                                        child.calculated_offset_y = Some(if i == 0 { start_y } else { row_gap });
1619                                    }
1620                                    x = start_x;
1621                                    y += child.bounding_calculated_height().unwrap() + row_gap;
1622                                }
1623                            }
1624                        }
1625                    }
1626
1627                    // absolute positioned
1628
1629                    let Container {
1630                        calculated_width: Some(width),
1631                        calculated_height: Some(height),
1632                        ..
1633                    } = relative_container
1634                    else {
1635                        panic!("Missing relative_container size");
1636                    };
1637                    let width = *width;
1638                    let height = *height;
1639
1640                    macro_rules! position_absolute {
1641                        ($iter:expr) => {
1642                            for child in ($iter) {
1643                                let mut x = 0.0;
1644                                let mut y = 0.0;
1645
1646                                if let Some(left) = &child.left {
1647                                    let left = left.calc(width, view_width, view_height);
1648                                    x = left;
1649                                }
1650                                if let Some(right) = &child.right {
1651                                    let right = right.calc(width, view_width, view_height);
1652                                    let bounding_width = child.bounding_calculated_width().unwrap();
1653                                    let right = width - right - bounding_width;
1654                                    x = right;
1655                                }
1656                                if let Some(top) = &child.top {
1657                                    let top = top.calc(height, view_width, view_height);
1658                                    y = top;
1659                                }
1660                                if let Some(bottom) = &child.bottom {
1661                                    let bottom = bottom.calc(height, view_width, view_height);
1662                                    let bounding_height = child.bounding_calculated_height().unwrap();
1663                                    let bottom = height - bottom - bounding_height;
1664                                    y = bottom;
1665                                }
1666
1667                                child.calculated_x = Some(x);
1668                                child.calculated_y = Some(y);
1669                            }
1670                        };
1671                    }
1672
1673                    position_absolute!(parent.absolute_positioned_elements_mut());
1674                    position_absolute!(parent.fixed_positioned_elements_mut());
1675                },
1676            );
1677
1678            changed
1679        }
1680    }
1681}
1682
1683impl Container {
1684    fn is_expandable(&self, parent: &Self) -> bool {
1685        !self.is_span() && (!parent.is_flex_container() || self.flex.is_some())
1686    }
1687}
1688
1689macro_rules! axis_sum_func {
1690    ($prop:ident, $unit:ident, $x:ident, $y:ident $(,)?) => {
1691        paste! {
1692            impl Container {
1693                #[must_use]
1694                pub fn [<$prop _ $unit>](&self) -> Option<f32> {
1695                    let mut value = None;
1696                    if let Some(x) = self.[<calculated_ $prop _ $x>] {
1697                        value = Some(x);
1698                    }
1699                    if let Some(y) = self.[<calculated_ $prop _ $y>] {
1700                        value.replace(value.map_or(y, |x| x + y));
1701                    }
1702                    value
1703                }
1704            }
1705        }
1706    };
1707}
1708
1709axis_sum_func!(margin, x, left, right);
1710axis_sum_func!(margin, y, top, bottom);
1711axis_sum_func!(padding, x, left, right);
1712axis_sum_func!(padding, y, top, bottom);
1713
1714impl Container {
1715    #[must_use]
1716    pub fn border_x(&self) -> Option<f32> {
1717        let mut borders = None;
1718        if let Some((_, border_left)) = self.calculated_border_left {
1719            borders = Some(border_left);
1720        }
1721        if let Some((_, border_right)) = self.calculated_border_right {
1722            borders.replace(borders.map_or(border_right, |x| x + border_right));
1723        }
1724        borders
1725    }
1726
1727    #[must_use]
1728    pub fn border_y(&self) -> Option<f32> {
1729        let mut borders = None;
1730        if let Some((_, border_top)) = self.calculated_border_top {
1731            borders = Some(border_top);
1732        }
1733        if let Some((_, border_bottom)) = self.calculated_border_bottom {
1734            borders.replace(borders.map_or(border_bottom, |x| x + border_bottom));
1735        }
1736        borders
1737    }
1738
1739    #[must_use]
1740    pub fn bounding_calculated_width(&self) -> Option<f32> {
1741        self.calculated_width.map(|width| {
1742            width
1743                + self.padding_x().unwrap_or(0.0)
1744                + self.scrollbar_right.unwrap_or(0.0)
1745                + self.margin_x().unwrap_or(0.0)
1746        })
1747    }
1748
1749    #[must_use]
1750    pub fn bounding_calculated_height(&self) -> Option<f32> {
1751        self.calculated_height.map(|height| {
1752            height
1753                + self.padding_y().unwrap_or(0.0)
1754                + self.scrollbar_bottom.unwrap_or(0.0)
1755                + self.margin_y().unwrap_or(0.0)
1756        })
1757    }
1758}
1759
1760#[cfg(test)]
1761mod test {
1762    use hyperchad_transformer_models::AlignItems;
1763    use maud::html;
1764    use paste::paste;
1765    use pretty_assertions::assert_eq;
1766
1767    use crate::{
1768        Calculation, Container, Element, HeaderSize, Number, Position,
1769        layout::{
1770            Calc as _,
1771            font::{FontMetrics, FontMetricsBounds, FontMetricsRow},
1772            get_scrollbar_size,
1773        },
1774        models::{JustifyContent, LayoutDirection, LayoutOverflow, LayoutPosition},
1775    };
1776
1777    use super::{Calculator, CalculatorDefaults};
1778
1779    fn compare_containers(a: &Container, b: &Container) {
1780        assert_eq!(
1781            a.display_to_string(
1782                true,
1783                true,
1784                #[cfg(feature = "format")]
1785                true,
1786                #[cfg(feature = "syntax-highlighting")]
1787                false
1788            )
1789            .unwrap(),
1790            b.display_to_string(
1791                true,
1792                true,
1793                #[cfg(feature = "format")]
1794                true,
1795                #[cfg(feature = "syntax-highlighting")]
1796                false
1797            )
1798            .unwrap()
1799        );
1800    }
1801
1802    struct DefaultFontMetrics;
1803
1804    #[cfg_attr(feature = "profiling", profiling::all_functions)]
1805    impl FontMetrics for DefaultFontMetrics {
1806        fn measure_text(&self, text: &str, size: f32, wrap_width: f32) -> FontMetricsBounds {
1807            let mut rows = vec![];
1808            #[allow(clippy::cast_precision_loss)]
1809            let mut width = text.len() as f32 * size;
1810
1811            #[allow(clippy::while_float)]
1812            while width > wrap_width {
1813                rows.push(FontMetricsRow {
1814                    width: wrap_width,
1815                    height: size,
1816                });
1817                width -= wrap_width;
1818            }
1819
1820            if width > 0.0 {
1821                rows.push(FontMetricsRow {
1822                    width,
1823                    height: size,
1824                });
1825            }
1826
1827            FontMetricsBounds { rows }
1828        }
1829    }
1830
1831    #[allow(clippy::derivable_impls)]
1832    impl Default for CalculatorDefaults {
1833        fn default() -> Self {
1834            Self {
1835                font_size: Default::default(),
1836                font_margin_top: Default::default(),
1837                font_margin_bottom: Default::default(),
1838                h1_font_size: Default::default(),
1839                h1_font_margin_top: Default::default(),
1840                h1_font_margin_bottom: Default::default(),
1841                h2_font_size: Default::default(),
1842                h2_font_margin_top: Default::default(),
1843                h2_font_margin_bottom: Default::default(),
1844                h3_font_size: Default::default(),
1845                h3_font_margin_top: Default::default(),
1846                h3_font_margin_bottom: Default::default(),
1847                h4_font_size: Default::default(),
1848                h4_font_margin_top: Default::default(),
1849                h4_font_margin_bottom: Default::default(),
1850                h5_font_size: Default::default(),
1851                h5_font_margin_top: Default::default(),
1852                h5_font_margin_bottom: Default::default(),
1853                h6_font_size: Default::default(),
1854                h6_font_margin_top: Default::default(),
1855                h6_font_margin_bottom: Default::default(),
1856            }
1857        }
1858    }
1859
1860    static CALCULATOR: Calculator<DefaultFontMetrics> = Calculator::new(
1861        DefaultFontMetrics,
1862        CalculatorDefaults {
1863            font_size: 14.0,
1864            font_margin_top: 0.0,
1865            font_margin_bottom: 0.0,
1866            h1_font_size: 32.0,
1867            h1_font_margin_top: 0.0,
1868            h1_font_margin_bottom: 0.0,
1869            h2_font_size: 24.0,
1870            h2_font_margin_top: 0.0,
1871            h2_font_margin_bottom: 0.0,
1872            h3_font_size: 18.72,
1873            h3_font_margin_top: 0.0,
1874            h3_font_margin_bottom: 0.0,
1875            h4_font_size: 16.0,
1876            h4_font_margin_top: 0.0,
1877            h4_font_margin_bottom: 0.0,
1878            h5_font_size: 13.28,
1879            h5_font_margin_top: 0.0,
1880            h5_font_margin_bottom: 0.0,
1881            h6_font_size: 10.72,
1882            h6_font_margin_top: 0.0,
1883            h6_font_margin_bottom: 0.0,
1884        },
1885    );
1886
1887    mod scrollbar {
1888        use super::*;
1889
1890        #[test_log::test]
1891        #[ignore]
1892        fn calc_calculates_resized_wrapped_content_with_scrollbar_and_padding_correctly() {
1893            let mut container: Container = html! {
1894                div sx-width="100%" sx-height="100%" sx-position="relative" {
1895                    section sx-dir="row" sx-height=("calc(100% - 140px)") {
1896                        aside sx-width="calc(max(240, min(280, 15%)))" {}
1897                        main sx-overflow-y="auto" {
1898                            div
1899                                sx-dir="row"
1900                                sx-overflow-x="wrap"
1901                                sx-justify-content="space-evenly"
1902                                sx-gap=(15)
1903                                sx-padding-left=(30)
1904                                sx-padding-right=(30)
1905                                sx-padding-top=(15)
1906                                sx-padding-bottom=(15)
1907                            {
1908                                @for _ in 0..19 {
1909                                    div sx-width=(200) sx-height=(200 + 30) {}
1910                                }
1911                            }
1912                        }
1913                    }
1914                    div
1915                        sx-width="calc(min(500, 30%))"
1916                        sx-height="calc(100% - 200)"
1917                        sx-padding=(20)
1918                        sx-position="absolute"
1919                        sx-bottom=(170)
1920                        sx-right=(0)
1921                    {}
1922                }
1923            }
1924            .try_into()
1925            .unwrap();
1926
1927            container.calculated_width = Some(1600.0);
1928            container.calculated_height = Some(1000.0);
1929
1930            CALCULATOR.calc(&mut container);
1931            log::trace!("container:\n{container}");
1932
1933            let container = container.children[0].children[0].children[1].children[0].clone();
1934
1935            compare_containers(
1936                &container.clone(),
1937                &Container {
1938                    calculated_width: Some(1360.0 - 30.0 - 30.0 - f32::from(get_scrollbar_size())),
1939                    calculated_height: Some(920.0),
1940                    calculated_x: Some(0.0),
1941                    calculated_y: Some(0.0),
1942                    calculated_padding_left: Some(30.0),
1943                    calculated_padding_right: Some(30.0),
1944                    calculated_padding_top: Some(15.0),
1945                    calculated_padding_bottom: Some(15.0),
1946                    ..container
1947                },
1948            );
1949        }
1950
1951        #[test_log::test]
1952        #[ignore]
1953        fn calc_auto_y_wraps_nested_elements_properly_by_taking_into_account_scrollbar_size() {
1954            let mut container = Container {
1955                children: vec![Container {
1956                    children: vec![
1957                        Container {
1958                            width: Some(Number::Integer(25)),
1959                            ..Default::default()
1960                        },
1961                        Container {
1962                            width: Some(Number::Integer(25)),
1963                            ..Default::default()
1964                        },
1965                        Container {
1966                            width: Some(Number::Integer(25)),
1967                            ..Default::default()
1968                        },
1969                        Container {
1970                            width: Some(Number::Integer(25)),
1971                            ..Default::default()
1972                        },
1973                        Container {
1974                            width: Some(Number::Integer(25)),
1975                            ..Default::default()
1976                        },
1977                    ],
1978                    calculated_width: Some(75.0),
1979                    calculated_height: Some(40.0),
1980                    direction: LayoutDirection::Row,
1981                    overflow_x: LayoutOverflow::Wrap { grid: true },
1982                    overflow_y: LayoutOverflow::Expand,
1983                    ..Default::default()
1984                }],
1985
1986                calculated_width: Some(75.0),
1987                calculated_height: Some(40.0),
1988                overflow_y: LayoutOverflow::Auto,
1989                ..Default::default()
1990            };
1991            CALCULATOR.calc(&mut container);
1992            log::trace!("container:\n{container}");
1993
1994            compare_containers(
1995                &container.clone(),
1996                &Container {
1997                    children: vec![Container {
1998                        children: vec![
1999                            Container {
2000                                calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 0 }),
2001                                calculated_width: Some(25.0),
2002                                calculated_height: Some(40.0),
2003                                calculated_x: Some(0.0),
2004                                calculated_y: Some(0.0),
2005                                ..container.children[0].children[0].clone()
2006                            },
2007                            Container {
2008                                calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
2009                                calculated_width: Some(25.0),
2010                                calculated_height: Some(40.0),
2011                                calculated_x: Some(25.0),
2012                                calculated_y: Some(0.0),
2013                                ..container.children[0].children[1].clone()
2014                            },
2015                            Container {
2016                                calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 0 }),
2017                                calculated_width: Some(25.0),
2018                                calculated_height: Some(40.0),
2019                                calculated_x: Some(0.0),
2020                                calculated_y: Some(40.0),
2021                                ..container.children[0].children[2].clone()
2022                            },
2023                            Container {
2024                                calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 1 }),
2025                                calculated_width: Some(25.0),
2026                                calculated_height: Some(40.0),
2027                                calculated_x: Some(25.0),
2028                                calculated_y: Some(40.0),
2029                                ..container.children[0].children[3].clone()
2030                            },
2031                            Container {
2032                                calculated_position: Some(LayoutPosition::Wrap { row: 2, col: 0 }),
2033                                calculated_width: Some(25.0),
2034                                calculated_height: Some(40.0),
2035                                calculated_x: Some(0.0),
2036                                calculated_y: Some(80.0),
2037                                ..container.children[0].children[4].clone()
2038                            },
2039                        ],
2040                        ..container.children[0].clone()
2041                    }],
2042
2043                    calculated_width: Some(75.0 - f32::from(get_scrollbar_size())),
2044                    calculated_height: Some(40.0),
2045                    ..container
2046                },
2047            );
2048        }
2049    }
2050
2051    mod table {
2052        use super::*;
2053
2054        #[test_log::test]
2055        #[ignore]
2056        fn calc_can_calc_table_column_and_row_sizes() {
2057            let mut container = Container {
2058                children: vec![Container {
2059                    element: Element::Table,
2060                    children: vec![
2061                        Container {
2062                            element: Element::TR,
2063                            direction: LayoutDirection::Row,
2064                            children: vec![
2065                                Container {
2066                                    element: Element::TD,
2067                                    children: vec![Container {
2068                                        element: Element::Div,
2069                                        width: Some(Number::Integer(40)),
2070                                        height: Some(Number::Integer(10)),
2071                                        ..Default::default()
2072                                    }],
2073                                    ..Container::default()
2074                                },
2075                                Container {
2076                                    element: Element::TD,
2077                                    children: vec![Container {
2078                                        element: Element::Div,
2079                                        width: Some(Number::Integer(30)),
2080                                        height: Some(Number::Integer(20)),
2081                                        ..Default::default()
2082                                    }],
2083                                    ..Container::default()
2084                                },
2085                            ],
2086                            ..Default::default()
2087                        },
2088                        Container {
2089                            element: Element::TR,
2090                            direction: LayoutDirection::Row,
2091                            children: vec![
2092                                Container {
2093                                    element: Element::TD,
2094                                    children: vec![Container {
2095                                        element: Element::Div,
2096                                        width: Some(Number::Integer(10)),
2097                                        height: Some(Number::Integer(40)),
2098                                        ..Default::default()
2099                                    }],
2100                                    ..Container::default()
2101                                },
2102                                Container {
2103                                    element: Element::TD,
2104                                    children: vec![Container {
2105                                        element: Element::Div,
2106                                        width: Some(Number::Integer(20)),
2107                                        height: Some(Number::Integer(30)),
2108                                        ..Default::default()
2109                                    }],
2110                                    ..Container::default()
2111                                },
2112                            ],
2113                            ..Default::default()
2114                        },
2115                    ],
2116                    ..Default::default()
2117                }],
2118                calculated_width: Some(70.0),
2119                calculated_height: Some(80.0),
2120                ..Default::default()
2121            };
2122            CALCULATOR.calc(&mut container);
2123            log::trace!("container:\n{container}");
2124
2125            compare_containers(
2126                &container.clone(),
2127                &Container {
2128                    children: vec![Container {
2129                        children: vec![
2130                            Container {
2131                                children: vec![
2132                                    Container {
2133                                        children: vec![Container {
2134                                            calculated_width: Some(40.0),
2135                                            calculated_height: Some(10.0),
2136                                            ..container.children[0].children[0].children[0].children
2137                                                [0]
2138                                            .clone()
2139                                        }],
2140                                        calculated_width: Some(40.0),
2141                                        calculated_height: Some(20.0),
2142                                        ..container.children[0].children[0].children[0].clone()
2143                                    },
2144                                    Container {
2145                                        children: vec![Container {
2146                                            calculated_width: Some(30.0),
2147                                            calculated_height: Some(20.0),
2148                                            ..container.children[0].children[0].children[1].children
2149                                                [0]
2150                                            .clone()
2151                                        }],
2152                                        calculated_width: Some(30.0),
2153                                        calculated_height: Some(20.0),
2154                                        ..container.children[0].children[0].children[1].clone()
2155                                    },
2156                                ],
2157                                calculated_width: Some(70.0),
2158                                calculated_height: Some(20.0),
2159                                ..container.children[0].children[0].clone()
2160                            },
2161                            Container {
2162                                children: vec![
2163                                    Container {
2164                                        children: vec![Container {
2165                                            calculated_width: Some(10.0),
2166                                            calculated_height: Some(40.0),
2167                                            ..container.children[0].children[1].children[0].children
2168                                                [0]
2169                                            .clone()
2170                                        }],
2171                                        calculated_width: Some(40.0),
2172                                        calculated_height: Some(40.0),
2173                                        ..container.children[0].children[1].children[0].clone()
2174                                    },
2175                                    Container {
2176                                        children: vec![Container {
2177                                            calculated_width: Some(20.0),
2178                                            calculated_height: Some(30.0),
2179                                            ..container.children[0].children[1].children[1].children
2180                                                [0]
2181                                            .clone()
2182                                        }],
2183                                        calculated_width: Some(30.0),
2184                                        calculated_height: Some(40.0),
2185                                        ..container.children[0].children[1].children[1].clone()
2186                                    },
2187                                ],
2188                                calculated_width: Some(70.0),
2189                                calculated_height: Some(40.0),
2190                                ..container.children[0].children[1].clone()
2191                            },
2192                        ],
2193                        calculated_width: Some(70.0),
2194                        calculated_height: Some(20.0 + 40.0),
2195                        ..container.children[0].clone()
2196                    }],
2197                    ..container
2198                },
2199            );
2200        }
2201
2202        #[test_log::test]
2203        #[ignore]
2204        fn calc_can_calc_table_column_and_row_sizes_and_expand_to_fill_width() {
2205            let mut container = Container {
2206                children: vec![Container {
2207                    element: Element::Table,
2208                    children: vec![
2209                        Container {
2210                            element: Element::TR,
2211                            direction: LayoutDirection::Row,
2212                            children: vec![
2213                                Container {
2214                                    element: Element::TD,
2215                                    children: vec![Container {
2216                                        width: Some(Number::Integer(40)),
2217                                        height: Some(Number::Integer(10)),
2218                                        ..Default::default()
2219                                    }],
2220                                    ..Container::default()
2221                                },
2222                                Container {
2223                                    element: Element::TD,
2224                                    children: vec![Container {
2225                                        width: Some(Number::Integer(30)),
2226                                        height: Some(Number::Integer(20)),
2227                                        ..Default::default()
2228                                    }],
2229                                    ..Container::default()
2230                                },
2231                            ],
2232                            ..Default::default()
2233                        },
2234                        Container {
2235                            element: Element::TR,
2236                            direction: LayoutDirection::Row,
2237                            children: vec![
2238                                Container {
2239                                    element: Element::TD,
2240                                    children: vec![Container {
2241                                        width: Some(Number::Integer(10)),
2242                                        height: Some(Number::Integer(40)),
2243                                        ..Default::default()
2244                                    }],
2245                                    ..Container::default()
2246                                },
2247                                Container {
2248                                    element: Element::TD,
2249                                    children: vec![Container {
2250                                        width: Some(Number::Integer(20)),
2251                                        height: Some(Number::Integer(30)),
2252                                        ..Default::default()
2253                                    }],
2254                                    ..Container::default()
2255                                },
2256                            ],
2257                            ..Default::default()
2258                        },
2259                    ],
2260                    ..Default::default()
2261                }],
2262                calculated_width: Some(100.0),
2263                calculated_height: Some(80.0),
2264                ..Default::default()
2265            };
2266            CALCULATOR.calc(&mut container);
2267            log::trace!("container:\n{container}");
2268
2269            compare_containers(
2270                &container.clone(),
2271                &Container {
2272                    children: vec![Container {
2273                        children: vec![
2274                            Container {
2275                                children: vec![
2276                                    Container {
2277                                        children: vec![Container {
2278                                            calculated_width: Some(40.0),
2279                                            calculated_height: Some(10.0),
2280                                            ..container.children[0].children[0].children[0].children
2281                                                [0]
2282                                            .clone()
2283                                        }],
2284                                        calculated_width: Some(50.0),
2285                                        calculated_height: Some(20.0),
2286                                        ..container.children[0].children[0].children[0].clone()
2287                                    },
2288                                    Container {
2289                                        children: vec![Container {
2290                                            calculated_width: Some(30.0),
2291                                            calculated_height: Some(20.0),
2292                                            ..container.children[0].children[0].children[1].children
2293                                                [0]
2294                                            .clone()
2295                                        }],
2296                                        calculated_width: Some(50.0),
2297                                        calculated_height: Some(20.0),
2298                                        ..container.children[0].children[0].children[1].clone()
2299                                    },
2300                                ],
2301                                calculated_width: Some(100.0),
2302                                calculated_height: Some(20.0),
2303                                ..container.children[0].children[0].clone()
2304                            },
2305                            Container {
2306                                children: vec![
2307                                    Container {
2308                                        children: vec![Container {
2309                                            calculated_width: Some(10.0),
2310                                            calculated_height: Some(40.0),
2311                                            ..container.children[0].children[1].children[0].children
2312                                                [0]
2313                                            .clone()
2314                                        }],
2315                                        calculated_width: Some(50.0),
2316                                        calculated_height: Some(40.0),
2317                                        ..container.children[0].children[1].children[0].clone()
2318                                    },
2319                                    Container {
2320                                        children: vec![Container {
2321                                            calculated_width: Some(20.0),
2322                                            calculated_height: Some(30.0),
2323                                            ..container.children[0].children[1].children[1].children
2324                                                [0]
2325                                            .clone()
2326                                        }],
2327                                        calculated_width: Some(50.0),
2328                                        calculated_height: Some(40.0),
2329                                        ..container.children[0].children[1].children[1].clone()
2330                                    },
2331                                ],
2332                                calculated_width: Some(100.0),
2333                                calculated_height: Some(40.0),
2334                                ..container.children[0].children[1].clone()
2335                            },
2336                        ],
2337                        calculated_width: Some(100.0),
2338                        calculated_height: Some(20.0 + 40.0),
2339                        ..container.children[0].clone()
2340                    }],
2341                    ..container
2342                },
2343            );
2344        }
2345
2346        #[test_log::test]
2347        #[ignore]
2348        fn calc_can_calc_table_column_and_row_sizes_and_auto_size_unsized_cells() {
2349            let mut container = Container {
2350                children: vec![Container {
2351                    element: Element::Table,
2352                    children: vec![
2353                        Container {
2354                            element: Element::TR,
2355                            direction: LayoutDirection::Row,
2356                            children: vec![
2357                                Container {
2358                                    element: Element::TD,
2359                                    children: vec![Container {
2360                                        width: Some(Number::Integer(40)),
2361                                        height: Some(Number::Integer(10)),
2362                                        ..Default::default()
2363                                    }],
2364                                    ..Container::default()
2365                                },
2366                                Container {
2367                                    element: Element::TD,
2368                                    children: vec![Container::default()],
2369                                    ..Container::default()
2370                                },
2371                            ],
2372                            ..Default::default()
2373                        },
2374                        Container {
2375                            element: Element::TR,
2376                            direction: LayoutDirection::Row,
2377                            children: vec![
2378                                Container {
2379                                    element: Element::TD,
2380                                    children: vec![Container::default()],
2381                                    ..Container::default()
2382                                },
2383                                Container {
2384                                    element: Element::TD,
2385                                    children: vec![Container {
2386                                        width: Some(Number::Integer(20)),
2387                                        height: Some(Number::Integer(30)),
2388                                        ..Default::default()
2389                                    }],
2390                                    ..Container::default()
2391                                },
2392                            ],
2393                            ..Default::default()
2394                        },
2395                    ],
2396                    ..Default::default()
2397                }],
2398                calculated_width: Some(100.0),
2399                calculated_height: Some(80.0),
2400                ..Default::default()
2401            };
2402            CALCULATOR.calc(&mut container);
2403            log::trace!("container:\n{container}");
2404
2405            compare_containers(
2406                &container.clone(),
2407                &Container {
2408                    children: vec![Container {
2409                        children: vec![
2410                            Container {
2411                                children: vec![
2412                                    Container {
2413                                        children: vec![Container {
2414                                            calculated_width: Some(40.0),
2415                                            calculated_height: Some(10.0),
2416                                            ..container.children[0].children[0].children[0].children
2417                                                [0]
2418                                            .clone()
2419                                        }],
2420                                        calculated_width: Some(50.0),
2421                                        calculated_height: Some(10.0),
2422                                        ..container.children[0].children[0].children[0].clone()
2423                                    },
2424                                    Container {
2425                                        calculated_width: Some(50.0),
2426                                        calculated_height: Some(10.0),
2427                                        ..container.children[0].children[0].children[1].clone()
2428                                    },
2429                                ],
2430                                calculated_width: Some(100.0),
2431                                calculated_height: Some(10.0),
2432                                ..container.children[0].children[0].clone()
2433                            },
2434                            Container {
2435                                children: vec![
2436                                    Container {
2437                                        calculated_width: Some(50.0),
2438                                        calculated_height: Some(30.0),
2439                                        ..container.children[0].children[1].children[0].clone()
2440                                    },
2441                                    Container {
2442                                        children: vec![Container {
2443                                            calculated_width: Some(20.0),
2444                                            calculated_height: Some(30.0),
2445                                            ..container.children[0].children[1].children[1].children
2446                                                [0]
2447                                            .clone()
2448                                        }],
2449                                        calculated_width: Some(50.0),
2450                                        calculated_height: Some(30.0),
2451                                        ..container.children[0].children[1].children[1].clone()
2452                                    },
2453                                ],
2454                                calculated_width: Some(100.0),
2455                                calculated_height: Some(30.0),
2456                                ..container.children[0].children[1].clone()
2457                            },
2458                        ],
2459                        calculated_width: Some(100.0),
2460                        calculated_height: Some(10.0 + 30.0),
2461                        ..container.children[0].clone()
2462                    }],
2463                    ..container
2464                },
2465            );
2466        }
2467
2468        #[test_log::test]
2469        #[ignore]
2470        fn calc_can_calc_table_column_and_row_sizes_and_auto_size_unsized_cells_when_all_are_unsized()
2471         {
2472            let mut container = Container {
2473                children: vec![Container {
2474                    element: Element::Table,
2475                    children: vec![
2476                        Container {
2477                            element: Element::TR,
2478                            direction: LayoutDirection::Row,
2479                            children: vec![
2480                                Container {
2481                                    element: Element::TD,
2482                                    children: vec![Container::default()],
2483                                    ..Container::default()
2484                                },
2485                                Container {
2486                                    element: Element::TD,
2487                                    children: vec![Container::default()],
2488                                    ..Container::default()
2489                                },
2490                            ],
2491                            ..Default::default()
2492                        },
2493                        Container {
2494                            element: Element::TR,
2495                            direction: LayoutDirection::Row,
2496                            children: vec![
2497                                Container {
2498                                    element: Element::TD,
2499                                    children: vec![Container::default()],
2500                                    ..Container::default()
2501                                },
2502                                Container {
2503                                    element: Element::TD,
2504                                    children: vec![Container::default()],
2505                                    ..Container::default()
2506                                },
2507                            ],
2508                            ..Default::default()
2509                        },
2510                    ],
2511                    ..Default::default()
2512                }],
2513                calculated_width: Some(100.0),
2514                calculated_height: Some(80.0),
2515                ..Default::default()
2516            };
2517            CALCULATOR.calc(&mut container);
2518            log::trace!("container:\n{container}");
2519
2520            compare_containers(
2521                &container.clone(),
2522                &Container {
2523                    children: vec![Container {
2524                        children: vec![
2525                            Container {
2526                                children: vec![
2527                                    Container {
2528                                        children: vec![Container {
2529                                            calculated_width: Some(50.0),
2530                                            calculated_height: Some(25.0),
2531                                            ..container.children[0].children[0].children[0].children
2532                                                [0]
2533                                            .clone()
2534                                        }],
2535                                        calculated_width: Some(50.0),
2536                                        calculated_height: Some(25.0),
2537                                        ..container.children[0].children[0].children[0].clone()
2538                                    },
2539                                    Container {
2540                                        children: vec![Container {
2541                                            calculated_width: Some(50.0),
2542                                            calculated_height: Some(25.0),
2543                                            ..container.children[0].children[0].children[1].children
2544                                                [0]
2545                                            .clone()
2546                                        }],
2547                                        calculated_width: Some(50.0),
2548                                        calculated_height: Some(25.0),
2549                                        ..container.children[0].children[0].children[1].clone()
2550                                    },
2551                                ],
2552                                calculated_width: Some(100.0),
2553                                calculated_height: Some(25.0),
2554                                ..container.children[0].children[0].clone()
2555                            },
2556                            Container {
2557                                children: vec![
2558                                    Container {
2559                                        children: vec![Container {
2560                                            calculated_width: Some(50.0),
2561                                            calculated_height: Some(25.0),
2562                                            ..container.children[0].children[1].children[0].children
2563                                                [0]
2564                                            .clone()
2565                                        }],
2566                                        calculated_width: Some(50.0),
2567                                        calculated_height: Some(25.0),
2568                                        ..container.children[0].children[1].children[0].clone()
2569                                    },
2570                                    Container {
2571                                        children: vec![Container {
2572                                            calculated_width: Some(50.0),
2573                                            calculated_height: Some(25.0),
2574                                            ..container.children[0].children[1].children[1].children
2575                                                [0]
2576                                            .clone()
2577                                        }],
2578                                        calculated_width: Some(50.0),
2579                                        calculated_height: Some(25.0),
2580                                        ..container.children[0].children[1].children[1].clone()
2581                                    },
2582                                ],
2583                                calculated_width: Some(100.0),
2584                                calculated_height: Some(25.0),
2585                                ..container.children[0].children[1].clone()
2586                            },
2587                        ],
2588                        calculated_width: Some(100.0),
2589                        calculated_height: Some(25.0 + 25.0),
2590                        ..container.children[0].clone()
2591                    }],
2592                    ..container
2593                },
2594            );
2595        }
2596
2597        #[test_log::test]
2598        #[ignore]
2599        fn calc_can_calc_table_column_and_row_sizes_and_auto_size_raw_data() {
2600            let mut container: Container = html! {
2601                table {
2602                    tr {
2603                        td { "test" }
2604                        td { "test" }
2605                    }
2606                    tr {
2607                        td { "test" }
2608                        td { "test" }
2609                    }
2610                }
2611            }
2612            .try_into()
2613            .unwrap();
2614
2615            container.calculated_width = Some(100.0);
2616            container.calculated_height = Some(80.0);
2617
2618            CALCULATOR.calc(&mut container);
2619            log::trace!("container:\n{container}");
2620
2621            compare_containers(
2622                &container.clone(),
2623                &Container {
2624                    children: vec![Container {
2625                        children: vec![
2626                            Container {
2627                                children: vec![
2628                                    Container {
2629                                        children: container.children[0].children[0].children[0]
2630                                            .children
2631                                            .clone(),
2632                                        calculated_width: Some(50.0),
2633                                        calculated_height: Some(25.0),
2634                                        ..container.children[0].children[0].children[0].clone()
2635                                    },
2636                                    Container {
2637                                        children: container.children[0].children[0].children[1]
2638                                            .children
2639                                            .clone(),
2640                                        calculated_width: Some(50.0),
2641                                        calculated_height: Some(25.0),
2642                                        ..container.children[0].children[0].children[1].clone()
2643                                    },
2644                                ],
2645                                calculated_width: Some(100.0),
2646                                calculated_height: Some(25.0),
2647                                ..container.children[0].children[0].clone()
2648                            },
2649                            Container {
2650                                children: vec![
2651                                    Container {
2652                                        children: container.children[0].children[1].children[0]
2653                                            .children
2654                                            .clone(),
2655                                        calculated_width: Some(50.0),
2656                                        calculated_height: Some(25.0),
2657                                        ..container.children[0].children[1].children[0].clone()
2658                                    },
2659                                    Container {
2660                                        children: container.children[0].children[1].children[1]
2661                                            .children
2662                                            .clone(),
2663                                        calculated_width: Some(50.0),
2664                                        calculated_height: Some(25.0),
2665                                        ..container.children[0].children[1].children[1].clone()
2666                                    },
2667                                ],
2668                                calculated_width: Some(100.0),
2669                                calculated_height: Some(25.0),
2670                                ..container.children[0].children[1].clone()
2671                            },
2672                        ],
2673                        calculated_width: Some(100.0),
2674                        calculated_height: Some(25.0 + 25.0),
2675                        ..container.children[0].clone()
2676                    }],
2677                    ..container
2678                },
2679            );
2680        }
2681
2682        #[test_log::test]
2683        #[ignore]
2684        fn calc_can_calc_table_column_and_row_sizes_with_tbody() {
2685            let mut container = Container {
2686                children: vec![Container {
2687                    element: Element::Table,
2688                    children: vec![Container {
2689                        element: Element::TBody,
2690                        children: vec![
2691                            Container {
2692                                element: Element::TR,
2693                                direction: LayoutDirection::Row,
2694                                children: vec![
2695                                    Container {
2696                                        element: Element::TD,
2697                                        children: vec![Container {
2698                                            element: Element::Raw {
2699                                                value: "test".to_string(),
2700                                            },
2701                                            ..Container::default()
2702                                        }],
2703                                        ..Container::default()
2704                                    },
2705                                    Container {
2706                                        element: Element::TD,
2707                                        children: vec![Container {
2708                                            element: Element::Raw {
2709                                                value: "test".to_string(),
2710                                            },
2711                                            ..Container::default()
2712                                        }],
2713                                        ..Container::default()
2714                                    },
2715                                ],
2716                                ..Default::default()
2717                            },
2718                            Container {
2719                                element: Element::TR,
2720                                direction: LayoutDirection::Row,
2721                                children: vec![
2722                                    Container {
2723                                        element: Element::TD,
2724                                        children: vec![Container {
2725                                            element: Element::Raw {
2726                                                value: "test".to_string(),
2727                                            },
2728                                            ..Container::default()
2729                                        }],
2730                                        ..Container::default()
2731                                    },
2732                                    Container {
2733                                        element: Element::TD,
2734                                        children: vec![Container {
2735                                            element: Element::Raw {
2736                                                value: "test".to_string(),
2737                                            },
2738                                            ..Container::default()
2739                                        }],
2740                                        ..Container::default()
2741                                    },
2742                                ],
2743                                ..Default::default()
2744                            },
2745                        ],
2746                        ..Default::default()
2747                    }],
2748                    ..Default::default()
2749                }],
2750                calculated_width: Some(100.0),
2751                calculated_height: Some(80.0),
2752                ..Default::default()
2753            };
2754            CALCULATOR.calc(&mut container);
2755            log::trace!("container:\n{container}");
2756
2757            compare_containers(
2758                &container.clone(),
2759                &Container {
2760                    children: vec![Container {
2761                        children: vec![Container {
2762                            children: vec![
2763                                Container {
2764                                    children: vec![
2765                                        Container {
2766                                            children: container.children[0].children[0].children[0]
2767                                                .children[0]
2768                                                .children
2769                                                .clone(),
2770                                            calculated_width: Some(50.0),
2771                                            calculated_height: Some(25.0),
2772                                            ..container.children[0].children[0].children[0].children
2773                                                [0]
2774                                            .clone()
2775                                        },
2776                                        Container {
2777                                            children: container.children[0].children[0].children[0]
2778                                                .children[1]
2779                                                .children
2780                                                .clone(),
2781                                            calculated_width: Some(50.0),
2782                                            calculated_height: Some(25.0),
2783                                            ..container.children[0].children[0].children[0].children
2784                                                [1]
2785                                            .clone()
2786                                        },
2787                                    ],
2788                                    calculated_width: Some(100.0),
2789                                    calculated_height: Some(25.0),
2790                                    ..container.children[0].children[0].children[0].clone()
2791                                },
2792                                Container {
2793                                    children: vec![
2794                                        Container {
2795                                            children: container.children[0].children[0].children[1]
2796                                                .children[0]
2797                                                .children
2798                                                .clone(),
2799                                            calculated_width: Some(50.0),
2800                                            calculated_height: Some(25.0),
2801                                            ..container.children[0].children[0].children[1].children
2802                                                [0]
2803                                            .clone()
2804                                        },
2805                                        Container {
2806                                            children: container.children[0].children[0].children[1]
2807                                                .children[1]
2808                                                .children
2809                                                .clone(),
2810                                            calculated_width: Some(50.0),
2811                                            calculated_height: Some(25.0),
2812                                            ..container.children[0].children[0].children[1].children
2813                                                [1]
2814                                            .clone()
2815                                        },
2816                                    ],
2817                                    calculated_width: Some(100.0),
2818                                    calculated_height: Some(25.0),
2819                                    ..container.children[0].children[0].children[1].clone()
2820                                },
2821                            ],
2822                            calculated_width: Some(100.0),
2823                            calculated_height: Some(25.0 + 25.0),
2824                            ..container.children[0].children[0].clone()
2825                        }],
2826                        ..container.children[0].clone()
2827                    }],
2828                    ..container
2829                },
2830            );
2831        }
2832
2833        #[test_log::test]
2834        #[ignore]
2835        fn calc_calculates_table_td_height_correctly() {
2836            let mut container: Container = html! {
2837                table {
2838                    tr {
2839                        td sx-height=(30) {}
2840                    }
2841                }
2842            }
2843            .try_into()
2844            .unwrap();
2845
2846            container.calculated_width = Some(50.0);
2847            container.calculated_height = Some(100.0);
2848
2849            CALCULATOR.calc(&mut container);
2850            log::trace!("container:\n{container}");
2851
2852            let td = container.children[0].children[0].children[0].clone();
2853
2854            compare_containers(
2855                &td.clone(),
2856                &Container {
2857                    calculated_height: Some(30.0),
2858                    ..td
2859                },
2860            );
2861        }
2862
2863        #[test_log::test]
2864        #[ignore]
2865        fn calc_calculates_table_tr_height_correctly() {
2866            let mut container: Container = html! {
2867                table {
2868                    tr {
2869                        td sx-height=(30) {}
2870                    }
2871                }
2872            }
2873            .try_into()
2874            .unwrap();
2875
2876            container.calculated_width = Some(50.0);
2877            container.calculated_height = Some(100.0);
2878
2879            CALCULATOR.calc(&mut container);
2880            log::trace!("container:\n{container}");
2881
2882            let tr = container.children[0].children[0].clone();
2883
2884            compare_containers(
2885                &tr.clone(),
2886                &Container {
2887                    calculated_height: Some(30.0),
2888                    ..tr
2889                },
2890            );
2891        }
2892
2893        #[test_log::test]
2894        #[ignore]
2895        fn calc_calculates_table_height_correctly() {
2896            let mut container: Container = html! {
2897                table {
2898                    tr sx-height=(30) {
2899                        td sx-height=(30) {}
2900                        td sx-height=(30) {}
2901                        td sx-height=(30) {}
2902                    }
2903                    tr sx-height=(30) {
2904                        td sx-height=(30) {}
2905                        td sx-height=(30) {}
2906                        td sx-height=(30) {}
2907                    }
2908                    tr sx-height=(30) {
2909                        td sx-height=(30) {}
2910                        td sx-height=(30) {}
2911                        td sx-height=(30) {}
2912                    }
2913                }
2914            }
2915            .try_into()
2916            .unwrap();
2917
2918            container.calculated_width = Some(50.0);
2919            container.calculated_height = Some(100.0);
2920
2921            CALCULATOR.calc(&mut container);
2922            log::trace!("container:\n{container}");
2923
2924            compare_containers(
2925                &container,
2926                &Container {
2927                    children: vec![Container {
2928                        calculated_height: Some(90.0),
2929                        ..container.children[0].clone()
2930                    }],
2931                    calculated_height: Some(100.0),
2932                    ..container.clone()
2933                },
2934            );
2935        }
2936
2937        #[test_log::test]
2938        #[ignore]
2939        fn calc_overflow_y_squash_calculates_table_sibling_element_height_correctly() {
2940            let mut container: Container = html! {
2941                div {}
2942                table {
2943                    tr sx-height=(30) {
2944                        td sx-height=(30) {}
2945                        td sx-height=(30) {}
2946                        td sx-height=(30) {}
2947                    }
2948                    tr sx-height=(30) {
2949                        td sx-height=(30) {}
2950                        td sx-height=(30) {}
2951                        td sx-height=(30) {}
2952                    }
2953                    tr sx-height=(30) {
2954                        td sx-height=(30) {}
2955                        td sx-height=(30) {}
2956                        td sx-height=(30) {}
2957                    }
2958                }
2959            }
2960            .try_into()
2961            .unwrap();
2962
2963            container.overflow_y = LayoutOverflow::Squash;
2964            container.calculated_width = Some(50.0);
2965            container.calculated_height = Some(100.0);
2966
2967            CALCULATOR.calc(&mut container);
2968            log::trace!("container:\n{container}");
2969
2970            compare_containers(
2971                &container,
2972                &Container {
2973                    children: vec![
2974                        Container {
2975                            calculated_height: Some(10.0),
2976                            ..container.children[0].clone()
2977                        },
2978                        Container {
2979                            calculated_height: Some(90.0),
2980                            ..container.children[1].clone()
2981                        },
2982                    ],
2983                    calculated_height: Some(100.0),
2984                    ..container.clone()
2985                },
2986            );
2987        }
2988
2989        #[test_log::test]
2990        #[ignore]
2991        fn calc_overflow_y_expand_calculates_table_sibling_element_height_correctly() {
2992            let mut container: Container = html! {
2993                div {}
2994                table {
2995                    tr sx-height=(30) {
2996                        td sx-height=(30) {}
2997                        td sx-height=(30) {}
2998                        td sx-height=(30) {}
2999                    }
3000                    tr sx-height=(30) {
3001                        td sx-height=(30) {}
3002                        td sx-height=(30) {}
3003                        td sx-height=(30) {}
3004                    }
3005                    tr sx-height=(30) {
3006                        td sx-height=(30) {}
3007                        td sx-height=(30) {}
3008                        td sx-height=(30) {}
3009                    }
3010                }
3011            }
3012            .try_into()
3013            .unwrap();
3014
3015            container.calculated_width = Some(50.0);
3016            container.calculated_height = Some(100.0);
3017
3018            CALCULATOR.calc(&mut container);
3019            log::trace!("container:\n{container}");
3020
3021            compare_containers(
3022                &container,
3023                &Container {
3024                    children: vec![
3025                        Container {
3026                            calculated_height: Some(10.0),
3027                            ..container.children[0].clone()
3028                        },
3029                        Container {
3030                            calculated_height: Some(90.0),
3031                            ..container.children[1].clone()
3032                        },
3033                    ],
3034                    calculated_height: Some(100.0),
3035                    ..container.clone()
3036                },
3037            );
3038        }
3039
3040        #[test_log::test]
3041        #[ignore]
3042        fn calc_calculates_table_column_widths_the_same_across_headers_and_body() {
3043            let mut container: Container = html! {
3044                table {
3045                    thead {
3046                      tr {
3047                        th { "#" }
3048                        th { "Time" }
3049                      }
3050                    }
3051                    tbody id="album-page-tracks" {
3052                        tr sx-border-radius=(5) {
3053                            td sx-padding-x=(10) sx-padding-y=(15) {
3054                                span class="track-number" { "1" }
3055                                button class="play-button" sx-visibility="hidden" {
3056                                    img sx-width=(12) sx-height=(12);
3057                                }
3058                            }
3059                            td sx-padding-x=(10) sx-padding-y=(15) {
3060                                "Even Still I Want To"
3061                            }
3062                        }
3063                    }
3064                }
3065            }
3066            .try_into()
3067            .unwrap();
3068
3069            container.calculated_width = Some(1232.0);
3070            container.calculated_height = Some(500.0);
3071
3072            CALCULATOR.calc(&mut container);
3073            log::trace!("container:\n{container}");
3074
3075            compare_containers(
3076                &container.clone(),
3077                &Container {
3078                    children: vec![Container {
3079                        children: vec![
3080                            Container {
3081                                children: vec![Container {
3082                                    children: vec![
3083                                        Container {
3084                                            calculated_width: Some(616.0),
3085                                            ..container.children[0].children[0].children[0].children
3086                                                [0]
3087                                            .clone()
3088                                        },
3089                                        Container {
3090                                            calculated_width: Some(616.0),
3091                                            ..container.children[0].children[0].children[0].children
3092                                                [1]
3093                                            .clone()
3094                                        },
3095                                    ],
3096                                    ..container.children[0].children[0].children[0].clone()
3097                                }],
3098                                ..container.children[0].children[0].clone()
3099                            },
3100                            Container {
3101                                children: vec![Container {
3102                                    children: vec![
3103                                        Container {
3104                                            calculated_width: Some(596.0),
3105                                            ..container.children[0].children[1].children[0].children
3106                                                [0]
3107                                            .clone()
3108                                        },
3109                                        Container {
3110                                            calculated_width: Some(596.0),
3111                                            ..container.children[0].children[1].children[0].children
3112                                                [1]
3113                                            .clone()
3114                                        },
3115                                    ],
3116                                    ..container.children[0].children[1].children[0].clone()
3117                                }],
3118                                ..container.children[0].children[1].clone()
3119                            },
3120                        ],
3121                        ..container.children[0].clone()
3122                    }],
3123                    ..container
3124                },
3125            );
3126        }
3127
3128        #[test_log::test]
3129        #[ignore]
3130        fn calc_calculates_table_th_sizes_with_padding_taken_into_account() {
3131            let mut container: Container = html! {
3132                table {
3133                    thead {
3134                        tr {
3135                            th sx-padding-x=(10) sx-padding-y=(15) {}
3136                        }
3137                    }
3138                }
3139            }
3140            .try_into()
3141            .unwrap();
3142
3143            container.calculated_width = Some(1232.0);
3144            container.calculated_height = Some(500.0);
3145
3146            CALCULATOR.calc(&mut container);
3147            log::trace!("container:\n{container}");
3148
3149            compare_containers(
3150                &container,
3151                &Container {
3152                    children: vec![Container {
3153                        children: vec![Container {
3154                            children: vec![Container {
3155                                children: vec![Container {
3156                                    calculated_width: Some(1212.0),
3157                                    calculated_height: Some(25.0),
3158                                    ..container.children[0].children[0].children[0].children[0]
3159                                        .clone()
3160                                }],
3161                                ..container.children[0].children[0].children[0].clone()
3162                            }],
3163                            ..container.children[0].children[0].clone()
3164                        }],
3165                        ..container.children[0].clone()
3166                    }],
3167                    ..container.clone()
3168                },
3169            );
3170        }
3171
3172        #[test_log::test]
3173        #[ignore]
3174        fn calc_calculates_table_td_sizes_with_padding_taken_into_account() {
3175            let mut container: Container = html! {
3176                table {
3177                    tr {
3178                        td sx-padding-x=(10) sx-padding-y=(15) {}
3179                    }
3180                }
3181            }
3182            .try_into()
3183            .unwrap();
3184
3185            container.calculated_width = Some(1232.0);
3186            container.calculated_height = Some(500.0);
3187
3188            CALCULATOR.calc(&mut container);
3189            log::trace!("container:\n{container}");
3190
3191            compare_containers(
3192                &container,
3193                &Container {
3194                    children: vec![Container {
3195                        children: vec![Container {
3196                            children: vec![Container {
3197                                calculated_width: Some(1212.0),
3198                                calculated_height: Some(25.0),
3199                                ..container.children[0].children[0].children[0].clone()
3200                            }],
3201                            ..container.children[0].children[0].clone()
3202                        }],
3203                        ..container.children[0].clone()
3204                    }],
3205                    ..container.clone()
3206                },
3207            );
3208        }
3209    }
3210
3211    #[test_log::test]
3212    fn calc_can_calc_single_element_size() {
3213        let mut container = Container {
3214            children: vec![Container::default()],
3215            calculated_width: Some(100.0),
3216            calculated_height: Some(50.0),
3217            justify_content: Some(JustifyContent::Start),
3218            ..Default::default()
3219        };
3220        CALCULATOR.calc(&mut container);
3221        log::trace!("container:\n{container}");
3222
3223        compare_containers(
3224            &container,
3225            &Container {
3226                children: vec![Container {
3227                    calculated_width: Some(100.0),
3228                    calculated_height: Some(0.0),
3229                    calculated_x: Some(0.0),
3230                    calculated_y: Some(0.0),
3231                    calculated_position: Some(LayoutPosition::Default),
3232                    ..container.children[0].clone()
3233                }],
3234                ..container.clone()
3235            },
3236        );
3237    }
3238
3239    #[test_log::test]
3240    fn calc_can_calc_two_elements_with_size_split_evenly_row() {
3241        let mut container: Container = html! {
3242            div sx-dir=(LayoutDirection::Row) {
3243                div {} div {}
3244            }
3245        }
3246        .try_into()
3247        .unwrap();
3248
3249        container.calculated_width = Some(100.0);
3250        container.calculated_height = Some(40.0);
3251        container.justify_content = Some(JustifyContent::Start);
3252
3253        CALCULATOR.calc(&mut container);
3254        log::trace!("container:\n{container}");
3255
3256        compare_containers(
3257            &container,
3258            &Container {
3259                children: vec![Container {
3260                    children: vec![
3261                        Container {
3262                            calculated_width: Some(0.0),
3263                            calculated_height: Some(0.0),
3264                            calculated_x: Some(0.0),
3265                            calculated_y: Some(0.0),
3266                            calculated_position: Some(LayoutPosition::Default),
3267                            ..container.children[0].children[0].clone()
3268                        },
3269                        Container {
3270                            calculated_width: Some(0.0),
3271                            calculated_height: Some(0.0),
3272                            calculated_x: Some(0.0),
3273                            calculated_y: Some(0.0),
3274                            calculated_position: Some(LayoutPosition::Default),
3275                            ..container.children[0].children[1].clone()
3276                        },
3277                    ],
3278                    calculated_width: Some(100.0),
3279                    calculated_height: Some(0.0),
3280                    calculated_x: Some(0.0),
3281                    calculated_y: Some(0.0),
3282                    calculated_position: Some(LayoutPosition::Default),
3283                    direction: LayoutDirection::Row,
3284                    ..container.children[0].clone()
3285                }],
3286                ..container.clone()
3287            },
3288        );
3289    }
3290
3291    #[test_log::test]
3292    fn calc_can_calc_horizontal_split_above_a_vertial_split() {
3293        let mut container: Container = html! {
3294            div sx-dir=(LayoutDirection::Row) sx-justify-content=(JustifyContent::Start) {
3295                div {} div {}
3296            }
3297            div {}
3298        }
3299        .try_into()
3300        .unwrap();
3301
3302        container.calculated_width = Some(100.0);
3303        container.calculated_height = Some(40.0);
3304        container.justify_content = Some(JustifyContent::Start);
3305
3306        CALCULATOR.calc(&mut container);
3307        log::trace!("container:\n{container}");
3308
3309        compare_containers(
3310            &container,
3311            &Container {
3312                children: vec![
3313                    Container {
3314                        children: vec![
3315                            Container {
3316                                calculated_height: Some(0.0),
3317                                calculated_y: Some(0.0),
3318                                calculated_position: Some(LayoutPosition::Default),
3319                                ..container.children[0].children[0].clone()
3320                            },
3321                            Container {
3322                                calculated_height: Some(0.0),
3323                                calculated_y: Some(0.0),
3324                                calculated_position: Some(LayoutPosition::Default),
3325                                ..container.children[0].children[1].clone()
3326                            },
3327                        ],
3328                        calculated_width: Some(100.0),
3329                        calculated_height: Some(0.0),
3330                        calculated_x: Some(0.0),
3331                        calculated_y: Some(0.0),
3332                        calculated_position: Some(LayoutPosition::Default),
3333                        direction: LayoutDirection::Row,
3334                        ..container.children[0].clone()
3335                    },
3336                    Container {
3337                        calculated_width: Some(100.0),
3338                        calculated_height: Some(0.0),
3339                        calculated_x: Some(0.0),
3340                        calculated_y: Some(0.0),
3341                        calculated_position: Some(LayoutPosition::Default),
3342                        ..container.children[1].clone()
3343                    },
3344                ],
3345                ..container.clone()
3346            },
3347        );
3348    }
3349
3350    #[test_log::test]
3351    fn calc_calcs_contained_height_correctly() {
3352        let mut container: Container = html! {
3353            div {}
3354            div sx-dir=(LayoutDirection::Row) {
3355                div {}
3356                div {}
3357            }
3358        }
3359        .try_into()
3360        .unwrap();
3361
3362        container.calculated_width = Some(100.0);
3363        container.calculated_height = Some(40.0);
3364        container.direction = LayoutDirection::Row;
3365        container.overflow_x = LayoutOverflow::Squash;
3366        container.overflow_y = LayoutOverflow::Squash;
3367
3368        CALCULATOR.calc(&mut container);
3369        log::trace!("container:\n{container}");
3370
3371        compare_containers(
3372            &container,
3373            &Container {
3374                children: vec![
3375                    Container {
3376                        calculated_height: Some(40.0),
3377                        ..container.children[0].clone()
3378                    },
3379                    Container {
3380                        children: vec![
3381                            Container {
3382                                calculated_height: Some(40.0),
3383                                ..container.children[1].children[0].clone()
3384                            },
3385                            Container {
3386                                calculated_height: Some(40.0),
3387                                ..container.children[1].children[1].clone()
3388                            },
3389                        ],
3390                        calculated_height: Some(40.0),
3391                        ..container.children[1].clone()
3392                    },
3393                ],
3394                ..container.clone()
3395            },
3396        );
3397    }
3398
3399    #[test_log::test]
3400    fn handles_justify_content_space_between_and_wraps_elements_properly() {
3401        let mut container = Container {
3402            children: vec![
3403                Container {
3404                    width: Some(Number::Integer(20)),
3405                    calculated_width: Some(20.0),
3406                    calculated_height: Some(20.0),
3407                    ..Default::default()
3408                },
3409                Container {
3410                    width: Some(Number::Integer(20)),
3411                    calculated_width: Some(20.0),
3412                    calculated_height: Some(20.0),
3413                    ..Default::default()
3414                },
3415                Container {
3416                    width: Some(Number::Integer(20)),
3417                    calculated_width: Some(20.0),
3418                    calculated_height: Some(20.0),
3419                    ..Default::default()
3420                },
3421                Container {
3422                    width: Some(Number::Integer(20)),
3423                    calculated_width: Some(20.0),
3424                    calculated_height: Some(20.0),
3425                    ..Default::default()
3426                },
3427                Container {
3428                    width: Some(Number::Integer(20)),
3429                    calculated_width: Some(20.0),
3430                    calculated_height: Some(20.0),
3431                    ..Default::default()
3432                },
3433            ],
3434            calculated_width: Some(75.0),
3435            calculated_height: Some(40.0),
3436            direction: LayoutDirection::Row,
3437            overflow_x: LayoutOverflow::Wrap { grid: true },
3438            justify_content: Some(JustifyContent::SpaceBetween),
3439            ..Default::default()
3440        };
3441
3442        CALCULATOR.calc(&mut container);
3443        log::trace!("container:\n{container}");
3444
3445        compare_containers(
3446            &container.clone(),
3447            &Container {
3448                children: vec![
3449                    Container {
3450                        calculated_width: Some(20.0),
3451                        calculated_height: Some(20.0),
3452                        calculated_x: Some(0.0),
3453                        calculated_y: Some(0.0),
3454                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 0 }),
3455                        ..container.children[0].clone()
3456                    },
3457                    Container {
3458                        calculated_width: Some(20.0),
3459                        calculated_height: Some(20.0),
3460                        calculated_x: Some(20.0 + 7.5),
3461                        calculated_y: Some(0.0),
3462                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
3463                        ..container.children[1].clone()
3464                    },
3465                    Container {
3466                        calculated_width: Some(20.0),
3467                        calculated_height: Some(20.0),
3468                        calculated_x: Some(40.0 + 7.5 + 7.5),
3469                        calculated_y: Some(0.0),
3470                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 2 }),
3471                        ..container.children[2].clone()
3472                    },
3473                    Container {
3474                        calculated_width: Some(20.0),
3475                        calculated_height: Some(20.0),
3476                        calculated_x: Some(0.0),
3477                        calculated_y: Some(20.0),
3478                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 0 }),
3479                        ..container.children[3].clone()
3480                    },
3481                    Container {
3482                        calculated_width: Some(20.0),
3483                        calculated_height: Some(20.0),
3484                        calculated_x: Some(20.0 + 7.5),
3485                        calculated_y: Some(20.0),
3486                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 1 }),
3487                        ..container.children[4].clone()
3488                    },
3489                ],
3490                calculated_width: Some(75.0),
3491                calculated_height: Some(40.0),
3492                ..container
3493            },
3494        );
3495    }
3496
3497    #[test_log::test]
3498    fn handles_justify_content_space_between_and_wraps_elements_properly_with_hidden_div() {
3499        let mut container = Container {
3500            children: vec![
3501                Container {
3502                    width: Some(Number::Integer(20)),
3503                    calculated_width: Some(20.0),
3504                    calculated_height: Some(20.0),
3505                    calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 0 }),
3506                    ..Default::default()
3507                },
3508                Container {
3509                    width: Some(Number::Integer(20)),
3510                    calculated_width: Some(20.0),
3511                    calculated_height: Some(20.0),
3512                    calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
3513                    ..Default::default()
3514                },
3515                Container {
3516                    width: Some(Number::Integer(20)),
3517                    calculated_width: Some(20.0),
3518                    calculated_height: Some(20.0),
3519                    calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
3520                    ..Default::default()
3521                },
3522                Container {
3523                    width: Some(Number::Integer(20)),
3524                    calculated_width: Some(20.0),
3525                    calculated_height: Some(20.0),
3526                    calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 0 }),
3527                    ..Default::default()
3528                },
3529                Container {
3530                    width: Some(Number::Integer(20)),
3531                    calculated_width: Some(20.0),
3532                    calculated_height: Some(20.0),
3533                    calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 1 }),
3534                    ..Default::default()
3535                },
3536                Container {
3537                    hidden: Some(true),
3538                    ..Default::default()
3539                },
3540            ],
3541            calculated_width: Some(75.0),
3542            calculated_height: Some(40.0),
3543            direction: LayoutDirection::Row,
3544            overflow_x: LayoutOverflow::Wrap { grid: true },
3545            justify_content: Some(JustifyContent::SpaceBetween),
3546            ..Default::default()
3547        };
3548
3549        CALCULATOR.calc(&mut container);
3550        log::trace!("container:\n{container}");
3551
3552        compare_containers(
3553            &container.clone(),
3554            &Container {
3555                children: vec![
3556                    Container {
3557                        calculated_width: Some(20.0),
3558                        calculated_height: Some(20.0),
3559                        calculated_x: Some(0.0),
3560                        calculated_y: Some(0.0),
3561                        ..container.children[0].clone()
3562                    },
3563                    Container {
3564                        calculated_width: Some(20.0),
3565                        calculated_height: Some(20.0),
3566                        calculated_x: Some(20.0 + 7.5),
3567                        calculated_y: Some(0.0),
3568                        ..container.children[1].clone()
3569                    },
3570                    Container {
3571                        calculated_width: Some(20.0),
3572                        calculated_height: Some(20.0),
3573                        calculated_x: Some(40.0 + 7.5 + 7.5),
3574                        calculated_y: Some(0.0),
3575                        ..container.children[2].clone()
3576                    },
3577                    Container {
3578                        calculated_width: Some(20.0),
3579                        calculated_height: Some(20.0),
3580                        calculated_x: Some(0.0),
3581                        calculated_y: Some(20.0),
3582                        ..container.children[3].clone()
3583                    },
3584                    Container {
3585                        calculated_width: Some(20.0),
3586                        calculated_height: Some(20.0),
3587                        calculated_x: Some(20.0 + 7.5),
3588                        calculated_y: Some(20.0),
3589                        ..container.children[4].clone()
3590                    },
3591                    Container {
3592                        hidden: Some(true),
3593                        ..container.children[5].clone()
3594                    },
3595                ],
3596                calculated_width: Some(75.0),
3597                calculated_height: Some(40.0),
3598                ..container
3599            },
3600        );
3601    }
3602
3603    #[test_log::test]
3604    fn handle_overflow_y_squash_handles_justify_content_space_between_and_wraps_elements_properly_and_can_recalc_with_new_rows()
3605     {
3606        const ROW_HEIGHT: f32 = 40.0 / 4.0;
3607
3608        let div = Container {
3609            width: Some(Number::Integer(20)),
3610            calculated_width: Some(20.0),
3611            calculated_height: Some(20.0),
3612            ..Default::default()
3613        };
3614
3615        let mut container = Container {
3616            children: vec![
3617                div.clone(),
3618                div.clone(),
3619                div.clone(),
3620                div.clone(),
3621                div.clone(),
3622            ],
3623            calculated_width: Some(75.0),
3624            calculated_height: Some(40.0),
3625            direction: LayoutDirection::Row,
3626            overflow_x: LayoutOverflow::Wrap { grid: true },
3627            overflow_y: LayoutOverflow::Squash,
3628            justify_content: Some(JustifyContent::SpaceBetween),
3629            ..Default::default()
3630        };
3631
3632        log::debug!("First calc");
3633        CALCULATOR.calc(&mut container);
3634        log::trace!("first container:\n{container}");
3635
3636        container.children.extend(vec![
3637            div.clone(),
3638            div.clone(),
3639            div.clone(),
3640            div.clone(),
3641            div,
3642        ]);
3643
3644        log::debug!("Second calc");
3645        CALCULATOR.calc(&mut container);
3646        log::trace!("second container:\n{container}");
3647
3648        compare_containers(
3649            &container.clone(),
3650            &Container {
3651                children: vec![
3652                    Container {
3653                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 0 }),
3654                        calculated_width: Some(20.0),
3655                        calculated_height: Some(10.0),
3656                        calculated_x: Some(0.0),
3657                        calculated_y: Some(ROW_HEIGHT * 0.0),
3658                        ..container.children[0].clone()
3659                    },
3660                    Container {
3661                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
3662                        calculated_width: Some(20.0),
3663                        calculated_height: Some(10.0),
3664                        calculated_x: Some(20.0 + 7.5),
3665                        calculated_y: Some(ROW_HEIGHT * 0.0),
3666                        ..container.children[1].clone()
3667                    },
3668                    Container {
3669                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 2 }),
3670                        calculated_width: Some(20.0),
3671                        calculated_height: Some(10.0),
3672                        calculated_x: Some(40.0 + 7.5 + 7.5),
3673                        calculated_y: Some(ROW_HEIGHT * 0.0),
3674                        ..container.children[2].clone()
3675                    },
3676                    Container {
3677                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 0 }),
3678                        calculated_width: Some(20.0),
3679                        calculated_height: Some(10.0),
3680                        calculated_x: Some(0.0),
3681                        calculated_y: Some(ROW_HEIGHT * 1.0),
3682                        ..container.children[3].clone()
3683                    },
3684                    Container {
3685                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 1 }),
3686                        calculated_width: Some(20.0),
3687                        calculated_height: Some(10.0),
3688                        calculated_x: Some(20.0 + 7.5),
3689                        calculated_y: Some(ROW_HEIGHT * 1.0),
3690                        ..container.children[4].clone()
3691                    },
3692                    Container {
3693                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 2 }),
3694                        calculated_width: Some(20.0),
3695                        calculated_height: Some(10.0),
3696                        calculated_x: Some(40.0 + 7.5 + 7.5),
3697                        calculated_y: Some(ROW_HEIGHT * 1.0),
3698                        ..container.children[5].clone()
3699                    },
3700                    Container {
3701                        calculated_position: Some(LayoutPosition::Wrap { row: 2, col: 0 }),
3702                        calculated_width: Some(20.0),
3703                        calculated_height: Some(10.0),
3704                        calculated_x: Some(0.0),
3705                        calculated_y: Some(ROW_HEIGHT * 2.0),
3706                        ..container.children[6].clone()
3707                    },
3708                    Container {
3709                        calculated_position: Some(LayoutPosition::Wrap { row: 2, col: 1 }),
3710                        calculated_width: Some(20.0),
3711                        calculated_height: Some(10.0),
3712                        calculated_x: Some(20.0 + 7.5),
3713                        calculated_y: Some(ROW_HEIGHT * 2.0),
3714                        ..container.children[7].clone()
3715                    },
3716                    Container {
3717                        calculated_position: Some(LayoutPosition::Wrap { row: 2, col: 2 }),
3718                        calculated_width: Some(20.0),
3719                        calculated_height: Some(10.0),
3720                        calculated_x: Some(40.0 + 7.5 + 7.5),
3721                        calculated_y: Some(ROW_HEIGHT * 2.0),
3722                        ..container.children[8].clone()
3723                    },
3724                    Container {
3725                        calculated_position: Some(LayoutPosition::Wrap { row: 3, col: 0 }),
3726                        calculated_width: Some(20.0),
3727                        calculated_height: Some(10.0),
3728                        calculated_x: Some(0.0),
3729                        calculated_y: Some(ROW_HEIGHT * 3.0),
3730                        ..container.children[9].clone()
3731                    },
3732                ],
3733                calculated_width: Some(75.0),
3734                calculated_height: Some(40.0),
3735                ..container
3736            },
3737        );
3738    }
3739
3740    #[test_log::test]
3741    fn handle_overflow_y_expand_handles_justify_content_space_between_and_wraps_elements_properly_and_can_recalc_with_new_rows()
3742     {
3743        const ROW_HEIGHT: f32 = 10.0;
3744
3745        let div = Container {
3746            width: Some(Number::Integer(20)),
3747            ..Default::default()
3748        };
3749
3750        let mut container = Container {
3751            children: vec![
3752                div.clone(),
3753                div.clone(),
3754                div.clone(),
3755                div.clone(),
3756                div.clone(),
3757            ],
3758            calculated_width: Some(75.0),
3759            calculated_height: Some(40.0),
3760            direction: LayoutDirection::Row,
3761            overflow_x: LayoutOverflow::Wrap { grid: true },
3762            overflow_y: LayoutOverflow::Expand,
3763            justify_content: Some(JustifyContent::SpaceBetween),
3764            ..Default::default()
3765        };
3766
3767        log::debug!("First calc");
3768        CALCULATOR.calc(&mut container);
3769        log::trace!("first container:\n{container}");
3770
3771        container.children.extend(vec![
3772            div.clone(),
3773            div.clone(),
3774            div.clone(),
3775            div.clone(),
3776            div,
3777        ]);
3778
3779        log::debug!("Second calc");
3780        CALCULATOR.calc(&mut container);
3781        log::trace!("second container:\n{container}");
3782
3783        compare_containers(
3784            &container.clone(),
3785            &Container {
3786                children: vec![
3787                    Container {
3788                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 0 }),
3789                        calculated_width: Some(20.0),
3790                        calculated_height: Some(ROW_HEIGHT),
3791                        calculated_x: Some(0.0),
3792                        calculated_y: Some(ROW_HEIGHT * 0.0),
3793                        ..container.children[0].clone()
3794                    },
3795                    Container {
3796                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
3797                        calculated_width: Some(20.0),
3798                        calculated_height: Some(ROW_HEIGHT),
3799                        calculated_x: Some(20.0 + 7.5),
3800                        calculated_y: Some(ROW_HEIGHT * 0.0),
3801                        ..container.children[1].clone()
3802                    },
3803                    Container {
3804                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 2 }),
3805                        calculated_width: Some(20.0),
3806                        calculated_height: Some(ROW_HEIGHT),
3807                        calculated_x: Some(40.0 + 7.5 + 7.5),
3808                        calculated_y: Some(ROW_HEIGHT * 0.0),
3809                        ..container.children[2].clone()
3810                    },
3811                    Container {
3812                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 0 }),
3813                        calculated_width: Some(20.0),
3814                        calculated_height: Some(ROW_HEIGHT),
3815                        calculated_x: Some(0.0),
3816                        calculated_y: Some(ROW_HEIGHT * 1.0),
3817                        ..container.children[3].clone()
3818                    },
3819                    Container {
3820                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 1 }),
3821                        calculated_width: Some(20.0),
3822                        calculated_height: Some(ROW_HEIGHT),
3823                        calculated_x: Some(20.0 + 7.5),
3824                        calculated_y: Some(ROW_HEIGHT * 1.0),
3825                        ..container.children[4].clone()
3826                    },
3827                    Container {
3828                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 2 }),
3829                        calculated_width: Some(20.0),
3830                        calculated_height: Some(ROW_HEIGHT),
3831                        calculated_x: Some(40.0 + 7.5 + 7.5),
3832                        calculated_y: Some(ROW_HEIGHT * 1.0),
3833                        ..container.children[5].clone()
3834                    },
3835                    Container {
3836                        calculated_position: Some(LayoutPosition::Wrap { row: 2, col: 0 }),
3837                        calculated_width: Some(20.0),
3838                        calculated_height: Some(ROW_HEIGHT),
3839                        calculated_x: Some(0.0),
3840                        calculated_y: Some(ROW_HEIGHT * 2.0),
3841                        ..container.children[6].clone()
3842                    },
3843                    Container {
3844                        calculated_position: Some(LayoutPosition::Wrap { row: 2, col: 1 }),
3845                        calculated_width: Some(20.0),
3846                        calculated_height: Some(ROW_HEIGHT),
3847                        calculated_x: Some(20.0 + 7.5),
3848                        calculated_y: Some(ROW_HEIGHT * 2.0),
3849                        ..container.children[7].clone()
3850                    },
3851                    Container {
3852                        calculated_position: Some(LayoutPosition::Wrap { row: 2, col: 2 }),
3853                        calculated_width: Some(20.0),
3854                        calculated_height: Some(ROW_HEIGHT),
3855                        calculated_x: Some(40.0 + 7.5 + 7.5),
3856                        calculated_y: Some(ROW_HEIGHT * 2.0),
3857                        ..container.children[8].clone()
3858                    },
3859                    Container {
3860                        calculated_position: Some(LayoutPosition::Wrap { row: 3, col: 0 }),
3861                        calculated_width: Some(20.0),
3862                        calculated_height: Some(ROW_HEIGHT),
3863                        calculated_x: Some(0.0),
3864                        calculated_y: Some(ROW_HEIGHT * 3.0),
3865                        ..container.children[9].clone()
3866                    },
3867                ],
3868                calculated_width: Some(75.0),
3869                calculated_height: Some(40.0),
3870                ..container
3871            },
3872        );
3873    }
3874
3875    #[test_log::test]
3876    fn handles_justify_content_space_between_with_gap_and_wraps_elements_properly() {
3877        const ROW_HEIGHT: f32 = 40.0 / 3.0;
3878
3879        let mut container = Container {
3880            children: vec![
3881                Container {
3882                    width: Some(Number::Integer(20)),
3883                    ..Default::default()
3884                },
3885                Container {
3886                    width: Some(Number::Integer(20)),
3887                    ..Default::default()
3888                },
3889                Container {
3890                    width: Some(Number::Integer(20)),
3891                    ..Default::default()
3892                },
3893                Container {
3894                    width: Some(Number::Integer(20)),
3895                    ..Default::default()
3896                },
3897                Container {
3898                    width: Some(Number::Integer(20)),
3899                    ..Default::default()
3900                },
3901            ],
3902            calculated_width: Some(75.0),
3903            calculated_height: Some(40.0),
3904            direction: LayoutDirection::Row,
3905            overflow_x: LayoutOverflow::Wrap { grid: true },
3906            overflow_y: LayoutOverflow::Expand,
3907            justify_content: Some(JustifyContent::SpaceBetween),
3908            column_gap: Some(Number::Integer(10)),
3909            row_gap: Some(Number::Integer(10)),
3910            ..Default::default()
3911        };
3912
3913        CALCULATOR.calc(&mut container);
3914        log::trace!("container:\n{container}");
3915
3916        compare_containers(
3917            &container,
3918            &Container {
3919                children: vec![
3920                    Container {
3921                        calculated_width: Some(20.0),
3922                        calculated_height: Some(ROW_HEIGHT),
3923                        calculated_x: Some(0.0),
3924                        calculated_y: Some(0.0),
3925                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 0 }),
3926                        ..container.children[0].clone()
3927                    },
3928                    Container {
3929                        calculated_width: Some(20.0),
3930                        calculated_height: Some(ROW_HEIGHT),
3931                        calculated_x: Some(75.0 - 20.0),
3932                        calculated_y: Some(0.0),
3933                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
3934                        ..container.children[1].clone()
3935                    },
3936                    Container {
3937                        calculated_width: Some(20.0),
3938                        calculated_height: Some(ROW_HEIGHT),
3939                        calculated_x: Some(0.0),
3940                        calculated_y: Some(ROW_HEIGHT.mul_add(1.0, 10.0)),
3941                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 0 }),
3942                        ..container.children[2].clone()
3943                    },
3944                    Container {
3945                        calculated_width: Some(20.0),
3946                        calculated_height: Some(ROW_HEIGHT),
3947                        calculated_x: Some(75.0 - 20.0),
3948                        calculated_y: Some(ROW_HEIGHT.mul_add(1.0, 10.0)),
3949                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 1 }),
3950                        ..container.children[3].clone()
3951                    },
3952                    Container {
3953                        calculated_width: Some(20.0),
3954                        calculated_height: Some(ROW_HEIGHT),
3955                        calculated_x: Some(0.0),
3956                        calculated_y: Some(ROW_HEIGHT.mul_add(2.0, 10.0 + 10.0)),
3957                        calculated_position: Some(LayoutPosition::Wrap { row: 2, col: 0 }),
3958                        ..container.children[4].clone()
3959                    },
3960                ],
3961                calculated_width: Some(75.0),
3962                calculated_height: Some(40.0),
3963                ..container.clone()
3964            },
3965        );
3966    }
3967
3968    #[test_log::test]
3969    fn handles_justify_content_space_between_with_gap_and_wraps_elements_properly_and_can_recalc() {
3970        const ROW_HEIGHT: f32 = 40.0 / 3.0;
3971
3972        let mut container = Container {
3973            children: vec![
3974                Container {
3975                    width: Some(Number::Integer(20)),
3976                    ..Default::default()
3977                },
3978                Container {
3979                    width: Some(Number::Integer(20)),
3980                    ..Default::default()
3981                },
3982                Container {
3983                    width: Some(Number::Integer(20)),
3984                    ..Default::default()
3985                },
3986                Container {
3987                    width: Some(Number::Integer(20)),
3988                    ..Default::default()
3989                },
3990                Container {
3991                    width: Some(Number::Integer(20)),
3992                    ..Default::default()
3993                },
3994            ],
3995            calculated_width: Some(75.0),
3996            calculated_height: Some(40.0),
3997            direction: LayoutDirection::Row,
3998            overflow_x: LayoutOverflow::Wrap { grid: true },
3999            overflow_y: LayoutOverflow::Expand,
4000            justify_content: Some(JustifyContent::SpaceBetween),
4001            column_gap: Some(Number::Integer(10)),
4002            row_gap: Some(Number::Integer(10)),
4003            ..Default::default()
4004        };
4005
4006        CALCULATOR.calc(&mut container);
4007        log::trace!("first container:\n{container}");
4008
4009        let mut actual = container.clone();
4010        let expected = Container {
4011            children: vec![
4012                Container {
4013                    calculated_width: Some(20.0),
4014                    calculated_height: Some(ROW_HEIGHT),
4015                    calculated_x: Some(0.0),
4016                    calculated_y: Some(0.0),
4017                    calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 0 }),
4018                    ..container.children[0].clone()
4019                },
4020                Container {
4021                    calculated_width: Some(20.0),
4022                    calculated_height: Some(ROW_HEIGHT),
4023                    calculated_x: Some(75.0 - 20.0),
4024                    calculated_y: Some(0.0),
4025                    calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
4026                    ..container.children[1].clone()
4027                },
4028                Container {
4029                    calculated_width: Some(20.0),
4030                    calculated_height: Some(ROW_HEIGHT),
4031                    calculated_x: Some(0.0),
4032                    calculated_y: Some(ROW_HEIGHT.mul_add(1.0, 10.0)),
4033                    calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 0 }),
4034                    ..container.children[2].clone()
4035                },
4036                Container {
4037                    calculated_width: Some(20.0),
4038                    calculated_height: Some(ROW_HEIGHT),
4039                    calculated_x: Some(75.0 - 20.0),
4040                    calculated_y: Some(ROW_HEIGHT.mul_add(1.0, 10.0)),
4041                    calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 1 }),
4042                    ..container.children[3].clone()
4043                },
4044                Container {
4045                    calculated_width: Some(20.0),
4046                    calculated_height: Some(ROW_HEIGHT),
4047                    calculated_x: Some(0.0),
4048                    calculated_y: Some(ROW_HEIGHT.mul_add(2.0, 10.0 + 10.0)),
4049                    calculated_position: Some(LayoutPosition::Wrap { row: 2, col: 0 }),
4050                    ..container.children[4].clone()
4051                },
4052            ],
4053            calculated_width: Some(75.0),
4054            calculated_height: Some(40.0),
4055            ..container
4056        };
4057
4058        compare_containers(&actual, &expected);
4059
4060        CALCULATOR.calc(&mut actual);
4061        log::trace!("second container:\n{actual}");
4062
4063        compare_containers(&actual, &expected);
4064    }
4065
4066    #[test_log::test]
4067    fn handles_justify_content_space_evenly_and_wraps_elements_properly() {
4068        const ROW_HEIGHT: f32 = 40.0 / 2.0;
4069
4070        let mut container = Container {
4071            children: vec![
4072                Container {
4073                    width: Some(Number::Integer(20)),
4074                    ..Default::default()
4075                },
4076                Container {
4077                    width: Some(Number::Integer(20)),
4078                    ..Default::default()
4079                },
4080                Container {
4081                    width: Some(Number::Integer(20)),
4082                    ..Default::default()
4083                },
4084                Container {
4085                    width: Some(Number::Integer(20)),
4086                    ..Default::default()
4087                },
4088                Container {
4089                    width: Some(Number::Integer(20)),
4090                    ..Default::default()
4091                },
4092            ],
4093            calculated_width: Some(75.0),
4094            calculated_height: Some(40.0),
4095            direction: LayoutDirection::Row,
4096            overflow_x: LayoutOverflow::Wrap { grid: true },
4097            justify_content: Some(JustifyContent::SpaceEvenly),
4098            ..Default::default()
4099        };
4100
4101        CALCULATOR.calc(&mut container);
4102        log::trace!("container:\n{container}");
4103
4104        compare_containers(
4105            &container,
4106            &Container {
4107                children: vec![
4108                    Container {
4109                        calculated_width: Some(20.0),
4110                        calculated_height: Some(ROW_HEIGHT),
4111                        calculated_x: Some(3.75),
4112                        calculated_y: Some(ROW_HEIGHT * 0.0),
4113                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 0 }),
4114                        ..container.children[0].clone()
4115                    },
4116                    Container {
4117                        calculated_width: Some(20.0),
4118                        calculated_height: Some(ROW_HEIGHT),
4119                        calculated_x: Some(20.0 + 3.75 + 3.75),
4120                        calculated_y: Some(ROW_HEIGHT * 0.0),
4121                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
4122                        ..container.children[1].clone()
4123                    },
4124                    Container {
4125                        calculated_width: Some(20.0),
4126                        calculated_height: Some(ROW_HEIGHT),
4127                        calculated_x: Some(40.0 + 3.75 + 3.75 + 3.75),
4128                        calculated_y: Some(ROW_HEIGHT * 0.0),
4129                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 2 }),
4130                        ..container.children[2].clone()
4131                    },
4132                    Container {
4133                        calculated_width: Some(20.0),
4134                        calculated_height: Some(ROW_HEIGHT),
4135                        calculated_x: Some(3.75),
4136                        calculated_y: Some(ROW_HEIGHT * 1.0),
4137                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 0 }),
4138                        ..container.children[3].clone()
4139                    },
4140                    Container {
4141                        calculated_width: Some(20.0),
4142                        calculated_height: Some(ROW_HEIGHT),
4143                        calculated_x: Some(20.0 + 3.75 + 3.75),
4144                        calculated_y: Some(ROW_HEIGHT * 1.0),
4145                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 1 }),
4146                        ..container.children[4].clone()
4147                    },
4148                ],
4149                calculated_width: Some(75.0),
4150                calculated_height: Some(40.0),
4151                ..container.clone()
4152            },
4153        );
4154    }
4155
4156    #[test_log::test]
4157    fn handle_overflow_y_squash_handles_justify_content_space_evenly_with_padding_and_wraps_elements_properly()
4158     {
4159        let mut container = Container {
4160            children: vec![
4161                Container {
4162                    width: Some(Number::Integer(20)),
4163                    height: Some(Number::Integer(20)),
4164                    ..Default::default()
4165                },
4166                Container {
4167                    width: Some(Number::Integer(20)),
4168                    height: Some(Number::Integer(20)),
4169                    ..Default::default()
4170                },
4171                Container {
4172                    width: Some(Number::Integer(20)),
4173                    height: Some(Number::Integer(20)),
4174                    ..Default::default()
4175                },
4176                Container {
4177                    width: Some(Number::Integer(20)),
4178                    height: Some(Number::Integer(20)),
4179                    ..Default::default()
4180                },
4181                Container {
4182                    width: Some(Number::Integer(20)),
4183                    height: Some(Number::Integer(20)),
4184                    ..Default::default()
4185                },
4186            ],
4187            calculated_width: Some(75.0),
4188            calculated_height: Some(40.0),
4189            calculated_padding_left: Some(20.0),
4190            calculated_padding_right: Some(20.0),
4191            direction: LayoutDirection::Row,
4192            overflow_x: LayoutOverflow::Wrap { grid: true },
4193            overflow_y: LayoutOverflow::Squash,
4194            justify_content: Some(JustifyContent::SpaceEvenly),
4195            ..Default::default()
4196        };
4197        CALCULATOR.calc(&mut container);
4198        log::trace!("container:\n{container}");
4199
4200        compare_containers(
4201            &container.clone(),
4202            &Container {
4203                children: vec![
4204                    Container {
4205                        calculated_width: Some(20.0),
4206                        calculated_height: Some(20.0),
4207                        calculated_x: Some(3.75),
4208                        calculated_y: Some(0.0),
4209                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 0 }),
4210                        ..container.children[0].clone()
4211                    },
4212                    Container {
4213                        calculated_width: Some(20.0),
4214                        calculated_height: Some(20.0),
4215                        calculated_x: Some(20.0 + 3.75 + 3.75),
4216                        calculated_y: Some(0.0),
4217                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
4218                        ..container.children[1].clone()
4219                    },
4220                    Container {
4221                        calculated_width: Some(20.0),
4222                        calculated_height: Some(20.0),
4223                        calculated_x: Some(40.0 + 3.75 + 3.75 + 3.75),
4224                        calculated_y: Some(0.0),
4225                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 2 }),
4226                        ..container.children[2].clone()
4227                    },
4228                    Container {
4229                        calculated_width: Some(20.0),
4230                        calculated_height: Some(20.0),
4231                        calculated_x: Some(3.75),
4232                        calculated_y: Some(20.0),
4233                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 0 }),
4234                        ..container.children[3].clone()
4235                    },
4236                    Container {
4237                        calculated_width: Some(20.0),
4238                        calculated_height: Some(20.0),
4239                        calculated_x: Some(20.0 + 3.75 + 3.75),
4240                        calculated_y: Some(20.0),
4241                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 1 }),
4242                        ..container.children[4].clone()
4243                    },
4244                ],
4245                ..container
4246            },
4247        );
4248    }
4249
4250    #[test_log::test]
4251    fn handle_overflow_y_expand_handles_justify_content_space_evenly_with_padding_and_wraps_elements_properly()
4252     {
4253        let mut container: Container = html! {
4254            div sx-width=(20) {}
4255            div sx-width=(20) {}
4256            div sx-width=(20) {}
4257            div sx-width=(20) {}
4258            div sx-width=(20) {}
4259        }
4260        .try_into()
4261        .unwrap();
4262
4263        container.calculated_width = Some(75.0);
4264        container.calculated_height = Some(40.0);
4265        container.calculated_padding_left = Some(20.0);
4266        container.calculated_padding_right = Some(20.0);
4267        container.direction = LayoutDirection::Row;
4268        container.overflow_x = LayoutOverflow::Wrap { grid: true };
4269        container.overflow_y = LayoutOverflow::Expand;
4270        container.justify_content = Some(JustifyContent::SpaceEvenly);
4271
4272        CALCULATOR.calc(&mut container);
4273        log::trace!("container:\n{container}");
4274
4275        compare_containers(
4276            &container.clone(),
4277            &Container {
4278                children: vec![
4279                    Container {
4280                        calculated_width: Some(20.0),
4281                        calculated_height: Some(20.0),
4282                        calculated_x: Some(3.75),
4283                        calculated_y: Some(0.0),
4284                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 0 }),
4285                        ..container.children[0].clone()
4286                    },
4287                    Container {
4288                        calculated_width: Some(20.0),
4289                        calculated_height: Some(20.0),
4290                        calculated_x: Some(20.0 + 3.75 + 3.75),
4291                        calculated_y: Some(0.0),
4292                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
4293                        ..container.children[1].clone()
4294                    },
4295                    Container {
4296                        calculated_width: Some(20.0),
4297                        calculated_height: Some(20.0),
4298                        calculated_x: Some(40.0 + 3.75 + 3.75 + 3.75),
4299                        calculated_y: Some(0.0),
4300                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 2 }),
4301                        ..container.children[2].clone()
4302                    },
4303                    Container {
4304                        calculated_width: Some(20.0),
4305                        calculated_height: Some(20.0),
4306                        calculated_x: Some(3.75),
4307                        calculated_y: Some(20.0),
4308                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 0 }),
4309                        ..container.children[3].clone()
4310                    },
4311                    Container {
4312                        calculated_width: Some(20.0),
4313                        calculated_height: Some(20.0),
4314                        calculated_x: Some(20.0 + 3.75 + 3.75),
4315                        calculated_y: Some(20.0),
4316                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 1 }),
4317                        ..container.children[4].clone()
4318                    },
4319                ],
4320                ..container
4321            },
4322        );
4323    }
4324
4325    #[test_log::test]
4326    fn handles_justify_content_space_evenly_and_wraps_elements_properly_with_hidden_div() {
4327        let mut container: Container = html! {
4328            div sx-width=(20) {}
4329            div sx-width=(20) {}
4330            div sx-width=(20) {}
4331            div sx-width=(20) {}
4332            div sx-width=(20) {}
4333            div sx-hidden=(true) {}
4334        }
4335        .try_into()
4336        .unwrap();
4337
4338        container.calculated_width = Some(75.0);
4339        container.calculated_height = Some(40.0);
4340        container.direction = LayoutDirection::Row;
4341        container.overflow_x = LayoutOverflow::Wrap { grid: true };
4342        container.justify_content = Some(JustifyContent::SpaceEvenly);
4343
4344        CALCULATOR.calc(&mut container);
4345        log::trace!("container:\n{container}");
4346
4347        compare_containers(
4348            &container.clone(),
4349            &Container {
4350                children: vec![
4351                    Container {
4352                        calculated_width: Some(20.0),
4353                        calculated_height: Some(20.0),
4354                        calculated_x: Some(3.75),
4355                        calculated_y: Some(0.0),
4356                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 0 }),
4357                        ..container.children[0].clone()
4358                    },
4359                    Container {
4360                        calculated_width: Some(20.0),
4361                        calculated_height: Some(20.0),
4362                        calculated_x: Some(20.0 + 3.75 + 3.75),
4363                        calculated_y: Some(0.0),
4364                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
4365                        ..container.children[1].clone()
4366                    },
4367                    Container {
4368                        calculated_width: Some(20.0),
4369                        calculated_height: Some(20.0),
4370                        calculated_x: Some(40.0 + 3.75 + 3.75 + 3.75),
4371                        calculated_y: Some(0.0),
4372                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 2 }),
4373                        ..container.children[2].clone()
4374                    },
4375                    Container {
4376                        calculated_width: Some(20.0),
4377                        calculated_height: Some(20.0),
4378                        calculated_x: Some(3.75),
4379                        calculated_y: Some(20.0),
4380                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 0 }),
4381                        ..container.children[3].clone()
4382                    },
4383                    Container {
4384                        calculated_width: Some(20.0),
4385                        calculated_height: Some(20.0),
4386                        calculated_x: Some(20.0 + 3.75 + 3.75),
4387                        calculated_y: Some(20.0),
4388                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 1 }),
4389                        ..container.children[4].clone()
4390                    },
4391                    Container {
4392                        hidden: Some(true),
4393                        ..container.children[5].clone()
4394                    },
4395                ],
4396                ..container
4397            },
4398        );
4399    }
4400
4401    #[test_log::test]
4402    fn handle_overflow_y_squash_handles_justify_content_space_evenly_and_wraps_elements_properly_and_can_recalc_with_new_rows()
4403     {
4404        const ROW_HEIGHT: f32 = 40.0 / 4.0;
4405
4406        let div = Container {
4407            width: Some(Number::Integer(20)),
4408            ..Default::default()
4409        };
4410
4411        let mut container = Container {
4412            children: vec![
4413                div.clone(),
4414                div.clone(),
4415                div.clone(),
4416                div.clone(),
4417                div.clone(),
4418            ],
4419            calculated_width: Some(75.0),
4420            calculated_height: Some(40.0),
4421            direction: LayoutDirection::Row,
4422            overflow_x: LayoutOverflow::Wrap { grid: true },
4423            overflow_y: LayoutOverflow::Squash,
4424            justify_content: Some(JustifyContent::SpaceEvenly),
4425            ..Default::default()
4426        };
4427
4428        log::debug!("First calc");
4429        CALCULATOR.calc(&mut container);
4430        log::trace!("first container:\n{container}");
4431
4432        container.children.extend(vec![
4433            div.clone(),
4434            div.clone(),
4435            div.clone(),
4436            div.clone(),
4437            div,
4438        ]);
4439
4440        log::debug!("Second calc");
4441        CALCULATOR.calc(&mut container);
4442        log::trace!("second container:\n{container}");
4443
4444        compare_containers(
4445            &container.clone(),
4446            &Container {
4447                children: vec![
4448                    Container {
4449                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 0 }),
4450                        calculated_width: Some(20.0),
4451                        calculated_height: Some(10.0),
4452                        calculated_x: Some(3.75),
4453                        calculated_y: Some(ROW_HEIGHT * 0.0),
4454                        ..container.children[0].clone()
4455                    },
4456                    Container {
4457                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
4458                        calculated_width: Some(20.0),
4459                        calculated_height: Some(10.0),
4460                        calculated_x: Some(20.0 + 3.75 + 3.75),
4461                        calculated_y: Some(ROW_HEIGHT * 0.0),
4462                        ..container.children[1].clone()
4463                    },
4464                    Container {
4465                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 2 }),
4466                        calculated_width: Some(20.0),
4467                        calculated_height: Some(10.0),
4468                        calculated_x: Some(40.0 + 3.75 + 3.75 + 3.75),
4469                        calculated_y: Some(ROW_HEIGHT * 0.0),
4470                        ..container.children[2].clone()
4471                    },
4472                    Container {
4473                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 0 }),
4474                        calculated_width: Some(20.0),
4475                        calculated_height: Some(10.0),
4476                        calculated_x: Some(3.75),
4477                        calculated_y: Some(ROW_HEIGHT * 1.0),
4478                        ..container.children[3].clone()
4479                    },
4480                    Container {
4481                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 1 }),
4482                        calculated_width: Some(20.0),
4483                        calculated_height: Some(10.0),
4484                        calculated_x: Some(20.0 + 3.75 + 3.75),
4485                        calculated_y: Some(ROW_HEIGHT * 1.0),
4486                        ..container.children[4].clone()
4487                    },
4488                    Container {
4489                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 2 }),
4490                        calculated_width: Some(20.0),
4491                        calculated_height: Some(10.0),
4492                        calculated_x: Some(40.0 + 3.75 + 3.75 + 3.75),
4493                        calculated_y: Some(ROW_HEIGHT * 1.0),
4494                        ..container.children[5].clone()
4495                    },
4496                    Container {
4497                        calculated_position: Some(LayoutPosition::Wrap { row: 2, col: 0 }),
4498                        calculated_width: Some(20.0),
4499                        calculated_height: Some(10.0),
4500                        calculated_x: Some(3.75),
4501                        calculated_y: Some(ROW_HEIGHT * 2.0),
4502                        ..container.children[6].clone()
4503                    },
4504                    Container {
4505                        calculated_position: Some(LayoutPosition::Wrap { row: 2, col: 1 }),
4506                        calculated_width: Some(20.0),
4507                        calculated_height: Some(10.0),
4508                        calculated_x: Some(20.0 + 3.75 + 3.75),
4509                        calculated_y: Some(ROW_HEIGHT * 2.0),
4510                        ..container.children[7].clone()
4511                    },
4512                    Container {
4513                        calculated_position: Some(LayoutPosition::Wrap { row: 2, col: 2 }),
4514                        calculated_width: Some(20.0),
4515                        calculated_height: Some(10.0),
4516                        calculated_x: Some(40.0 + 3.75 + 3.75 + 3.75),
4517                        calculated_y: Some(ROW_HEIGHT * 2.0),
4518                        ..container.children[8].clone()
4519                    },
4520                    Container {
4521                        calculated_position: Some(LayoutPosition::Wrap { row: 3, col: 0 }),
4522                        calculated_width: Some(20.0),
4523                        calculated_height: Some(10.0),
4524                        calculated_x: Some(3.75),
4525                        calculated_y: Some(ROW_HEIGHT * 3.0),
4526                        ..container.children[9].clone()
4527                    },
4528                ],
4529                calculated_width: Some(75.0),
4530                calculated_height: Some(40.0),
4531                ..container
4532            },
4533        );
4534    }
4535
4536    #[test_log::test]
4537    fn handle_overflow_y_expand_handles_justify_content_space_evenly_and_wraps_elements_properly_and_can_recalc_with_new_rows()
4538     {
4539        const ROW_HEIGHT: f32 = 40.0 / 4.0;
4540
4541        let div = Container {
4542            width: Some(Number::Integer(20)),
4543            ..Default::default()
4544        };
4545
4546        let mut container = Container {
4547            children: vec![
4548                div.clone(),
4549                div.clone(),
4550                div.clone(),
4551                div.clone(),
4552                div.clone(),
4553            ],
4554            calculated_width: Some(75.0),
4555            calculated_height: Some(40.0),
4556            direction: LayoutDirection::Row,
4557            overflow_x: LayoutOverflow::Wrap { grid: true },
4558            overflow_y: LayoutOverflow::Expand,
4559            justify_content: Some(JustifyContent::SpaceEvenly),
4560            ..Default::default()
4561        };
4562
4563        log::debug!("First calc");
4564        CALCULATOR.calc(&mut container);
4565        log::trace!("first container:\n{container}");
4566
4567        container.children.extend(vec![
4568            div.clone(),
4569            div.clone(),
4570            div.clone(),
4571            div.clone(),
4572            div,
4573        ]);
4574
4575        log::debug!("Second calc");
4576        CALCULATOR.calc(&mut container);
4577        log::trace!("second container:\n{container}");
4578
4579        compare_containers(
4580            &container,
4581            &Container {
4582                children: vec![
4583                    Container {
4584                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 0 }),
4585                        calculated_width: Some(20.0),
4586                        calculated_height: Some(ROW_HEIGHT),
4587                        calculated_x: Some(3.75),
4588                        calculated_y: Some(ROW_HEIGHT * 0.0),
4589                        ..container.children[0].clone()
4590                    },
4591                    Container {
4592                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
4593                        calculated_width: Some(20.0),
4594                        calculated_height: Some(ROW_HEIGHT),
4595                        calculated_x: Some(20.0 + 3.75 + 3.75),
4596                        calculated_y: Some(ROW_HEIGHT * 0.0),
4597                        ..container.children[1].clone()
4598                    },
4599                    Container {
4600                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 2 }),
4601                        calculated_width: Some(20.0),
4602                        calculated_height: Some(ROW_HEIGHT),
4603                        calculated_x: Some(40.0 + 3.75 + 3.75 + 3.75),
4604                        calculated_y: Some(ROW_HEIGHT * 0.0),
4605                        ..container.children[2].clone()
4606                    },
4607                    Container {
4608                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 0 }),
4609                        calculated_width: Some(20.0),
4610                        calculated_height: Some(ROW_HEIGHT),
4611                        calculated_x: Some(3.75),
4612                        calculated_y: Some(ROW_HEIGHT * 1.0),
4613                        ..container.children[3].clone()
4614                    },
4615                    Container {
4616                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 1 }),
4617                        calculated_width: Some(20.0),
4618                        calculated_height: Some(ROW_HEIGHT),
4619                        calculated_x: Some(20.0 + 3.75 + 3.75),
4620                        calculated_y: Some(ROW_HEIGHT * 1.0),
4621                        ..container.children[4].clone()
4622                    },
4623                    Container {
4624                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 2 }),
4625                        calculated_width: Some(20.0),
4626                        calculated_height: Some(ROW_HEIGHT),
4627                        calculated_x: Some(40.0 + 3.75 + 3.75 + 3.75),
4628                        calculated_y: Some(ROW_HEIGHT * 1.0),
4629                        ..container.children[5].clone()
4630                    },
4631                    Container {
4632                        calculated_position: Some(LayoutPosition::Wrap { row: 2, col: 0 }),
4633                        calculated_width: Some(20.0),
4634                        calculated_height: Some(ROW_HEIGHT),
4635                        calculated_x: Some(3.75),
4636                        calculated_y: Some(ROW_HEIGHT * 2.0),
4637                        ..container.children[6].clone()
4638                    },
4639                    Container {
4640                        calculated_position: Some(LayoutPosition::Wrap { row: 2, col: 1 }),
4641                        calculated_width: Some(20.0),
4642                        calculated_height: Some(ROW_HEIGHT),
4643                        calculated_x: Some(20.0 + 3.75 + 3.75),
4644                        calculated_y: Some(ROW_HEIGHT * 2.0),
4645                        ..container.children[7].clone()
4646                    },
4647                    Container {
4648                        calculated_position: Some(LayoutPosition::Wrap { row: 2, col: 2 }),
4649                        calculated_width: Some(20.0),
4650                        calculated_height: Some(ROW_HEIGHT),
4651                        calculated_x: Some(40.0 + 3.75 + 3.75 + 3.75),
4652                        calculated_y: Some(ROW_HEIGHT * 2.0),
4653                        ..container.children[8].clone()
4654                    },
4655                    Container {
4656                        calculated_position: Some(LayoutPosition::Wrap { row: 3, col: 0 }),
4657                        calculated_width: Some(20.0),
4658                        calculated_height: Some(ROW_HEIGHT),
4659                        calculated_x: Some(3.75),
4660                        calculated_y: Some(ROW_HEIGHT * 3.0),
4661                        ..container.children[9].clone()
4662                    },
4663                ],
4664                calculated_width: Some(75.0),
4665                calculated_height: Some(40.0),
4666                ..container.clone()
4667            },
4668        );
4669    }
4670
4671    #[test_log::test]
4672    fn handles_justify_content_space_evenly_with_gap_and_wraps_elements_properly() {
4673        const ROW_HEIGHT: f32 = 40.0 / 3.0;
4674
4675        let mut container = Container {
4676            children: vec![
4677                Container {
4678                    width: Some(Number::Integer(20)),
4679                    calculated_width: Some(20.0),
4680                    calculated_height: Some(20.0),
4681                    ..Default::default()
4682                },
4683                Container {
4684                    width: Some(Number::Integer(20)),
4685                    calculated_width: Some(20.0),
4686                    calculated_height: Some(20.0),
4687                    ..Default::default()
4688                },
4689                Container {
4690                    width: Some(Number::Integer(20)),
4691                    calculated_width: Some(20.0),
4692                    calculated_height: Some(20.0),
4693                    ..Default::default()
4694                },
4695                Container {
4696                    width: Some(Number::Integer(20)),
4697                    calculated_width: Some(20.0),
4698                    calculated_height: Some(20.0),
4699                    ..Default::default()
4700                },
4701                Container {
4702                    width: Some(Number::Integer(20)),
4703                    calculated_width: Some(20.0),
4704                    calculated_height: Some(20.0),
4705                    ..Default::default()
4706                },
4707            ],
4708            calculated_width: Some(75.0),
4709            calculated_height: Some(40.0),
4710            direction: LayoutDirection::Row,
4711            overflow_x: LayoutOverflow::Wrap { grid: true },
4712            overflow_y: LayoutOverflow::Expand,
4713            justify_content: Some(JustifyContent::SpaceEvenly),
4714            column_gap: Some(Number::Integer(10)),
4715            row_gap: Some(Number::Integer(10)),
4716            ..Default::default()
4717        };
4718
4719        CALCULATOR.calc(&mut container);
4720        log::trace!("container:\n{container}");
4721
4722        compare_containers(
4723            &container,
4724            &Container {
4725                children: vec![
4726                    Container {
4727                        calculated_width: Some(20.0),
4728                        calculated_height: Some(ROW_HEIGHT),
4729                        calculated_x: Some(11.666_667),
4730                        calculated_y: Some(0.0),
4731                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 0 }),
4732                        ..container.children[0].clone()
4733                    },
4734                    Container {
4735                        calculated_width: Some(20.0),
4736                        calculated_height: Some(ROW_HEIGHT),
4737                        calculated_x: Some(43.333_336),
4738                        calculated_y: Some(0.0),
4739                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
4740                        ..container.children[1].clone()
4741                    },
4742                    Container {
4743                        calculated_width: Some(20.0),
4744                        calculated_height: Some(ROW_HEIGHT),
4745                        calculated_x: Some(11.666_667),
4746                        calculated_y: Some(ROW_HEIGHT + 10.0),
4747                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 0 }),
4748                        ..container.children[2].clone()
4749                    },
4750                    Container {
4751                        calculated_width: Some(20.0),
4752                        calculated_height: Some(ROW_HEIGHT),
4753                        calculated_x: Some(43.333_336),
4754                        calculated_y: Some(ROW_HEIGHT + 10.0),
4755                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 1 }),
4756                        ..container.children[3].clone()
4757                    },
4758                    Container {
4759                        calculated_width: Some(20.0),
4760                        calculated_height: Some(ROW_HEIGHT),
4761                        calculated_x: Some(11.666_667),
4762                        calculated_y: Some(ROW_HEIGHT.mul_add(2.0, 10.0 + 10.0)),
4763                        calculated_position: Some(LayoutPosition::Wrap { row: 2, col: 0 }),
4764                        ..container.children[4].clone()
4765                    },
4766                ],
4767                calculated_width: Some(75.0),
4768                calculated_height: Some(40.0),
4769                ..container.clone()
4770            },
4771        );
4772    }
4773
4774    #[test_log::test]
4775    fn handles_justify_content_space_evenly_with_gap_and_wraps_elements_properly_and_can_recalc() {
4776        const ROW_HEIGHT: f32 = 40.0 / 3.0;
4777
4778        let mut container = Container {
4779            children: vec![
4780                Container {
4781                    width: Some(Number::Integer(20)),
4782                    calculated_width: Some(20.0),
4783                    calculated_height: Some(20.0),
4784                    ..Default::default()
4785                },
4786                Container {
4787                    width: Some(Number::Integer(20)),
4788                    calculated_width: Some(20.0),
4789                    calculated_height: Some(20.0),
4790                    ..Default::default()
4791                },
4792                Container {
4793                    width: Some(Number::Integer(20)),
4794                    calculated_width: Some(20.0),
4795                    calculated_height: Some(20.0),
4796                    ..Default::default()
4797                },
4798                Container {
4799                    width: Some(Number::Integer(20)),
4800                    calculated_width: Some(20.0),
4801                    calculated_height: Some(20.0),
4802                    ..Default::default()
4803                },
4804                Container {
4805                    width: Some(Number::Integer(20)),
4806                    calculated_width: Some(20.0),
4807                    calculated_height: Some(20.0),
4808                    ..Default::default()
4809                },
4810            ],
4811            calculated_width: Some(75.0),
4812            calculated_height: Some(40.0),
4813            direction: LayoutDirection::Row,
4814            overflow_x: LayoutOverflow::Wrap { grid: true },
4815            overflow_y: LayoutOverflow::Expand,
4816            justify_content: Some(JustifyContent::SpaceEvenly),
4817            column_gap: Some(Number::Integer(10)),
4818            row_gap: Some(Number::Integer(10)),
4819            ..Default::default()
4820        };
4821
4822        CALCULATOR.calc(&mut container);
4823        log::trace!("first container:\n{container}");
4824
4825        let mut actual = container.clone();
4826        let expected = Container {
4827            children: vec![
4828                Container {
4829                    calculated_width: Some(20.0),
4830                    calculated_height: Some(ROW_HEIGHT),
4831                    calculated_x: Some(11.666_667),
4832                    calculated_y: Some(0.0),
4833                    calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 0 }),
4834                    ..container.children[0].clone()
4835                },
4836                Container {
4837                    calculated_width: Some(20.0),
4838                    calculated_height: Some(ROW_HEIGHT),
4839                    calculated_x: Some(43.333_336),
4840                    calculated_y: Some(0.0),
4841                    calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
4842                    ..container.children[1].clone()
4843                },
4844                Container {
4845                    calculated_width: Some(20.0),
4846                    calculated_height: Some(ROW_HEIGHT),
4847                    calculated_x: Some(11.666_667),
4848                    calculated_y: Some(ROW_HEIGHT + 10.0),
4849                    calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 0 }),
4850                    ..container.children[2].clone()
4851                },
4852                Container {
4853                    calculated_width: Some(20.0),
4854                    calculated_height: Some(ROW_HEIGHT),
4855                    calculated_x: Some(43.333_336),
4856                    calculated_y: Some(ROW_HEIGHT + 10.0),
4857                    calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 1 }),
4858                    ..container.children[3].clone()
4859                },
4860                Container {
4861                    calculated_width: Some(20.0),
4862                    calculated_height: Some(ROW_HEIGHT),
4863                    calculated_x: Some(11.666_667),
4864                    calculated_y: Some(ROW_HEIGHT.mul_add(2.0, 10.0 + 10.0)),
4865                    calculated_position: Some(LayoutPosition::Wrap { row: 2, col: 0 }),
4866                    ..container.children[4].clone()
4867                },
4868            ],
4869            calculated_width: Some(75.0),
4870            calculated_height: Some(40.0),
4871            ..container
4872        };
4873
4874        compare_containers(&actual, &expected);
4875
4876        CALCULATOR.calc(&mut actual);
4877        log::trace!("second container:\n{actual}");
4878
4879        compare_containers(&actual, &expected);
4880    }
4881
4882    #[test_log::test]
4883    fn calc_child_minimum_height_is_propagated_upward() {
4884        let mut container = Container {
4885            children: vec![Container {
4886                children: vec![
4887                    Container {
4888                        width: Some(Number::Integer(25)),
4889                        height: Some(Number::Integer(40)),
4890                        ..Default::default()
4891                    },
4892                    Container {
4893                        width: Some(Number::Integer(25)),
4894                        height: Some(Number::Integer(40)),
4895                        ..Default::default()
4896                    },
4897                    Container {
4898                        width: Some(Number::Integer(25)),
4899                        height: Some(Number::Integer(40)),
4900                        ..Default::default()
4901                    },
4902                ],
4903                ..Default::default()
4904            }],
4905            calculated_width: Some(50.0),
4906            calculated_height: Some(40.0),
4907            direction: LayoutDirection::Row,
4908            overflow_x: LayoutOverflow::Wrap { grid: true },
4909            overflow_y: LayoutOverflow::Expand,
4910            ..Default::default()
4911        };
4912
4913        CALCULATOR.calc(&mut container);
4914        log::trace!("container:\n{container}");
4915
4916        compare_containers(
4917            &container,
4918            &Container {
4919                children: vec![Container {
4920                    calculated_child_min_width: Some(25.0),
4921                    calculated_width: Some(25.0),
4922                    calculated_height: Some(120.0),
4923                    ..container.children[0].clone()
4924                }],
4925                calculated_width: Some(50.0),
4926                calculated_height: Some(40.0),
4927                direction: LayoutDirection::Row,
4928                ..container.clone()
4929            },
4930        );
4931    }
4932
4933    #[test_log::test]
4934    fn calc_child_minimum_height_is_propagated_upward_and_recalc() {
4935        let mut container = Container {
4936            children: vec![Container {
4937                children: vec![
4938                    Container {
4939                        width: Some(Number::Integer(25)),
4940                        height: Some(Number::Integer(40)),
4941                        ..Default::default()
4942                    },
4943                    Container {
4944                        width: Some(Number::Integer(25)),
4945                        height: Some(Number::Integer(40)),
4946                        ..Default::default()
4947                    },
4948                    Container {
4949                        width: Some(Number::Integer(25)),
4950                        height: Some(Number::Integer(40)),
4951                        ..Default::default()
4952                    },
4953                ],
4954                ..Default::default()
4955            }],
4956            calculated_width: Some(50.0),
4957            calculated_height: Some(40.0),
4958            direction: LayoutDirection::Row,
4959            overflow_x: LayoutOverflow::Wrap { grid: true },
4960            overflow_y: LayoutOverflow::Expand,
4961            ..Default::default()
4962        };
4963
4964        CALCULATOR.calc(&mut container);
4965        log::trace!("first container:\n{container}");
4966
4967        CALCULATOR.calc(&mut container);
4968        log::trace!("second container:\n{container}");
4969
4970        compare_containers(
4971            &container,
4972            &Container {
4973                children: vec![Container {
4974                    calculated_child_min_width: Some(25.0),
4975                    calculated_width: Some(25.0),
4976                    calculated_height: Some(120.0),
4977                    ..container.children[0].clone()
4978                }],
4979                calculated_width: Some(50.0),
4980                calculated_height: Some(40.0),
4981                direction: LayoutDirection::Row,
4982                ..container.clone()
4983            },
4984        );
4985    }
4986
4987    #[test_log::test]
4988    fn calc_resizes_when_a_new_row_was_shifted_into_view() {
4989        let mut container = Container {
4990            children: vec![
4991                Container {
4992                    width: Some(Number::Integer(25)),
4993                    height: Some(Number::Integer(40)),
4994                    ..Default::default()
4995                },
4996                Container {
4997                    width: Some(Number::Integer(25)),
4998                    height: Some(Number::Integer(40)),
4999                    ..Default::default()
5000                },
5001                Container {
5002                    width: Some(Number::Integer(25)),
5003                    height: Some(Number::Integer(40)),
5004                    ..Default::default()
5005                },
5006            ],
5007            calculated_width: Some(50.0),
5008            calculated_height: Some(40.0),
5009            direction: LayoutDirection::Row,
5010            overflow_x: LayoutOverflow::Wrap { grid: true },
5011            overflow_y: LayoutOverflow::Squash,
5012            ..Default::default()
5013        };
5014
5015        CALCULATOR.calc(&mut container);
5016        log::trace!("container:\n{container}");
5017
5018        compare_containers(
5019            &container,
5020            &Container {
5021                children: vec![
5022                    Container {
5023                        calculated_height: Some(40.0),
5024                        ..container.children[0].clone()
5025                    },
5026                    Container {
5027                        calculated_height: Some(40.0),
5028                        ..container.children[1].clone()
5029                    },
5030                    Container {
5031                        calculated_height: Some(40.0),
5032                        ..container.children[2].clone()
5033                    },
5034                ],
5035                ..container.clone()
5036            },
5037        );
5038    }
5039
5040    #[test_log::test]
5041    fn calc_allows_expanding_height_for_overflow_y_scroll() {
5042        let mut container = Container {
5043            children: vec![
5044                Container {
5045                    width: Some(Number::Integer(25)),
5046                    height: Some(Number::Integer(40)),
5047                    ..Default::default()
5048                },
5049                Container {
5050                    width: Some(Number::Integer(25)),
5051                    height: Some(Number::Integer(40)),
5052                    ..Default::default()
5053                },
5054                Container {
5055                    width: Some(Number::Integer(25)),
5056                    height: Some(Number::Integer(40)),
5057                    ..Default::default()
5058                },
5059            ],
5060            calculated_width: Some(50.0 + f32::from(get_scrollbar_size())),
5061            calculated_height: Some(40.0),
5062            direction: LayoutDirection::Row,
5063            overflow_x: LayoutOverflow::Wrap { grid: true },
5064            overflow_y: LayoutOverflow::Scroll,
5065            ..Default::default()
5066        };
5067
5068        CALCULATOR.calc(&mut container);
5069        log::trace!("container:\n{container}");
5070
5071        compare_containers(
5072            &container,
5073            &Container {
5074                children: vec![
5075                    Container {
5076                        calculated_height: Some(40.0),
5077                        ..container.children[0].clone()
5078                    },
5079                    Container {
5080                        calculated_height: Some(40.0),
5081                        ..container.children[1].clone()
5082                    },
5083                    Container {
5084                        calculated_height: Some(40.0),
5085                        ..container.children[2].clone()
5086                    },
5087                ],
5088                ..container.clone()
5089            },
5090        );
5091    }
5092
5093    #[test_log::test]
5094    fn handle_overflow_wraps_single_row_overflow_content_correctly() {
5095        let mut container = Container {
5096            children: vec![
5097                Container {
5098                    width: Some(Number::Integer(25)),
5099                    height: Some(Number::Integer(40)),
5100                    ..Default::default()
5101                },
5102                Container {
5103                    width: Some(Number::Integer(25)),
5104                    height: Some(Number::Integer(40)),
5105                    ..Default::default()
5106                },
5107                Container {
5108                    width: Some(Number::Integer(25)),
5109                    height: Some(Number::Integer(40)),
5110                    ..Default::default()
5111                },
5112            ],
5113            calculated_width: Some(50.0),
5114            calculated_height: Some(40.0),
5115            direction: LayoutDirection::Row,
5116            overflow_x: LayoutOverflow::Wrap { grid: true },
5117            overflow_y: LayoutOverflow::Squash,
5118            ..Default::default()
5119        };
5120
5121        CALCULATOR.calc(&mut container);
5122        log::trace!("container:\n{container}");
5123
5124        compare_containers(
5125            &container,
5126            &Container {
5127                children: vec![
5128                    Container {
5129                        calculated_width: Some(25.0),
5130                        calculated_height: Some(40.0),
5131                        calculated_x: Some(0.0),
5132                        calculated_y: Some(0.0),
5133                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 0 }),
5134                        ..container.children[0].clone()
5135                    },
5136                    Container {
5137                        calculated_width: Some(25.0),
5138                        calculated_height: Some(40.0),
5139                        calculated_x: Some(25.0),
5140                        calculated_y: Some(0.0),
5141                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
5142                        ..container.children[1].clone()
5143                    },
5144                    Container {
5145                        calculated_width: Some(25.0),
5146                        calculated_height: Some(40.0),
5147                        calculated_x: Some(0.0),
5148                        calculated_y: Some(40.0),
5149                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 0 }),
5150                        ..container.children[2].clone()
5151                    },
5152                ],
5153                ..container.clone()
5154            },
5155        );
5156    }
5157
5158    #[test_log::test]
5159    fn handle_overflow_wraps_multi_row_overflow_content_correctly() {
5160        const ROW_HEIGHT: f32 = 40.0;
5161
5162        let mut container = Container {
5163            children: vec![
5164                Container {
5165                    width: Some(Number::Integer(25)),
5166                    height: Some(Number::Integer(40)),
5167                    ..Default::default()
5168                },
5169                Container {
5170                    width: Some(Number::Integer(25)),
5171                    height: Some(Number::Integer(40)),
5172                    ..Default::default()
5173                },
5174                Container {
5175                    width: Some(Number::Integer(25)),
5176                    height: Some(Number::Integer(40)),
5177                    ..Default::default()
5178                },
5179                Container {
5180                    width: Some(Number::Integer(25)),
5181                    height: Some(Number::Integer(40)),
5182                    ..Default::default()
5183                },
5184                Container {
5185                    width: Some(Number::Integer(25)),
5186                    height: Some(Number::Integer(40)),
5187                    ..Default::default()
5188                },
5189            ],
5190            calculated_width: Some(50.0),
5191            calculated_height: Some(40.0),
5192            direction: LayoutDirection::Row,
5193            overflow_x: LayoutOverflow::Wrap { grid: true },
5194            overflow_y: LayoutOverflow::Squash,
5195            ..Default::default()
5196        };
5197
5198        CALCULATOR.calc(&mut container);
5199        log::trace!("container:\n{container}");
5200
5201        compare_containers(
5202            &container,
5203            &Container {
5204                children: vec![
5205                    Container {
5206                        calculated_width: Some(25.0),
5207                        calculated_height: Some(ROW_HEIGHT),
5208                        calculated_x: Some(0.0),
5209                        calculated_y: Some(0.0),
5210                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 0 }),
5211                        ..container.children[0].clone()
5212                    },
5213                    Container {
5214                        calculated_width: Some(25.0),
5215                        calculated_height: Some(ROW_HEIGHT),
5216                        calculated_x: Some(25.0),
5217                        calculated_y: Some(0.0),
5218                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
5219                        ..container.children[1].clone()
5220                    },
5221                    Container {
5222                        calculated_width: Some(25.0),
5223                        calculated_height: Some(ROW_HEIGHT),
5224                        calculated_x: Some(0.0),
5225                        calculated_y: Some(ROW_HEIGHT),
5226                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 0 }),
5227                        ..container.children[2].clone()
5228                    },
5229                    Container {
5230                        calculated_width: Some(25.0),
5231                        calculated_height: Some(ROW_HEIGHT),
5232                        calculated_x: Some(25.0),
5233                        calculated_y: Some(ROW_HEIGHT),
5234                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 1 }),
5235                        ..container.children[3].clone()
5236                    },
5237                    Container {
5238                        calculated_width: Some(25.0),
5239                        calculated_height: Some(ROW_HEIGHT),
5240                        calculated_x: Some(0.0),
5241                        calculated_y: Some(ROW_HEIGHT * 2.0),
5242                        calculated_position: Some(LayoutPosition::Wrap { row: 2, col: 0 }),
5243                        ..container.children[4].clone()
5244                    },
5245                ],
5246                ..container.clone()
5247            },
5248        );
5249    }
5250
5251    #[test_log::test]
5252    fn handle_overflow_wraps_row_content_correctly_in_overflow_y_scroll() {
5253        let mut container = Container {
5254            children: vec![
5255                Container {
5256                    width: Some(Number::Integer(25)),
5257                    height: Some(Number::Integer(40)),
5258                    ..Default::default()
5259                },
5260                Container {
5261                    width: Some(Number::Integer(25)),
5262                    height: Some(Number::Integer(40)),
5263                    ..Default::default()
5264                },
5265                Container {
5266                    width: Some(Number::Integer(25)),
5267                    height: Some(Number::Integer(40)),
5268                    ..Default::default()
5269                },
5270            ],
5271            calculated_width: Some(50.0 + f32::from(get_scrollbar_size())),
5272            calculated_height: Some(80.0),
5273            direction: LayoutDirection::Row,
5274            overflow_x: LayoutOverflow::Wrap { grid: true },
5275            overflow_y: LayoutOverflow::Scroll,
5276            ..Default::default()
5277        };
5278
5279        CALCULATOR.calc(&mut container);
5280        log::trace!("container:\n{container}");
5281
5282        compare_containers(
5283            &container.clone(),
5284            &Container {
5285                children: vec![
5286                    Container {
5287                        calculated_width: Some(25.0),
5288                        calculated_height: Some(40.0),
5289                        calculated_x: Some(0.0),
5290                        calculated_y: Some(0.0),
5291                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 0 }),
5292                        ..container.children[0].clone()
5293                    },
5294                    Container {
5295                        calculated_width: Some(25.0),
5296                        calculated_height: Some(40.0),
5297                        calculated_x: Some(25.0),
5298                        calculated_y: Some(0.0),
5299                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
5300                        ..container.children[1].clone()
5301                    },
5302                    Container {
5303                        calculated_width: Some(25.0),
5304                        calculated_height: Some(40.0),
5305                        calculated_x: Some(0.0),
5306                        calculated_y: Some(40.0),
5307                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 0 }),
5308                        ..container.children[2].clone()
5309                    },
5310                ],
5311                ..container
5312            },
5313        );
5314    }
5315
5316    #[test_log::test]
5317    fn calc_inner_wraps_row_content_correctly() {
5318        let mut container = Container {
5319            children: vec![
5320                Container {
5321                    width: Some(Number::Integer(25)),
5322                    ..Default::default()
5323                },
5324                Container {
5325                    width: Some(Number::Integer(25)),
5326                    ..Default::default()
5327                },
5328                Container {
5329                    width: Some(Number::Integer(25)),
5330                    ..Default::default()
5331                },
5332            ],
5333            calculated_width: Some(50.0),
5334            calculated_height: Some(40.0),
5335            direction: LayoutDirection::Row,
5336            overflow_x: LayoutOverflow::Wrap { grid: true },
5337            overflow_y: LayoutOverflow::Squash,
5338            ..Default::default()
5339        };
5340        CALCULATOR.calc(&mut container);
5341        log::trace!("container:\n{container}");
5342
5343        compare_containers(
5344            &container,
5345            &Container {
5346                children: vec![
5347                    Container {
5348                        width: Some(Number::Integer(25)),
5349                        calculated_width: Some(25.0),
5350                        calculated_height: Some(20.0),
5351                        calculated_x: Some(0.0),
5352                        calculated_y: Some(0.0),
5353                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 0 }),
5354                        ..container.children[0].clone()
5355                    },
5356                    Container {
5357                        width: Some(Number::Integer(25)),
5358                        calculated_width: Some(25.0),
5359                        calculated_height: Some(20.0),
5360                        calculated_x: Some(25.0),
5361                        calculated_y: Some(0.0),
5362                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
5363                        ..container.children[1].clone()
5364                    },
5365                    Container {
5366                        width: Some(Number::Integer(25)),
5367                        calculated_width: Some(25.0),
5368                        calculated_height: Some(20.0),
5369                        calculated_x: Some(0.0),
5370                        calculated_y: Some(20.0),
5371                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 0 }),
5372                        ..container.children[2].clone()
5373                    },
5374                ],
5375                ..container.clone()
5376            },
5377        );
5378    }
5379
5380    #[test_log::test]
5381    fn calc_inner_children_overflow_squash_wraps_row_content_with_nested_width_correctly() {
5382        let mut container = Container {
5383            children: vec![
5384                Container {
5385                    children: vec![Container {
5386                        width: Some(Number::Integer(25)),
5387                        ..Default::default()
5388                    }],
5389                    overflow_x: LayoutOverflow::Squash,
5390                    overflow_y: LayoutOverflow::Squash,
5391                    justify_content: Some(JustifyContent::Start),
5392                    ..Default::default()
5393                },
5394                Container {
5395                    children: vec![Container {
5396                        width: Some(Number::Integer(25)),
5397                        ..Default::default()
5398                    }],
5399                    overflow_x: LayoutOverflow::Squash,
5400                    overflow_y: LayoutOverflow::Squash,
5401                    justify_content: Some(JustifyContent::Start),
5402                    ..Default::default()
5403                },
5404                Container {
5405                    children: vec![Container {
5406                        width: Some(Number::Integer(25)),
5407                        ..Default::default()
5408                    }],
5409                    overflow_x: LayoutOverflow::Squash,
5410                    overflow_y: LayoutOverflow::Squash,
5411                    justify_content: Some(JustifyContent::Start),
5412                    ..Default::default()
5413                },
5414            ],
5415            calculated_width: Some(50.0),
5416            calculated_height: Some(40.0),
5417            direction: LayoutDirection::Row,
5418            overflow_x: LayoutOverflow::Wrap { grid: true },
5419            overflow_y: LayoutOverflow::Squash,
5420            justify_content: Some(JustifyContent::Start),
5421            ..Default::default()
5422        };
5423        CALCULATOR.calc(&mut container);
5424        log::trace!("container:\n{container}");
5425
5426        compare_containers(
5427            &container.clone(),
5428            &Container {
5429                children: vec![
5430                    Container {
5431                        children: vec![Container {
5432                            calculated_width: Some(25.0),
5433                            calculated_height: Some(0.0),
5434                            calculated_x: Some(0.0),
5435                            calculated_y: Some(0.0),
5436                            calculated_position: Some(LayoutPosition::default()),
5437                            ..container.children[0].children[0].clone()
5438                        }],
5439                        calculated_width: Some(25.0),
5440                        calculated_height: Some(20.0),
5441                        calculated_x: Some(0.0),
5442                        calculated_y: Some(0.0),
5443                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 0 }),
5444                        ..container.children[0].clone()
5445                    },
5446                    Container {
5447                        children: vec![Container {
5448                            width: Some(Number::Integer(25)),
5449                            calculated_width: Some(25.0),
5450                            calculated_height: Some(0.0),
5451                            calculated_x: Some(0.0),
5452                            calculated_y: Some(0.0),
5453                            calculated_position: Some(LayoutPosition::default()),
5454                            ..container.children[1].children[0].clone()
5455                        }],
5456                        calculated_width: Some(25.0),
5457                        calculated_height: Some(20.0),
5458                        calculated_x: Some(25.0),
5459                        calculated_y: Some(0.0),
5460                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
5461                        ..container.children[1].clone()
5462                    },
5463                    Container {
5464                        children: vec![Container {
5465                            width: Some(Number::Integer(25)),
5466                            calculated_width: Some(25.0),
5467                            calculated_height: Some(0.0),
5468                            calculated_x: Some(0.0),
5469                            calculated_y: Some(0.0),
5470                            calculated_position: Some(LayoutPosition::default()),
5471                            ..container.children[2].children[0].clone()
5472                        }],
5473                        calculated_width: Some(25.0),
5474                        calculated_height: Some(20.0),
5475                        calculated_x: Some(0.0),
5476                        calculated_y: Some(20.0),
5477                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 0 }),
5478                        ..container.children[2].clone()
5479                    },
5480                ],
5481                ..container
5482            },
5483        );
5484    }
5485
5486    #[test_log::test]
5487    fn calc_inner_children_overflow_expand_wraps_row_content_with_nested_width_correctly() {
5488        let mut container = Container {
5489            children: vec![
5490                Container {
5491                    children: vec![Container {
5492                        width: Some(Number::Integer(25)),
5493                        ..Default::default()
5494                    }],
5495                    overflow_x: LayoutOverflow::Expand,
5496                    overflow_y: LayoutOverflow::Expand,
5497                    justify_content: Some(JustifyContent::Start),
5498                    ..Default::default()
5499                },
5500                Container {
5501                    children: vec![Container {
5502                        width: Some(Number::Integer(25)),
5503                        ..Default::default()
5504                    }],
5505                    overflow_x: LayoutOverflow::Expand,
5506                    overflow_y: LayoutOverflow::Expand,
5507                    justify_content: Some(JustifyContent::Start),
5508                    ..Default::default()
5509                },
5510                Container {
5511                    children: vec![Container {
5512                        width: Some(Number::Integer(25)),
5513                        ..Default::default()
5514                    }],
5515                    overflow_x: LayoutOverflow::Expand,
5516                    overflow_y: LayoutOverflow::Expand,
5517                    justify_content: Some(JustifyContent::Start),
5518                    ..Default::default()
5519                },
5520            ],
5521            calculated_width: Some(50.0),
5522            calculated_height: Some(40.0),
5523            direction: LayoutDirection::Row,
5524            overflow_x: LayoutOverflow::Wrap { grid: true },
5525            overflow_y: LayoutOverflow::Squash,
5526            justify_content: Some(JustifyContent::Start),
5527            ..Default::default()
5528        };
5529
5530        CALCULATOR.calc(&mut container);
5531        log::trace!("container:\n{container}");
5532
5533        compare_containers(
5534            &container.clone(),
5535            &Container {
5536                children: vec![
5537                    Container {
5538                        children: vec![Container {
5539                            width: Some(Number::Integer(25)),
5540                            calculated_width: Some(25.0),
5541                            calculated_height: Some(0.0),
5542                            calculated_x: Some(0.0),
5543                            calculated_y: Some(0.0),
5544                            calculated_position: Some(LayoutPosition::default()),
5545                            ..container.children[0].children[0].clone()
5546                        }],
5547                        calculated_width: Some(25.0),
5548                        calculated_height: Some(20.0),
5549                        calculated_x: Some(0.0),
5550                        calculated_y: Some(0.0),
5551                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 0 }),
5552                        ..container.children[0].clone()
5553                    },
5554                    Container {
5555                        children: vec![Container {
5556                            width: Some(Number::Integer(25)),
5557                            calculated_width: Some(25.0),
5558                            calculated_height: Some(0.0),
5559                            calculated_x: Some(0.0),
5560                            calculated_y: Some(0.0),
5561                            calculated_position: Some(LayoutPosition::default()),
5562                            ..container.children[1].children[0].clone()
5563                        }],
5564                        calculated_width: Some(25.0),
5565                        calculated_height: Some(20.0),
5566                        calculated_x: Some(25.0),
5567                        calculated_y: Some(0.0),
5568                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
5569                        ..container.children[1].clone()
5570                    },
5571                    Container {
5572                        children: vec![Container {
5573                            width: Some(Number::Integer(25)),
5574                            calculated_width: Some(25.0),
5575                            calculated_height: Some(0.0),
5576                            calculated_x: Some(0.0),
5577                            calculated_y: Some(0.0),
5578                            calculated_position: Some(LayoutPosition::default()),
5579                            ..container.children[2].children[0].clone()
5580                        }],
5581                        calculated_width: Some(25.0),
5582                        calculated_height: Some(20.0),
5583                        calculated_x: Some(0.0),
5584                        calculated_y: Some(20.0),
5585                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 0 }),
5586                        ..container.children[2].clone()
5587                    },
5588                ],
5589                ..container
5590            },
5591        );
5592    }
5593
5594    #[test_log::test]
5595    fn calc_inner_children_overflow_squash_wraps_row_content_with_nested_explicit_width_correctly()
5596    {
5597        let mut container = Container {
5598            children: vec![
5599                Container {
5600                    width: Some(Number::Integer(25)),
5601                    children: vec![Container {
5602                        width: Some(Number::Integer(25)),
5603                        ..Default::default()
5604                    }],
5605                    overflow_x: LayoutOverflow::Squash,
5606                    overflow_y: LayoutOverflow::Squash,
5607                    justify_content: Some(JustifyContent::Start),
5608                    ..Default::default()
5609                },
5610                Container {
5611                    width: Some(Number::Integer(25)),
5612                    children: vec![Container {
5613                        width: Some(Number::Integer(25)),
5614                        ..Default::default()
5615                    }],
5616                    overflow_x: LayoutOverflow::Squash,
5617                    overflow_y: LayoutOverflow::Squash,
5618                    justify_content: Some(JustifyContent::Start),
5619                    ..Default::default()
5620                },
5621                Container {
5622                    width: Some(Number::Integer(25)),
5623                    children: vec![Container {
5624                        width: Some(Number::Integer(25)),
5625                        ..Default::default()
5626                    }],
5627                    overflow_x: LayoutOverflow::Squash,
5628                    overflow_y: LayoutOverflow::Squash,
5629                    justify_content: Some(JustifyContent::Start),
5630                    ..Default::default()
5631                },
5632            ],
5633            calculated_width: Some(50.0),
5634            calculated_height: Some(40.0),
5635            direction: LayoutDirection::Row,
5636            overflow_x: LayoutOverflow::Wrap { grid: true },
5637            overflow_y: LayoutOverflow::Squash,
5638            justify_content: Some(JustifyContent::Start),
5639            ..Default::default()
5640        };
5641        CALCULATOR.calc(&mut container);
5642        log::trace!("container:\n{container}");
5643
5644        compare_containers(
5645            &container.clone(),
5646            &Container {
5647                children: vec![
5648                    Container {
5649                        width: Some(Number::Integer(25)),
5650                        children: vec![Container {
5651                            width: Some(Number::Integer(25)),
5652                            calculated_width: Some(25.0),
5653                            calculated_height: Some(0.0),
5654                            calculated_x: Some(0.0),
5655                            calculated_y: Some(0.0),
5656                            calculated_position: Some(LayoutPosition::default()),
5657                            ..container.children[0].children[0].clone()
5658                        }],
5659                        calculated_width: Some(25.0),
5660                        calculated_height: Some(20.0),
5661                        calculated_x: Some(0.0),
5662                        calculated_y: Some(0.0),
5663                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 0 }),
5664                        ..container.children[0].clone()
5665                    },
5666                    Container {
5667                        width: Some(Number::Integer(25)),
5668                        children: vec![Container {
5669                            width: Some(Number::Integer(25)),
5670                            calculated_width: Some(25.0),
5671                            calculated_height: Some(0.0),
5672                            calculated_x: Some(0.0),
5673                            calculated_y: Some(0.0),
5674                            calculated_position: Some(LayoutPosition::default()),
5675                            ..container.children[1].children[0].clone()
5676                        }],
5677                        calculated_width: Some(25.0),
5678                        calculated_height: Some(20.0),
5679                        calculated_x: Some(25.0),
5680                        calculated_y: Some(0.0),
5681                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
5682                        ..container.children[1].clone()
5683                    },
5684                    Container {
5685                        width: Some(Number::Integer(25)),
5686                        children: vec![Container {
5687                            width: Some(Number::Integer(25)),
5688                            calculated_width: Some(25.0),
5689                            calculated_height: Some(0.0),
5690                            calculated_x: Some(0.0),
5691                            calculated_y: Some(0.0),
5692                            calculated_position: Some(LayoutPosition::default()),
5693                            ..container.children[2].children[0].clone()
5694                        }],
5695                        calculated_width: Some(25.0),
5696                        calculated_height: Some(20.0),
5697                        calculated_x: Some(0.0),
5698                        calculated_y: Some(20.0),
5699                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 0 }),
5700                        ..container.children[2].clone()
5701                    },
5702                ],
5703                ..container
5704            },
5705        );
5706    }
5707
5708    #[test_log::test]
5709    fn calc_inner_children_overflow_expand_wraps_row_content_with_nested_explicit_width_correctly()
5710    {
5711        let mut container = Container {
5712            children: vec![
5713                Container {
5714                    width: Some(Number::Integer(25)),
5715                    children: vec![Container {
5716                        width: Some(Number::Integer(25)),
5717                        ..Default::default()
5718                    }],
5719                    overflow_x: LayoutOverflow::Expand,
5720                    overflow_y: LayoutOverflow::Expand,
5721                    justify_content: Some(JustifyContent::Start),
5722                    ..Default::default()
5723                },
5724                Container {
5725                    width: Some(Number::Integer(25)),
5726                    children: vec![Container {
5727                        width: Some(Number::Integer(25)),
5728                        ..Default::default()
5729                    }],
5730                    overflow_x: LayoutOverflow::Expand,
5731                    overflow_y: LayoutOverflow::Expand,
5732                    justify_content: Some(JustifyContent::Start),
5733                    ..Default::default()
5734                },
5735                Container {
5736                    width: Some(Number::Integer(25)),
5737                    children: vec![Container {
5738                        width: Some(Number::Integer(25)),
5739                        ..Default::default()
5740                    }],
5741                    overflow_x: LayoutOverflow::Expand,
5742                    overflow_y: LayoutOverflow::Expand,
5743                    justify_content: Some(JustifyContent::Start),
5744                    ..Default::default()
5745                },
5746            ],
5747            calculated_width: Some(50.0),
5748            calculated_height: Some(40.0),
5749            direction: LayoutDirection::Row,
5750            overflow_x: LayoutOverflow::Wrap { grid: true },
5751            overflow_y: LayoutOverflow::Squash,
5752            justify_content: Some(JustifyContent::Start),
5753            ..Default::default()
5754        };
5755        CALCULATOR.calc(&mut container);
5756        log::trace!("container:\n{container}");
5757
5758        compare_containers(
5759            &container.clone(),
5760            &Container {
5761                children: vec![
5762                    Container {
5763                        width: Some(Number::Integer(25)),
5764                        children: vec![Container {
5765                            width: Some(Number::Integer(25)),
5766                            calculated_width: Some(25.0),
5767                            calculated_height: Some(0.0),
5768                            calculated_x: Some(0.0),
5769                            calculated_y: Some(0.0),
5770                            calculated_position: Some(LayoutPosition::default()),
5771                            ..container.children[0].children[0].clone()
5772                        }],
5773                        calculated_width: Some(25.0),
5774                        calculated_height: Some(20.0),
5775                        calculated_x: Some(0.0),
5776                        calculated_y: Some(0.0),
5777                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 0 }),
5778                        ..container.children[0].clone()
5779                    },
5780                    Container {
5781                        width: Some(Number::Integer(25)),
5782                        children: vec![Container {
5783                            width: Some(Number::Integer(25)),
5784                            calculated_width: Some(25.0),
5785                            calculated_height: Some(0.0),
5786                            calculated_x: Some(0.0),
5787                            calculated_y: Some(0.0),
5788                            calculated_position: Some(LayoutPosition::default()),
5789                            ..container.children[1].children[0].clone()
5790                        }],
5791                        calculated_width: Some(25.0),
5792                        calculated_height: Some(20.0),
5793                        calculated_x: Some(25.0),
5794                        calculated_y: Some(0.0),
5795                        calculated_position: Some(LayoutPosition::Wrap { row: 0, col: 1 }),
5796                        ..container.children[1].clone()
5797                    },
5798                    Container {
5799                        width: Some(Number::Integer(25)),
5800                        children: vec![Container {
5801                            width: Some(Number::Integer(25)),
5802                            calculated_width: Some(25.0),
5803                            calculated_height: Some(0.0),
5804                            calculated_x: Some(0.0),
5805                            calculated_y: Some(0.0),
5806                            calculated_position: Some(LayoutPosition::default()),
5807                            ..container.children[2].children[0].clone()
5808                        }],
5809                        calculated_width: Some(25.0),
5810                        calculated_height: Some(20.0),
5811                        calculated_x: Some(0.0),
5812                        calculated_y: Some(20.0),
5813                        calculated_position: Some(LayoutPosition::Wrap { row: 1, col: 0 }),
5814                        ..container.children[2].clone()
5815                    },
5816                ],
5817                ..container
5818            },
5819        );
5820    }
5821
5822    #[test_log::test]
5823    fn calc_can_calc_horizontal_split_with_row_content_in_right_pane_above_a_vertial_split() {
5824        let mut container = Container {
5825            children: vec![
5826                Container {
5827                    children: vec![
5828                        Container::default(),
5829                        Container {
5830                            children: vec![Container::default(), Container::default()],
5831                            direction: LayoutDirection::Row,
5832                            justify_content: Some(JustifyContent::Start),
5833                            ..Default::default()
5834                        },
5835                    ],
5836                    direction: LayoutDirection::Row,
5837                    justify_content: Some(JustifyContent::Start),
5838                    ..Default::default()
5839                },
5840                Container::default(),
5841            ],
5842            calculated_width: Some(100.0),
5843            calculated_height: Some(40.0),
5844            justify_content: Some(JustifyContent::Start),
5845            ..Default::default()
5846        };
5847        CALCULATOR.calc(&mut container);
5848        log::trace!("container:\n{container}");
5849
5850        compare_containers(
5851            &container,
5852            &Container {
5853                children: vec![
5854                    Container {
5855                        children: vec![
5856                            Container {
5857                                calculated_width: Some(0.0),
5858                                calculated_height: Some(0.0),
5859                                calculated_x: Some(0.0),
5860                                calculated_y: Some(0.0),
5861                                calculated_position: Some(LayoutPosition::Default),
5862                                ..container.children[0].children[0].clone()
5863                            },
5864                            Container {
5865                                calculated_width: Some(0.0),
5866                                calculated_height: Some(0.0),
5867                                calculated_x: Some(0.0),
5868                                calculated_y: Some(0.0),
5869                                calculated_position: Some(LayoutPosition::Default),
5870                                direction: LayoutDirection::Row,
5871                                children: vec![
5872                                    Container {
5873                                        calculated_width: Some(0.0),
5874                                        calculated_height: Some(0.0),
5875                                        calculated_x: Some(0.0),
5876                                        calculated_y: Some(0.0),
5877                                        calculated_position: Some(LayoutPosition::Default),
5878                                        ..container.children[0].children[1].children[0].clone()
5879                                    },
5880                                    Container {
5881                                        calculated_width: Some(0.0),
5882                                        calculated_height: Some(0.0),
5883                                        calculated_x: Some(0.0),
5884                                        calculated_y: Some(0.0),
5885                                        calculated_position: Some(LayoutPosition::Default),
5886                                        ..container.children[0].children[1].children[1].clone()
5887                                    },
5888                                ],
5889                                ..container.children[0].children[1].clone()
5890                            },
5891                        ],
5892                        calculated_width: Some(100.0),
5893                        calculated_height: Some(0.0),
5894                        calculated_x: Some(0.0),
5895                        calculated_y: Some(0.0),
5896                        calculated_position: Some(LayoutPosition::Default),
5897                        direction: LayoutDirection::Row,
5898                        ..container.children[0].clone()
5899                    },
5900                    Container {
5901                        calculated_width: Some(100.0),
5902                        calculated_height: Some(0.0),
5903                        calculated_x: Some(0.0),
5904                        calculated_y: Some(0.0),
5905                        calculated_position: Some(LayoutPosition::Default),
5906                        ..container.children[1].clone()
5907                    },
5908                ],
5909                ..container.clone()
5910            },
5911        );
5912    }
5913
5914    #[test_log::test]
5915    fn calc_can_calc_horizontal_split_with_row_content_in_right_pane_above_a_vertial_split_with_a_specified_height()
5916     {
5917        let mut container = Container {
5918            children: vec![
5919                Container {
5920                    children: vec![
5921                        Container::default(),
5922                        Container {
5923                            children: vec![Container::default(), Container::default()],
5924                            direction: LayoutDirection::Row,
5925                            justify_content: Some(JustifyContent::Start),
5926                            ..Default::default()
5927                        },
5928                    ],
5929                    direction: LayoutDirection::Row,
5930                    justify_content: Some(JustifyContent::Start),
5931                    ..Default::default()
5932                },
5933                Container {
5934                    height: Some(Number::Integer(10)),
5935                    ..Default::default()
5936                },
5937            ],
5938            calculated_width: Some(100.0),
5939            calculated_height: Some(80.0),
5940            justify_content: Some(JustifyContent::Start),
5941            ..Default::default()
5942        };
5943        CALCULATOR.calc(&mut container);
5944        log::trace!("container:\n{container}");
5945
5946        compare_containers(
5947            &container.clone(),
5948            &Container {
5949                children: vec![
5950                    Container {
5951                        children: vec![
5952                            Container {
5953                                calculated_width: Some(0.0),
5954                                calculated_height: Some(0.0),
5955                                calculated_x: Some(0.0),
5956                                calculated_y: Some(0.0),
5957                                calculated_position: Some(LayoutPosition::Default),
5958                                ..container.children[0].children[0].clone()
5959                            },
5960                            Container {
5961                                calculated_width: Some(0.0),
5962                                calculated_height: Some(0.0),
5963                                calculated_x: Some(0.0),
5964                                calculated_y: Some(0.0),
5965                                calculated_position: Some(LayoutPosition::Default),
5966                                direction: LayoutDirection::Row,
5967                                children: vec![
5968                                    Container {
5969                                        calculated_width: Some(0.0),
5970                                        calculated_height: Some(0.0),
5971                                        calculated_x: Some(0.0),
5972                                        calculated_y: Some(0.0),
5973                                        calculated_position: Some(LayoutPosition::Default),
5974                                        ..container.children[0].children[1].children[0].clone()
5975                                    },
5976                                    Container {
5977                                        calculated_width: Some(0.0),
5978                                        calculated_height: Some(0.0),
5979                                        calculated_x: Some(0.0),
5980                                        calculated_y: Some(0.0),
5981                                        calculated_position: Some(LayoutPosition::Default),
5982                                        ..container.children[0].children[1].children[1].clone()
5983                                    },
5984                                ],
5985                                ..container.children[0].children[1].clone()
5986                            },
5987                        ],
5988                        calculated_width: Some(100.0),
5989                        calculated_height: Some(0.0),
5990                        calculated_x: Some(0.0),
5991                        calculated_y: Some(0.0),
5992                        calculated_position: Some(LayoutPosition::Default),
5993                        direction: LayoutDirection::Row,
5994                        ..container.children[0].clone()
5995                    },
5996                    Container {
5997                        height: Some(Number::Integer(10)),
5998                        calculated_width: Some(100.0),
5999                        calculated_height: Some(10.0),
6000                        calculated_x: Some(0.0),
6001                        calculated_y: Some(0.0),
6002                        calculated_position: Some(LayoutPosition::Default),
6003                        ..container.children[1].clone()
6004                    },
6005                ],
6006                ..container
6007            },
6008        );
6009    }
6010
6011    #[test_log::test]
6012    fn calc_can_calc_absolute_positioned_element_on_top_of_a_relative_element() {
6013        let mut container = Container {
6014            children: vec![
6015                Container::default(),
6016                Container {
6017                    position: Some(Position::Absolute),
6018                    ..Default::default()
6019                },
6020            ],
6021            calculated_width: Some(100.0),
6022            calculated_height: Some(50.0),
6023            position: Some(Position::Relative),
6024            justify_content: Some(JustifyContent::Start),
6025            ..Default::default()
6026        };
6027        CALCULATOR.calc(&mut container);
6028        log::trace!("container:\n{container}");
6029
6030        compare_containers(
6031            &container,
6032            &Container {
6033                children: vec![
6034                    Container {
6035                        calculated_width: Some(100.0),
6036                        calculated_x: Some(0.0),
6037                        calculated_position: Some(LayoutPosition::Default),
6038                        ..container.children[0].clone()
6039                    },
6040                    Container {
6041                        calculated_width: Some(100.0),
6042                        calculated_height: Some(50.0),
6043                        calculated_x: Some(0.0),
6044                        calculated_y: Some(0.0),
6045                        position: Some(Position::Absolute),
6046                        ..container.children[1].clone()
6047                    },
6048                ],
6049                ..container.clone()
6050            },
6051        );
6052    }
6053
6054    #[test_log::test]
6055    fn calc_can_calc_absolute_positioned_element_nested_on_top_of_a_relative_element_with_left_offset()
6056     {
6057        let mut container = Container {
6058            children: vec![Container {
6059                children: vec![
6060                    Container::default(),
6061                    Container {
6062                        left: Some(Number::Integer(30)),
6063                        position: Some(Position::Absolute),
6064                        ..Default::default()
6065                    },
6066                ],
6067                justify_content: Some(JustifyContent::Start),
6068                ..Default::default()
6069            }],
6070            calculated_width: Some(100.0),
6071            calculated_height: Some(50.0),
6072            position: Some(Position::Relative),
6073            justify_content: Some(JustifyContent::Start),
6074            ..Default::default()
6075        };
6076        CALCULATOR.calc(&mut container);
6077        log::trace!("container:\n{container}");
6078
6079        compare_containers(
6080            &container.clone(),
6081            &Container {
6082                children: vec![Container {
6083                    children: vec![
6084                        Container {
6085                            calculated_width: Some(100.0),
6086                            calculated_height: Some(0.0),
6087                            calculated_x: Some(0.0),
6088                            calculated_y: Some(0.0),
6089                            calculated_position: Some(LayoutPosition::Default),
6090                            ..container.children[0].children[0].clone()
6091                        },
6092                        Container {
6093                            calculated_width: Some(100.0),
6094                            calculated_height: Some(50.0),
6095                            calculated_x: Some(30.0),
6096                            calculated_y: Some(0.0),
6097                            position: Some(Position::Absolute),
6098                            ..container.children[0].children[1].clone()
6099                        },
6100                    ],
6101                    ..container.children[0].clone()
6102                }],
6103                ..container
6104            },
6105        );
6106    }
6107
6108    #[test_log::test]
6109    fn calc_can_calc_absolute_positioned_element_on_top_of_a_relative_element_with_left_offset() {
6110        let mut container = Container {
6111            children: vec![
6112                Container::default(),
6113                Container {
6114                    left: Some(Number::Integer(30)),
6115                    position: Some(Position::Absolute),
6116                    ..Default::default()
6117                },
6118            ],
6119            calculated_width: Some(100.0),
6120            calculated_height: Some(50.0),
6121            position: Some(Position::Relative),
6122            justify_content: Some(JustifyContent::Start),
6123            ..Default::default()
6124        };
6125        CALCULATOR.calc(&mut container);
6126        log::trace!("container:\n{container}");
6127
6128        compare_containers(
6129            &container.clone(),
6130            &Container {
6131                children: vec![
6132                    Container {
6133                        calculated_width: Some(100.0),
6134                        calculated_x: Some(0.0),
6135                        calculated_position: Some(LayoutPosition::Default),
6136                        ..container.children[0].clone()
6137                    },
6138                    Container {
6139                        calculated_width: Some(100.0),
6140                        calculated_height: Some(50.0),
6141                        calculated_x: Some(30.0),
6142                        calculated_y: Some(0.0),
6143                        position: Some(Position::Absolute),
6144                        ..container.children[1].clone()
6145                    },
6146                ],
6147                ..container
6148            },
6149        );
6150    }
6151
6152    #[test_log::test]
6153    fn calc_can_calc_absolute_positioned_element_with_explicit_sizes() {
6154        let mut container = Container {
6155            children: vec![
6156                Container::default(),
6157                Container {
6158                    width: Some(Number::Integer(30)),
6159                    height: Some(Number::Integer(20)),
6160                    left: Some(Number::Integer(30)),
6161                    position: Some(Position::Absolute),
6162                    ..Default::default()
6163                },
6164            ],
6165            calculated_width: Some(100.0),
6166            calculated_height: Some(50.0),
6167            position: Some(Position::Relative),
6168            justify_content: Some(JustifyContent::Start),
6169            ..Default::default()
6170        };
6171        CALCULATOR.calc(&mut container);
6172        log::trace!("container:\n{container}");
6173
6174        compare_containers(
6175            &container.clone(),
6176            &Container {
6177                children: vec![
6178                    Container {
6179                        calculated_width: Some(100.0),
6180                        calculated_x: Some(0.0),
6181                        calculated_position: Some(LayoutPosition::Default),
6182                        ..container.children[0].clone()
6183                    },
6184                    Container {
6185                        calculated_width: Some(30.0),
6186                        calculated_height: Some(20.0),
6187                        calculated_x: Some(30.0),
6188                        calculated_y: Some(0.0),
6189                        position: Some(Position::Absolute),
6190                        ..container.children[1].clone()
6191                    },
6192                ],
6193                ..container
6194            },
6195        );
6196    }
6197
6198    #[test_log::test]
6199    fn calc_can_calc_justify_content_center_horizontally() {
6200        let mut container = Container {
6201            children: vec![Container {
6202                width: Some(Number::Integer(30)),
6203                ..Default::default()
6204            }],
6205
6206            calculated_width: Some(100.0),
6207            calculated_height: Some(50.0),
6208            direction: LayoutDirection::Row,
6209            justify_content: Some(JustifyContent::Center),
6210            ..Default::default()
6211        };
6212        CALCULATOR.calc(&mut container);
6213        log::trace!("container:\n{container}");
6214
6215        compare_containers(
6216            &container,
6217            &Container {
6218                children: vec![Container {
6219                    calculated_x: Some((100.0 - 30.0) / 2.0),
6220                    ..container.children[0].clone()
6221                }],
6222                ..container.clone()
6223            },
6224        );
6225    }
6226
6227    #[test_log::test]
6228    fn calc_can_calc_justify_content_start() {
6229        let mut container = Container {
6230            children: vec![
6231                Container {
6232                    width: Some(Number::Integer(30)),
6233                    ..Default::default()
6234                },
6235                Container {
6236                    width: Some(Number::Integer(30)),
6237                    ..Default::default()
6238                },
6239            ],
6240            calculated_width: Some(100.0),
6241            calculated_height: Some(50.0),
6242            direction: LayoutDirection::Row,
6243            justify_content: Some(JustifyContent::Start),
6244            ..Default::default()
6245        };
6246        CALCULATOR.calc(&mut container);
6247        log::trace!("container:\n{container}");
6248
6249        compare_containers(
6250            &container.clone(),
6251            &Container {
6252                children: vec![
6253                    Container {
6254                        calculated_x: Some(0.0),
6255                        ..container.children[0].clone()
6256                    },
6257                    Container {
6258                        calculated_x: Some(30.0),
6259                        ..container.children[1].clone()
6260                    },
6261                ],
6262                ..container
6263            },
6264        );
6265    }
6266
6267    #[test_log::test]
6268    fn calc_includes_horizontal_margins_in_content_width() {
6269        let mut container = Container {
6270            children: vec![
6271                Container {
6272                    width: Some(Number::Integer(30)),
6273                    margin_left: Some(Number::Integer(35)),
6274                    ..Default::default()
6275                },
6276                Container {
6277                    width: Some(Number::Integer(20)),
6278                    ..Default::default()
6279                },
6280            ],
6281            calculated_width: Some(100.0),
6282            calculated_height: Some(50.0),
6283            direction: LayoutDirection::Row,
6284            ..Default::default()
6285        };
6286        CALCULATOR.calc(&mut container);
6287        log::trace!("container:\n{container}");
6288
6289        compare_containers(
6290            &container.clone(),
6291            &Container {
6292                children: vec![
6293                    Container {
6294                        calculated_width: Some(30.0),
6295                        calculated_margin_left: Some(35.0),
6296                        calculated_x: Some(0.0),
6297                        ..container.children[0].clone()
6298                    },
6299                    Container {
6300                        calculated_width: Some(20.0),
6301                        calculated_x: Some(65.0),
6302                        ..container.children[1].clone()
6303                    },
6304                ],
6305                ..container
6306            },
6307        );
6308    }
6309
6310    #[test_log::test]
6311    fn calc_includes_horizontal_padding_in_content_width() {
6312        let mut container = Container {
6313            children: vec![
6314                Container {
6315                    width: Some(Number::Integer(30)),
6316                    padding_right: Some(Number::Integer(35)),
6317                    ..Default::default()
6318                },
6319                Container {
6320                    width: Some(Number::Integer(20)),
6321                    ..Default::default()
6322                },
6323            ],
6324            calculated_width: Some(100.0),
6325            calculated_height: Some(50.0),
6326            direction: LayoutDirection::Row,
6327            ..Default::default()
6328        };
6329        CALCULATOR.calc(&mut container);
6330        log::trace!("container:\n{container}");
6331
6332        compare_containers(
6333            &container.clone(),
6334            &Container {
6335                children: vec![
6336                    Container {
6337                        calculated_width: Some(30.0),
6338                        calculated_padding_right: Some(35.0),
6339                        calculated_x: Some(0.0),
6340                        ..container.children[0].clone()
6341                    },
6342                    Container {
6343                        calculated_width: Some(20.0),
6344                        calculated_x: Some(65.0),
6345                        ..container.children[1].clone()
6346                    },
6347                ],
6348                ..container
6349            },
6350        );
6351    }
6352
6353    #[test_log::test]
6354    fn calc_includes_horizontal_padding_in_auto_calculated_content_width() {
6355        let mut container = Container {
6356            children: vec![
6357                Container::default(),
6358                Container {
6359                    padding_right: Some(Number::Integer(30)),
6360                    ..Default::default()
6361                },
6362            ],
6363            calculated_width: Some(100.0),
6364            calculated_height: Some(50.0),
6365            direction: LayoutDirection::Row,
6366            overflow_x: LayoutOverflow::Wrap { grid: true },
6367            ..Default::default()
6368        };
6369        CALCULATOR.calc(&mut container);
6370        log::trace!("container:\n{container}");
6371
6372        compare_containers(
6373            &container.clone(),
6374            &Container {
6375                children: vec![
6376                    Container {
6377                        calculated_width: Some(0.0),
6378                        calculated_x: Some(0.0),
6379                        ..container.children[0].clone()
6380                    },
6381                    Container {
6382                        calculated_width: Some(0.0),
6383                        calculated_padding_right: Some(30.0),
6384                        calculated_x: Some(0.0),
6385                        ..container.children[1].clone()
6386                    },
6387                ],
6388                ..container
6389            },
6390        );
6391    }
6392
6393    #[test_log::test]
6394    fn calc_includes_horizontal_margin_in_auto_calculated_content_width() {
6395        let mut container = Container {
6396            children: vec![
6397                Container::default(),
6398                Container {
6399                    margin_right: Some(Number::Integer(30)),
6400                    ..Default::default()
6401                },
6402            ],
6403            calculated_width: Some(100.0),
6404            calculated_height: Some(50.0),
6405            direction: LayoutDirection::Row,
6406            overflow_x: LayoutOverflow::Wrap { grid: true },
6407            ..Default::default()
6408        };
6409        CALCULATOR.calc(&mut container);
6410        log::trace!("container:\n{container}");
6411
6412        compare_containers(
6413            &container.clone(),
6414            &Container {
6415                children: vec![
6416                    Container {
6417                        calculated_width: Some(0.0),
6418                        calculated_x: Some(0.0),
6419                        ..container.children[0].clone()
6420                    },
6421                    Container {
6422                        calculated_width: Some(0.0),
6423                        calculated_margin_right: Some(30.0),
6424                        calculated_x: Some(0.0),
6425                        ..container.children[1].clone()
6426                    },
6427                ],
6428                ..container
6429            },
6430        );
6431    }
6432
6433    #[test_log::test]
6434    fn calc_calculates_sized_widths_based_on_the_container_width_minus_all_its_childrens_padding() {
6435        let mut container = Container {
6436            children: vec![
6437                Container {
6438                    width: Some(Number::IntegerPercent(50)),
6439                    padding_right: Some(Number::Integer(20)),
6440                    ..Default::default()
6441                },
6442                Container {
6443                    width: Some(Number::IntegerPercent(50)),
6444                    ..Default::default()
6445                },
6446            ],
6447            calculated_width: Some(100.0),
6448            calculated_height: Some(50.0),
6449            direction: LayoutDirection::Row,
6450            overflow_x: LayoutOverflow::Wrap { grid: true },
6451            ..Default::default()
6452        };
6453        CALCULATOR.calc(&mut container);
6454        log::trace!("container:\n{container}");
6455
6456        compare_containers(
6457            &container.clone(),
6458            &Container {
6459                children: vec![
6460                    Container {
6461                        calculated_width: Some(40.0),
6462                        calculated_padding_right: Some(20.0),
6463                        calculated_x: Some(0.0),
6464                        ..container.children[0].clone()
6465                    },
6466                    Container {
6467                        calculated_width: Some(40.0),
6468                        calculated_x: Some(60.0),
6469                        ..container.children[1].clone()
6470                    },
6471                ],
6472                ..container
6473            },
6474        );
6475    }
6476
6477    #[test_log::test]
6478    fn calc_calculates_unsized_widths_based_on_the_container_width_minus_all_its_childrens_padding()
6479    {
6480        let mut container = Container {
6481            children: vec![
6482                Container {
6483                    width: Some(Number::IntegerPercent(50)),
6484                    padding_right: Some(Number::Integer(20)),
6485                    ..Default::default()
6486                },
6487                Container::default(),
6488            ],
6489            calculated_width: Some(100.0),
6490            calculated_height: Some(50.0),
6491            direction: LayoutDirection::Row,
6492            overflow_x: LayoutOverflow::Wrap { grid: true },
6493            ..Default::default()
6494        };
6495        CALCULATOR.calc(&mut container);
6496        log::trace!("container:\n{container}");
6497
6498        compare_containers(
6499            &container.clone(),
6500            &Container {
6501                children: vec![
6502                    Container {
6503                        calculated_width: Some(40.0),
6504                        calculated_padding_right: Some(20.0),
6505                        calculated_x: Some(0.0),
6506                        ..container.children[0].clone()
6507                    },
6508                    Container {
6509                        calculated_width: Some(0.0),
6510                        calculated_x: Some(60.0),
6511                        ..container.children[1].clone()
6512                    },
6513                ],
6514                ..container
6515            },
6516        );
6517    }
6518
6519    #[test_log::test]
6520    fn calc_calculates_unsized_widths_based_on_the_container_width_minus_second_childs_padding() {
6521        let mut container = Container {
6522            children: vec![
6523                Container {
6524                    width: Some(Number::IntegerPercent(50)),
6525                    ..Default::default()
6526                },
6527                Container {
6528                    padding_right: Some(Number::Integer(20)),
6529                    ..Default::default()
6530                },
6531            ],
6532            calculated_width: Some(100.0),
6533            calculated_height: Some(50.0),
6534            direction: LayoutDirection::Row,
6535            overflow_x: LayoutOverflow::Wrap { grid: true },
6536            ..Default::default()
6537        };
6538        CALCULATOR.calc(&mut container);
6539        log::trace!("container:\n{container}");
6540
6541        compare_containers(
6542            &container.clone(),
6543            &Container {
6544                children: vec![
6545                    Container {
6546                        calculated_width: Some(40.0),
6547                        calculated_x: Some(0.0),
6548                        ..container.children[0].clone()
6549                    },
6550                    Container {
6551                        calculated_width: Some(0.0),
6552                        calculated_padding_right: Some(20.0),
6553                        calculated_x: Some(40.0),
6554                        ..container.children[1].clone()
6555                    },
6556                ],
6557                ..container
6558            },
6559        );
6560    }
6561
6562    #[test_log::test]
6563    fn calc_horizontal_padding_on_vertical_sibling_doesnt_affect_size_of_other_sibling() {
6564        let mut container = Container {
6565            children: vec![
6566                Container::default(),
6567                Container {
6568                    padding_right: Some(Number::Integer(20)),
6569                    ..Default::default()
6570                },
6571            ],
6572            calculated_width: Some(100.0),
6573            calculated_height: Some(50.0),
6574            ..Default::default()
6575        };
6576        CALCULATOR.calc(&mut container);
6577        log::trace!("container:\n{container}");
6578
6579        compare_containers(
6580            &container.clone(),
6581            &Container {
6582                children: vec![
6583                    Container {
6584                        calculated_width: Some(100.0),
6585                        calculated_x: Some(0.0),
6586                        ..container.children[0].clone()
6587                    },
6588                    Container {
6589                        calculated_width: Some(80.0),
6590                        calculated_padding_right: Some(20.0),
6591                        calculated_x: Some(0.0),
6592                        ..container.children[1].clone()
6593                    },
6594                ],
6595                ..container
6596            },
6597        );
6598    }
6599
6600    #[test_log::test]
6601    fn calc_child_padding_does_not_add_to_parent_container() {
6602        let mut container = Container {
6603            children: vec![
6604                Container {
6605                    padding_right: Some(Number::Integer(20)),
6606                    ..Default::default()
6607                },
6608                Container::default(),
6609                Container::default(),
6610            ],
6611            calculated_width: Some(110.0),
6612            calculated_height: Some(50.0),
6613            direction: LayoutDirection::Row,
6614            overflow_x: LayoutOverflow::Wrap { grid: true },
6615            ..Default::default()
6616        };
6617        CALCULATOR.calc(&mut container);
6618        log::trace!("container:\n{container}");
6619
6620        compare_containers(
6621            &container.clone(),
6622            &Container {
6623                children: vec![
6624                    Container {
6625                        calculated_width: Some(0.0),
6626                        calculated_padding_right: Some(20.0),
6627                        calculated_x: Some(0.0),
6628                        ..container.children[0].clone()
6629                    },
6630                    Container {
6631                        calculated_width: Some(0.0),
6632                        calculated_x: Some(20.0),
6633                        ..container.children[1].clone()
6634                    },
6635                    Container {
6636                        calculated_width: Some(0.0),
6637                        calculated_x: Some(20.0),
6638                        ..container.children[2].clone()
6639                    },
6640                ],
6641                ..container
6642            },
6643        );
6644    }
6645
6646    #[test_log::test]
6647    fn calc_nested_child_padding_does_not_offset_unsized_container_siblings() {
6648        let mut container = Container {
6649            children: vec![
6650                Container {
6651                    children: vec![Container {
6652                        padding_right: Some(Number::Integer(20)),
6653                        ..Default::default()
6654                    }],
6655                    ..Default::default()
6656                },
6657                Container::default(),
6658                Container::default(),
6659            ],
6660            calculated_width: Some(90.0),
6661            calculated_height: Some(50.0),
6662            direction: LayoutDirection::Row,
6663            ..Default::default()
6664        };
6665        CALCULATOR.calc(&mut container);
6666        log::trace!("container:\n{container}");
6667
6668        compare_containers(
6669            &container.clone(),
6670            &Container {
6671                children: vec![
6672                    Container {
6673                        children: vec![Container {
6674                            calculated_width: Some(20.0),
6675                            calculated_padding_right: Some(20.0),
6676                            calculated_x: Some(0.0),
6677                            ..container.children[0].children[0].clone()
6678                        }],
6679                        calculated_width: Some(20.0),
6680                        calculated_x: Some(0.0),
6681                        ..container.children[0].clone()
6682                    },
6683                    Container {
6684                        calculated_width: Some(0.0),
6685                        calculated_x: Some(20.0),
6686                        ..container.children[1].clone()
6687                    },
6688                    Container {
6689                        calculated_width: Some(0.0),
6690                        calculated_x: Some(20.0),
6691                        ..container.children[2].clone()
6692                    },
6693                ],
6694                ..container
6695            },
6696        );
6697    }
6698
6699    #[test_log::test]
6700    fn calc_horizontal_sibling_left_raw_still_divides_the_unsized_width() {
6701        let metrics = DefaultFontMetrics;
6702        let text_width = metrics.measure_text("test", 14.0, f32::INFINITY).width();
6703
6704        let mut container = Container {
6705            children: vec![
6706                Container {
6707                    element: Element::Raw {
6708                        value: "test".to_string(),
6709                    },
6710                    ..Container::default()
6711                },
6712                Container::default(),
6713            ],
6714            calculated_width: Some(100.0),
6715            calculated_height: Some(50.0),
6716            direction: LayoutDirection::Row,
6717            ..Default::default()
6718        };
6719        CALCULATOR.calc(&mut container);
6720        log::trace!("container:\n{container}");
6721
6722        compare_containers(
6723            &container,
6724            &Container {
6725                children: vec![
6726                    container.children[0].clone(),
6727                    Container {
6728                        calculated_width: Some(0.0),
6729                        calculated_x: Some(text_width),
6730                        ..container.children[1].clone()
6731                    },
6732                ],
6733                calculated_width: Some(100.0),
6734                ..container.clone()
6735            },
6736        );
6737    }
6738
6739    #[test_log::test]
6740    fn calc_calculates_width_minus_the_horizontal_padding() {
6741        let mut container = Container {
6742            children: vec![Container {
6743                padding_left: Some(Number::Integer(10)),
6744                padding_right: Some(Number::Integer(20)),
6745                ..Default::default()
6746            }],
6747            calculated_width: Some(100.0),
6748            calculated_height: Some(50.0),
6749            ..Default::default()
6750        };
6751        CALCULATOR.calc(&mut container);
6752        log::trace!("container:\n{container}");
6753
6754        compare_containers(
6755            &container.clone(),
6756            &Container {
6757                children: vec![Container {
6758                    calculated_width: Some(70.0),
6759                    calculated_x: Some(0.0),
6760                    ..container.children[0].clone()
6761                }],
6762                ..container
6763            },
6764        );
6765    }
6766
6767    #[test_log::test]
6768    fn calc_calculates_height_minus_the_vertical_padding() {
6769        let mut container = Container {
6770            children: vec![Container {
6771                padding_top: Some(Number::Integer(10)),
6772                padding_bottom: Some(Number::Integer(20)),
6773                ..Default::default()
6774            }],
6775            calculated_width: Some(100.0),
6776            calculated_height: Some(50.0),
6777            justify_content: Some(JustifyContent::Start),
6778            ..Default::default()
6779        };
6780
6781        CALCULATOR.calc(&mut container);
6782        log::trace!("container:\n{container}");
6783
6784        compare_containers(
6785            &container.clone(),
6786            &Container {
6787                children: vec![Container {
6788                    calculated_height: Some(0.0),
6789                    calculated_y: Some(0.0),
6790                    ..container.children[0].clone()
6791                }],
6792                ..container
6793            },
6794        );
6795    }
6796
6797    #[test_log::test]
6798    fn calc_calculates_width_minus_the_horizontal_padding_with_percentage_width() {
6799        let mut container = Container {
6800            children: vec![Container {
6801                width: Some(Number::IntegerPercent(50)),
6802                padding_left: Some(Number::Integer(10)),
6803                padding_right: Some(Number::Integer(20)),
6804                padding_top: Some(Number::Integer(15)),
6805                ..Default::default()
6806            }],
6807            calculated_width: Some(100.0),
6808            calculated_height: Some(50.0),
6809            height: Some(Number::Integer(50)),
6810            justify_content: Some(JustifyContent::Start),
6811            ..Default::default()
6812        };
6813        CALCULATOR.calc(&mut container);
6814        log::trace!("container:\n{container}");
6815
6816        compare_containers(
6817            &container.clone(),
6818            &Container {
6819                children: vec![Container {
6820                    calculated_width: Some(35.0),
6821                    calculated_x: Some(0.0),
6822                    ..container.children[0].clone()
6823                }],
6824                ..container
6825            },
6826        );
6827    }
6828
6829    #[test_log::test]
6830    fn calc_calculates_width_minus_the_horizontal_padding_with_percentage_width_nested() {
6831        let mut container = Container {
6832            children: vec![Container {
6833                children: vec![Container {
6834                    width: Some(Number::IntegerPercent(50)),
6835                    padding_left: Some(Number::Integer(2)),
6836                    padding_right: Some(Number::Integer(3)),
6837                    padding_top: Some(Number::Integer(1)),
6838                    ..Default::default()
6839                }],
6840                width: Some(Number::IntegerPercent(100)),
6841                padding_left: Some(Number::Integer(10)),
6842                padding_right: Some(Number::Integer(20)),
6843                padding_top: Some(Number::Integer(15)),
6844                justify_content: Some(JustifyContent::Start),
6845                ..Default::default()
6846            }],
6847            calculated_width: Some(100.0),
6848            calculated_height: Some(50.0),
6849            height: Some(Number::Integer(50)),
6850            justify_content: Some(JustifyContent::Start),
6851            ..Default::default()
6852        };
6853        CALCULATOR.calc(&mut container);
6854        log::trace!("container:\n{container}");
6855
6856        compare_containers(
6857            &container.clone(),
6858            &Container {
6859                children: vec![Container {
6860                    children: vec![Container {
6861                        calculated_width: Some(32.5),
6862                        calculated_x: Some(0.0),
6863                        calculated_padding_left: Some(2.0),
6864                        calculated_padding_right: Some(3.0),
6865                        calculated_padding_top: Some(1.0),
6866                        ..container.children[0].children[0].clone()
6867                    }],
6868                    calculated_width: Some(70.0),
6869                    calculated_x: Some(0.0),
6870                    calculated_padding_left: Some(10.0),
6871                    calculated_padding_right: Some(20.0),
6872                    calculated_padding_top: Some(15.0),
6873                    ..container.children[0].clone()
6874                }],
6875                ..container
6876            },
6877        );
6878    }
6879
6880    #[test_log::test]
6881    fn calc_calculates_width_minus_the_horizontal_padding_with_calc_width_nested() {
6882        let mut container = Container {
6883            children: vec![Container {
6884                children: vec![Container {
6885                    width: Some(Number::IntegerPercent(50)),
6886                    padding_left: Some(Number::Integer(2)),
6887                    padding_right: Some(Number::Integer(3)),
6888                    padding_top: Some(Number::Integer(1)),
6889                    ..Default::default()
6890                }],
6891                width: Some(Number::Calc(Calculation::Number(Box::new(
6892                    Number::IntegerPercent(100),
6893                )))),
6894                padding_left: Some(Number::Integer(10)),
6895                padding_right: Some(Number::Integer(20)),
6896                padding_top: Some(Number::Integer(15)),
6897                justify_content: Some(JustifyContent::Start),
6898                ..Default::default()
6899            }],
6900            calculated_width: Some(100.0),
6901            calculated_height: Some(50.0),
6902            height: Some(Number::Integer(50)),
6903            justify_content: Some(JustifyContent::Start),
6904            ..Default::default()
6905        };
6906        CALCULATOR.calc(&mut container);
6907        log::trace!("container:\n{container}");
6908
6909        compare_containers(
6910            &container.clone(),
6911            &Container {
6912                children: vec![Container {
6913                    children: vec![Container {
6914                        calculated_width: Some(32.5),
6915                        calculated_x: Some(0.0),
6916                        calculated_padding_left: Some(2.0),
6917                        calculated_padding_right: Some(3.0),
6918                        calculated_padding_top: Some(1.0),
6919                        ..container.children[0].children[0].clone()
6920                    }],
6921                    calculated_width: Some(70.0),
6922                    calculated_x: Some(0.0),
6923                    calculated_padding_left: Some(10.0),
6924                    calculated_padding_right: Some(20.0),
6925                    calculated_padding_top: Some(15.0),
6926                    ..container.children[0].clone()
6927                }],
6928                ..container
6929            },
6930        );
6931    }
6932
6933    #[test_log::test]
6934    fn calc_calculates_width_minus_the_horizontal_padding_for_absolute_position_children() {
6935        let mut container = Container {
6936            children: vec![Container {
6937                width: Some(Number::Calc(Calculation::Number(Box::new(
6938                    Number::IntegerPercent(100),
6939                )))),
6940                padding_left: Some(Number::Integer(10)),
6941                padding_right: Some(Number::Integer(20)),
6942                padding_top: Some(Number::Integer(15)),
6943                position: Some(Position::Absolute),
6944                ..Default::default()
6945            }],
6946            calculated_width: Some(100.0),
6947            calculated_height: Some(50.0),
6948            position: Some(Position::Relative),
6949            justify_content: Some(JustifyContent::Start),
6950            ..Default::default()
6951        };
6952        CALCULATOR.calc(&mut container);
6953        log::trace!("container:\n{container}");
6954
6955        compare_containers(
6956            &container.clone(),
6957            &Container {
6958                children: vec![Container {
6959                    calculated_width: Some(70.0),
6960                    calculated_height: Some(35.0),
6961                    calculated_x: Some(0.0),
6962                    calculated_y: Some(0.0),
6963                    calculated_padding_left: Some(10.0),
6964                    calculated_padding_right: Some(20.0),
6965                    calculated_padding_top: Some(15.0),
6966                    ..container.children[0].clone()
6967                }],
6968                ..container
6969            },
6970        );
6971    }
6972
6973    #[test_log::test]
6974    fn calc_uses_bounding_width_for_absolute_position_children_with_right_offset() {
6975        let mut container = Container {
6976            children: vec![Container {
6977                width: Some(Number::Calc(Calculation::Number(Box::new(
6978                    Number::IntegerPercent(50),
6979                )))),
6980                padding_left: Some(Number::Integer(10)),
6981                padding_right: Some(Number::Integer(20)),
6982                right: Some(Number::Integer(5)),
6983                position: Some(Position::Absolute),
6984                ..Default::default()
6985            }],
6986
6987            calculated_width: Some(100.0),
6988            calculated_height: Some(50.0),
6989            position: Some(Position::Relative),
6990            ..Default::default()
6991        };
6992        CALCULATOR.calc(&mut container);
6993        log::trace!("container:\n{container}");
6994
6995        compare_containers(
6996            &container.clone(),
6997            &Container {
6998                children: vec![Container {
6999                    calculated_width: Some(35.0),
7000                    calculated_height: Some(50.0),
7001                    calculated_x: Some(100.0 - 35.0 - 10.0 - 20.0 - 5.0),
7002                    calculated_y: Some(0.0),
7003                    calculated_padding_left: Some(10.0),
7004                    calculated_padding_right: Some(20.0),
7005                    ..container.children[0].clone()
7006                }],
7007                ..container
7008            },
7009        );
7010    }
7011
7012    #[test_log::test]
7013    fn calc_calculates_flex_height_for_single_unsized_child_with_sized_child() {
7014        let mut container: Container = html! {
7015            div {
7016                div sx-dir="row" {
7017                    div sx-width=(50) sx-height=(36) { "Albums" }
7018                }
7019            }
7020        }
7021        .try_into()
7022        .unwrap();
7023
7024        container.calculated_width = Some(160.0);
7025        container.calculated_height = Some(100.0);
7026
7027        CALCULATOR.calc(&mut container);
7028        log::trace!("container:\n{container}");
7029
7030        compare_containers(
7031            &container,
7032            &Container {
7033                children: vec![Container {
7034                    children: vec![Container {
7035                        children: vec![Container {
7036                            calculated_width: Some(50.0),
7037                            calculated_height: Some(36.0),
7038                            ..container.children[0].children[0].children[0].clone()
7039                        }],
7040                        ..container.children[0].children[0].clone()
7041                    }],
7042                    ..container.children[0].clone()
7043                }],
7044                ..container.clone()
7045            },
7046        );
7047    }
7048
7049    #[test_log::test]
7050    fn calc_calculates_flex_height_for_two_unsized_children_with_sized_child() {
7051        let mut container: Container = html! {
7052            div {
7053                div sx-dir="row" {
7054                    div sx-width=(50) sx-height=(36) { "Albums" }
7055                }
7056                div sx-dir="row" {
7057                    div sx-width=(50) sx-height=(36) { "Albums2" }
7058                }
7059            }
7060        }
7061        .try_into()
7062        .unwrap();
7063
7064        container.calculated_width = Some(160.0);
7065        container.calculated_height = Some(100.0);
7066
7067        CALCULATOR.calc(&mut container);
7068        log::trace!("container:\n{container}");
7069
7070        compare_containers(
7071            &container,
7072            &Container {
7073                children: vec![Container {
7074                    children: vec![
7075                        Container {
7076                            children: vec![Container {
7077                                calculated_width: Some(50.0),
7078                                calculated_height: Some(36.0),
7079                                ..container.children[0].children[0].children[0].clone()
7080                            }],
7081                            ..container.children[0].children[0].clone()
7082                        },
7083                        Container {
7084                            children: vec![Container {
7085                                calculated_width: Some(50.0),
7086                                calculated_height: Some(36.0),
7087                                ..container.children[0].children[1].children[0].clone()
7088                            }],
7089                            ..container.children[0].children[1].clone()
7090                        },
7091                    ],
7092                    ..container.children[0].clone()
7093                }],
7094                ..container.clone()
7095            },
7096        );
7097    }
7098
7099    #[test_log::test]
7100    fn calc_calculates_width_minus_the_horizontal_padding_for_nested_children_with_calc_parent_sizes()
7101     {
7102        let mut container: Container = html! {
7103            div sx-width="100%" sx-height="100%" sx-position="relative" {
7104                section sx-dir="row" sx-height=("calc(100% - 140px)") {
7105                    aside sx-width="calc(max(240, min(280, 15%)))" {}
7106                    main sx-overflow-y="auto" sx-flex=(1) {
7107                        div sx-height=(76) sx-justify-content=(JustifyContent::Start) {
7108                            div
7109                                sx-padding-left=(30)
7110                                sx-padding-right=(30)
7111                                sx-padding-top=(15)
7112                            {
7113                                div sx-dir="row" {
7114                                    h1 sx-width=(50) sx-height=(36) { "Albums" }
7115                                }
7116                            }
7117                        }
7118                    }
7119                }
7120            }
7121        }
7122        .try_into()
7123        .unwrap();
7124
7125        container.calculated_width = Some(1600.0);
7126        container.calculated_height = Some(1000.0);
7127        container.justify_content = Some(JustifyContent::Start);
7128
7129        CALCULATOR.calc(&mut container);
7130        log::trace!("container:\n{container}");
7131
7132        let container = container.children[0].children[0].children[1].clone();
7133
7134        compare_containers(
7135            &container.clone(),
7136            &Container {
7137                children: vec![Container {
7138                    children: vec![Container {
7139                        children: vec![Container {
7140                            children: vec![Container {
7141                                element: Element::Heading {
7142                                    size: HeaderSize::H1,
7143                                },
7144                                calculated_width: Some(50.0),
7145                                calculated_height: Some(36.0),
7146                                ..container.children[0].children[0].children[0].children[0].clone()
7147                            }],
7148                            ..container.children[0].children[0].children[0].clone()
7149                        }],
7150                        calculated_width: Some(1300.0),
7151                        calculated_height: Some(36.0),
7152                        calculated_padding_left: Some(30.0),
7153                        calculated_padding_right: Some(30.0),
7154                        calculated_padding_top: Some(15.0),
7155                        calculated_x: Some(0.0),
7156                        calculated_y: Some(0.0),
7157                        ..container.children[0].children[0].clone()
7158                    }],
7159                    calculated_width: Some(1360.0),
7160                    calculated_height: Some(76.0),
7161                    calculated_x: Some(0.0),
7162                    calculated_y: Some(0.0),
7163                    ..container.children[0].clone()
7164                }],
7165                ..container
7166            },
7167        );
7168    }
7169
7170    #[test_log::test]
7171    fn calc_calculates_horizontal_position_from_right_for_absolute_position_with_padding() {
7172        let mut container: Container = html! {
7173            div
7174                sx-width="calc(min(500, 30%))"
7175                sx-height="calc(100% - 200)"
7176                sx-padding-left=(20)
7177                sx-padding-right=(20)
7178                sx-position="absolute"
7179                sx-right=(0)
7180            {}
7181        }
7182        .try_into()
7183        .unwrap();
7184
7185        container.calculated_width = Some(1600.0);
7186        container.calculated_height = Some(1000.0);
7187        container.position = Some(Position::Relative);
7188
7189        CALCULATOR.calc(&mut container);
7190        log::trace!("container:\n{container}");
7191
7192        compare_containers(
7193            &container.clone(),
7194            &Container {
7195                children: vec![Container {
7196                    calculated_width: Some((1600.0 - 40.0) * 0.3),
7197                    calculated_height: Some(800.0),
7198                    calculated_x: Some(1092.0),
7199                    calculated_y: Some(0.0),
7200                    calculated_padding_left: Some(20.0),
7201                    calculated_padding_right: Some(20.0),
7202                    ..container.children[0].clone()
7203                }],
7204                ..container
7205            },
7206        );
7207    }
7208
7209    #[test_log::test]
7210    fn calc_calculates_vertical_position_from_right_for_absolute_position_with_padding() {
7211        let mut container: Container = html! {
7212            div
7213                sx-width="calc(min(500, 30%))"
7214                sx-height="calc(100% - 200)"
7215                sx-padding-top=(20)
7216                sx-padding-bottom=(20)
7217                sx-position="absolute"
7218                sx-bottom=(170)
7219            {}
7220        }
7221        .try_into()
7222        .unwrap();
7223
7224        container.calculated_width = Some(1600.0);
7225        container.calculated_height = Some(1000.0);
7226        container.position = Some(Position::Relative);
7227
7228        CALCULATOR.calc(&mut container);
7229        log::trace!("container:\n{container}");
7230
7231        compare_containers(
7232            &container.clone(),
7233            &Container {
7234                children: vec![Container {
7235                    calculated_width: Some(1600.0 * 0.3),
7236                    calculated_height: Some(1000.0 - 200.0 - 40.0),
7237                    calculated_x: Some(0.0),
7238                    calculated_y: Some(30.0),
7239                    calculated_padding_top: Some(20.0),
7240                    calculated_padding_bottom: Some(20.0),
7241                    ..container.children[0].clone()
7242                }],
7243                ..container
7244            },
7245        );
7246    }
7247
7248    #[test_log::test]
7249    fn calc_calculates_horizontal_and_vertical_position_from_right_for_absolute_position_with_padding()
7250     {
7251        let mut container: Container = html! {
7252            div
7253                sx-width="calc(min(500, 30%))"
7254                sx-height="calc(100% - 200)"
7255                sx-padding=(20)
7256                sx-position="absolute"
7257                sx-bottom=(170)
7258                sx-right=(0)
7259            {}
7260        }
7261        .try_into()
7262        .unwrap();
7263
7264        container.calculated_width = Some(1600.0);
7265        container.calculated_height = Some(1000.0);
7266        container.position = Some(Position::Relative);
7267
7268        CALCULATOR.calc(&mut container);
7269        log::trace!("container:\n{container}");
7270
7271        compare_containers(
7272            &container.clone(),
7273            &Container {
7274                children: vec![Container {
7275                    calculated_width: Some((1600.0 - 40.0) * 0.3),
7276                    calculated_height: Some(1000.0 - 200.0 - 40.0),
7277                    calculated_x: Some(1092.0),
7278                    calculated_y: Some(30.0),
7279                    calculated_padding_left: Some(20.0),
7280                    calculated_padding_right: Some(20.0),
7281                    calculated_padding_top: Some(20.0),
7282                    calculated_padding_bottom: Some(20.0),
7283                    ..container.children[0].clone()
7284                }],
7285                ..container
7286            },
7287        );
7288    }
7289
7290    #[test_log::test]
7291    fn calc_calculates_horizontal_and_vertical_position_from_right_for_nested_absolute_position_with_padding()
7292     {
7293        let mut container: Container = html! {
7294            div sx-width="100%" sx-height="100%" sx-position="relative" {
7295                section sx-dir="row" sx-height=("calc(100% - 140px)") {
7296                    aside sx-width="calc(max(240, min(280, 15%)))" {}
7297                    main sx-overflow-y="auto" {}
7298                }
7299                div
7300                    sx-width="calc(min(500, 30%))"
7301                    sx-height="calc(100% - 200)"
7302                    sx-padding=(20)
7303                    sx-position="absolute"
7304                    sx-bottom=(170)
7305                    sx-right=(0)
7306                {}
7307            }
7308        }
7309        .try_into()
7310        .unwrap();
7311
7312        container.calculated_width = Some(1600.0);
7313        container.calculated_height = Some(1000.0);
7314
7315        CALCULATOR.calc(&mut container);
7316        log::trace!("container:\n{container}");
7317
7318        let container = container.children[0].children[1].clone();
7319
7320        compare_containers(
7321            &container.clone(),
7322            &Container {
7323                calculated_width: Some((1600.0 - 40.0) * 0.3),
7324                calculated_height: Some(1000.0 - 200.0 - 40.0),
7325                calculated_x: Some(1092.0),
7326                calculated_y: Some(30.0),
7327                calculated_padding_left: Some(20.0),
7328                calculated_padding_right: Some(20.0),
7329                calculated_padding_top: Some(20.0),
7330                calculated_padding_bottom: Some(20.0),
7331                ..container
7332            },
7333        );
7334    }
7335
7336    #[test_log::test]
7337    fn calc_calculates_horizontal_padding_on_sized_element_correctly() {
7338        let mut container: Container = html! {
7339            div sx-width="100%" sx-height="100%" sx-position="relative" {
7340                section sx-dir="row" sx-height=("calc(100% - 140)") {
7341                    aside sx-width="calc(max(240, min(280, 15%)))" sx-padding=(20) {}
7342                    main sx-overflow-y="auto" sx-flex=(1) {}
7343                }
7344            }
7345        }
7346        .try_into()
7347        .unwrap();
7348
7349        container.calculated_width = Some(1600.0);
7350        container.calculated_height = Some(1000.0);
7351
7352        CALCULATOR.calc(&mut container);
7353        log::trace!("container:\n{container}");
7354
7355        let main = container.children[0].children[0].children[1].clone();
7356
7357        compare_containers(
7358            &main.clone(),
7359            &Container {
7360                calculated_width: Some(1320.0),
7361                calculated_height: Some(860.0),
7362                calculated_x: Some(280.0),
7363                calculated_y: Some(0.0),
7364                ..main
7365            },
7366        );
7367
7368        let aside = container.children[0].children[0].children[0].clone();
7369
7370        compare_containers(
7371            &aside.clone(),
7372            &Container {
7373                calculated_width: Some(240.0),
7374                calculated_x: Some(0.0),
7375                calculated_y: Some(0.0),
7376                calculated_padding_left: Some(20.0),
7377                calculated_padding_right: Some(20.0),
7378                ..aside
7379            },
7380        );
7381    }
7382
7383    #[test_log::test]
7384    fn calc_calculates_vertical_padding_on_sized_element_correctly() {
7385        let mut container: Container = html! {
7386            div sx-width="100%" sx-height="100%" sx-position="relative" {
7387                section sx-dir="row" sx-height=("calc(100% - 140)") {
7388                    aside
7389                        sx-justify-content=(JustifyContent::Start)
7390                        sx-width="calc(max(240, min(280, 15%)))"
7391                        sx-padding=(20)
7392                    {
7393                        div sx-justify-content=(JustifyContent::Start) {
7394                            div {}
7395                            ul sx-justify-content=(JustifyContent::Start) { li {} li {} }
7396                        }
7397                    }
7398                    main sx-overflow-y="auto" sx-flex=(1) {}
7399                }
7400                footer sx-height=(140) {}
7401            }
7402        }
7403        .try_into()
7404        .unwrap();
7405
7406        container.calculated_width = Some(1600.0);
7407        container.calculated_height = Some(1000.0);
7408        container.justify_content = Some(JustifyContent::Start);
7409
7410        CALCULATOR.calc(&mut container);
7411        log::trace!("container:\n{container}");
7412
7413        let main = container.children[0].children[0].children[1].clone();
7414
7415        compare_containers(
7416            &main.clone(),
7417            &Container {
7418                calculated_width: Some(1320.0),
7419                calculated_height: Some(860.0),
7420                calculated_x: Some(280.0),
7421                calculated_y: Some(0.0),
7422                ..main
7423            },
7424        );
7425
7426        let aside = container.children[0].children[0].children[0].clone();
7427
7428        compare_containers(
7429            &aside.clone(),
7430            &Container {
7431                calculated_height: Some(820.0),
7432                calculated_x: Some(0.0),
7433                calculated_y: Some(0.0),
7434                calculated_padding_top: Some(20.0),
7435                calculated_padding_bottom: Some(20.0),
7436                ..aside
7437            },
7438        );
7439    }
7440
7441    #[test_log::test]
7442    fn calc_overflow_y_squash_expands_height_of_largest_child_as_much_as_possible() {
7443        let mut container: Container = html! {
7444            div {
7445                div sx-height=(40) {}
7446            }
7447            div {
7448                div sx-height=(600) {}
7449            }
7450        }
7451        .try_into()
7452        .unwrap();
7453
7454        container.calculated_width = Some(100.0);
7455        container.calculated_height = Some(500.0);
7456
7457        CALCULATOR.calc(&mut container);
7458        log::trace!("container:\n{container}");
7459
7460        compare_containers(
7461            &container,
7462            &Container {
7463                children: vec![
7464                    Container {
7465                        calculated_height: Some(40.0),
7466                        ..container.children[0].clone()
7467                    },
7468                    Container {
7469                        calculated_height: Some(600.0),
7470                        ..container.children[1].clone()
7471                    },
7472                ],
7473                calculated_height: Some(500.0),
7474                ..container.clone()
7475            },
7476        );
7477    }
7478
7479    #[test_log::test]
7480    fn calc_overflow_y_expand_expands_height_when_contained_height_is_greater_than_single_unsized_div()
7481     {
7482        let mut container: Container = html! {
7483            div {
7484                div {
7485                    div sx-height=(600) {}
7486                }
7487            }
7488        }
7489        .try_into()
7490        .unwrap();
7491
7492        container.calculated_width = Some(100.0);
7493        container.calculated_height = Some(500.0);
7494
7495        CALCULATOR.calc(&mut container);
7496        log::trace!("container:\n{container}");
7497
7498        compare_containers(
7499            &container,
7500            &Container {
7501                children: vec![Container {
7502                    children: vec![Container {
7503                        children: vec![Container {
7504                            calculated_height: Some(600.0),
7505                            ..container.children[0].children[0].children[0].clone()
7506                        }],
7507                        calculated_height: Some(600.0),
7508                        ..container.children[0].children[0].clone()
7509                    }],
7510                    calculated_height: Some(600.0),
7511                    ..container.children[0].clone()
7512                }],
7513                calculated_height: Some(500.0),
7514                ..container.clone()
7515            },
7516        );
7517    }
7518
7519    #[test_log::test]
7520    fn calc_overflow_y_expand_expands_height_when_contained_height_is_greater_than_two_unsized_divs()
7521     {
7522        let mut container: Container = html! {
7523            div {
7524                div {
7525                    div sx-height=(40) {}
7526                }
7527                div {
7528                    div sx-height=(600) {}
7529                }
7530            }
7531        }
7532        .try_into()
7533        .unwrap();
7534
7535        container.calculated_width = Some(100.0);
7536        container.calculated_height = Some(500.0);
7537
7538        CALCULATOR.calc(&mut container);
7539        log::trace!("container:\n{container}");
7540
7541        compare_containers(
7542            &container,
7543            &Container {
7544                children: vec![Container {
7545                    children: vec![
7546                        Container {
7547                            calculated_height: Some(40.0),
7548                            ..container.children[0].children[0].clone()
7549                        },
7550                        Container {
7551                            calculated_height: Some(600.0),
7552                            ..container.children[0].children[1].clone()
7553                        },
7554                    ],
7555                    calculated_height: Some(640.0),
7556                    ..container.children[0].clone()
7557                }],
7558                calculated_height: Some(500.0),
7559                ..container.clone()
7560            },
7561        );
7562    }
7563
7564    #[test_log::test]
7565    fn calc_overflow_y_auto_justify_content_start_only_takes_up_sized_height() {
7566        let mut container: Container = html! {
7567            div sx-overflow-y="auto" sx-justify-content=(JustifyContent::Start) {
7568                div {
7569                    div sx-height=(40) {}
7570                }
7571                div {
7572                    div sx-height=(600) {}
7573                }
7574            }
7575        }
7576        .try_into()
7577        .unwrap();
7578
7579        container.calculated_width = Some(100.0);
7580        container.calculated_height = Some(500.0);
7581        container.justify_content = Some(JustifyContent::Start);
7582
7583        CALCULATOR.calc(&mut container);
7584        log::trace!("container:\n{container}");
7585
7586        compare_containers(
7587            &container,
7588            &Container {
7589                children: vec![Container {
7590                    children: vec![
7591                        Container {
7592                            calculated_height: Some(40.0),
7593                            ..container.children[0].children[0].clone()
7594                        },
7595                        Container {
7596                            calculated_height: Some(600.0),
7597                            ..container.children[0].children[1].clone()
7598                        },
7599                    ],
7600                    calculated_height: Some(500.0),
7601                    ..container.children[0].clone()
7602                }],
7603                calculated_height: Some(500.0),
7604                ..container.clone()
7605            },
7606        );
7607    }
7608
7609    #[test_log::test]
7610    fn calc_does_calculate_fixed_top_left_border_radius() {
7611        let mut container: Container = html! {
7612            div sx-border-top-left-radius=(5) {}
7613        }
7614        .try_into()
7615        .unwrap();
7616
7617        container.calculated_width = Some(100.0);
7618        container.calculated_height = Some(500.0);
7619
7620        CALCULATOR.calc(&mut container);
7621        log::trace!("container:\n{container}");
7622
7623        compare_containers(
7624            &container,
7625            &Container {
7626                children: vec![Container {
7627                    calculated_border_top_left_radius: Some(5.0),
7628                    ..container.children[0].clone()
7629                }],
7630                ..container.clone()
7631            },
7632        );
7633    }
7634
7635    #[test_log::test]
7636    fn calc_does_calculate_fixed_top_right_border_radius() {
7637        let mut container: Container = html! {
7638            div sx-border-top-right-radius=(5) {}
7639        }
7640        .try_into()
7641        .unwrap();
7642
7643        container.calculated_width = Some(100.0);
7644        container.calculated_height = Some(500.0);
7645
7646        CALCULATOR.calc(&mut container);
7647        log::trace!("container:\n{container}");
7648
7649        compare_containers(
7650            &container,
7651            &Container {
7652                children: vec![Container {
7653                    calculated_border_top_right_radius: Some(5.0),
7654                    ..container.children[0].clone()
7655                }],
7656                ..container.clone()
7657            },
7658        );
7659    }
7660
7661    #[test_log::test]
7662    fn calc_does_calculate_fixed_bottom_left_border_radius() {
7663        let mut container: Container = html! {
7664            div sx-border-bottom-left-radius=(5) {}
7665        }
7666        .try_into()
7667        .unwrap();
7668
7669        container.calculated_width = Some(100.0);
7670        container.calculated_height = Some(500.0);
7671
7672        CALCULATOR.calc(&mut container);
7673        log::trace!("container:\n{container}");
7674
7675        compare_containers(
7676            &container,
7677            &Container {
7678                children: vec![Container {
7679                    calculated_border_bottom_left_radius: Some(5.0),
7680                    ..container.children[0].clone()
7681                }],
7682                ..container.clone()
7683            },
7684        );
7685    }
7686
7687    #[test_log::test]
7688    fn calc_does_calculate_fixed_bottom_right_border_radius() {
7689        let mut container: Container = html! {
7690            div sx-border-bottom-right-radius=(5) {}
7691        }
7692        .try_into()
7693        .unwrap();
7694
7695        container.calculated_width = Some(100.0);
7696        container.calculated_height = Some(500.0);
7697
7698        CALCULATOR.calc(&mut container);
7699        log::trace!("container:\n{container}");
7700
7701        compare_containers(
7702            &container,
7703            &Container {
7704                children: vec![Container {
7705                    calculated_border_bottom_right_radius: Some(5.0),
7706                    ..container.children[0].clone()
7707                }],
7708                ..container.clone()
7709            },
7710        );
7711    }
7712
7713    #[test_log::test]
7714    fn calc_does_calculate_percentage_top_left_border_radius() {
7715        let mut container: Container = html! {
7716            div sx-border-top-left-radius="100%" {}
7717        }
7718        .try_into()
7719        .unwrap();
7720
7721        container.calculated_width = Some(100.0);
7722        container.calculated_height = Some(500.0);
7723
7724        CALCULATOR.calc(&mut container);
7725        log::trace!("container:\n{container}");
7726
7727        compare_containers(
7728            &container,
7729            &Container {
7730                children: vec![Container {
7731                    calculated_border_top_left_radius: Some(100.0),
7732                    ..container.children[0].clone()
7733                }],
7734                ..container.clone()
7735            },
7736        );
7737    }
7738
7739    #[test_log::test]
7740    fn calc_does_calculate_percentage_top_right_border_radius() {
7741        let mut container: Container = html! {
7742            div sx-border-top-right-radius="100%" {}
7743        }
7744        .try_into()
7745        .unwrap();
7746
7747        container.calculated_width = Some(100.0);
7748        container.calculated_height = Some(500.0);
7749
7750        CALCULATOR.calc(&mut container);
7751        log::trace!("container:\n{container}");
7752
7753        compare_containers(
7754            &container,
7755            &Container {
7756                children: vec![Container {
7757                    calculated_border_top_right_radius: Some(100.0),
7758                    ..container.children[0].clone()
7759                }],
7760                ..container.clone()
7761            },
7762        );
7763    }
7764
7765    #[test_log::test]
7766    fn calc_does_calculate_percentage_bottom_left_border_radius() {
7767        let mut container: Container = html! {
7768            div sx-border-bottom-left-radius="100%" {}
7769        }
7770        .try_into()
7771        .unwrap();
7772
7773        container.calculated_width = Some(100.0);
7774        container.calculated_height = Some(500.0);
7775
7776        CALCULATOR.calc(&mut container);
7777        log::trace!("container:\n{container}");
7778
7779        compare_containers(
7780            &container,
7781            &Container {
7782                children: vec![Container {
7783                    calculated_border_bottom_left_radius: Some(100.0),
7784                    ..container.children[0].clone()
7785                }],
7786                ..container.clone()
7787            },
7788        );
7789    }
7790
7791    #[test_log::test]
7792    fn calc_does_calculate_percentage_bottom_right_border_radius() {
7793        let mut container: Container = html! {
7794            div sx-border-bottom-right-radius="100%" {}
7795        }
7796        .try_into()
7797        .unwrap();
7798
7799        container.calculated_width = Some(100.0);
7800        container.calculated_height = Some(500.0);
7801
7802        CALCULATOR.calc(&mut container);
7803        log::trace!("container:\n{container}");
7804
7805        compare_containers(
7806            &container,
7807            &Container {
7808                children: vec![Container {
7809                    calculated_border_bottom_right_radius: Some(100.0),
7810                    ..container.children[0].clone()
7811                }],
7812                ..container.clone()
7813            },
7814        );
7815    }
7816
7817    #[test_log::test]
7818    fn calc_does_calculate_fixed_opacity() {
7819        let mut container: Container = html! {
7820            div sx-opacity=(0.5) {}
7821        }
7822        .try_into()
7823        .unwrap();
7824
7825        container.calculated_width = Some(100.0);
7826        container.calculated_height = Some(500.0);
7827
7828        CALCULATOR.calc(&mut container);
7829        log::trace!("container:\n{container}");
7830
7831        compare_containers(
7832            &container,
7833            &Container {
7834                children: vec![Container {
7835                    calculated_opacity: Some(0.5),
7836                    ..container.children[0].clone()
7837                }],
7838                ..container.clone()
7839            },
7840        );
7841    }
7842
7843    #[test_log::test]
7844    fn calc_does_calculate_percentage_opacity() {
7845        let mut container: Container = html! {
7846            div sx-opacity="100%" {}
7847        }
7848        .try_into()
7849        .unwrap();
7850
7851        container.calculated_width = Some(100.0);
7852        container.calculated_height = Some(500.0);
7853
7854        CALCULATOR.calc(&mut container);
7855        log::trace!("container:\n{container}");
7856
7857        compare_containers(
7858            &container,
7859            &Container {
7860                children: vec![Container {
7861                    calculated_opacity: Some(1.0),
7862                    ..container.children[0].clone()
7863                }],
7864                ..container.clone()
7865            },
7866        );
7867    }
7868
7869    #[test_log::test]
7870    fn calc_includes_fixed_left_margin_in_min_size_with_no_explicit_fixed_size() {
7871        let mut container: Container = html! {
7872            div sx-margin-left=(50.0) {}
7873        }
7874        .try_into()
7875        .unwrap();
7876
7877        container.calculated_width = Some(100.0);
7878        container.calculated_height = Some(500.0);
7879
7880        CALCULATOR.calc(&mut container);
7881        log::trace!("container:\n{container}");
7882
7883        compare_containers(
7884            &container,
7885            &Container {
7886                children: vec![Container {
7887                    calculated_width: Some(50.0),
7888                    calculated_child_min_width: Some(50.0),
7889                    ..container.children[0].clone()
7890                }],
7891                ..container.clone()
7892            },
7893        );
7894    }
7895
7896    #[test_log::test]
7897    fn calc_includes_fixed_right_margin_in_min_size_with_no_explicit_fixed_size() {
7898        let mut container: Container = html! {
7899            div sx-margin-right=(50.0) {}
7900        }
7901        .try_into()
7902        .unwrap();
7903
7904        container.calculated_width = Some(100.0);
7905        container.calculated_height = Some(500.0);
7906
7907        CALCULATOR.calc(&mut container);
7908        log::trace!("container:\n{container}");
7909
7910        compare_containers(
7911            &container,
7912            &Container {
7913                children: vec![Container {
7914                    calculated_width: Some(50.0),
7915                    calculated_child_min_width: Some(50.0),
7916                    ..container.children[0].clone()
7917                }],
7918                ..container.clone()
7919            },
7920        );
7921    }
7922
7923    #[test_log::test]
7924    fn calc_includes_fixed_top_margin_in_min_size_with_no_explicit_fixed_size() {
7925        let mut container: Container = html! {
7926            div sx-margin-top=(50.0) {}
7927        }
7928        .try_into()
7929        .unwrap();
7930
7931        container.calculated_width = Some(100.0);
7932        container.calculated_height = Some(500.0);
7933        container.justify_content = Some(JustifyContent::Start);
7934
7935        CALCULATOR.calc(&mut container);
7936        log::trace!("container:\n{container}");
7937
7938        compare_containers(
7939            &container,
7940            &Container {
7941                children: vec![Container {
7942                    calculated_height: Some(0.0),
7943                    calculated_child_min_height: Some(50.0),
7944                    ..container.children[0].clone()
7945                }],
7946                ..container.clone()
7947            },
7948        );
7949    }
7950
7951    #[test_log::test]
7952    fn calc_includes_fixed_bottom_margin_in_min_size_with_no_explicit_fixed_size() {
7953        let mut container: Container = html! {
7954            div sx-margin-bottom=(50.0) {}
7955        }
7956        .try_into()
7957        .unwrap();
7958
7959        container.calculated_width = Some(100.0);
7960        container.calculated_height = Some(500.0);
7961        container.justify_content = Some(JustifyContent::Start);
7962
7963        CALCULATOR.calc(&mut container);
7964        log::trace!("container:\n{container}");
7965
7966        compare_containers(
7967            &container,
7968            &Container {
7969                children: vec![Container {
7970                    calculated_height: Some(0.0),
7971                    calculated_child_min_height: Some(50.0),
7972                    ..container.children[0].clone()
7973                }],
7974                ..container.clone()
7975            },
7976        );
7977    }
7978
7979    #[test_log::test]
7980    fn calc_includes_fixed_left_margin_in_min_size_with_explicit_fixed_size() {
7981        let mut container: Container = html! {
7982            div sx-margin-left=(50.0) sx-width=(25.0) {}
7983        }
7984        .try_into()
7985        .unwrap();
7986
7987        container.calculated_width = Some(100.0);
7988        container.calculated_height = Some(500.0);
7989        container.justify_content = Some(JustifyContent::Start);
7990
7991        CALCULATOR.calc(&mut container);
7992        log::trace!("container:\n{container}");
7993
7994        compare_containers(
7995            &container,
7996            &Container {
7997                children: vec![Container {
7998                    calculated_width: Some(25.0),
7999                    calculated_child_min_width: Some(75.0),
8000                    ..container.children[0].clone()
8001                }],
8002                ..container.clone()
8003            },
8004        );
8005    }
8006
8007    #[test_log::test]
8008    fn calc_includes_fixed_right_margin_in_min_size_with_explicit_fixed_size() {
8009        let mut container: Container = html! {
8010            div sx-margin-right=(50.0) sx-width=(25.0) {}
8011        }
8012        .try_into()
8013        .unwrap();
8014
8015        container.calculated_width = Some(100.0);
8016        container.calculated_height = Some(500.0);
8017        container.justify_content = Some(JustifyContent::Start);
8018
8019        CALCULATOR.calc(&mut container);
8020        log::trace!("container:\n{container}");
8021
8022        compare_containers(
8023            &container,
8024            &Container {
8025                children: vec![Container {
8026                    calculated_width: Some(25.0),
8027                    calculated_child_min_width: Some(75.0),
8028                    ..container.children[0].clone()
8029                }],
8030                ..container.clone()
8031            },
8032        );
8033    }
8034
8035    #[test_log::test]
8036    fn calc_includes_fixed_top_margin_in_min_size_with_explicit_fixed_size() {
8037        let mut container: Container = html! {
8038            div sx-margin-top=(50.0) sx-height=(25.0) {}
8039        }
8040        .try_into()
8041        .unwrap();
8042
8043        container.calculated_width = Some(100.0);
8044        container.calculated_height = Some(500.0);
8045        container.justify_content = Some(JustifyContent::Start);
8046
8047        CALCULATOR.calc(&mut container);
8048        log::trace!("container:\n{container}");
8049
8050        compare_containers(
8051            &container,
8052            &Container {
8053                children: vec![Container {
8054                    calculated_height: Some(25.0),
8055                    calculated_child_min_height: Some(75.0),
8056                    ..container.children[0].clone()
8057                }],
8058                ..container.clone()
8059            },
8060        );
8061    }
8062
8063    #[test_log::test]
8064    fn calc_includes_fixed_bottom_margin_in_min_size_with_explicit_fixed_size() {
8065        let mut container: Container = html! {
8066            div sx-margin-bottom=(50.0) sx-height=(25.0) {}
8067        }
8068        .try_into()
8069        .unwrap();
8070
8071        container.calculated_width = Some(100.0);
8072        container.calculated_height = Some(500.0);
8073        container.justify_content = Some(JustifyContent::Start);
8074
8075        CALCULATOR.calc(&mut container);
8076        log::trace!("container:\n{container}");
8077
8078        compare_containers(
8079            &container,
8080            &Container {
8081                children: vec![Container {
8082                    calculated_height: Some(25.0),
8083                    calculated_child_min_height: Some(75.0),
8084                    ..container.children[0].clone()
8085                }],
8086                ..container.clone()
8087            },
8088        );
8089    }
8090
8091    #[test_log::test]
8092    fn calc_includes_fixed_left_padding_in_min_size_with_no_explicit_fixed_size() {
8093        let mut container: Container = html! {
8094            div sx-padding-left=(50.0) {}
8095        }
8096        .try_into()
8097        .unwrap();
8098
8099        container.calculated_width = Some(100.0);
8100        container.calculated_height = Some(500.0);
8101        container.justify_content = Some(JustifyContent::Start);
8102
8103        CALCULATOR.calc(&mut container);
8104        log::trace!("container:\n{container}");
8105
8106        compare_containers(
8107            &container,
8108            &Container {
8109                children: vec![Container {
8110                    calculated_width: Some(50.0),
8111                    calculated_child_min_width: Some(50.0),
8112                    ..container.children[0].clone()
8113                }],
8114                ..container.clone()
8115            },
8116        );
8117    }
8118
8119    #[test_log::test]
8120    fn calc_includes_fixed_right_padding_in_min_size_with_no_explicit_fixed_size() {
8121        let mut container: Container = html! {
8122            div sx-padding-right=(50.0) {}
8123        }
8124        .try_into()
8125        .unwrap();
8126
8127        container.calculated_width = Some(100.0);
8128        container.calculated_height = Some(500.0);
8129        container.justify_content = Some(JustifyContent::Start);
8130
8131        CALCULATOR.calc(&mut container);
8132        log::trace!("container:\n{container}");
8133
8134        compare_containers(
8135            &container,
8136            &Container {
8137                children: vec![Container {
8138                    calculated_width: Some(50.0),
8139                    calculated_child_min_width: Some(50.0),
8140                    ..container.children[0].clone()
8141                }],
8142                ..container.clone()
8143            },
8144        );
8145    }
8146
8147    #[test_log::test]
8148    fn calc_includes_fixed_top_padding_in_min_size_with_no_explicit_fixed_size() {
8149        let mut container: Container = html! {
8150            div sx-padding-top=(50.0) {}
8151        }
8152        .try_into()
8153        .unwrap();
8154
8155        container.calculated_width = Some(100.0);
8156        container.calculated_height = Some(500.0);
8157        container.justify_content = Some(JustifyContent::Start);
8158
8159        CALCULATOR.calc(&mut container);
8160        log::trace!("container:\n{container}");
8161
8162        compare_containers(
8163            &container,
8164            &Container {
8165                children: vec![Container {
8166                    calculated_height: Some(0.0),
8167                    calculated_child_min_height: Some(50.0),
8168                    ..container.children[0].clone()
8169                }],
8170                ..container.clone()
8171            },
8172        );
8173    }
8174
8175    #[test_log::test]
8176    fn calc_includes_fixed_bottom_padding_in_min_size_with_no_explicit_fixed_size() {
8177        let mut container: Container = html! {
8178            div sx-padding-bottom=(50.0) {}
8179        }
8180        .try_into()
8181        .unwrap();
8182
8183        container.calculated_width = Some(100.0);
8184        container.calculated_height = Some(500.0);
8185        container.justify_content = Some(JustifyContent::Start);
8186
8187        CALCULATOR.calc(&mut container);
8188        log::trace!("container:\n{container}");
8189
8190        compare_containers(
8191            &container,
8192            &Container {
8193                children: vec![Container {
8194                    calculated_height: Some(0.0),
8195                    calculated_child_min_height: Some(50.0),
8196                    ..container.children[0].clone()
8197                }],
8198                ..container.clone()
8199            },
8200        );
8201    }
8202
8203    #[test_log::test]
8204    fn calc_includes_fixed_left_padding_in_min_size_with_explicit_fixed_size() {
8205        let mut container: Container = html! {
8206            div sx-padding-left=(50.0) sx-width=(25.0) {}
8207        }
8208        .try_into()
8209        .unwrap();
8210
8211        container.calculated_width = Some(100.0);
8212        container.calculated_height = Some(500.0);
8213        container.justify_content = Some(JustifyContent::Start);
8214
8215        CALCULATOR.calc(&mut container);
8216        log::trace!("container:\n{container}");
8217
8218        compare_containers(
8219            &container,
8220            &Container {
8221                children: vec![Container {
8222                    calculated_width: Some(25.0),
8223                    calculated_child_min_width: Some(75.0),
8224                    ..container.children[0].clone()
8225                }],
8226                ..container.clone()
8227            },
8228        );
8229    }
8230
8231    #[test_log::test]
8232    fn calc_includes_fixed_right_padding_in_min_size_with_explicit_fixed_size() {
8233        let mut container: Container = html! {
8234            div sx-padding-right=(50.0) sx-width=(25.0) {}
8235        }
8236        .try_into()
8237        .unwrap();
8238
8239        container.calculated_width = Some(100.0);
8240        container.calculated_height = Some(500.0);
8241        container.justify_content = Some(JustifyContent::Start);
8242
8243        CALCULATOR.calc(&mut container);
8244        log::trace!("container:\n{container}");
8245
8246        compare_containers(
8247            &container,
8248            &Container {
8249                children: vec![Container {
8250                    calculated_width: Some(25.0),
8251                    calculated_child_min_width: Some(75.0),
8252                    ..container.children[0].clone()
8253                }],
8254                ..container.clone()
8255            },
8256        );
8257    }
8258
8259    #[test_log::test]
8260    fn calc_includes_fixed_top_padding_in_min_size_with_explicit_fixed_size() {
8261        let mut container: Container = html! {
8262            div sx-padding-top=(50.0) sx-height=(25.0) {}
8263        }
8264        .try_into()
8265        .unwrap();
8266
8267        container.calculated_width = Some(100.0);
8268        container.calculated_height = Some(500.0);
8269        container.justify_content = Some(JustifyContent::Start);
8270
8271        CALCULATOR.calc(&mut container);
8272        log::trace!("container:\n{container}");
8273
8274        compare_containers(
8275            &container,
8276            &Container {
8277                children: vec![Container {
8278                    calculated_height: Some(25.0),
8279                    calculated_child_min_height: Some(75.0),
8280                    ..container.children[0].clone()
8281                }],
8282                ..container.clone()
8283            },
8284        );
8285    }
8286
8287    #[test_log::test]
8288    fn calc_includes_fixed_bottom_padding_in_min_size_with_explicit_fixed_size() {
8289        let mut container: Container = html! {
8290            div sx-padding-bottom=(50.0) sx-height=(25.0) {}
8291        }
8292        .try_into()
8293        .unwrap();
8294
8295        container.calculated_width = Some(100.0);
8296        container.calculated_height = Some(500.0);
8297        container.justify_content = Some(JustifyContent::Start);
8298
8299        CALCULATOR.calc(&mut container);
8300        log::trace!("container:\n{container}");
8301
8302        compare_containers(
8303            &container,
8304            &Container {
8305                children: vec![Container {
8306                    calculated_height: Some(25.0),
8307                    calculated_child_min_height: Some(75.0),
8308                    ..container.children[0].clone()
8309                }],
8310                ..container.clone()
8311            },
8312        );
8313    }
8314
8315    #[test_log::test]
8316    fn calc_evenly_distributes_row_width_even_when_one_child_has_a_min_width() {
8317        let mut container: Container = html! {
8318            div sx-dir="row" {
8319                div {}
8320                div {
8321                    div sx-width=(50) {}
8322                }
8323            }
8324        }
8325        .try_into()
8326        .unwrap();
8327
8328        container.calculated_width = Some(400.0);
8329        container.calculated_height = Some(100.0);
8330        container.justify_content = Some(JustifyContent::Start);
8331        CALCULATOR.calc(&mut container);
8332        log::trace!("container:\n{container}");
8333
8334        compare_containers(
8335            &container,
8336            &Container {
8337                children: vec![Container {
8338                    children: vec![
8339                        Container {
8340                            calculated_width: Some(0.0),
8341                            calculated_height: Some(0.0),
8342                            ..container.children[0].children[0].clone()
8343                        },
8344                        Container {
8345                            calculated_width: Some(50.0),
8346                            calculated_height: Some(0.0),
8347                            ..container.children[0].children[1].clone()
8348                        },
8349                    ],
8350                    calculated_width: Some(400.0),
8351                    calculated_height: Some(0.0),
8352                    ..container.children[0].clone()
8353                }],
8354                calculated_width: Some(400.0),
8355                calculated_height: Some(100.0),
8356                ..container.clone()
8357            },
8358        );
8359    }
8360
8361    #[test_log::test]
8362    fn calc_only_takes_height_necessary_for_non_flex_container_contents() {
8363        let mut container: Container = html! {
8364            div {
8365                div sx-height=(10) {}
8366            }
8367            div {
8368                div sx-height=(15) {}
8369            }
8370        }
8371        .try_into()
8372        .unwrap();
8373
8374        container.calculated_width = Some(400.0);
8375        container.calculated_height = Some(100.0);
8376
8377        CALCULATOR.calc(&mut container);
8378        log::trace!("container:\n{container}");
8379
8380        compare_containers(
8381            &container,
8382            &Container {
8383                children: vec![
8384                    Container {
8385                        calculated_width: Some(400.0),
8386                        calculated_height: Some(10.0),
8387                        ..container.children[0].clone()
8388                    },
8389                    Container {
8390                        calculated_width: Some(400.0),
8391                        calculated_height: Some(15.0),
8392                        ..container.children[1].clone()
8393                    },
8394                ],
8395                calculated_width: Some(400.0),
8396                calculated_height: Some(100.0),
8397                ..container.clone()
8398            },
8399        );
8400    }
8401
8402    #[test_log::test]
8403    fn calc_only_takes_height_necessary_for_flex_cross_axis_column_container_contents_when_align_items_is_set()
8404     {
8405        let mut container: Container = html! {
8406            div sx-dir=(LayoutDirection::Row) sx-align-items=(AlignItems::Center) sx-height=(50) {
8407                div { div { "one" } div { "two" } }
8408                div { "three" }
8409            }
8410        }
8411        .try_into()
8412        .unwrap();
8413
8414        container.calculated_width = Some(400.0);
8415        container.calculated_height = Some(100.0);
8416
8417        CALCULATOR.calc(&mut container);
8418        log::trace!("full container:\n{container}");
8419        container = container.children[0].clone();
8420        log::trace!("container:\n{container}");
8421
8422        compare_containers(
8423            &container,
8424            &Container {
8425                children: vec![
8426                    Container {
8427                        calculated_height: Some(14.0 * 2.0),
8428                        ..container.children[0].clone()
8429                    },
8430                    Container {
8431                        calculated_height: Some(14.0),
8432                        ..container.children[1].clone()
8433                    },
8434                ],
8435                calculated_height: Some(50.0),
8436                ..container.clone()
8437            },
8438        );
8439    }
8440
8441    #[test_log::test]
8442    fn calc_only_takes_height_necessary_for_flex_cross_axis_row_container_contents_when_align_items_is_set()
8443     {
8444        let mut container: Container = html! {
8445            div sx-align-items=(AlignItems::Center) sx-width=(150) {
8446                div sx-dir=(LayoutDirection::Row) { div { "one" } div { "two" } }
8447                div sx-dir=(LayoutDirection::Row) { "three" }
8448            }
8449        }
8450        .try_into()
8451        .unwrap();
8452
8453        container.calculated_width = Some(400.0);
8454        container.calculated_height = Some(100.0);
8455
8456        CALCULATOR.calc(&mut container);
8457        log::trace!("full container:\n{container}");
8458        container = container.children[0].clone();
8459        log::trace!("container:\n{container}");
8460
8461        compare_containers(
8462            &container,
8463            &Container {
8464                children: vec![
8465                    Container {
8466                        calculated_width: Some(14.0 * 6.0),
8467                        ..container.children[0].clone()
8468                    },
8469                    Container {
8470                        calculated_width: Some(14.0 * 5.0),
8471                        ..container.children[1].clone()
8472                    },
8473                ],
8474                calculated_width: Some(150.0),
8475                ..container.clone()
8476            },
8477        );
8478    }
8479
8480    #[test_log::test]
8481    fn calc_direction_row_doesnt_take_full_width() {
8482        let mut container: Container = html! {
8483            div sx-width=(200) sx-dir=(LayoutDirection::Row) {
8484                h1 { "test" }
8485                div sx-width=(10) {}
8486            }
8487        }
8488        .try_into()
8489        .unwrap();
8490
8491        container.calculated_width = Some(400.0);
8492        container.calculated_height = Some(100.0);
8493
8494        CALCULATOR.calc(&mut container);
8495        log::trace!("full container:\n{container}");
8496        container = container.children[0].clone();
8497        log::trace!("container:\n{container}");
8498
8499        compare_containers(
8500            &container,
8501            &Container {
8502                children: vec![
8503                    Container {
8504                        calculated_width: Some(32.0 * 4.0),
8505                        ..container.children[0].clone()
8506                    },
8507                    Container {
8508                        calculated_width: Some(10.0),
8509                        ..container.children[1].clone()
8510                    },
8511                ],
8512                calculated_width: Some(200.0),
8513                ..container.clone()
8514            },
8515        );
8516    }
8517
8518    mod text {
8519        use super::*;
8520
8521        #[test_log::test]
8522        fn does_calculate_text_height_properly() {
8523            let mut container: Container = html! {
8524                div { "test" }
8525            }
8526            .try_into()
8527            .unwrap();
8528
8529            container.calculated_width = Some(400.0);
8530            container.calculated_height = Some(100.0);
8531
8532            CALCULATOR.calc(&mut container);
8533            log::trace!("full container:\n{container}");
8534            container = container.children[0].clone();
8535            log::trace!("container:\n{container}");
8536
8537            compare_containers(
8538                &container,
8539                &Container {
8540                    children: vec![Container {
8541                        calculated_height: Some(14.0),
8542                        ..container.children[0].clone()
8543                    }],
8544                    ..container.clone()
8545                },
8546            );
8547        }
8548
8549        #[test_log::test]
8550        fn does_propagate_text_height_properly() {
8551            let mut container: Container = html! {
8552                div { "test" }
8553            }
8554            .try_into()
8555            .unwrap();
8556
8557            container.calculated_width = Some(400.0);
8558            container.calculated_height = Some(100.0);
8559
8560            CALCULATOR.calc(&mut container);
8561            log::trace!("full container:\n{container}");
8562            container = container.children[0].clone();
8563            log::trace!("container:\n{container}");
8564
8565            compare_containers(
8566                &container,
8567                &Container {
8568                    children: vec![Container {
8569                        calculated_height: Some(14.0),
8570                        ..container.children[0].clone()
8571                    }],
8572                    calculated_height: Some(14.0),
8573                    ..container.clone()
8574                },
8575            );
8576        }
8577
8578        #[test_log::test]
8579        fn does_use_preferred_width_for_nested_text() {
8580            let mut container: Container = html! {
8581                div sx-dir=(LayoutDirection::Row) sx-align-items=(AlignItems::Start) {
8582                    "test" span { "two" }
8583                }
8584            }
8585            .try_into()
8586            .unwrap();
8587
8588            container.calculated_width = Some(400.0);
8589            container.calculated_height = Some(100.0);
8590
8591            CALCULATOR.calc(&mut container);
8592            log::trace!("full container:\n{container}");
8593            container = container.children[0].clone();
8594            log::trace!("container:\n{container}");
8595
8596            compare_containers(
8597                &container,
8598                &Container {
8599                    children: vec![
8600                        Container {
8601                            calculated_width: Some(14.0 * 4.0),
8602                            ..container.children[0].clone()
8603                        },
8604                        Container {
8605                            calculated_width: Some(14.0 * 3.0),
8606                            ..container.children[1].clone()
8607                        },
8608                    ],
8609                    ..container.clone()
8610                },
8611            );
8612        }
8613
8614        #[test_log::test]
8615        fn does_use_preferred_width_for_nested_text_in_dynamically_sized_child() {
8616            let mut container: Container = html! {
8617                div sx-dir=(LayoutDirection::Row) sx-align-items=(AlignItems::Center) {
8618                    div sx-justify-content=(JustifyContent::Center) {
8619                        div sx-dir=(LayoutDirection::Row) {
8620                            "test" span { "two" }
8621                        }
8622                    }
8623                }
8624            }
8625            .try_into()
8626            .unwrap();
8627
8628            container.calculated_width = Some(400.0);
8629            container.calculated_height = Some(100.0);
8630
8631            CALCULATOR.calc(&mut container);
8632            log::trace!("full container:\n{container}");
8633            container = container.children[0].clone();
8634            log::trace!("container:\n{container}");
8635
8636            compare_containers(
8637                &container,
8638                &Container {
8639                    children: vec![Container {
8640                        children: vec![Container {
8641                            children: vec![
8642                                Container {
8643                                    calculated_width: Some(14.0 * 4.0),
8644                                    ..container.children[0].children[0].children[0].clone()
8645                                },
8646                                Container {
8647                                    calculated_width: Some(14.0 * 3.0),
8648                                    ..container.children[0].children[0].children[1].clone()
8649                                },
8650                            ],
8651                            calculated_width: Some(14.0 * (4.0 + 3.0)),
8652                            ..container.children[0].children[0].clone()
8653                        }],
8654                        ..container.children[0].clone()
8655                    }],
8656                    ..container.clone()
8657                },
8658            );
8659        }
8660
8661        #[test_log::test]
8662        fn does_not_expand_past_preferred_width() {
8663            let mut container: Container = html! {
8664                div sx-width=(100) { "test" }
8665            }
8666            .try_into()
8667            .unwrap();
8668
8669            container.calculated_width = Some(400.0);
8670            container.calculated_height = Some(100.0);
8671
8672            CALCULATOR.calc(&mut container);
8673            log::trace!("full container:\n{container}");
8674            container = container.children[0].clone();
8675            log::trace!("container:\n{container}");
8676
8677            compare_containers(
8678                &container,
8679                &Container {
8680                    children: vec![Container {
8681                        calculated_width: Some(14.0 * 4.0),
8682                        ..container.children[0].clone()
8683                    }],
8684                    calculated_width: Some(100.0),
8685                    ..container.clone()
8686                },
8687            );
8688        }
8689
8690        #[test_log::test]
8691        fn does_wrap_long_line_of_text_to_2_lines() {
8692            let mut container: Container = html! {
8693                div sx-width=(100) { "test test" }
8694            }
8695            .try_into()
8696            .unwrap();
8697
8698            container.calculated_width = Some(400.0);
8699            container.calculated_height = Some(100.0);
8700
8701            CALCULATOR.calc(&mut container);
8702            log::trace!("full container:\n{container}");
8703            container = container.children[0].clone();
8704            log::trace!("container:\n{container}");
8705
8706            compare_containers(
8707                &container,
8708                &Container {
8709                    children: vec![Container {
8710                        calculated_width: Some(100.0),
8711                        calculated_height: Some(14.0 * 2.0),
8712                        ..container.children[0].clone()
8713                    }],
8714                    calculated_width: Some(100.0),
8715                    ..container.clone()
8716                },
8717            );
8718        }
8719
8720        #[test_log::test]
8721        fn does_wrap_nested_text_longer_than_container_can_fit() {
8722            let mut container: Container = html! {
8723                div sx-width=(200) {
8724                    span { "aoeu aoeu aoeu aoeu aoeu" }
8725                }
8726            }
8727            .try_into()
8728            .unwrap();
8729
8730            container.calculated_width = Some(400.0);
8731            container.calculated_height = Some(100.0);
8732
8733            CALCULATOR.calc(&mut container);
8734            log::trace!("full container:\n{container}");
8735            container = container.children[0].clone();
8736            log::trace!("container:\n{container}");
8737
8738            compare_containers(
8739                &container,
8740                &Container {
8741                    children: vec![Container {
8742                        calculated_width: Some(200.0),
8743                        calculated_height: Some(14.0 * 2.0),
8744                        ..container.children[0].clone()
8745                    }],
8746                    calculated_width: Some(200.0),
8747                    ..container.clone()
8748                },
8749            );
8750        }
8751
8752        #[test_log::test]
8753        fn does_wrap_nested_text_longer_than_container_can_fit_with_align_items_center() {
8754            let mut container: Container = html! {
8755                div sx-width=(200) sx-align-items=(AlignItems::Center) {
8756                    span { "aoeu aoeu aoeu aoeu aoeu" }
8757                }
8758            }
8759            .try_into()
8760            .unwrap();
8761
8762            container.calculated_width = Some(400.0);
8763            container.calculated_height = Some(100.0);
8764
8765            CALCULATOR.calc(&mut container);
8766            log::trace!("full container:\n{container}");
8767            container = container.children[0].clone();
8768            log::trace!("container:\n{container}");
8769
8770            compare_containers(
8771                &container,
8772                &Container {
8773                    children: vec![Container {
8774                        calculated_width: Some(200.0),
8775                        calculated_height: Some(14.0 * 2.0),
8776                        ..container.children[0].clone()
8777                    }],
8778                    calculated_width: Some(200.0),
8779                    ..container.clone()
8780                },
8781            );
8782        }
8783
8784        #[test_log::test]
8785        fn does_wrap_text_longer_than_nested_div_container_can_fit_with_align_items_center() {
8786            let mut container: Container = html! {
8787                div sx-width=(200) sx-align-items=(AlignItems::Center) {
8788                    div { "aoeu aoeu aoeu aoeu aoeu" }
8789                }
8790            }
8791            .try_into()
8792            .unwrap();
8793
8794            container.calculated_width = Some(400.0);
8795            container.calculated_height = Some(100.0);
8796
8797            CALCULATOR.calc(&mut container);
8798            log::trace!("full container:\n{container}");
8799            container = container.children[0].clone();
8800            log::trace!("container:\n{container}");
8801
8802            compare_containers(
8803                &container,
8804                &Container {
8805                    children: vec![Container {
8806                        calculated_width: Some(200.0),
8807                        calculated_height: Some(14.0 * 2.0),
8808                        ..container.children[0].clone()
8809                    }],
8810                    calculated_width: Some(200.0),
8811                    ..container.clone()
8812                },
8813            );
8814        }
8815
8816        #[test_log::test]
8817        fn does_use_default_font_size() {
8818            let mut container: Container = html! {
8819                "aoeu"
8820            }
8821            .try_into()
8822            .unwrap();
8823
8824            container.calculated_font_size = Some(20.0);
8825            container.calculated_width = Some(400.0);
8826            container.calculated_height = Some(100.0);
8827
8828            let calculator = Calculator::new(
8829                DefaultFontMetrics,
8830                CalculatorDefaults {
8831                    font_size: 20.0,
8832                    ..Default::default()
8833                },
8834            );
8835            calculator.calc(&mut container);
8836            log::trace!("container:\n{container}");
8837
8838            compare_containers(
8839                &container,
8840                &Container {
8841                    children: vec![Container {
8842                        calculated_width: Some(20.0 * 4.0),
8843                        calculated_height: Some(20.0),
8844                        ..container.children[0].clone()
8845                    }],
8846                    ..container.clone()
8847                },
8848            );
8849        }
8850
8851        #[test_log::test]
8852        fn does_use_direct_parent_fixed_font_size() {
8853            let mut container: Container = html! {
8854                div sx-font-size=(10) {
8855                    "aoeu"
8856                }
8857            }
8858            .try_into()
8859            .unwrap();
8860
8861            container.calculated_width = Some(400.0);
8862            container.calculated_height = Some(100.0);
8863
8864            let calculator = Calculator::new(
8865                DefaultFontMetrics,
8866                CalculatorDefaults {
8867                    font_size: 20.0,
8868                    ..Default::default()
8869                },
8870            );
8871            calculator.calc(&mut container);
8872            log::trace!("container:\n{container}");
8873
8874            compare_containers(
8875                &container,
8876                &Container {
8877                    children: vec![Container {
8878                        children: vec![Container {
8879                            calculated_width: Some(10.0 * 4.0),
8880                            calculated_height: Some(10.0),
8881                            ..container.children[0].children[0].clone()
8882                        }],
8883                        ..container.children[0].clone()
8884                    }],
8885                    ..container.clone()
8886                },
8887            );
8888        }
8889
8890        #[test_log::test]
8891        fn does_use_direct_parent_dynamic_font_size() {
8892            let mut container: Container = html! {
8893                div sx-font-size="80%" {
8894                    "aoeu"
8895                }
8896            }
8897            .try_into()
8898            .unwrap();
8899
8900            container.calculated_width = Some(400.0);
8901            container.calculated_height = Some(100.0);
8902
8903            let calculator = Calculator::new(
8904                DefaultFontMetrics,
8905                CalculatorDefaults {
8906                    font_size: 20.0,
8907                    ..Default::default()
8908                },
8909            );
8910            calculator.calc(&mut container);
8911            log::trace!("container:\n{container}");
8912
8913            compare_containers(
8914                &container,
8915                &Container {
8916                    children: vec![Container {
8917                        children: vec![Container {
8918                            calculated_width: Some(16.0 * 4.0),
8919                            calculated_height: Some(16.0),
8920                            ..container.children[0].children[0].clone()
8921                        }],
8922                        ..container.children[0].clone()
8923                    }],
8924                    ..container.clone()
8925                },
8926            );
8927        }
8928
8929        #[test_log::test]
8930        fn does_use_ascestor_fixed_font_size() {
8931            let mut container: Container = html! {
8932                div sx-font-size=(10) {
8933                    div { "aoeu" }
8934                }
8935            }
8936            .try_into()
8937            .unwrap();
8938
8939            container.calculated_width = Some(400.0);
8940            container.calculated_height = Some(100.0);
8941
8942            let calculator = Calculator::new(
8943                DefaultFontMetrics,
8944                CalculatorDefaults {
8945                    font_size: 20.0,
8946                    ..Default::default()
8947                },
8948            );
8949            calculator.calc(&mut container);
8950            log::trace!("container:\n{container}");
8951
8952            compare_containers(
8953                &container,
8954                &Container {
8955                    children: vec![Container {
8956                        children: vec![Container {
8957                            children: vec![Container {
8958                                calculated_width: Some(10.0 * 4.0),
8959                                calculated_height: Some(10.0),
8960                                ..container.children[0].children[0].children[0].clone()
8961                            }],
8962                            ..container.children[0].children[0].clone()
8963                        }],
8964                        ..container.children[0].clone()
8965                    }],
8966                    ..container.clone()
8967                },
8968            );
8969        }
8970
8971        #[test_log::test]
8972        fn does_use_ascestor_dynamic_font_size() {
8973            let mut container: Container = html! {
8974                div sx-font-size="80%" {
8975                    div { "aoeu" }
8976                }
8977            }
8978            .try_into()
8979            .unwrap();
8980
8981            container.calculated_width = Some(400.0);
8982            container.calculated_height = Some(100.0);
8983
8984            let calculator = Calculator::new(
8985                DefaultFontMetrics,
8986                CalculatorDefaults {
8987                    font_size: 20.0,
8988                    ..Default::default()
8989                },
8990            );
8991            calculator.calc(&mut container);
8992            log::trace!("container:\n{container}");
8993
8994            compare_containers(
8995                &container,
8996                &Container {
8997                    children: vec![Container {
8998                        children: vec![Container {
8999                            children: vec![Container {
9000                                calculated_width: Some(16.0 * 4.0),
9001                                calculated_height: Some(16.0),
9002                                ..container.children[0].children[0].children[0].clone()
9003                            }],
9004                            ..container.children[0].children[0].clone()
9005                        }],
9006                        ..container.children[0].clone()
9007                    }],
9008                    ..container.clone()
9009                },
9010            );
9011        }
9012
9013        #[test_log::test]
9014        fn doesnt_use_sibling_fixed_font_size() {
9015            let mut container: Container = html! {
9016                div sx-font-size=(10) {}
9017                div { "aoeu" }
9018            }
9019            .try_into()
9020            .unwrap();
9021
9022            container.calculated_width = Some(400.0);
9023            container.calculated_height = Some(100.0);
9024
9025            let calculator = Calculator::new(
9026                DefaultFontMetrics,
9027                CalculatorDefaults {
9028                    font_size: 20.0,
9029                    ..Default::default()
9030                },
9031            );
9032            calculator.calc(&mut container);
9033            log::trace!("container:\n{container}");
9034
9035            compare_containers(
9036                &container,
9037                &Container {
9038                    children: vec![
9039                        container.children[0].clone(),
9040                        Container {
9041                            children: vec![Container {
9042                                calculated_width: Some(20.0 * 4.0),
9043                                calculated_height: Some(20.0),
9044                                ..container.children[1].children[0].clone()
9045                            }],
9046                            ..container.children[1].clone()
9047                        },
9048                    ],
9049                    ..container.clone()
9050                },
9051            );
9052        }
9053
9054        #[test_log::test]
9055        fn doesnt_use_sibling_dynamic_font_size() {
9056            let mut container: Container = html! {
9057                div sx-font-size="80%" {}
9058                div { "aoeu" }
9059            }
9060            .try_into()
9061            .unwrap();
9062
9063            container.calculated_width = Some(400.0);
9064            container.calculated_height = Some(100.0);
9065
9066            let calculator = Calculator::new(
9067                DefaultFontMetrics,
9068                CalculatorDefaults {
9069                    font_size: 20.0,
9070                    ..Default::default()
9071                },
9072            );
9073            calculator.calc(&mut container);
9074            log::trace!("container:\n{container}");
9075
9076            compare_containers(
9077                &container,
9078                &Container {
9079                    children: vec![
9080                        container.children[0].clone(),
9081                        Container {
9082                            children: vec![Container {
9083                                calculated_width: Some(20.0 * 4.0),
9084                                calculated_height: Some(20.0),
9085                                ..container.children[1].children[0].clone()
9086                            }],
9087                            ..container.children[1].clone()
9088                        },
9089                    ],
9090                    ..container.clone()
9091                },
9092            );
9093        }
9094
9095        macro_rules! test_heading {
9096            ($heading:tt, $font_size:ident, $margin_top:ident, $margin_bottom:ident $(,)?) => {
9097                paste! {
9098                    #[test_log::test]
9099                    fn [<does_use_ $heading _font_size>]() {
9100                        let mut container: Container = html! {
9101                            $heading {
9102                                "aoeu"
9103                            }
9104                        }
9105                        .try_into()
9106                        .unwrap();
9107
9108                        container.calculated_font_size = Some(20.0);
9109                        container.calculated_width = Some(400.0);
9110                        container.calculated_height = Some(100.0);
9111
9112                        let calculator = Calculator::new(
9113                            DefaultFontMetrics,
9114                            CalculatorDefaults {
9115                                font_size: 20.0,
9116                                $font_size: 30.0,
9117                                ..Default::default()
9118                            },
9119                        );
9120                        calculator.calc(&mut container);
9121                        log::trace!("container:\n{}", container);
9122
9123                        compare_containers(
9124                            &container,
9125                            &Container {
9126                                children: vec![Container {
9127                                    calculated_font_size: Some(30.0),
9128                                    ..container.children[0].clone()
9129                                }],
9130                                calculated_font_size: Some(20.0),
9131                                ..container.clone()
9132                            },
9133                        );
9134                    }
9135
9136                    #[test_log::test]
9137                    fn [<does_use_ $heading _font_size_for_raw_child>]() {
9138                        let mut container: Container = html! {
9139                            $heading {
9140                                "aoeu"
9141                            }
9142                        }
9143                        .try_into()
9144                        .unwrap();
9145
9146                        container.calculated_font_size = Some(20.0);
9147                        container.calculated_width = Some(400.0);
9148                        container.calculated_height = Some(100.0);
9149
9150                        let calculator = Calculator::new(
9151                            DefaultFontMetrics,
9152                            CalculatorDefaults {
9153                                font_size: 20.0,
9154                                $font_size: 30.0,
9155                                ..Default::default()
9156                            },
9157                        );
9158                        calculator.calc(&mut container);
9159                        log::trace!("container:\n{}", container);
9160
9161                        compare_containers(
9162                            &container,
9163                            &Container {
9164                                children: vec![Container {
9165                                    children: vec![Container {
9166                                        calculated_font_size: Some(30.0),
9167                                        ..container.children[0].children[0].clone()
9168                                    }],
9169                                    calculated_font_size: Some(30.0),
9170                                    ..container.children[0].clone()
9171                                }],
9172                                calculated_font_size: Some(20.0),
9173                                ..container.clone()
9174                            },
9175                        );
9176                    }
9177
9178                    #[test_log::test]
9179                    fn [<does_use_ $heading _font_size_for_nested_raw_child>]() {
9180                        let mut container: Container = html! {
9181                            $heading {
9182                                div {
9183                                    "aoeu"
9184                                }
9185                            }
9186                        }
9187                        .try_into()
9188                        .unwrap();
9189
9190                        container.calculated_font_size = Some(20.0);
9191                        container.calculated_width = Some(400.0);
9192                        container.calculated_height = Some(100.0);
9193
9194                        let calculator = Calculator::new(
9195                            DefaultFontMetrics,
9196                            CalculatorDefaults {
9197                                font_size: 20.0,
9198                                $font_size: 30.0,
9199                                ..Default::default()
9200                            },
9201                        );
9202                        calculator.calc(&mut container);
9203                        log::trace!("container:\n{}", container);
9204
9205                        compare_containers(
9206                            &container,
9207                            &Container {
9208                                children: vec![Container {
9209                                    children: vec![Container {
9210                                        children: vec![Container {
9211                                            calculated_font_size: Some(30.0),
9212                                            ..container.children[0].children[0].children[0].clone()
9213                                        }],
9214                                        calculated_font_size: Some(30.0),
9215                                        ..container.children[0].children[0].clone()
9216                                    }],
9217                                    calculated_font_size: Some(30.0),
9218                                    ..container.children[0].clone()
9219                                }],
9220                                calculated_font_size: Some(20.0),
9221                                ..container.clone()
9222                            },
9223                        );
9224                    }
9225
9226                    #[test_log::test]
9227                    fn [<does_use_ $margin_top>]() {
9228                        let mut container: Container = html! {
9229                            $heading {
9230                                "aoeu"
9231                            }
9232                        }
9233                        .try_into()
9234                        .unwrap();
9235
9236                        container.calculated_font_size = Some(20.0);
9237                        container.calculated_width = Some(400.0);
9238                        container.calculated_height = Some(100.0);
9239
9240                        let calculator = Calculator::new(
9241                            DefaultFontMetrics,
9242                            CalculatorDefaults {
9243                                font_size: 20.0,
9244                                $font_size: 30.0,
9245                                $margin_top: 6.0,
9246                                ..Default::default()
9247                            },
9248                        );
9249                        calculator.calc(&mut container);
9250                        log::trace!("container:\n{}", container);
9251
9252                        compare_containers(
9253                            &container,
9254                            &Container {
9255                                children: vec![Container {
9256                                    calculated_margin_top: Some(6.0),
9257                                    ..container.children[0].clone()
9258                                }],
9259                                ..container.clone()
9260                            },
9261                        );
9262                    }
9263                    #[test_log::test]
9264                    fn [<does_use_ $margin_bottom>]() {
9265                        let mut container: Container = html! {
9266                            $heading {
9267                                "aoeu"
9268                            }
9269                        }
9270                        .try_into()
9271                        .unwrap();
9272
9273                        container.calculated_font_size = Some(20.0);
9274                        container.calculated_width = Some(400.0);
9275                        container.calculated_height = Some(100.0);
9276
9277                        let calculator = Calculator::new(
9278                            DefaultFontMetrics,
9279                            CalculatorDefaults {
9280                                font_size: 20.0,
9281                                $font_size: 30.0,
9282                                $margin_bottom: 6.0,
9283                                ..Default::default()
9284                            },
9285                        );
9286                        calculator.calc(&mut container);
9287                        log::trace!("container:\n{}", container);
9288
9289                        compare_containers(
9290                            &container,
9291                            &Container {
9292                                children: vec![Container {
9293                                    calculated_margin_bottom: Some(6.0),
9294                                    ..container.children[0].clone()
9295                                }],
9296                                ..container.clone()
9297                            },
9298                        );
9299                    }
9300
9301                    #[test_log::test]
9302                    fn [<doesnt_propagate_ $margin_top _to_children>]() {
9303                        let mut container: Container = html! {
9304                            $heading {
9305                                "aoeu"
9306                            }
9307                        }
9308                        .try_into()
9309                        .unwrap();
9310
9311                        container.calculated_font_size = Some(20.0);
9312                        container.calculated_width = Some(400.0);
9313                        container.calculated_height = Some(100.0);
9314
9315                        let calculator = Calculator::new(
9316                            DefaultFontMetrics,
9317                            CalculatorDefaults {
9318                                font_size: 20.0,
9319                                $font_size: 30.0,
9320                                $margin_top: 6.0,
9321                                ..Default::default()
9322                            },
9323                        );
9324                        calculator.calc(&mut container);
9325                        log::trace!("container:\n{}", container);
9326
9327                        compare_containers(
9328                            &container,
9329                            &Container {
9330                                children: vec![Container {
9331                                    children: vec![Container {
9332                                        calculated_margin_bottom: None,
9333                                        ..container.children[0].children[0].clone()
9334                                    }],
9335                                    calculated_margin_top: Some(6.0),
9336                                    ..container.children[0].clone()
9337                                }],
9338                                ..container.clone()
9339                            },
9340                        );
9341                    }
9342
9343                    #[test_log::test]
9344                    fn [<doesnt_propagate_ $margin_bottom _to_children>]() {
9345                        let mut container: Container = html! {
9346                            $heading {
9347                                "aoeu"
9348                            }
9349                        }
9350                        .try_into()
9351                        .unwrap();
9352
9353                        container.calculated_font_size = Some(20.0);
9354                        container.calculated_width = Some(400.0);
9355                        container.calculated_height = Some(100.0);
9356
9357                        let calculator = Calculator::new(
9358                            DefaultFontMetrics,
9359                            CalculatorDefaults {
9360                                font_size: 20.0,
9361                                $font_size: 30.0,
9362                                $margin_bottom: 6.0,
9363                                ..Default::default()
9364                            },
9365                        );
9366                        calculator.calc(&mut container);
9367                        log::trace!("container:\n{}", container);
9368
9369                        compare_containers(
9370                            &container,
9371                            &Container {
9372                                children: vec![Container {
9373                                    children: vec![Container {
9374                                        calculated_margin_bottom: None,
9375                                        ..container.children[0].children[0].clone()
9376                                    }],
9377                                    calculated_margin_bottom: Some(6.0),
9378                                    ..container.children[0].clone()
9379                                }],
9380                                ..container.clone()
9381                            },
9382                        );
9383                    }
9384                }
9385            };
9386        }
9387
9388        test_heading!(h1, h1_font_size, h1_font_margin_top, h1_font_margin_bottom);
9389        test_heading!(h2, h2_font_size, h2_font_margin_top, h2_font_margin_bottom);
9390        test_heading!(h3, h3_font_size, h3_font_margin_top, h3_font_margin_bottom);
9391        test_heading!(h4, h4_font_size, h4_font_margin_top, h4_font_margin_bottom);
9392        test_heading!(h5, h5_font_size, h5_font_margin_top, h5_font_margin_bottom);
9393        test_heading!(h6, h6_font_size, h6_font_margin_top, h6_font_margin_bottom);
9394    }
9395
9396    mod sizing {
9397        use super::*;
9398
9399        #[test_log::test]
9400        fn does_take_into_account_explicit_fixed_min_width() {
9401            let mut container: Container = html! {
9402                div sx-dir=(LayoutDirection::Row) {
9403                    div sx-min-width=(100) {}
9404                }
9405            }
9406            .try_into()
9407            .unwrap();
9408
9409            container.calculated_width = Some(400.0);
9410            container.calculated_height = Some(100.0);
9411
9412            CALCULATOR.calc(&mut container);
9413            log::trace!("full container:\n{container}");
9414            container = container.children[0].clone();
9415            log::trace!("container:\n{container}");
9416
9417            compare_containers(
9418                &container,
9419                &Container {
9420                    children: vec![Container {
9421                        calculated_width: Some(100.0),
9422                        ..container.children[0].clone()
9423                    }],
9424                    calculated_width: Some(400.0),
9425                    ..container.clone()
9426                },
9427            );
9428        }
9429
9430        #[test_log::test]
9431        fn does_take_into_account_explicit_fixed_min_width_with_fixed_child_content() {
9432            let mut container: Container = html! {
9433                div sx-dir=(LayoutDirection::Row) {
9434                    div sx-min-width=(100) {
9435                        div sx-width=(10) {}
9436                    }
9437                }
9438            }
9439            .try_into()
9440            .unwrap();
9441
9442            container.calculated_width = Some(400.0);
9443            container.calculated_height = Some(100.0);
9444
9445            CALCULATOR.calc(&mut container);
9446            log::trace!("full container:\n{container}");
9447            container = container.children[0].clone();
9448            log::trace!("container:\n{container}");
9449
9450            compare_containers(
9451                &container,
9452                &Container {
9453                    children: vec![Container {
9454                        calculated_width: Some(100.0),
9455                        ..container.children[0].clone()
9456                    }],
9457                    calculated_width: Some(400.0),
9458                    ..container.clone()
9459                },
9460            );
9461        }
9462
9463        #[test_log::test]
9464        fn does_take_into_account_explicit_fixed_min_height() {
9465            let mut container: Container = html! {
9466                div sx-dir=(LayoutDirection::Column) sx-height="100%" {
9467                    div sx-min-height=(100) {}
9468                }
9469            }
9470            .try_into()
9471            .unwrap();
9472
9473            container.calculated_width = Some(100.0);
9474            container.calculated_height = Some(400.0);
9475
9476            CALCULATOR.calc(&mut container);
9477            log::trace!("full container:\n{container}");
9478            container = container.children[0].clone();
9479            log::trace!("container:\n{container}");
9480
9481            compare_containers(
9482                &container,
9483                &Container {
9484                    children: vec![Container {
9485                        calculated_height: Some(100.0),
9486                        ..container.children[0].clone()
9487                    }],
9488                    calculated_height: Some(400.0),
9489                    ..container.clone()
9490                },
9491            );
9492        }
9493
9494        #[test_log::test]
9495        fn does_take_into_account_explicit_fixed_min_height_with_fixed_child_content() {
9496            let mut container: Container = html! {
9497                div sx-dir=(LayoutDirection::Column) sx-height="100%" {
9498                    div sx-min-height=(100) {
9499                        div sx-height=(10) {}
9500                    }
9501                }
9502            }
9503            .try_into()
9504            .unwrap();
9505
9506            container.calculated_width = Some(100.0);
9507            container.calculated_height = Some(400.0);
9508
9509            CALCULATOR.calc(&mut container);
9510            log::trace!("full container:\n{container}");
9511            container = container.children[0].clone();
9512            log::trace!("container:\n{container}");
9513
9514            compare_containers(
9515                &container,
9516                &Container {
9517                    children: vec![Container {
9518                        calculated_height: Some(100.0),
9519                        ..container.children[0].clone()
9520                    }],
9521                    calculated_height: Some(400.0),
9522                    ..container.clone()
9523                },
9524            );
9525        }
9526
9527        #[test_log::test]
9528        fn does_take_into_account_explicit_dynamic_min_width() {
9529            let mut container: Container = html! {
9530                div sx-dir=(LayoutDirection::Row) {
9531                    div sx-min-width="50%" {}
9532                }
9533            }
9534            .try_into()
9535            .unwrap();
9536
9537            container.calculated_width = Some(400.0);
9538            container.calculated_height = Some(100.0);
9539
9540            CALCULATOR.calc(&mut container);
9541            log::trace!("full container:\n{container}");
9542            container = container.children[0].clone();
9543            log::trace!("container:\n{container}");
9544
9545            compare_containers(
9546                &container,
9547                &Container {
9548                    children: vec![Container {
9549                        calculated_width: Some(200.0),
9550                        ..container.children[0].clone()
9551                    }],
9552                    calculated_width: Some(400.0),
9553                    ..container.clone()
9554                },
9555            );
9556        }
9557
9558        #[test_log::test]
9559        fn does_take_into_account_explicit_dynamic_min_width_with_fixed_child_content() {
9560            let mut container: Container = html! {
9561                div sx-dir=(LayoutDirection::Row) {
9562                    div sx-min-width="50%" {
9563                        div sx-width=(10) {}
9564                    }
9565                }
9566            }
9567            .try_into()
9568            .unwrap();
9569
9570            container.calculated_width = Some(400.0);
9571            container.calculated_height = Some(100.0);
9572
9573            CALCULATOR.calc(&mut container);
9574            log::trace!("full container:\n{container}");
9575            container = container.children[0].clone();
9576            log::trace!("container:\n{container}");
9577
9578            compare_containers(
9579                &container,
9580                &Container {
9581                    children: vec![Container {
9582                        calculated_width: Some(200.0),
9583                        ..container.children[0].clone()
9584                    }],
9585                    calculated_width: Some(400.0),
9586                    ..container.clone()
9587                },
9588            );
9589        }
9590
9591        #[test_log::test]
9592        fn does_take_into_account_explicit_dynamic_min_height() {
9593            let mut container: Container = html! {
9594                div sx-dir=(LayoutDirection::Column) sx-height="100%" {
9595                    div sx-min-height="50%" {}
9596                }
9597            }
9598            .try_into()
9599            .unwrap();
9600
9601            container.calculated_width = Some(100.0);
9602            container.calculated_height = Some(400.0);
9603
9604            CALCULATOR.calc(&mut container);
9605            log::trace!("full container:\n{container}");
9606            container = container.children[0].clone();
9607            log::trace!("container:\n{container}");
9608
9609            compare_containers(
9610                &container,
9611                &Container {
9612                    children: vec![Container {
9613                        calculated_height: Some(200.0),
9614                        ..container.children[0].clone()
9615                    }],
9616                    calculated_height: Some(400.0),
9617                    ..container.clone()
9618                },
9619            );
9620        }
9621
9622        #[test_log::test]
9623        fn does_take_into_account_explicit_dynamic_min_height_with_fixed_child_content() {
9624            let mut container: Container = html! {
9625                div sx-dir=(LayoutDirection::Column) sx-height="100%" {
9626                    div sx-min-height="50%" {
9627                        div sx-height=(10) {}
9628                    }
9629                }
9630            }
9631            .try_into()
9632            .unwrap();
9633
9634            container.calculated_width = Some(100.0);
9635            container.calculated_height = Some(400.0);
9636
9637            CALCULATOR.calc(&mut container);
9638            log::trace!("full container:\n{container}");
9639            container = container.children[0].clone();
9640            log::trace!("container:\n{container}");
9641
9642            compare_containers(
9643                &container,
9644                &Container {
9645                    children: vec![Container {
9646                        calculated_height: Some(200.0),
9647                        ..container.children[0].clone()
9648                    }],
9649                    calculated_height: Some(400.0),
9650                    ..container.clone()
9651                },
9652            );
9653        }
9654
9655        #[test_log::test]
9656        fn does_take_into_account_explicit_fixed_max_width() {
9657            let mut container: Container = html! {
9658                div sx-dir=(LayoutDirection::Column) {
9659                    div sx-max-width=(100) {}
9660                }
9661            }
9662            .try_into()
9663            .unwrap();
9664
9665            container.calculated_width = Some(400.0);
9666            container.calculated_height = Some(100.0);
9667
9668            CALCULATOR.calc(&mut container);
9669            log::trace!("full container:\n{container}");
9670            container = container.children[0].clone();
9671            log::trace!("container:\n{container}");
9672
9673            compare_containers(
9674                &container,
9675                &Container {
9676                    children: vec![Container {
9677                        calculated_width: Some(100.0),
9678                        ..container.children[0].clone()
9679                    }],
9680                    calculated_width: Some(400.0),
9681                    ..container.clone()
9682                },
9683            );
9684        }
9685
9686        #[test_log::test]
9687        fn does_take_into_account_explicit_fixed_max_width_with_fixed_child_content() {
9688            let mut container: Container = html! {
9689                div sx-dir=(LayoutDirection::Column) {
9690                    div sx-max-width=(100) {
9691                        div sx-width=(200) {}
9692                    }
9693                }
9694            }
9695            .try_into()
9696            .unwrap();
9697
9698            container.calculated_width = Some(400.0);
9699            container.calculated_height = Some(100.0);
9700
9701            CALCULATOR.calc(&mut container);
9702            log::trace!("full container:\n{container}");
9703            container = container.children[0].clone();
9704            log::trace!("container:\n{container}");
9705
9706            compare_containers(
9707                &container,
9708                &Container {
9709                    children: vec![Container {
9710                        calculated_width: Some(100.0),
9711                        ..container.children[0].clone()
9712                    }],
9713                    calculated_width: Some(400.0),
9714                    ..container.clone()
9715                },
9716            );
9717        }
9718
9719        #[test_log::test]
9720        fn does_take_into_account_explicit_fixed_max_height() {
9721            let mut container: Container = html! {
9722                div sx-dir=(LayoutDirection::Row) sx-height="100%" {
9723                    div sx-max-height=(100) {}
9724                }
9725            }
9726            .try_into()
9727            .unwrap();
9728
9729            container.calculated_width = Some(100.0);
9730            container.calculated_height = Some(400.0);
9731
9732            CALCULATOR.calc(&mut container);
9733            log::trace!("full container:\n{container}");
9734            container = container.children[0].clone();
9735            log::trace!("container:\n{container}");
9736
9737            compare_containers(
9738                &container,
9739                &Container {
9740                    children: vec![Container {
9741                        calculated_height: Some(100.0),
9742                        ..container.children[0].clone()
9743                    }],
9744                    calculated_height: Some(400.0),
9745                    ..container.clone()
9746                },
9747            );
9748        }
9749
9750        #[test_log::test]
9751        fn does_take_into_account_explicit_fixed_max_height_with_fixed_child_content() {
9752            let mut container: Container = html! {
9753                div sx-dir=(LayoutDirection::Row) sx-height="100%" {
9754                    div sx-max-height=(100) {
9755                        div sx-height=(200) {}
9756                    }
9757                }
9758            }
9759            .try_into()
9760            .unwrap();
9761
9762            container.calculated_width = Some(100.0);
9763            container.calculated_height = Some(400.0);
9764
9765            CALCULATOR.calc(&mut container);
9766            log::trace!("full container:\n{container}");
9767            container = container.children[0].clone();
9768            log::trace!("container:\n{container}");
9769
9770            compare_containers(
9771                &container,
9772                &Container {
9773                    children: vec![Container {
9774                        calculated_height: Some(100.0),
9775                        ..container.children[0].clone()
9776                    }],
9777                    calculated_height: Some(400.0),
9778                    ..container.clone()
9779                },
9780            );
9781        }
9782
9783        #[test_log::test]
9784        fn does_take_into_account_explicit_dynamic_max_width() {
9785            let mut container: Container = html! {
9786                div sx-dir=(LayoutDirection::Column) {
9787                    div sx-max-width="50%" {}
9788                }
9789            }
9790            .try_into()
9791            .unwrap();
9792
9793            container.calculated_width = Some(400.0);
9794            container.calculated_height = Some(100.0);
9795
9796            CALCULATOR.calc(&mut container);
9797            log::trace!("full container:\n{container}");
9798            container = container.children[0].clone();
9799            log::trace!("container:\n{container}");
9800
9801            compare_containers(
9802                &container,
9803                &Container {
9804                    children: vec![Container {
9805                        calculated_width: Some(200.0),
9806                        ..container.children[0].clone()
9807                    }],
9808                    calculated_width: Some(400.0),
9809                    ..container.clone()
9810                },
9811            );
9812        }
9813
9814        #[test_log::test]
9815        fn does_take_into_account_explicit_dynamic_max_width_with_fixed_child_content() {
9816            let mut container: Container = html! {
9817                div sx-dir=(LayoutDirection::Column) {
9818                    div sx-max-width="50%" {
9819                        div sx-width=(300) {}
9820                    }
9821                }
9822            }
9823            .try_into()
9824            .unwrap();
9825
9826            container.calculated_width = Some(400.0);
9827            container.calculated_height = Some(100.0);
9828
9829            CALCULATOR.calc(&mut container);
9830            log::trace!("full container:\n{container}");
9831            container = container.children[0].clone();
9832            log::trace!("container:\n{container}");
9833
9834            compare_containers(
9835                &container,
9836                &Container {
9837                    children: vec![Container {
9838                        calculated_width: Some(200.0),
9839                        ..container.children[0].clone()
9840                    }],
9841                    calculated_width: Some(400.0),
9842                    ..container.clone()
9843                },
9844            );
9845        }
9846
9847        #[test_log::test]
9848        fn does_take_into_account_explicit_dynamic_max_height() {
9849            let mut container: Container = html! {
9850                div sx-dir=(LayoutDirection::Row) sx-height="100%" {
9851                    div sx-max-height="50%" {}
9852                }
9853            }
9854            .try_into()
9855            .unwrap();
9856
9857            container.calculated_width = Some(100.0);
9858            container.calculated_height = Some(400.0);
9859
9860            CALCULATOR.calc(&mut container);
9861            log::trace!("full container:\n{container}");
9862            container = container.children[0].clone();
9863            log::trace!("container:\n{container}");
9864
9865            compare_containers(
9866                &container,
9867                &Container {
9868                    children: vec![Container {
9869                        calculated_height: Some(200.0),
9870                        ..container.children[0].clone()
9871                    }],
9872                    calculated_height: Some(400.0),
9873                    ..container.clone()
9874                },
9875            );
9876        }
9877
9878        #[test_log::test]
9879        fn does_take_into_account_explicit_dynamic_max_height_with_fixed_child_content() {
9880            let mut container: Container = html! {
9881                div sx-dir=(LayoutDirection::Row) sx-height="100%" {
9882                    div sx-max-height="50%" {
9883                        div sx-height=(300) {}
9884                    }
9885                }
9886            }
9887            .try_into()
9888            .unwrap();
9889
9890            container.calculated_width = Some(100.0);
9891            container.calculated_height = Some(400.0);
9892
9893            CALCULATOR.calc(&mut container);
9894            log::trace!("full container:\n{container}");
9895            container = container.children[0].clone();
9896            log::trace!("container:\n{container}");
9897
9898            compare_containers(
9899                &container,
9900                &Container {
9901                    children: vec![Container {
9902                        calculated_height: Some(200.0),
9903                        ..container.children[0].clone()
9904                    }],
9905                    calculated_height: Some(400.0),
9906                    ..container.clone()
9907                },
9908            );
9909        }
9910
9911        #[test_log::test]
9912        fn does_prioritize_explicit_fixed_min_width_and_max_fixed_width() {
9913            let mut container: Container = html! {
9914                div sx-dir=(LayoutDirection::Row) {
9915                    div sx-min-width=(100) sx-max-width=(90) {}
9916                }
9917            }
9918            .try_into()
9919            .unwrap();
9920
9921            container.calculated_width = Some(400.0);
9922            container.calculated_height = Some(100.0);
9923
9924            CALCULATOR.calc(&mut container);
9925            log::trace!("full container:\n{container}");
9926            container = container.children[0].clone();
9927            log::trace!("container:\n{container}");
9928
9929            compare_containers(
9930                &container,
9931                &Container {
9932                    children: vec![Container {
9933                        calculated_width: Some(100.0),
9934                        ..container.children[0].clone()
9935                    }],
9936                    calculated_width: Some(400.0),
9937                    ..container.clone()
9938                },
9939            );
9940        }
9941
9942        #[test_log::test]
9943        fn does_prioritize_explicit_fixed_min_width_and_max_fixed_width_with_fixed_child_content() {
9944            let mut container: Container = html! {
9945                div sx-dir=(LayoutDirection::Row) {
9946                    div sx-min-width=(100) sx-max-width=(90) {
9947                        div sx-width=(10) {}
9948                    }
9949                }
9950            }
9951            .try_into()
9952            .unwrap();
9953
9954            container.calculated_width = Some(400.0);
9955            container.calculated_height = Some(100.0);
9956
9957            CALCULATOR.calc(&mut container);
9958            log::trace!("full container:\n{container}");
9959            container = container.children[0].clone();
9960            log::trace!("container:\n{container}");
9961
9962            compare_containers(
9963                &container,
9964                &Container {
9965                    children: vec![Container {
9966                        calculated_width: Some(100.0),
9967                        ..container.children[0].clone()
9968                    }],
9969                    calculated_width: Some(400.0),
9970                    ..container.clone()
9971                },
9972            );
9973        }
9974
9975        #[test_log::test]
9976        fn does_prioritize_explicit_fixed_min_height_and_max_fixed_height() {
9977            let mut container: Container = html! {
9978                div sx-dir=(LayoutDirection::Column) sx-height="100%" {
9979                    div sx-min-height=(100) sx-max-height=(90) {}
9980                }
9981            }
9982            .try_into()
9983            .unwrap();
9984
9985            container.calculated_width = Some(100.0);
9986            container.calculated_height = Some(400.0);
9987
9988            CALCULATOR.calc(&mut container);
9989            log::trace!("full container:\n{container}");
9990            container = container.children[0].clone();
9991            log::trace!("container:\n{container}");
9992
9993            compare_containers(
9994                &container,
9995                &Container {
9996                    children: vec![Container {
9997                        calculated_height: Some(100.0),
9998                        ..container.children[0].clone()
9999                    }],
10000                    calculated_height: Some(400.0),
10001                    ..container.clone()
10002                },
10003            );
10004        }
10005
10006        #[test_log::test]
10007        fn does_prioritize_explicit_fixed_min_height_and_max_fixed_height_with_fixed_child_content()
10008        {
10009            let mut container: Container = html! {
10010                div sx-dir=(LayoutDirection::Column) sx-height="100%" {
10011                    div sx-min-height=(100) sx-max-height=(90) {
10012                        div sx-height=(10) {}
10013                    }
10014                }
10015            }
10016            .try_into()
10017            .unwrap();
10018
10019            container.calculated_width = Some(100.0);
10020            container.calculated_height = Some(400.0);
10021
10022            CALCULATOR.calc(&mut container);
10023            log::trace!("full container:\n{container}");
10024            container = container.children[0].clone();
10025            log::trace!("container:\n{container}");
10026
10027            compare_containers(
10028                &container,
10029                &Container {
10030                    children: vec![Container {
10031                        calculated_height: Some(100.0),
10032                        ..container.children[0].clone()
10033                    }],
10034                    calculated_height: Some(400.0),
10035                    ..container.clone()
10036                },
10037            );
10038        }
10039
10040        #[test_log::test]
10041        fn does_prioritize_explicit_dynamic_min_width_and_max_fixed_width() {
10042            let mut container: Container = html! {
10043                div sx-dir=(LayoutDirection::Row) {
10044                    div sx-min-width="50%" sx-max-width=(90) {}
10045                }
10046            }
10047            .try_into()
10048            .unwrap();
10049
10050            container.calculated_width = Some(400.0);
10051            container.calculated_height = Some(100.0);
10052
10053            CALCULATOR.calc(&mut container);
10054            log::trace!("full container:\n{container}");
10055            container = container.children[0].clone();
10056            log::trace!("container:\n{container}");
10057
10058            compare_containers(
10059                &container,
10060                &Container {
10061                    children: vec![Container {
10062                        calculated_width: Some(200.0),
10063                        ..container.children[0].clone()
10064                    }],
10065                    calculated_width: Some(400.0),
10066                    ..container.clone()
10067                },
10068            );
10069        }
10070
10071        #[test_log::test]
10072        fn does_prioritize_explicit_dynamic_min_width_and_max_fixed_width_with_fixed_child_content()
10073        {
10074            let mut container: Container = html! {
10075                div sx-dir=(LayoutDirection::Row) {
10076                    div sx-min-width="50%" sx-max-width=(90) {
10077                        div sx-width=(10) {}
10078                    }
10079                }
10080            }
10081            .try_into()
10082            .unwrap();
10083
10084            container.calculated_width = Some(400.0);
10085            container.calculated_height = Some(100.0);
10086
10087            CALCULATOR.calc(&mut container);
10088            log::trace!("full container:\n{container}");
10089            container = container.children[0].clone();
10090            log::trace!("container:\n{container}");
10091
10092            compare_containers(
10093                &container,
10094                &Container {
10095                    children: vec![Container {
10096                        calculated_width: Some(200.0),
10097                        ..container.children[0].clone()
10098                    }],
10099                    calculated_width: Some(400.0),
10100                    ..container.clone()
10101                },
10102            );
10103        }
10104
10105        #[test_log::test]
10106        fn does_prioritize_explicit_dynamic_min_height_and_max_fixed_height() {
10107            let mut container: Container = html! {
10108                div sx-dir=(LayoutDirection::Column) sx-height="100%" {
10109                    div sx-min-height="50%" sx-max-height=(90) {}
10110                }
10111            }
10112            .try_into()
10113            .unwrap();
10114
10115            container.calculated_width = Some(100.0);
10116            container.calculated_height = Some(400.0);
10117
10118            CALCULATOR.calc(&mut container);
10119            log::trace!("full container:\n{container}");
10120            container = container.children[0].clone();
10121            log::trace!("container:\n{container}");
10122
10123            compare_containers(
10124                &container,
10125                &Container {
10126                    children: vec![Container {
10127                        calculated_height: Some(200.0),
10128                        ..container.children[0].clone()
10129                    }],
10130                    calculated_height: Some(400.0),
10131                    ..container.clone()
10132                },
10133            );
10134        }
10135
10136        #[test_log::test]
10137        fn does_prioritize_explicit_dynamic_min_height_and_max_fixed_height_with_fixed_child_content()
10138         {
10139            let mut container: Container = html! {
10140                div sx-dir=(LayoutDirection::Column) sx-height="100%" {
10141                    div sx-min-height="50%" sx-max-height=(90) {
10142                        div sx-height=(10) {}
10143                    }
10144                }
10145            }
10146            .try_into()
10147            .unwrap();
10148
10149            container.calculated_width = Some(100.0);
10150            container.calculated_height = Some(400.0);
10151
10152            CALCULATOR.calc(&mut container);
10153            log::trace!("full container:\n{container}");
10154            container = container.children[0].clone();
10155            log::trace!("container:\n{container}");
10156
10157            compare_containers(
10158                &container,
10159                &Container {
10160                    children: vec![Container {
10161                        calculated_height: Some(200.0),
10162                        ..container.children[0].clone()
10163                    }],
10164                    calculated_height: Some(400.0),
10165                    ..container.clone()
10166                },
10167            );
10168        }
10169
10170        #[test_log::test]
10171        fn does_prioritize_explicit_fixed_min_width_and_max_dynamic_width() {
10172            let mut container: Container = html! {
10173                div sx-dir=(LayoutDirection::Row) {
10174                    div sx-min-width=(100) sx-max-width="0%" {}
10175                }
10176            }
10177            .try_into()
10178            .unwrap();
10179
10180            container.calculated_width = Some(400.0);
10181            container.calculated_height = Some(100.0);
10182
10183            CALCULATOR.calc(&mut container);
10184            log::trace!("full container:\n{container}");
10185            container = container.children[0].clone();
10186            log::trace!("container:\n{container}");
10187
10188            compare_containers(
10189                &container,
10190                &Container {
10191                    children: vec![Container {
10192                        calculated_width: Some(100.0),
10193                        ..container.children[0].clone()
10194                    }],
10195                    calculated_width: Some(400.0),
10196                    ..container.clone()
10197                },
10198            );
10199        }
10200
10201        #[test_log::test]
10202        fn does_prioritize_explicit_fixed_min_width_and_max_dynamic_width_with_fixed_child_content()
10203        {
10204            let mut container: Container = html! {
10205                div sx-dir=(LayoutDirection::Row) {
10206                    div sx-min-width=(100) sx-max-width="0%" {
10207                        div sx-width=(10) {}
10208                    }
10209                }
10210            }
10211            .try_into()
10212            .unwrap();
10213
10214            container.calculated_width = Some(400.0);
10215            container.calculated_height = Some(100.0);
10216
10217            CALCULATOR.calc(&mut container);
10218            log::trace!("full container:\n{container}");
10219            container = container.children[0].clone();
10220            log::trace!("container:\n{container}");
10221
10222            compare_containers(
10223                &container,
10224                &Container {
10225                    children: vec![Container {
10226                        calculated_width: Some(100.0),
10227                        ..container.children[0].clone()
10228                    }],
10229                    calculated_width: Some(400.0),
10230                    ..container.clone()
10231                },
10232            );
10233        }
10234
10235        #[test_log::test]
10236        fn does_prioritize_explicit_fixed_min_height_and_max_dynamic_height() {
10237            let mut container: Container = html! {
10238                div sx-dir=(LayoutDirection::Column) sx-height="100%" {
10239                    div sx-min-height=(100) sx-max-height="0%" {}
10240                }
10241            }
10242            .try_into()
10243            .unwrap();
10244
10245            container.calculated_width = Some(100.0);
10246            container.calculated_height = Some(400.0);
10247
10248            CALCULATOR.calc(&mut container);
10249            log::trace!("full container:\n{container}");
10250            container = container.children[0].clone();
10251            log::trace!("container:\n{container}");
10252
10253            compare_containers(
10254                &container,
10255                &Container {
10256                    children: vec![Container {
10257                        calculated_height: Some(100.0),
10258                        ..container.children[0].clone()
10259                    }],
10260                    calculated_height: Some(400.0),
10261                    ..container.clone()
10262                },
10263            );
10264        }
10265
10266        #[test_log::test]
10267        fn does_prioritize_explicit_fixed_min_height_and_max_dynamic_height_with_fixed_child_content()
10268         {
10269            let mut container: Container = html! {
10270                div sx-dir=(LayoutDirection::Column) sx-height="100%" {
10271                    div sx-min-height=(100) sx-max-height="0%" {
10272                        div sx-height=(10) {}
10273                    }
10274                }
10275            }
10276            .try_into()
10277            .unwrap();
10278
10279            container.calculated_width = Some(100.0);
10280            container.calculated_height = Some(400.0);
10281
10282            CALCULATOR.calc(&mut container);
10283            log::trace!("full container:\n{container}");
10284            container = container.children[0].clone();
10285            log::trace!("container:\n{container}");
10286
10287            compare_containers(
10288                &container,
10289                &Container {
10290                    children: vec![Container {
10291                        calculated_height: Some(100.0),
10292                        ..container.children[0].clone()
10293                    }],
10294                    calculated_height: Some(400.0),
10295                    ..container.clone()
10296                },
10297            );
10298        }
10299
10300        #[test_log::test]
10301        fn does_prioritize_explicit_dynamic_min_width_and_max_dynamic_width() {
10302            let mut container: Container = html! {
10303                div sx-dir=(LayoutDirection::Row) {
10304                    div sx-min-width="50%" sx-max-width="0%" {}
10305                }
10306            }
10307            .try_into()
10308            .unwrap();
10309
10310            container.calculated_width = Some(400.0);
10311            container.calculated_height = Some(100.0);
10312
10313            CALCULATOR.calc(&mut container);
10314            log::trace!("full container:\n{container}");
10315            container = container.children[0].clone();
10316            log::trace!("container:\n{container}");
10317
10318            compare_containers(
10319                &container,
10320                &Container {
10321                    children: vec![Container {
10322                        calculated_width: Some(200.0),
10323                        ..container.children[0].clone()
10324                    }],
10325                    calculated_width: Some(400.0),
10326                    ..container.clone()
10327                },
10328            );
10329        }
10330
10331        #[test_log::test]
10332        fn does_prioritize_explicit_dynamic_min_width_and_max_dynamic_width_with_fixed_child_content()
10333         {
10334            let mut container: Container = html! {
10335                div sx-dir=(LayoutDirection::Row) {
10336                    div sx-min-width="50%" sx-max-width="0%" {
10337                        div sx-width=(10) {}
10338                    }
10339                }
10340            }
10341            .try_into()
10342            .unwrap();
10343
10344            container.calculated_width = Some(400.0);
10345            container.calculated_height = Some(100.0);
10346
10347            CALCULATOR.calc(&mut container);
10348            log::trace!("full container:\n{container}");
10349            container = container.children[0].clone();
10350            log::trace!("container:\n{container}");
10351
10352            compare_containers(
10353                &container,
10354                &Container {
10355                    children: vec![Container {
10356                        calculated_width: Some(200.0),
10357                        ..container.children[0].clone()
10358                    }],
10359                    calculated_width: Some(400.0),
10360                    ..container.clone()
10361                },
10362            );
10363        }
10364
10365        #[test_log::test]
10366        fn does_prioritize_explicit_dynamic_min_height_and_max_dynamic_height() {
10367            let mut container: Container = html! {
10368                div sx-dir=(LayoutDirection::Column) sx-height="100%" {
10369                    div sx-min-height="50%" sx-max-height="0%" {}
10370                }
10371            }
10372            .try_into()
10373            .unwrap();
10374
10375            container.calculated_width = Some(100.0);
10376            container.calculated_height = Some(400.0);
10377
10378            CALCULATOR.calc(&mut container);
10379            log::trace!("full container:\n{container}");
10380            container = container.children[0].clone();
10381            log::trace!("container:\n{container}");
10382
10383            compare_containers(
10384                &container,
10385                &Container {
10386                    children: vec![Container {
10387                        calculated_height: Some(200.0),
10388                        ..container.children[0].clone()
10389                    }],
10390                    calculated_height: Some(400.0),
10391                    ..container.clone()
10392                },
10393            );
10394        }
10395
10396        #[test_log::test]
10397        fn does_prioritize_explicit_dynamic_min_height_and_max_dynamic_height_with_fixed_child_content()
10398         {
10399            let mut container: Container = html! {
10400                div sx-dir=(LayoutDirection::Column) sx-height="100%" {
10401                    div sx-min-height="50%" sx-max-height="0%" {
10402                        div sx-height=(10) {}
10403                    }
10404                }
10405            }
10406            .try_into()
10407            .unwrap();
10408
10409            container.calculated_width = Some(100.0);
10410            container.calculated_height = Some(400.0);
10411
10412            CALCULATOR.calc(&mut container);
10413            log::trace!("full container:\n{container}");
10414            container = container.children[0].clone();
10415            log::trace!("container:\n{container}");
10416
10417            compare_containers(
10418                &container,
10419                &Container {
10420                    children: vec![Container {
10421                        calculated_height: Some(200.0),
10422                        ..container.children[0].clone()
10423                    }],
10424                    calculated_height: Some(400.0),
10425                    ..container.clone()
10426                },
10427            );
10428        }
10429
10430        #[test_log::test]
10431        fn does_include_margin_top_in_parent_height() {
10432            let mut container: Container = html! {
10433                div sx-dir=(LayoutDirection::Column) {
10434                    div sx-margin-top=(5) sx-height=(10) {}
10435                }
10436            }
10437            .try_into()
10438            .unwrap();
10439
10440            container.direction = LayoutDirection::Column;
10441            container.calculated_width = Some(100.0);
10442            container.calculated_height = Some(400.0);
10443
10444            CALCULATOR.calc(&mut container);
10445            log::trace!("container:\n{container}");
10446
10447            compare_containers(
10448                &container,
10449                &Container {
10450                    children: vec![Container {
10451                        children: vec![Container {
10452                            calculated_height: Some(10.0),
10453                            ..container.children[0].children[0].clone()
10454                        }],
10455                        calculated_height: Some(15.0),
10456                        ..container.children[0].clone()
10457                    }],
10458                    calculated_height: Some(400.0),
10459                    ..container.clone()
10460                },
10461            );
10462        }
10463
10464        #[test_log::test]
10465        fn does_include_margin_bottom_in_parent_height() {
10466            let mut container: Container = html! {
10467                div sx-dir=(LayoutDirection::Column) {
10468                    div sx-margin-bottom=(5) sx-height=(10) {}
10469                }
10470            }
10471            .try_into()
10472            .unwrap();
10473
10474            container.direction = LayoutDirection::Column;
10475            container.calculated_width = Some(100.0);
10476            container.calculated_height = Some(400.0);
10477
10478            CALCULATOR.calc(&mut container);
10479            log::trace!("container:\n{container}");
10480
10481            compare_containers(
10482                &container,
10483                &Container {
10484                    children: vec![Container {
10485                        children: vec![Container {
10486                            calculated_height: Some(10.0),
10487                            ..container.children[0].children[0].clone()
10488                        }],
10489                        calculated_height: Some(15.0),
10490                        ..container.children[0].clone()
10491                    }],
10492                    calculated_height: Some(400.0),
10493                    ..container.clone()
10494                },
10495            );
10496        }
10497
10498        #[test_log::test]
10499        fn does_include_margin_left_in_parent_width() {
10500            let mut container: Container = html! {
10501                div sx-dir=(LayoutDirection::Row) {
10502                    div sx-margin-left=(5) sx-width=(10) {}
10503                }
10504            }
10505            .try_into()
10506            .unwrap();
10507
10508            container.direction = LayoutDirection::Row;
10509            container.calculated_width = Some(400.0);
10510            container.calculated_height = Some(100.0);
10511
10512            CALCULATOR.calc(&mut container);
10513            log::trace!("container:\n{container}");
10514
10515            compare_containers(
10516                &container,
10517                &Container {
10518                    children: vec![Container {
10519                        children: vec![Container {
10520                            calculated_width: Some(10.0),
10521                            ..container.children[0].children[0].clone()
10522                        }],
10523                        calculated_width: Some(15.0),
10524                        ..container.children[0].clone()
10525                    }],
10526                    calculated_width: Some(400.0),
10527                    ..container.clone()
10528                },
10529            );
10530        }
10531
10532        #[test_log::test]
10533        fn does_include_margin_right_in_parent_width() {
10534            let mut container: Container = html! {
10535                div sx-dir=(LayoutDirection::Row) {
10536                    div sx-margin-right=(5) sx-width=(10) {}
10537                }
10538            }
10539            .try_into()
10540            .unwrap();
10541
10542            container.direction = LayoutDirection::Row;
10543            container.calculated_width = Some(400.0);
10544            container.calculated_height = Some(100.0);
10545
10546            CALCULATOR.calc(&mut container);
10547            log::trace!("container:\n{container}");
10548
10549            compare_containers(
10550                &container,
10551                &Container {
10552                    children: vec![Container {
10553                        children: vec![Container {
10554                            calculated_width: Some(10.0),
10555                            ..container.children[0].children[0].clone()
10556                        }],
10557                        calculated_width: Some(15.0),
10558                        ..container.children[0].clone()
10559                    }],
10560                    calculated_width: Some(400.0),
10561                    ..container.clone()
10562                },
10563            );
10564        }
10565
10566        #[test_log::test]
10567        #[ignore]
10568        fn flex_child_does_take_full_width_if_flex_is_specified() {
10569            let mut container: Container = html! {
10570                div sx-width="100%" sx-dir=(LayoutDirection::Row) {
10571                    div flex=(1) {}
10572                }
10573            }
10574            .try_into()
10575            .unwrap();
10576
10577            container.calculated_width = Some(400.0);
10578            container.calculated_height = Some(100.0);
10579
10580            CALCULATOR.calc(&mut container);
10581            log::trace!("container:\n{container}");
10582
10583            compare_containers(
10584                &container,
10585                &Container {
10586                    children: vec![Container {
10587                        children: vec![Container {
10588                            calculated_width: Some(400.0),
10589                            ..container.children[0].children[0].clone()
10590                        }],
10591                        calculated_width: Some(400.0),
10592                        ..container.children[0].clone()
10593                    }],
10594                    calculated_width: Some(400.0),
10595                    ..container.clone()
10596                },
10597            );
10598        }
10599    }
10600
10601    mod position_sticky {
10602        use super::*;
10603
10604        #[test_log::test]
10605        fn does_include_size_in_parent_width() {
10606            let mut container: Container = html! {
10607                div {
10608                    div sx-position=(Position::Sticky) sx-width=(100) {}
10609                }
10610            }
10611            .try_into()
10612            .unwrap();
10613
10614            container.direction = LayoutDirection::Row;
10615            container.calculated_width = Some(400.0);
10616            container.calculated_height = Some(100.0);
10617
10618            CALCULATOR.calc(&mut container);
10619            log::trace!("container:\n{container}");
10620
10621            compare_containers(
10622                &container,
10623                &Container {
10624                    children: vec![Container {
10625                        children: vec![Container {
10626                            calculated_width: Some(100.0),
10627                            ..container.children[0].children[0].clone()
10628                        }],
10629                        calculated_width: Some(100.0),
10630                        ..container.children[0].clone()
10631                    }],
10632                    ..container.clone()
10633                },
10634            );
10635        }
10636
10637        #[test_log::test]
10638        fn does_include_size_in_parent_height() {
10639            let mut container: Container = html! {
10640                div {
10641                    div sx-position=(Position::Sticky) sx-height=(100) {}
10642                }
10643            }
10644            .try_into()
10645            .unwrap();
10646
10647            container.direction = LayoutDirection::Column;
10648            container.calculated_width = Some(400.0);
10649            container.calculated_height = Some(200.0);
10650
10651            CALCULATOR.calc(&mut container);
10652            log::trace!("container:\n{container}");
10653
10654            compare_containers(
10655                &container,
10656                &Container {
10657                    children: vec![Container {
10658                        children: vec![Container {
10659                            calculated_height: Some(100.0),
10660                            ..container.children[0].children[0].clone()
10661                        }],
10662                        calculated_height: Some(100.0),
10663                        ..container.children[0].clone()
10664                    }],
10665                    ..container.clone()
10666                },
10667            );
10668        }
10669    }
10670
10671    mod position_fixed {
10672        use super::*;
10673
10674        #[test_log::test]
10675        fn does_size_dynamic_width_correctly() {
10676            let mut container: Container = html! {
10677                div sx-position=(Position::Fixed) sx-width="100%" {}
10678            }
10679            .try_into()
10680            .unwrap();
10681
10682            container.calculated_width = Some(400.0);
10683            container.calculated_height = Some(100.0);
10684
10685            CALCULATOR.calc(&mut container);
10686            log::trace!("container:\n{container}");
10687
10688            compare_containers(
10689                &container,
10690                &Container {
10691                    children: vec![Container {
10692                        calculated_width: Some(400.0),
10693                        ..container.children[0].clone()
10694                    }],
10695                    ..container.clone()
10696                },
10697            );
10698        }
10699
10700        #[test_log::test]
10701        fn does_size_dynamic_height_correctly() {
10702            let mut container: Container = html! {
10703                div sx-position=(Position::Fixed) sx-height="100%" {}
10704            }
10705            .try_into()
10706            .unwrap();
10707
10708            container.calculated_width = Some(400.0);
10709            container.calculated_height = Some(100.0);
10710
10711            CALCULATOR.calc(&mut container);
10712            log::trace!("container:\n{container}");
10713
10714            compare_containers(
10715                &container,
10716                &Container {
10717                    children: vec![Container {
10718                        calculated_height: Some(100.0),
10719                        ..container.children[0].clone()
10720                    }],
10721                    ..container.clone()
10722                },
10723            );
10724        }
10725
10726        #[test_log::test]
10727        fn does_place_child_element_with_horizontal_margins_correctly() {
10728            let mut container: Container = html! {
10729                div
10730                    sx-position=(Position::Fixed)
10731                    sx-width="100%"
10732                    sx-height="100%"
10733                    sx-justify-content=(JustifyContent::Center)
10734                {
10735                    div
10736                        sx-flex=(1)
10737                        sx-margin-x="calc(20vw)"
10738                        sx-min-height="calc(min(90vh, 300px))"
10739                        sx-max-height="90vh"
10740                        sx-overflow-y=(LayoutOverflow::Auto)
10741                    {}
10742                }
10743            }
10744            .try_into()
10745            .unwrap();
10746
10747            container.calculated_width = Some(1000.0);
10748            container.calculated_height = Some(500.0);
10749
10750            CALCULATOR.calc(&mut container);
10751            log::trace!("container:\n{container}");
10752
10753            compare_containers(
10754                &container,
10755                &Container {
10756                    children: vec![Container {
10757                        children: vec![Container {
10758                            calculated_x: Some(0.0),
10759                            calculated_y: Some(0.0),
10760                            calculated_width: Some(600.0),
10761                            calculated_height: Some(500.0),
10762                            ..container.children[0].children[0].clone()
10763                        }],
10764                        ..container.children[0].clone()
10765                    }],
10766                    ..container.clone()
10767                },
10768            );
10769        }
10770
10771        #[test_log::test]
10772        fn does_size_horizontally_child_element_correctly_with_flex_1_and_direction_row_parent() {
10773            let mut container: Container = html! {
10774                div
10775                    sx-dir=(LayoutDirection::Row)
10776                    sx-position=(Position::Fixed)
10777                    sx-width="100%"
10778                    sx-align-items=(AlignItems::Center)
10779                    sx-justify-content=(JustifyContent::Center)
10780                {
10781                    div
10782                        sx-flex=(1)
10783                        sx-margin-x="calc(20vw)"
10784                        sx-overflow-y=(LayoutOverflow::Auto)
10785                    { "test" }
10786                }
10787            }
10788            .try_into()
10789            .unwrap();
10790
10791            container.calculated_width = Some(1000.0);
10792            container.calculated_height = Some(500.0);
10793
10794            CALCULATOR.calc(&mut container);
10795            log::trace!("container:\n{container}");
10796
10797            compare_containers(
10798                &container,
10799                &Container {
10800                    children: vec![Container {
10801                        children: vec![Container {
10802                            calculated_width: Some(600.0),
10803                            ..container.children[0].children[0].clone()
10804                        }],
10805                        calculated_width: Some(1000.0),
10806                        ..container.children[0].clone()
10807                    }],
10808                    calculated_width: Some(1000.0),
10809                    ..container.clone()
10810                },
10811            );
10812        }
10813
10814        #[test_log::test]
10815        fn calc_can_calc_fixed_positioned_element_nested_on_top_of_a_relative_element_with_left_offset()
10816         {
10817            let mut container = Container {
10818                children: vec![Container {
10819                    children: vec![
10820                        Container::default(),
10821                        Container {
10822                            left: Some(Number::Integer(30)),
10823                            position: Some(Position::Fixed),
10824                            ..Default::default()
10825                        },
10826                    ],
10827                    justify_content: Some(JustifyContent::Start),
10828                    ..Default::default()
10829                }],
10830                calculated_width: Some(100.0),
10831                calculated_height: Some(50.0),
10832                position: Some(Position::Relative),
10833                justify_content: Some(JustifyContent::Start),
10834                ..Default::default()
10835            };
10836            CALCULATOR.calc(&mut container);
10837            log::trace!("container:\n{container}");
10838
10839            compare_containers(
10840                &container.clone(),
10841                &Container {
10842                    children: vec![Container {
10843                        children: vec![
10844                            Container {
10845                                calculated_width: Some(100.0),
10846                                calculated_x: Some(0.0),
10847                                calculated_position: Some(LayoutPosition::Default),
10848                                ..container.children[0].children[0].clone()
10849                            },
10850                            Container {
10851                                calculated_width: Some(0.0),
10852                                calculated_height: Some(0.0),
10853                                calculated_x: Some(30.0),
10854                                calculated_y: Some(0.0),
10855                                position: Some(Position::Fixed),
10856                                ..container.children[0].children[1].clone()
10857                            },
10858                        ],
10859                        ..container.children[0].clone()
10860                    }],
10861                    ..container
10862                },
10863            );
10864        }
10865
10866        #[test_log::test]
10867        fn calc_can_calc_fixed_positioned_element_on_top_of_a_relative_element_with_left_offset() {
10868            let mut container = Container {
10869                children: vec![
10870                    Container::default(),
10871                    Container {
10872                        left: Some(Number::Integer(30)),
10873                        position: Some(Position::Fixed),
10874                        ..Default::default()
10875                    },
10876                ],
10877                calculated_width: Some(100.0),
10878                calculated_height: Some(50.0),
10879                position: Some(Position::Relative),
10880                justify_content: Some(JustifyContent::Start),
10881                ..Default::default()
10882            };
10883            CALCULATOR.calc(&mut container);
10884            log::trace!("container:\n{container}");
10885
10886            compare_containers(
10887                &container.clone(),
10888                &Container {
10889                    children: vec![
10890                        Container {
10891                            calculated_width: Some(100.0),
10892                            calculated_x: Some(0.0),
10893                            calculated_position: Some(LayoutPosition::Default),
10894                            ..container.children[0].clone()
10895                        },
10896                        Container {
10897                            left: Some(Number::Integer(30)),
10898                            calculated_width: Some(0.0),
10899                            calculated_height: Some(0.0),
10900                            calculated_x: Some(30.0),
10901                            calculated_y: Some(0.0),
10902                            position: Some(Position::Fixed),
10903                            ..container.children[1].clone()
10904                        },
10905                    ],
10906                    ..container
10907                },
10908            );
10909        }
10910
10911        #[test_log::test]
10912        fn calc_can_calc_fixed_positioned_element_with_explicit_sizes() {
10913            let mut container = Container {
10914                children: vec![
10915                    Container::default(),
10916                    Container {
10917                        width: Some(Number::Integer(30)),
10918                        height: Some(Number::Integer(20)),
10919                        left: Some(Number::Integer(30)),
10920                        position: Some(Position::Fixed),
10921                        ..Default::default()
10922                    },
10923                ],
10924                calculated_width: Some(100.0),
10925                calculated_height: Some(50.0),
10926                position: Some(Position::Relative),
10927                justify_content: Some(JustifyContent::Start),
10928                ..Default::default()
10929            };
10930            CALCULATOR.calc(&mut container);
10931            log::trace!("container:\n{container}");
10932
10933            compare_containers(
10934                &container.clone(),
10935                &Container {
10936                    children: vec![
10937                        Container {
10938                            calculated_width: Some(100.0),
10939                            calculated_x: Some(0.0),
10940                            calculated_position: Some(LayoutPosition::Default),
10941                            ..container.children[0].clone()
10942                        },
10943                        Container {
10944                            calculated_width: Some(30.0),
10945                            calculated_height: Some(20.0),
10946                            calculated_x: Some(30.0),
10947                            calculated_y: Some(0.0),
10948                            position: Some(Position::Fixed),
10949                            ..container.children[1].clone()
10950                        },
10951                    ],
10952                    ..container
10953                },
10954            );
10955        }
10956
10957        #[test_log::test]
10958        fn calc_can_calc_fixed_positioned_element_on_top_of_a_relative_element_doesnt_affect_fixed_position_element_location()
10959         {
10960            let mut container = Container {
10961                children: vec![
10962                    Container::default(),
10963                    Container {
10964                        children: vec![Container {
10965                            position: Some(Position::Fixed),
10966                            ..Default::default()
10967                        }],
10968                        left: Some(Number::Integer(30)),
10969                        position: Some(Position::Relative),
10970                        ..Default::default()
10971                    },
10972                ],
10973                calculated_width: Some(100.0),
10974                calculated_height: Some(50.0),
10975                position: Some(Position::Relative),
10976                justify_content: Some(JustifyContent::Start),
10977                ..Default::default()
10978            };
10979
10980            CALCULATOR.calc(&mut container);
10981            log::trace!("container:\n{container}");
10982
10983            compare_containers(
10984                &container.clone(),
10985                &Container {
10986                    children: vec![
10987                        Container {
10988                            calculated_width: Some(100.0),
10989                            calculated_x: Some(0.0),
10990                            calculated_position: Some(LayoutPosition::Default),
10991                            ..container.children[0].clone()
10992                        },
10993                        Container {
10994                            children: vec![Container {
10995                                calculated_width: Some(0.0),
10996                                calculated_x: Some(0.0),
10997                                position: Some(Position::Fixed),
10998                                ..container.children[1].children[0].clone()
10999                            }],
11000                            calculated_width: Some(100.0),
11001                            calculated_x: Some(0.0),
11002                            position: Some(Position::Relative),
11003                            ..container.children[1].clone()
11004                        },
11005                    ],
11006                    ..container
11007                },
11008            );
11009        }
11010
11011        #[test_log::test]
11012        fn calc_can_calc_fixed_positioned_element_on_top_of_a_relative_element_and_have_it_not_inherit_position_or_size()
11013         {
11014            let mut container = Container {
11015                children: vec![
11016                    Container::default(),
11017                    Container {
11018                        position: Some(Position::Fixed),
11019                        ..Default::default()
11020                    },
11021                ],
11022                calculated_width: Some(100.0),
11023                calculated_height: Some(50.0),
11024                position: Some(Position::Relative),
11025                justify_content: Some(JustifyContent::Start),
11026                ..Default::default()
11027            };
11028            CALCULATOR.calc(&mut container);
11029            log::trace!("container:\n{container}");
11030
11031            compare_containers(
11032                &container.clone(),
11033                &Container {
11034                    children: vec![
11035                        Container {
11036                            calculated_width: Some(100.0),
11037                            calculated_x: Some(0.0),
11038                            calculated_position: Some(LayoutPosition::Default),
11039                            ..container.children[0].clone()
11040                        },
11041                        Container {
11042                            calculated_width: Some(0.0),
11043                            calculated_height: Some(0.0),
11044                            calculated_x: Some(0.0),
11045                            calculated_y: Some(0.0),
11046                            position: Some(Position::Fixed),
11047                            ..container.children[1].clone()
11048                        },
11049                    ],
11050                    ..container
11051                },
11052            );
11053        }
11054    }
11055
11056    mod positioning {
11057        use hyperchad_transformer_models::{AlignItems, TextAlign, Visibility};
11058
11059        use super::*;
11060
11061        #[test_log::test]
11062        fn does_center_child_correctly() {
11063            let mut container: Container = html! {
11064                div
11065                    sx-width=(100)
11066                    sx-height=(50)
11067                    sx-justify-content=(JustifyContent::Center)
11068                    sx-align-items=(AlignItems::Center)
11069                {
11070                    div sx-width=(20) sx-height=(10) {}
11071                }
11072            }
11073            .try_into()
11074            .unwrap();
11075
11076            container.calculated_width = Some(400.0);
11077            container.calculated_height = Some(100.0);
11078
11079            CALCULATOR.calc(&mut container);
11080            log::trace!("full container:\n{container}");
11081            container = container.children[0].clone();
11082            log::trace!("container:\n{container}");
11083
11084            compare_containers(
11085                &container,
11086                &Container {
11087                    children: vec![Container {
11088                        calculated_x: Some(40.0),
11089                        calculated_y: Some(20.0),
11090                        ..container.children[0].clone()
11091                    }],
11092                    ..container.clone()
11093                },
11094            );
11095        }
11096
11097        #[test_log::test]
11098        fn does_center_raw_content_vertically_correctly() {
11099            let mut container: Container = html! {
11100                div
11101                    sx-width=(100)
11102                    sx-height=(50)
11103                    sx-justify-content=(JustifyContent::Center)
11104                {
11105                    "test"
11106                }
11107            }
11108            .try_into()
11109            .unwrap();
11110
11111            container.calculated_width = Some(400.0);
11112            container.calculated_height = Some(100.0);
11113
11114            CALCULATOR.calc(&mut container);
11115            log::trace!("full container:\n{container}");
11116            container = container.children[0].clone();
11117            log::trace!("container:\n{container}");
11118
11119            compare_containers(
11120                &container,
11121                &Container {
11122                    children: vec![Container {
11123                        calculated_y: Some(18.0),
11124                        ..container.children[0].clone()
11125                    }],
11126                    ..container.clone()
11127                },
11128            );
11129        }
11130
11131        #[test_log::test]
11132        fn does_not_include_invisible_children_in_position() {
11133            let mut container: Container = html! {
11134                div sx-width=(100) sx-height=(50) {
11135                    div sx-visibility=(Visibility::Hidden) sx-height=(20) {}
11136                    "test"
11137                }
11138            }
11139            .try_into()
11140            .unwrap();
11141
11142            container.calculated_width = Some(400.0);
11143            container.calculated_height = Some(100.0);
11144
11145            CALCULATOR.calc(&mut container);
11146            log::trace!("full container:\n{container}");
11147            container = container.children[0].clone();
11148            log::trace!("container:\n{container}");
11149
11150            compare_containers(
11151                &container,
11152                &Container {
11153                    children: vec![
11154                        Container {
11155                            calculated_y: None,
11156                            ..container.children[0].clone()
11157                        },
11158                        Container {
11159                            calculated_y: Some(0.0),
11160                            ..container.children[1].clone()
11161                        },
11162                    ],
11163                    ..container.clone()
11164                },
11165            );
11166        }
11167
11168        #[test_log::test]
11169        fn does_center_child_correctly_with_dir_row_and_multiple_children() {
11170            let mut container: Container = html! {
11171                div
11172                    sx-dir=(LayoutDirection::Row)
11173                    sx-width=(100)
11174                    sx-height=(50)
11175                    sx-justify-content=(JustifyContent::Center)
11176                    sx-align-items=(AlignItems::Center)
11177                {
11178                    div sx-width=(20) sx-height=(10) {}
11179                    div sx-width=(20) sx-height=(10) {}
11180                    div sx-width=(20) sx-height=(10) {}
11181                }
11182            }
11183            .try_into()
11184            .unwrap();
11185
11186            container.calculated_width = Some(400.0);
11187            container.calculated_height = Some(100.0);
11188
11189            CALCULATOR.calc(&mut container);
11190            log::trace!("full container:\n{container}");
11191            container = container.children[0].clone();
11192            log::trace!("container:\n{container}");
11193
11194            compare_containers(
11195                &container,
11196                &Container {
11197                    children: vec![
11198                        Container {
11199                            calculated_x: Some(20.0),
11200                            calculated_y: Some(20.0),
11201                            ..container.children[0].clone()
11202                        },
11203                        Container {
11204                            calculated_x: Some(40.0),
11205                            calculated_y: Some(20.0),
11206                            ..container.children[1].clone()
11207                        },
11208                        Container {
11209                            calculated_x: Some(60.0),
11210                            calculated_y: Some(20.0),
11211                            ..container.children[2].clone()
11212                        },
11213                    ],
11214                    ..container.clone()
11215                },
11216            );
11217        }
11218
11219        #[test_log::test]
11220        fn does_center_row_text_when_text_align_is_center() {
11221            let mut container: Container = html! {
11222                div
11223                    sx-width=(100)
11224                    sx-height=(50)
11225                    sx-text-align=(TextAlign::Center)
11226                {
11227                    "test"
11228                }
11229            }
11230            .try_into()
11231            .unwrap();
11232
11233            container.calculated_width = Some(400.0);
11234            container.calculated_height = Some(100.0);
11235
11236            CALCULATOR.calc(&mut container);
11237            log::trace!("full container:\n{container}");
11238            container = container.children[0].clone();
11239            log::trace!("container:\n{container}");
11240
11241            compare_containers(
11242                &container,
11243                &Container {
11244                    children: vec![Container {
11245                        calculated_x: Some(22.0),
11246                        ..container.children[0].clone()
11247                    }],
11248                    ..container.clone()
11249                },
11250            );
11251        }
11252
11253        #[test_log::test]
11254        fn does_center_row_text_when_text_align_is_center_and_container_direction_is_row() {
11255            let mut container: Container = html! {
11256                div
11257                    sx-dir=(LayoutDirection::Row)
11258                    sx-width=(100)
11259                    sx-height=(50)
11260                    sx-text-align=(TextAlign::Center)
11261                {
11262                    "test"
11263                }
11264            }
11265            .try_into()
11266            .unwrap();
11267
11268            container.calculated_width = Some(400.0);
11269            container.calculated_height = Some(100.0);
11270
11271            CALCULATOR.calc(&mut container);
11272            log::trace!("full container:\n{container}");
11273            container = container.children[0].clone();
11274            log::trace!("container:\n{container}");
11275
11276            compare_containers(
11277                &container,
11278                &Container {
11279                    children: vec![Container {
11280                        calculated_x: Some(22.0),
11281                        ..container.children[0].clone()
11282                    }],
11283                    ..container.clone()
11284                },
11285            );
11286        }
11287
11288        #[test_log::test]
11289        fn does_center_vertical_row_children() {
11290            let mut container: Container = html! {
11291                div sx-dir=(LayoutDirection::Row) sx-width=(100) sx-height=(100) sx-align-items=(AlignItems::Center) {
11292                    div sx-height=(70) {}
11293                    div sx-height=(48) {}
11294                }
11295            }
11296            .try_into()
11297            .unwrap();
11298
11299            container.calculated_width = Some(400.0);
11300            container.calculated_height = Some(100.0);
11301
11302            CALCULATOR.calc(&mut container);
11303            log::trace!("full container:\n{container}");
11304            container = container.children[0].clone();
11305            log::trace!("container:\n{container}");
11306
11307            compare_containers(
11308                &container,
11309                &Container {
11310                    children: vec![
11311                        Container {
11312                            calculated_y: Some(15.0),
11313                            ..container.children[0].clone()
11314                        },
11315                        Container {
11316                            calculated_y: Some(26.0),
11317                            ..container.children[1].clone()
11318                        },
11319                    ],
11320                    ..container.clone()
11321                },
11322            );
11323        }
11324
11325        #[test_log::test]
11326        fn does_center_horizontal_column_children() {
11327            let mut container: Container = html! {
11328                div sx-width=(100) sx-height=(100) sx-align-items=(AlignItems::Center) {
11329                    div sx-width=(70) {}
11330                    div sx-width=(48) {}
11331                }
11332            }
11333            .try_into()
11334            .unwrap();
11335
11336            container.calculated_width = Some(400.0);
11337            container.calculated_height = Some(100.0);
11338
11339            CALCULATOR.calc(&mut container);
11340            log::trace!("full container:\n{container}");
11341            container = container.children[0].clone();
11342            log::trace!("container:\n{container}");
11343
11344            compare_containers(
11345                &container,
11346                &Container {
11347                    children: vec![
11348                        Container {
11349                            calculated_x: Some(15.0),
11350                            ..container.children[0].clone()
11351                        },
11352                        Container {
11353                            calculated_x: Some(26.0),
11354                            ..container.children[1].clone()
11355                        },
11356                    ],
11357                    ..container.clone()
11358                },
11359            );
11360        }
11361
11362        #[test_log::test]
11363        fn does_take_into_account_column_gap_for_non_wrapping_div() {
11364            let mut container: Container = html! {
11365                div sx-width=(20) {}
11366                div sx-width=(30) {}
11367            }
11368            .try_into()
11369            .unwrap();
11370
11371            container.direction = LayoutDirection::Row;
11372            container.calculated_width = Some(400.0);
11373            container.calculated_height = Some(100.0);
11374            container.column_gap = Some(Number::Integer(5));
11375
11376            CALCULATOR.calc(&mut container);
11377            log::trace!("container:\n{container}");
11378
11379            compare_containers(
11380                &container,
11381                &Container {
11382                    children: vec![
11383                        Container {
11384                            calculated_x: Some(0.0),
11385                            ..container.children[0].clone()
11386                        },
11387                        Container {
11388                            calculated_x: Some(20.0 + 5.0),
11389                            ..container.children[1].clone()
11390                        },
11391                    ],
11392                    ..container.clone()
11393                },
11394            );
11395        }
11396
11397        #[test_log::test]
11398        fn does_take_into_account_column_gap_for_non_wrapping_div_and_centers_properly() {
11399            let mut container: Container = html! {
11400                div sx-width=(20) {}
11401                div sx-width=(30) {}
11402            }
11403            .try_into()
11404            .unwrap();
11405
11406            container.direction = LayoutDirection::Row;
11407            container.calculated_width = Some(400.0);
11408            container.calculated_height = Some(100.0);
11409            container.column_gap = Some(Number::Integer(5));
11410            container.justify_content = Some(JustifyContent::Center);
11411
11412            CALCULATOR.calc(&mut container);
11413            log::trace!("container:\n{container}");
11414
11415            compare_containers(
11416                &container,
11417                &Container {
11418                    children: vec![
11419                        Container {
11420                            calculated_x: Some(400.0 / 2.0 - (20.0 + 30.0 + 5.0) / 2.0),
11421                            ..container.children[0].clone()
11422                        },
11423                        Container {
11424                            calculated_x: Some(
11425                                400.0 / 2.0 - (20.0 + 30.0 + 5.0) / 2.0 + 20.0 + 5.0,
11426                            ),
11427                            ..container.children[1].clone()
11428                        },
11429                    ],
11430                    ..container.clone()
11431                },
11432            );
11433        }
11434
11435        #[test_log::test]
11436        fn does_take_into_account_row_gap_for_non_wrapping_div() {
11437            let mut container: Container = html! {
11438                div sx-height=(20) {}
11439                div sx-height=(30) {}
11440            }
11441            .try_into()
11442            .unwrap();
11443
11444            container.direction = LayoutDirection::Column;
11445            container.calculated_width = Some(100.0);
11446            container.calculated_height = Some(400.0);
11447            container.row_gap = Some(Number::Integer(5));
11448
11449            CALCULATOR.calc(&mut container);
11450            log::trace!("container:\n{container}");
11451
11452            compare_containers(
11453                &container,
11454                &Container {
11455                    children: vec![
11456                        Container {
11457                            calculated_y: Some(0.0),
11458                            ..container.children[0].clone()
11459                        },
11460                        Container {
11461                            calculated_y: Some(20.0 + 5.0),
11462                            ..container.children[1].clone()
11463                        },
11464                    ],
11465                    ..container.clone()
11466                },
11467            );
11468        }
11469
11470        #[test_log::test]
11471        fn does_take_into_account_row_gap_for_non_wrapping_div_and_centers_properly() {
11472            let mut container: Container = html! {
11473                div sx-height=(20) {}
11474                div sx-height=(30) {}
11475            }
11476            .try_into()
11477            .unwrap();
11478
11479            container.direction = LayoutDirection::Column;
11480            container.calculated_width = Some(100.0);
11481            container.calculated_height = Some(400.0);
11482            container.row_gap = Some(Number::Integer(5));
11483            container.justify_content = Some(JustifyContent::Center);
11484
11485            CALCULATOR.calc(&mut container);
11486            log::trace!("container:\n{container}");
11487
11488            compare_containers(
11489                &container,
11490                &Container {
11491                    children: vec![
11492                        Container {
11493                            calculated_y: Some(400.0 / 2.0 - (20.0 + 30.0 + 5.0) / 2.0),
11494                            ..container.children[0].clone()
11495                        },
11496                        Container {
11497                            calculated_y: Some(
11498                                400.0 / 2.0 - (20.0 + 30.0 + 5.0) / 2.0 + 20.0 + 5.0,
11499                            ),
11500                            ..container.children[1].clone()
11501                        },
11502                    ],
11503                    ..container.clone()
11504                },
11505            );
11506        }
11507
11508        #[cfg(feature = "layout-offset")]
11509        mod offset {
11510            use super::*;
11511
11512            #[test_log::test]
11513            fn does_set_offset_x_for_single_element() {
11514                let mut container: Container = html! {
11515                    div {}
11516                }
11517                .try_into()
11518                .unwrap();
11519
11520                container.calculated_width = Some(400.0);
11521                container.calculated_height = Some(100.0);
11522
11523                CALCULATOR.calc(&mut container);
11524                log::trace!("full container:\n{container}");
11525                container = container.children[0].clone();
11526                log::trace!("container:\n{container}");
11527
11528                compare_containers(
11529                    &container,
11530                    &Container {
11531                        calculated_offset_x: Some(0.0),
11532                        ..container.clone()
11533                    },
11534                );
11535            }
11536
11537            #[test_log::test]
11538            fn does_set_offset_y_for_single_element() {
11539                let mut container: Container = html! {
11540                    div {}
11541                }
11542                .try_into()
11543                .unwrap();
11544
11545                container.calculated_width = Some(400.0);
11546                container.calculated_height = Some(100.0);
11547
11548                CALCULATOR.calc(&mut container);
11549                log::trace!("full container:\n{container}");
11550                container = container.children[0].clone();
11551                log::trace!("container:\n{container}");
11552
11553                compare_containers(
11554                    &container,
11555                    &Container {
11556                        calculated_offset_y: Some(0.0),
11557                        ..container.clone()
11558                    },
11559                );
11560            }
11561
11562            #[test_log::test]
11563            fn does_set_offset_x_for_two_elements_col() {
11564                let mut container: Container = html! {
11565                    div {
11566                        div {}
11567                        div {}
11568                    }
11569                }
11570                .try_into()
11571                .unwrap();
11572
11573                container.calculated_width = Some(400.0);
11574                container.calculated_height = Some(100.0);
11575
11576                CALCULATOR.calc(&mut container);
11577                log::trace!("full container:\n{container}");
11578                container = container.children[0].clone();
11579                log::trace!("container:\n{container}");
11580
11581                compare_containers(
11582                    &container,
11583                    &Container {
11584                        children: vec![
11585                            Container {
11586                                calculated_offset_x: Some(0.0),
11587                                ..container.children[0].clone()
11588                            },
11589                            Container {
11590                                calculated_offset_x: Some(0.0),
11591                                ..container.children[1].clone()
11592                            },
11593                        ],
11594                        ..container.clone()
11595                    },
11596                );
11597            }
11598
11599            #[test_log::test]
11600            fn does_set_offset_x_for_justify_content_end_row() {
11601                let mut container: Container = html! {
11602                    div sx-dir=(LayoutDirection::Row) sx-justify-content=(JustifyContent::End) {
11603                        div sx-width=(50) {}
11604                    }
11605                }
11606                .try_into()
11607                .unwrap();
11608
11609                container.calculated_width = Some(400.0);
11610                container.calculated_height = Some(100.0);
11611
11612                CALCULATOR.calc(&mut container);
11613                log::trace!("full container:\n{container}");
11614                container = container.children[0].clone();
11615                log::trace!("container:\n{container}");
11616
11617                compare_containers(
11618                    &container,
11619                    &Container {
11620                        children: vec![Container {
11621                            calculated_offset_x: Some(400.0 - 50.0),
11622                            ..container.children[0].clone()
11623                        }],
11624                        ..container.clone()
11625                    },
11626                );
11627            }
11628
11629            #[test_log::test]
11630            fn does_set_offset_y_for_justify_content_end_col() {
11631                let mut container: Container = html! {
11632                    div sx-height=(100) sx-justify-content=(JustifyContent::End) {
11633                        div sx-height=(20) {}
11634                    }
11635                }
11636                .try_into()
11637                .unwrap();
11638
11639                container.calculated_width = Some(400.0);
11640                container.calculated_height = Some(100.0);
11641
11642                CALCULATOR.calc(&mut container);
11643                log::trace!("full container:\n{container}");
11644                container = container.children[0].clone();
11645                log::trace!("container:\n{container}");
11646
11647                compare_containers(
11648                    &container,
11649                    &Container {
11650                        children: vec![Container {
11651                            calculated_offset_y: Some(100.0 - 20.0),
11652                            ..container.children[0].clone()
11653                        }],
11654                        ..container.clone()
11655                    },
11656                );
11657            }
11658
11659            #[test_log::test]
11660            fn does_set_offset_y_for_align_items_end_row() {
11661                let mut container: Container = html! {
11662                    div sx-height=(100) sx-dir=(LayoutDirection::Row) sx-align-items=(JustifyContent::End) {
11663                        div sx-height=(20) {}
11664                    }
11665                }
11666                .try_into()
11667                .unwrap();
11668
11669                container.calculated_width = Some(400.0);
11670                container.calculated_height = Some(100.0);
11671
11672                CALCULATOR.calc(&mut container);
11673                log::trace!("full container:\n{container}");
11674                container = container.children[0].clone();
11675                log::trace!("container:\n{container}");
11676
11677                compare_containers(
11678                    &container,
11679                    &Container {
11680                        children: vec![Container {
11681                            calculated_offset_y: Some(100.0 - 20.0),
11682                            ..container.children[0].clone()
11683                        }],
11684                        ..container.clone()
11685                    },
11686                );
11687            }
11688
11689            #[test_log::test]
11690            fn does_set_offset_x_for_align_items_end_col() {
11691                let mut container: Container = html! {
11692                    div sx-align-items=(JustifyContent::End) {
11693                        div sx-width=(50) {}
11694                    }
11695                }
11696                .try_into()
11697                .unwrap();
11698
11699                container.calculated_width = Some(400.0);
11700                container.calculated_height = Some(100.0);
11701
11702                CALCULATOR.calc(&mut container);
11703                log::trace!("full container:\n{container}");
11704                container = container.children[0].clone();
11705                log::trace!("container:\n{container}");
11706
11707                compare_containers(
11708                    &container,
11709                    &Container {
11710                        children: vec![Container {
11711                            calculated_offset_x: Some(400.0 - 50.0),
11712                            ..container.children[0].clone()
11713                        }],
11714                        ..container.clone()
11715                    },
11716                );
11717            }
11718
11719            #[test_log::test]
11720            fn does_set_offset_x_for_two_elements_row() {
11721                let mut container: Container = html! {
11722                    div sx-dir=(LayoutDirection::Row) {
11723                        div {}
11724                        div {}
11725                    }
11726                }
11727                .try_into()
11728                .unwrap();
11729
11730                container.calculated_width = Some(400.0);
11731                container.calculated_height = Some(100.0);
11732
11733                CALCULATOR.calc(&mut container);
11734                log::trace!("full container:\n{container}");
11735                container = container.children[0].clone();
11736                log::trace!("container:\n{container}");
11737
11738                compare_containers(
11739                    &container,
11740                    &Container {
11741                        children: vec![
11742                            Container {
11743                                calculated_offset_x: Some(0.0),
11744                                ..container.children[0].clone()
11745                            },
11746                            Container {
11747                                calculated_offset_x: Some(0.0),
11748                                ..container.children[1].clone()
11749                            },
11750                        ],
11751                        ..container.clone()
11752                    },
11753                );
11754            }
11755
11756            #[test_log::test]
11757            fn does_set_offset_y_for_two_elements_col() {
11758                let mut container: Container = html! {
11759                    div {
11760                        div {}
11761                        div {}
11762                    }
11763                }
11764                .try_into()
11765                .unwrap();
11766
11767                container.calculated_width = Some(400.0);
11768                container.calculated_height = Some(100.0);
11769
11770                CALCULATOR.calc(&mut container);
11771                log::trace!("full container:\n{container}");
11772                container = container.children[0].clone();
11773                log::trace!("container:\n{container}");
11774
11775                compare_containers(
11776                    &container,
11777                    &Container {
11778                        children: vec![
11779                            Container {
11780                                calculated_offset_y: Some(0.0),
11781                                ..container.children[0].clone()
11782                            },
11783                            Container {
11784                                calculated_offset_y: Some(0.0),
11785                                ..container.children[1].clone()
11786                            },
11787                        ],
11788                        ..container.clone()
11789                    },
11790                );
11791            }
11792
11793            #[test_log::test]
11794            fn does_set_offset_y_for_two_elements_row() {
11795                let mut container: Container = html! {
11796                    div sx-dir=(LayoutDirection::Row) {
11797                        div {}
11798                        div {}
11799                    }
11800                }
11801                .try_into()
11802                .unwrap();
11803
11804                container.calculated_width = Some(400.0);
11805                container.calculated_height = Some(100.0);
11806
11807                CALCULATOR.calc(&mut container);
11808                log::trace!("full container:\n{container}");
11809                container = container.children[0].clone();
11810                log::trace!("container:\n{container}");
11811
11812                compare_containers(
11813                    &container,
11814                    &Container {
11815                        children: vec![
11816                            Container {
11817                                calculated_offset_y: Some(0.0),
11818                                ..container.children[0].clone()
11819                            },
11820                            Container {
11821                                calculated_offset_y: Some(0.0),
11822                                ..container.children[1].clone()
11823                            },
11824                        ],
11825                        ..container.clone()
11826                    },
11827                );
11828            }
11829
11830            #[test_log::test]
11831            fn does_include_gap_in_offset_x_overflow_x_wrap() {
11832                let mut container: Container = html! {
11833                    div sx-dir=(LayoutDirection::Row) sx-overflow-x=(LayoutOverflow::Wrap { grid: false }) sx-gap=(10) {
11834                        div sx-width=(50) {}
11835                        div sx-width=(50) {}
11836                    }
11837                }
11838                .try_into()
11839                .unwrap();
11840
11841                container.calculated_width = Some(400.0);
11842                container.calculated_height = Some(100.0);
11843
11844                CALCULATOR.calc(&mut container);
11845                log::trace!("full container:\n{container}");
11846                container = container.children[0].clone();
11847                log::trace!("container:\n{container}");
11848
11849                compare_containers(
11850                    &container,
11851                    &Container {
11852                        children: vec![
11853                            Container {
11854                                calculated_offset_x: Some(0.0),
11855                                ..container.children[0].clone()
11856                            },
11857                            Container {
11858                                calculated_offset_x: Some(10.0),
11859                                ..container.children[1].clone()
11860                            },
11861                        ],
11862                        ..container.clone()
11863                    },
11864                );
11865            }
11866
11867            #[test_log::test]
11868            #[ignore]
11869            fn does_include_gap_in_offset_y_overflow_y_wrap() {
11870                let mut container: Container = html! {
11871                    div sx-overflow-y=(LayoutOverflow::Wrap { grid: false }) sx-gap=(10) {
11872                        div sx-height=(50) {}
11873                        div sx-height=(50) {}
11874                    }
11875                }
11876                .try_into()
11877                .unwrap();
11878
11879                container.calculated_width = Some(400.0);
11880                container.calculated_height = Some(100.0);
11881
11882                CALCULATOR.calc(&mut container);
11883                log::trace!("full container:\n{container}");
11884                container = container.children[0].clone();
11885                log::trace!("container:\n{container}");
11886
11887                compare_containers(
11888                    &container,
11889                    &Container {
11890                        children: vec![
11891                            Container {
11892                                calculated_offset_y: Some(0.0),
11893                                ..container.children[0].clone()
11894                            },
11895                            Container {
11896                                calculated_offset_y: Some(10.0),
11897                                ..container.children[1].clone()
11898                            },
11899                        ],
11900                        ..container.clone()
11901                    },
11902                );
11903            }
11904
11905            #[test_log::test]
11906            fn does_include_gap_in_offset_y_overflow_x_wrap() {
11907                let mut container: Container = html! {
11908                    div sx-width=(50) sx-dir=(LayoutDirection::Row) sx-overflow-x=(LayoutOverflow::Wrap { grid: false }) sx-gap=(10) {
11909                        div sx-width=(50) {}
11910                        div sx-width=(50) {}
11911                    }
11912                }
11913                .try_into()
11914                .unwrap();
11915
11916                container.calculated_width = Some(400.0);
11917                container.calculated_height = Some(100.0);
11918
11919                CALCULATOR.calc(&mut container);
11920                log::trace!("full container:\n{container}");
11921                container = container.children[0].clone();
11922                log::trace!("container:\n{container}");
11923
11924                compare_containers(
11925                    &container,
11926                    &Container {
11927                        children: vec![
11928                            Container {
11929                                calculated_offset_y: Some(0.0),
11930                                ..container.children[0].clone()
11931                            },
11932                            Container {
11933                                calculated_offset_y: Some(10.0),
11934                                ..container.children[1].clone()
11935                            },
11936                        ],
11937                        ..container.clone()
11938                    },
11939                );
11940            }
11941
11942            #[test_log::test]
11943            #[ignore]
11944            fn does_include_gap_in_offset_x_overflow_y_wrap() {
11945                let mut container: Container = html! {
11946                    div sx-height=(50) sx-overflow-y=(LayoutOverflow::Wrap { grid: false }) sx-gap=(10) {
11947                        div sx-height=(50) {}
11948                        div sx-height=(50) {}
11949                    }
11950                }
11951                .try_into()
11952                .unwrap();
11953
11954                container.calculated_width = Some(400.0);
11955                container.calculated_height = Some(100.0);
11956
11957                CALCULATOR.calc(&mut container);
11958                log::trace!("full container:\n{container}");
11959                container = container.children[0].clone();
11960                log::trace!("container:\n{container}");
11961
11962                compare_containers(
11963                    &container,
11964                    &Container {
11965                        children: vec![
11966                            Container {
11967                                calculated_offset_x: Some(0.0),
11968                                ..container.children[0].clone()
11969                            },
11970                            Container {
11971                                calculated_offset_x: Some(10.0),
11972                                ..container.children[1].clone()
11973                            },
11974                        ],
11975                        ..container.clone()
11976                    },
11977                );
11978            }
11979        }
11980    }
11981}