1use morphorm::Node;
2use skia_safe::wrapper::PointerWrapper;
3use vizia_storage::MorphormChildIter;
4
5use crate::prelude::*;
6use crate::resource::{ImageOrSvg, ResourceManager};
7use crate::text::TextContext;
8
9pub struct SubLayout<'a> {
10 pub text_context: &'a mut TextContext,
11 pub resource_manager: &'a ResourceManager,
12}
13
14impl Node for Entity {
15 type Store = Style;
16 type Tree = Tree<Entity>;
17 type CacheKey = Entity;
18 type ChildIter<'t> = MorphormChildIter<'t, Entity>;
19 type SubLayout<'a> = SubLayout<'a>;
20
21 fn children<'t>(&'t self, tree: &'t Self::Tree) -> Self::ChildIter<'t> {
22 MorphormChildIter::new(tree, *self)
23 }
24
25 fn key(&self) -> Self::CacheKey {
26 *self
27 }
28
29 fn visible(&self, store: &Self::Store) -> bool {
30 store.display.get(*self).copied().map(|display| display == Display::Flex).unwrap_or(true)
31 }
32
33 fn layout_type(&self, store: &Self::Store) -> Option<morphorm::LayoutType> {
34 store.layout_type.get(*self).copied()
35 }
36
37 fn position_type(&self, store: &Self::Store) -> Option<morphorm::PositionType> {
38 store.position_type.get(*self).copied()
39 }
40
41 fn left(&self, store: &Self::Store) -> Option<morphorm::Units> {
42 store.left.get(*self).cloned().map(|l| match l {
43 Units::Pixels(val) => Units::Pixels(store.logical_to_physical(val)),
44 t => t,
45 })
46 }
47
48 fn right(&self, store: &Self::Store) -> Option<morphorm::Units> {
49 store.right.get(*self).cloned().map(|r| match r {
50 Units::Pixels(val) => Units::Pixels(store.logical_to_physical(val)),
51 t => t,
52 })
53 }
54
55 fn top(&self, store: &Self::Store) -> Option<morphorm::Units> {
56 store.top.get(*self).cloned().map(|t| match t {
57 Units::Pixels(val) => Units::Pixels(store.logical_to_physical(val)),
58 t => t,
59 })
60 }
61
62 fn bottom(&self, store: &Self::Store) -> Option<morphorm::Units> {
63 store.bottom.get(*self).cloned().map(|b| match b {
64 Units::Pixels(val) => Units::Pixels(store.logical_to_physical(val)),
65 t => t,
66 })
67 }
68
69 fn width(&self, store: &Self::Store) -> Option<morphorm::Units> {
70 store.width.get(*self).cloned().map(|w| match w {
71 Units::Pixels(val) => Units::Pixels(store.logical_to_physical(val)),
72 t => t,
73 })
74 }
75
76 fn min_width(&self, store: &Self::Store) -> Option<morphorm::Units> {
77 store.min_width.get(*self).cloned().map(|w| match w {
78 Units::Pixels(val) => Units::Pixels(store.logical_to_physical(val)),
79 t => t,
80 })
81 }
82
83 fn max_width(&self, store: &Self::Store) -> Option<morphorm::Units> {
84 store.max_width.get(*self).cloned().map(|w| match w {
85 Units::Pixels(val) => Units::Pixels(store.logical_to_physical(val)),
86 t => t,
87 })
88 }
89
90 fn content_size(
91 &self,
92 store: &Self::Store,
93 sublayout: &mut Self::SubLayout<'_>,
94 width: Option<f32>,
95 height: Option<f32>,
96 ) -> Option<(f32, f32)> {
97 if let Some(paragraph) = sublayout.text_context.text_paragraphs.get_mut(*self) {
98 paragraph.layout(f32::MAX);
119
120 let padding_left = store.padding_left.get(*self).copied().unwrap_or_default();
121 let padding_right = store.padding_right.get(*self).copied().unwrap_or_default();
122 let padding_top = store.padding_top.get(*self).copied().unwrap_or_default();
123 let padding_bottom = store.padding_bottom.get(*self).copied().unwrap_or_default();
124
125 let mut child_space_x = 0.0;
126 let mut child_space_y = 0.0;
127
128 let mut p_left = 0.0;
129 let mut p_top = 0.0;
130
131 if let Pixels(val) = padding_left {
133 let val = val * store.scale_factor();
134 child_space_x += val;
135 p_left += val;
136 }
137 if let Pixels(val) = padding_right {
138 let val = val * store.scale_factor();
139 child_space_x += val;
140 }
141 if let Pixels(val) = padding_top {
142 let val = val * store.scale_factor();
143 child_space_y += val;
144 p_top += val;
145 }
146 if let Pixels(val) = padding_bottom {
147 let val = val * store.scale_factor();
148 child_space_y += val;
149 }
150
151 let border_width = store
152 .border_width
153 .get(*self)
154 .cloned()
155 .unwrap_or_default()
156 .to_pixels(0.0, store.scale_factor());
157
158 child_space_x += 2.0 * border_width;
159 child_space_y += 2.0 * border_width;
160
161 p_left += border_width;
162 p_top += border_width;
163
164 let text_width = match (
165 store.text_wrap.get(*self).copied().unwrap_or(true),
166 store.text_overflow.get(*self).copied(),
167 ) {
168 (true, _) => {
169 if let Some(width) = width {
170 width - child_space_x
171 } else {
172 paragraph.min_intrinsic_width().ceil()
173 }
174 }
175 (false, Some(TextOverflow::Ellipsis)) => {
176 if let Some(width) = width {
177 width - child_space_x
178 } else {
179 paragraph.max_intrinsic_width().ceil()
180 }
181 }
182 _ => {
183 if let Some(width) = width {
184 (width - child_space_x).max(paragraph.min_intrinsic_width().ceil())
185 } else {
186 paragraph.max_intrinsic_width().ceil()
187 }
188 }
189 };
190
191 paragraph.layout(text_width);
192
193 let text_height = if let Some(height) = height { height } else { paragraph.height() };
194
195 let width =
196 if let Some(width) = width { width } else { text_width.round() + child_space_x };
197
198 let height = if let Some(height) = height {
199 height
200 } else {
201 text_height.round() + child_space_y
202 };
203
204 sublayout.text_context.set_text_bounds(
206 *self,
207 BoundingBox { x: p_left, y: p_top, w: text_width, h: text_height },
208 );
209
210 Some((width, height))
211 } else if let Some(images) = store.background_image.get(*self) {
212 let mut max_width = 0.0f32;
213 let mut max_height = 0.0f32;
214 for image in images.iter() {
215 match image {
216 ImageOrGradient::Image(image_name) => {
217 if let Some(image_id) = sublayout.resource_manager.image_ids.get(image_name)
218 {
219 match sublayout
220 .resource_manager
221 .images
222 .get(image_id)
223 .map(|stored_img| &stored_img.image)
224 {
225 Some(ImageOrSvg::Image(image)) => {
226 max_width =
227 max_width.max(image.width() as f32 * store.scale_factor());
228 max_height = max_height
229 .max(image.height() as f32 * store.scale_factor());
230 }
231
232 Some(ImageOrSvg::Svg(svg)) => {
233 max_width = max_width.max(
234 svg.inner().fContainerSize.fWidth * store.scale_factor(),
235 );
236 max_height = max_height.max(
237 svg.inner().fContainerSize.fWidth * store.scale_factor(),
238 );
239 }
240
241 _ => {}
242 }
243 }
244 }
245 _ => {}
246 }
247 }
248
249 let width = if let Some(width) = width { width } else { max_width };
250 let height = if let Some(height) = height { height } else { max_height };
251 Some((width, height))
252 } else {
253 None
254 }
255 }
256
257 fn height(&self, store: &Self::Store) -> Option<morphorm::Units> {
258 store.height.get(*self).cloned().map(|h| match h {
259 Units::Pixels(val) => Units::Pixels(store.logical_to_physical(val)),
260 t => t,
261 })
262 }
263
264 fn min_height(&self, store: &Self::Store) -> Option<morphorm::Units> {
265 store.min_height.get(*self).cloned().map(|h| match h {
266 Units::Pixels(val) => Units::Pixels(store.logical_to_physical(val)),
267 t => t,
268 })
269 }
270
271 fn max_height(&self, store: &Self::Store) -> Option<morphorm::Units> {
272 store.max_height.get(*self).cloned().map(|h| match h {
273 Units::Pixels(val) => Units::Pixels(store.logical_to_physical(val)),
274 t => t,
275 })
276 }
277
278 fn padding_left(&self, store: &Self::Store) -> Option<morphorm::Units> {
279 store.padding_left.get(*self).cloned().map(|l| match l {
280 Units::Pixels(val) => Units::Pixels(store.logical_to_physical(val)),
281 t => t,
282 })
283 }
284
285 fn padding_right(&self, store: &Self::Store) -> Option<morphorm::Units> {
286 store.padding_right.get(*self).cloned().map(|r| match r {
287 Units::Pixels(val) => Units::Pixels(store.logical_to_physical(val)),
288 t => t,
289 })
290 }
291
292 fn padding_top(&self, store: &Self::Store) -> Option<morphorm::Units> {
293 store.padding_top.get(*self).cloned().map(|t| match t {
294 Units::Pixels(val) => Units::Pixels(store.logical_to_physical(val)),
295 t => t,
296 })
297 }
298
299 fn padding_bottom(&self, store: &Self::Store) -> Option<morphorm::Units> {
300 store.padding_bottom.get(*self).cloned().map(|b| match b {
301 Units::Pixels(val) => Units::Pixels(store.logical_to_physical(val)),
302 t => t,
303 })
304 }
305
306 fn vertical_gap(&self, store: &Self::Store) -> Option<morphorm::Units> {
307 store.vertical_gap.get(*self).cloned().map(|v| match v {
308 Units::Pixels(val) => Units::Pixels(store.logical_to_physical(val)),
309 t => t,
310 })
311 }
312
313 fn horizontal_gap(&self, store: &Self::Store) -> Option<morphorm::Units> {
314 store.horizontal_gap.get(*self).cloned().map(|v| match v {
315 Units::Pixels(val) => Units::Pixels(store.logical_to_physical(val)),
316 t => t,
317 })
318 }
319
320 fn border_left(&self, store: &Self::Store) -> Option<morphorm::Units> {
321 store.border_width.get(*self).map(|border_width| match border_width {
322 LengthOrPercentage::Length(val) => {
323 Units::Pixels(store.logical_to_physical(val.to_px().unwrap_or_default()))
324 }
325 LengthOrPercentage::Percentage(val) => Units::Percentage(*val),
326 })
327 }
328
329 fn border_right(&self, store: &Self::Store) -> Option<morphorm::Units> {
330 store.border_width.get(*self).map(|border_width| match border_width {
331 LengthOrPercentage::Length(val) => {
332 Units::Pixels(store.logical_to_physical(val.to_px().unwrap_or_default()))
333 }
334 LengthOrPercentage::Percentage(val) => Units::Percentage(*val),
335 })
336 }
337
338 fn border_top(&self, store: &Self::Store) -> Option<morphorm::Units> {
339 store.border_width.get(*self).map(|border_width| match border_width {
340 LengthOrPercentage::Length(val) => {
341 Units::Pixels(store.logical_to_physical(val.to_px().unwrap_or_default()))
342 }
343 LengthOrPercentage::Percentage(val) => Units::Percentage(*val),
344 })
345 }
346
347 fn border_bottom(&self, store: &Self::Store) -> Option<morphorm::Units> {
348 store.border_width.get(*self).map(|border_width| match border_width {
349 LengthOrPercentage::Length(val) => {
350 Units::Pixels(store.logical_to_physical(val.to_px().unwrap_or_default()))
351 }
352 LengthOrPercentage::Percentage(val) => Units::Percentage(*val),
353 })
354 }
355
356 fn alignment(&self, store: &Self::Store) -> Option<morphorm::Alignment> {
357 store.alignment.get(*self).copied()
358 }
359
360 fn vertical_scroll(&self, store: &Self::Store) -> Option<f32> {
361 store.vertical_scroll.get(*self).cloned().map(|val| store.logical_to_physical(val))
362 }
363
364 fn horizontal_scroll(&self, store: &Self::Store) -> Option<f32> {
365 store.horizontal_scroll.get(*self).cloned().map(|val| store.logical_to_physical(val))
366 }
367
368 fn min_vertical_gap(&self, store: &Self::Store) -> Option<Units> {
369 store.min_vertical_gap.get(*self).cloned().map(|h| match h {
370 Units::Pixels(val) => Units::Pixels(store.logical_to_physical(val)),
371 t => t,
372 })
373 }
374
375 fn min_horizontal_gap(&self, store: &Self::Store) -> Option<Units> {
376 store.min_horizontal_gap.get(*self).cloned().map(|h| match h {
377 Units::Pixels(val) => Units::Pixels(store.logical_to_physical(val)),
378 t => t,
379 })
380 }
381
382 fn max_vertical_gap(&self, store: &Self::Store) -> Option<Units> {
383 store.max_vertical_gap.get(*self).cloned().map(|h| match h {
384 Units::Pixels(val) => Units::Pixels(store.logical_to_physical(val)),
385 t => t,
386 })
387 }
388
389 fn max_horizontal_gap(&self, store: &Self::Store) -> Option<Units> {
390 store.max_horizontal_gap.get(*self).cloned().map(|h| match h {
391 Units::Pixels(val) => Units::Pixels(store.logical_to_physical(val)),
392 t => t,
393 })
394 }
395
396 fn grid_columns(&self, store: &Self::Store) -> Option<Vec<Units>> {
397 store.grid_columns.get(*self).cloned().map(|cols| {
398 cols.into_iter()
399 .map(|col| match col {
400 Units::Pixels(val) => Units::Pixels(store.logical_to_physical(val)),
401 t => t,
402 })
403 .collect()
404 })
405 }
406
407 fn grid_rows(&self, store: &Self::Store) -> Option<Vec<Units>> {
408 store.grid_rows.get(*self).cloned().map(|rows| {
409 rows.into_iter()
410 .map(|row| match row {
411 Units::Pixels(val) => Units::Pixels(store.logical_to_physical(val)),
412 t => t,
413 })
414 .collect()
415 })
416 }
417
418 fn column_start(&self, store: &Self::Store) -> Option<usize> {
419 store.column_start.get(*self).copied()
420 }
421
422 fn column_span(&self, store: &Self::Store) -> Option<usize> {
423 store.column_span.get(*self).copied()
424 }
425
426 fn row_start(&self, store: &Self::Store) -> Option<usize> {
427 store.row_start.get(*self).copied()
428 }
429
430 fn row_span(&self, store: &Self::Store) -> Option<usize> {
431 store.row_span.get(*self).copied()
432 }
433}