1use super::{
5 Concrete, Desc, Layout, Renderable, Staged, base, check_unsized, map_unsized_area,
6 nuetralize_unsized,
7};
8use crate::{DPoint, DValue, PxDim, PxRect, RowDirection, SourceID, UNSIZED_AXIS, rtree};
9use std::rc::Rc;
10
11pub trait Prop: base::Area + base::Limits + base::Anchor + base::Padding + base::Direction {
13 fn rows(&self) -> &[DValue];
14 fn columns(&self) -> &[DValue];
15 fn spacing(&self) -> DPoint; }
17
18crate::gen_from_to_dyn!(Prop);
19
20pub trait Child: base::RLimits {
21 fn coord(&self) -> (usize, usize);
23 fn span(&self) -> (usize, usize);
26}
27
28crate::gen_from_to_dyn!(Child);
29
30fn swap_coord((x, y): (usize, usize), (w, h): (usize, usize), dir: RowDirection) -> (usize, usize) {
31 match dir {
32 RowDirection::LeftToRight => (x, y),
33 RowDirection::RightToLeft => (w - 1 - x, y),
34 RowDirection::BottomToTop => (x, h - 1 - y),
35 RowDirection::TopToBottom => (w - 1 - x, h - 1 - y), }
37}
38
39impl Desc for dyn Prop {
40 type Props = dyn Prop;
41 type Child = dyn Child;
42 type Children = im::Vector<Option<Box<dyn Layout<Self::Child>>>>;
43
44 fn stage<'a>(
45 props: &Self::Props,
46 outer_area: crate::PxRect,
47 outer_limits: crate::PxLimits,
48 children: &Self::Children,
49 id: std::sync::Weak<SourceID>,
50 renderable: Option<Rc<dyn Renderable>>,
51 window: &mut crate::component::window::WindowState,
52 ) -> Box<dyn Staged + 'a> {
53 let mut limits = outer_limits + props.limits().resolve(window.dpi);
54 let myarea = props.area().resolve(window.dpi);
55 let (unsized_x, unsized_y) = check_unsized(myarea);
56 let padding = props.padding().as_perimeter(window.dpi);
57 let allpadding = padding.topleft() + padding.bottomright();
58 let minmax = limits.v.as_array_mut();
59 if unsized_x {
60 minmax[2] -= allpadding.width;
61 minmax[0] -= allpadding.width;
62 }
63 if unsized_y {
64 minmax[3] -= allpadding.height;
65 minmax[1] -= allpadding.height;
66 }
67
68 let outer_safe = nuetralize_unsized(outer_area);
69 let inner_dim = super::limit_dim(super::eval_dim(myarea, outer_area.dim()), limits)
70 - padding.topleft()
71 - padding.bottomright();
72
73 let spacing = props.spacing().resolve(window.dpi) * outer_safe.dim();
76 let nrows = props.rows().len();
77 let ncolumns = props.columns().len();
78
79 let mut staging: im::Vector<Option<Box<dyn Staged>>> = im::Vector::new();
80 let mut nodes: im::Vector<Option<Rc<rtree::Node>>> = im::Vector::new();
81
82 let evaluated_area =
83 crate::util::alloca_array::<f32, PxRect>((nrows + ncolumns) * 2, |x| {
84 let (resolved, sizes) = x.split_at_mut(nrows + ncolumns);
85 {
86 let (rows, columns) = resolved.split_at_mut(nrows);
87
88 sizes.fill(f32::NAN);
90
91 let (maxrows, maxcolumns) = sizes.split_at_mut(nrows);
92
93 for (i, row) in props.rows().iter().enumerate() {
95 rows[i] = row.resolve(window.dpi.height).resolve(inner_dim.height);
96 }
97 for (i, column) in props.columns().iter().enumerate() {
98 columns[i] = column.resolve(window.dpi.width).resolve(inner_dim.width);
99 }
100
101 for child in children.iter() {
103 let child_props = child.as_ref().unwrap().get_props();
104 let child_limit =
105 super::apply_limit(inner_dim, limits, *child_props.rlimits());
106 let (column, row) =
107 swap_coord(child_props.coord(), (ncolumns, nrows), props.direction());
108
109 if rows[row] == UNSIZED_AXIS || columns[column] == UNSIZED_AXIS {
110 let (w, h) = (columns[column], rows[row]);
111 let child_area = PxRect::new(0.0, 0.0, w, h);
112
113 let stage =
114 child
115 .as_ref()
116 .unwrap()
117 .stage(child_area, child_limit, window);
118 let area = stage.get_area();
119 maxrows[row] = maxrows[row].max(area.dim().height);
120 maxcolumns[column] = maxcolumns[column].max(area.dim().width);
121 }
122 }
123 }
124
125 for (i, size) in sizes.iter().enumerate() {
127 if resolved[i] == UNSIZED_AXIS {
128 resolved[i] = if size.is_nan() { 0.0 } else { *size };
129 }
130 }
131 let (rows, columns) = resolved.split_at_mut(nrows);
132 let (x_used, y_used) = (
133 columns.iter().fold(0.0, |x, y| x + y)
134 + (spacing.y * ncolumns.saturating_sub(1) as f32),
135 rows.iter().fold(0.0, |x, y| x + y)
136 + (spacing.x * nrows.saturating_sub(1) as f32),
137 );
138 let area = map_unsized_area(myarea, PxDim::new(x_used, y_used));
139
140 let (row_offsets, column_offsets) = sizes.split_at_mut(nrows);
142 let mut offset = 0.0;
143
144 for (i, row) in rows.iter().enumerate() {
145 row_offsets[i] = offset;
146 offset += row + spacing.x;
147 }
148
149 offset = 0.0;
150 for (i, column) in columns.iter().enumerate() {
151 column_offsets[i] = offset;
152 offset += column + spacing.y;
153 }
154
155 for child in children.iter() {
156 let child_props = child.as_ref().unwrap().get_props();
157 let child_limit = super::apply_limit(inner_dim, limits, *child_props.rlimits());
158 let (column, row) =
159 swap_coord(child_props.coord(), (ncolumns, nrows), props.direction());
160
161 let (x, y) = (column_offsets[column], row_offsets[row]);
162 let (w, h) = (columns[column], rows[row]);
163 let child_area = PxRect::new(x, y, x + w, y + h);
164
165 let stage = child
166 .as_ref()
167 .unwrap()
168 .stage(child_area, child_limit, window);
169 if let Some(node) = stage.get_rtree().upgrade() {
170 nodes.push_back(Some(node));
171 }
172 staging.push_back(Some(stage));
173 }
174
175 let evaluated_area = super::limit_area(area * outer_safe, limits) + padding;
177
178 let anchor = props.anchor().resolve(window.dpi) * evaluated_area.dim();
179 evaluated_area - anchor
180 });
181
182 Box::new(Concrete {
183 area: evaluated_area,
184 renderable,
185 rtree: rtree::Node::new(evaluated_area.to_untyped(), None, nodes, id, window),
186 children: staging,
187 layer: None,
188 })
189 }
190}