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