1use crate::Value;
5use crate::dynamic_item_tree::InstanceRef;
6use crate::eval::{self, EvalLocalContext};
7use i_slint_compiler::expression_tree::Expression;
8use i_slint_compiler::langtype::Type;
9use i_slint_compiler::layout::{
10 BoxLayout, GridLayout, LayoutConstraints, LayoutGeometry, Orientation, RowColExpr,
11};
12use i_slint_compiler::namedreference::NamedReference;
13use i_slint_compiler::object_tree::ElementRc;
14use i_slint_core::items::{DialogButtonRole, FlexboxLayoutDirection, ItemRc};
15use i_slint_core::layout::{self as core_layout, GridLayoutInputData, GridLayoutOrganizedData};
16use i_slint_core::model::RepeatedItemTree;
17use i_slint_core::slice::Slice;
18use i_slint_core::window::WindowAdapter;
19use std::rc::Rc;
20use std::str::FromStr;
21
22pub(crate) fn to_runtime(o: Orientation) -> core_layout::Orientation {
23 match o {
24 Orientation::Horizontal => core_layout::Orientation::Horizontal,
25 Orientation::Vertical => core_layout::Orientation::Vertical,
26 }
27}
28
29pub(crate) fn from_runtime(o: core_layout::Orientation) -> Orientation {
30 match o {
31 core_layout::Orientation::Horizontal => Orientation::Horizontal,
32 core_layout::Orientation::Vertical => Orientation::Vertical,
33 }
34}
35
36pub(crate) fn compute_grid_layout_info(
37 grid_layout: &GridLayout,
38 organized_data: &GridLayoutOrganizedData,
39 orientation: Orientation,
40 local_context: &mut EvalLocalContext,
41 cross_axis_size: Option<f32>,
42) -> Value {
43 let component = local_context.component_instance;
44 let expr_eval = |nr: &NamedReference| -> f32 {
45 eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
46 };
47 let (padding, spacing) = padding_and_spacing(&grid_layout.geometry, orientation, &expr_eval);
48 let repeater_steps = grid_repeater_steps(grid_layout, local_context);
49 let repeater_indices = grid_repeater_indices(grid_layout, local_context, &repeater_steps);
50 let constraints = grid_layout_constraints(
51 grid_layout,
52 orientation,
53 local_context,
54 &repeater_steps,
55 cross_axis_size,
56 );
57 core_layout::grid_layout_info(
58 organized_data.clone(),
59 Slice::from_slice(constraints.as_slice()),
60 Slice::from_slice(repeater_indices.as_slice()),
61 Slice::from_slice(repeater_steps.as_slice()),
62 spacing,
63 &padding,
64 to_runtime(orientation),
65 )
66 .into()
67}
68
69pub(crate) fn compute_box_layout_info(
71 box_layout: &BoxLayout,
72 orientation: Orientation,
73 local_context: &mut EvalLocalContext,
74 cross_axis_size: Option<f32>,
75) -> Value {
76 let component = local_context.component_instance;
77 let expr_eval = |nr: &NamedReference| -> f32 {
78 eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
79 };
80 let cross_axis_size = cross_axis_size.map(|w| {
81 let (cross_pad, _) =
82 padding_and_spacing(&box_layout.geometry, orientation.orthogonal(), &expr_eval);
83 w - cross_pad.begin - cross_pad.end
84 });
85 let (cells, alignment) = box_layout_data(
86 box_layout,
87 orientation,
88 component,
89 &expr_eval,
90 None,
91 cross_axis_size,
92 local_context,
93 None,
94 );
95 let (padding, spacing) = padding_and_spacing(&box_layout.geometry, orientation, &expr_eval);
96 if orientation == box_layout.orientation {
97 core_layout::box_layout_info(Slice::from(cells.as_slice()), spacing, &padding, alignment)
98 } else {
99 core_layout::box_layout_info_ortho(Slice::from(cells.as_slice()), &padding)
100 }
101 .into()
102}
103
104pub(crate) fn organize_grid_layout(
105 layout: &GridLayout,
106 local_context: &mut EvalLocalContext,
107) -> Value {
108 let repeater_steps = grid_repeater_steps(layout, local_context);
109 let cells = grid_layout_input_data(layout, local_context, &repeater_steps);
110 let repeater_indices = grid_repeater_indices(layout, local_context, &repeater_steps);
111 if let Some(buttons_roles) = &layout.dialog_button_roles {
112 let roles = buttons_roles
113 .iter()
114 .map(|r| DialogButtonRole::from_str(r).unwrap())
115 .collect::<Vec<_>>();
116 core_layout::organize_dialog_button_layout(
117 Slice::from_slice(cells.as_slice()),
118 Slice::from_slice(roles.as_slice()),
119 )
120 .into()
121 } else {
122 core_layout::organize_grid_layout(
123 Slice::from_slice(cells.as_slice()),
124 Slice::from_slice(repeater_indices.as_slice()),
125 Slice::from_slice(repeater_steps.as_slice()),
126 )
127 .into()
128 }
129}
130
131pub(crate) fn solve_grid_layout(
132 organized_data: &GridLayoutOrganizedData,
133 grid_layout: &GridLayout,
134 orientation: Orientation,
135 local_context: &mut EvalLocalContext,
136) -> Value {
137 let component = local_context.component_instance;
138 let expr_eval = |nr: &NamedReference| -> f32 {
139 eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
140 };
141 let repeater_steps = grid_repeater_steps(grid_layout, local_context);
142 let repeater_indices = grid_repeater_indices(grid_layout, local_context, &repeater_steps);
143 let constraints =
144 grid_layout_constraints(grid_layout, orientation, local_context, &repeater_steps, None);
145
146 let (padding, spacing) = padding_and_spacing(&grid_layout.geometry, orientation, &expr_eval);
147 let size_ref = grid_layout.geometry.rect.size_reference(orientation);
148
149 let data = core_layout::GridLayoutData {
150 size: size_ref.map(expr_eval).unwrap_or(0.),
151 spacing,
152 padding,
153 organized_data: organized_data.clone(),
154 };
155
156 core_layout::solve_grid_layout(
157 &data,
158 Slice::from_slice(constraints.as_slice()),
159 to_runtime(orientation),
160 Slice::from_slice(repeater_indices.as_slice()),
161 Slice::from_slice(repeater_steps.as_slice()),
162 )
163 .into()
164}
165
166pub(crate) fn solve_box_layout(
167 box_layout: &BoxLayout,
168 orientation: Orientation,
169 local_context: &mut EvalLocalContext,
170) -> Value {
171 let component = local_context.component_instance;
172 let expr_eval = |nr: &NamedReference| -> f32 {
173 eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
174 };
175
176 let mut repeated_indices = Vec::new();
177 let cross_axis_size = (orientation == box_layout.orientation
182 && orientation == Orientation::Horizontal
183 && box_layout
184 .elems
185 .iter()
186 .any(|c| c.element.borrow().inherited_layout_info_h_with_constraint().is_some()))
187 .then(|| {
188 let cross = orientation.orthogonal();
189 box_layout.geometry.rect.size_reference(cross).map(&expr_eval).map(|s| {
190 let (pad, _) = padding_and_spacing(&box_layout.geometry, cross, &expr_eval);
191 s - pad.begin - pad.end
192 })
193 })
194 .flatten();
195 let available_cross = (orientation != box_layout.orientation)
200 .then(|| {
201 box_layout.geometry.rect.size_reference(orientation).map(&expr_eval).map(|s| {
202 let (pad, _) = padding_and_spacing(&box_layout.geometry, orientation, &expr_eval);
203 s - pad.begin - pad.end
204 })
205 })
206 .flatten();
207 let (cells, alignment) = box_layout_data(
208 box_layout,
209 orientation,
210 component,
211 &expr_eval,
212 Some(&mut repeated_indices),
213 cross_axis_size,
214 local_context,
215 available_cross,
216 );
217 let (padding, spacing) = padding_and_spacing(&box_layout.geometry, orientation, &expr_eval);
218 let size = box_layout.geometry.rect.size_reference(orientation).map(&expr_eval).unwrap_or(0.);
219 if orientation == box_layout.orientation {
220 core_layout::solve_box_layout(
221 &core_layout::BoxLayoutData {
222 size,
223 spacing,
224 padding,
225 alignment,
226 cells: Slice::from(cells.as_slice()),
227 },
228 Slice::from(repeated_indices.as_slice()),
229 )
230 .into()
231 } else {
232 let cross_axis_alignment = box_layout
233 .cross_alignment
234 .as_ref()
235 .map(|nr| {
236 eval::load_property(component, &nr.element(), nr.name())
237 .unwrap()
238 .try_into()
239 .unwrap_or_default()
240 })
241 .unwrap_or_default();
242 core_layout::solve_box_layout_ortho(
243 &core_layout::BoxLayoutOrthoData {
244 size,
245 padding,
246 cross_axis_alignment,
247 cells: Slice::from(cells.as_slice()),
248 },
249 Slice::from(repeated_indices.as_slice()),
250 )
251 .into()
252 }
253}
254
255pub(crate) fn solve_flexbox_layout(
256 flexbox_layout: &i_slint_compiler::layout::FlexboxLayout,
257 local_context: &mut EvalLocalContext,
258) -> Value {
259 let component = local_context.component_instance;
260 let expr_eval = |nr: &NamedReference| -> f32 {
261 eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
262 };
263
264 let width_ref = &flexbox_layout.geometry.rect.width_reference;
265 let height_ref = &flexbox_layout.geometry.rect.height_reference;
266 let direction = flexbox_layout_direction(flexbox_layout, local_context);
267
268 let container_width_for_cells = match direction {
272 i_slint_core::items::FlexboxLayoutDirection::Column
273 | i_slint_core::items::FlexboxLayoutDirection::ColumnReverse => {
274 width_ref.as_ref().map(|w| {
275 let (pad_h, _) = padding_and_spacing(
276 &flexbox_layout.geometry,
277 Orientation::Horizontal,
278 &expr_eval,
279 );
280 expr_eval(w) - pad_h.begin - pad_h.end
281 })
282 }
283 _ => None,
284 };
285
286 let (cells_h, cells_v, flex_props, repeated_indices) = flexbox_layout_data(
287 flexbox_layout,
288 component,
289 &expr_eval,
290 local_context,
291 container_width_for_cells,
292 None,
293 );
294
295 let alignment = flexbox_layout
296 .geometry
297 .alignment
298 .as_ref()
299 .map_or(i_slint_core::items::LayoutAlignment::default(), |nr| {
300 eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
301 });
302 let cross_axis_line_alignment = flexbox_layout
303 .cross_axis_line_alignment
304 .as_ref()
305 .map_or(i_slint_core::items::CrossAxisLineAlignment::default(), |nr| {
306 eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
307 });
308 let cross_axis_alignment = flexbox_layout
309 .cross_axis_alignment
310 .as_ref()
311 .map_or(i_slint_core::items::CrossAxisAlignment::default(), |nr| {
312 eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
313 });
314 let flex_wrap = flexbox_layout
315 .flex_wrap
316 .as_ref()
317 .map_or(i_slint_core::items::FlexboxLayoutWrap::default(), |nr| {
318 eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
319 });
320
321 let (padding_h, spacing_h) =
322 padding_and_spacing(&flexbox_layout.geometry, Orientation::Horizontal, &expr_eval);
323 let (padding_v, spacing_v) =
324 padding_and_spacing(&flexbox_layout.geometry, Orientation::Vertical, &expr_eval);
325
326 let data = core_layout::FlexboxLayoutData {
327 width: width_ref.as_ref().map(&expr_eval).unwrap_or(0.),
328 height: height_ref.as_ref().map(&expr_eval).unwrap_or(0.),
329 spacing_h,
330 spacing_v,
331 padding_h,
332 padding_v,
333 alignment,
334 direction,
335 cross_axis_line_alignment,
336 cross_axis_alignment,
337 flex_wrap,
338 cells_h: Slice::from(cells_h.as_slice()),
339 cells_v: Slice::from(cells_v.as_slice()),
340 flex_props: Slice::from(flex_props.as_slice()),
341 };
342 let ri = Slice::from(repeated_indices.as_slice());
343
344 let window_adapter = component.window_adapter();
345
346 struct ChildElem {
356 elem: ElementRc,
357 has_constrained_layoutinfo_v: bool,
358 has_constrained_layoutinfo_h: bool,
359 has_aggregated_info: bool,
366 repeated_instance: Option<crate::dynamic_item_tree::DynamicComponentVRc>,
370 }
371 let mut child_elems: Vec<Option<ChildElem>> = Vec::new();
372 for layout_elem in &flexbox_layout.elems {
373 let placeholder = layout_elem.item.element.borrow();
374 let repeated = placeholder.repeated.is_some();
375 let query_elem = if repeated {
380 placeholder.base_type.as_component().root_element.clone()
381 } else {
382 layout_elem.item.element.clone()
383 };
384 drop(placeholder);
385 let qe = query_elem.borrow();
386 let has_constrained_layoutinfo_v = qe.inherited_layout_info_v_with_constraint().is_some();
387 let has_constrained_layoutinfo_h = qe.inherited_layout_info_h_with_constraint().is_some();
388 let has_aggregated_info = qe.layout_info_prop.is_some();
389 drop(qe);
390 if repeated {
391 let component_vec = repeater_instances(component, &layout_elem.item.element);
394 for instance in component_vec {
395 child_elems.push(Some(ChildElem {
396 elem: query_elem.clone(),
397 has_constrained_layoutinfo_v,
398 has_constrained_layoutinfo_h,
399 has_aggregated_info,
400 repeated_instance: Some(instance),
401 }));
402 }
403 } else {
404 child_elems.push(Some(ChildElem {
405 elem: query_elem,
406 has_constrained_layoutinfo_v,
407 has_constrained_layoutinfo_h,
408 has_aggregated_info,
409 repeated_instance: None,
410 }));
411 }
412 }
413
414 let mut measure = |child_index: usize,
415 known_w: Option<f32>,
416 known_h: Option<f32>|
417 -> (f32, f32) {
418 let default_w = cells_h.get(child_index).map_or(0., |c| c.constraint.preferred_bounded());
419 let default_h = cells_v.get(child_index).map_or(0., |c| c.constraint.preferred_bounded());
420 let w = known_w.unwrap_or(default_w);
421 let h = known_h.unwrap_or(default_h);
422
423 let ce = match child_elems.get(child_index) {
424 Some(Some(c)) => c,
425 _ => return (w, h),
426 };
427
428 let use_property_lookup = ce.has_aggregated_info
434 || ce.has_constrained_layoutinfo_v
435 || ce.has_constrained_layoutinfo_h;
436
437 let query = |orientation, constraint: Option<f32>| -> core_layout::LayoutInfo {
442 match &ce.repeated_instance {
443 Some(instance) => {
444 generativity::make_guard!(guard);
445 let unerased = instance.unerase(guard);
446 get_layout_info_with_constraint(
447 &ce.elem,
448 unerased.borrow_instance(),
449 &window_adapter,
450 orientation,
451 constraint,
452 )
453 }
454 None => get_layout_info_with_constraint(
455 &ce.elem,
456 component,
457 &window_adapter,
458 orientation,
459 constraint,
460 ),
461 }
462 };
463
464 if known_w.is_some() && known_h.is_none() {
465 if use_property_lookup {
466 let v_info =
467 query(Orientation::Vertical, ce.has_constrained_layoutinfo_v.then_some(w));
468 return (w, v_info.preferred_bounded());
469 }
470 if let Some(item_within) = ce
477 .repeated_instance
478 .is_none()
479 .then(|| component.description.items.get(ce.elem.borrow().id.as_str()))
480 .flatten()
481 {
482 let item_comp = component.self_weak().get().unwrap().upgrade().unwrap();
483 let item_rc =
484 ItemRc::new(vtable::VRc::into_dyn(item_comp), item_within.item_index());
485 let item = unsafe { item_within.item_from_item_tree(component.as_ptr()) };
486 let v_info = item.as_ref().layout_info(
487 to_runtime(Orientation::Vertical),
488 w,
489 &window_adapter,
490 &item_rc,
491 );
492 return (w, v_info.preferred_bounded());
493 }
494 return (w, h);
495 }
496 if known_h.is_some() && known_w.is_none() {
497 if use_property_lookup {
498 let h_info =
499 query(Orientation::Horizontal, ce.has_constrained_layoutinfo_h.then_some(h));
500 return (h_info.preferred_bounded(), h);
501 }
502 if let Some(item_within) = ce
505 .repeated_instance
506 .is_none()
507 .then(|| component.description.items.get(ce.elem.borrow().id.as_str()))
508 .flatten()
509 {
510 let item_comp = component.self_weak().get().unwrap().upgrade().unwrap();
511 let item_rc =
512 ItemRc::new(vtable::VRc::into_dyn(item_comp), item_within.item_index());
513 let item = unsafe { item_within.item_from_item_tree(component.as_ptr()) };
514 let h_info = item.as_ref().layout_info(
515 to_runtime(Orientation::Horizontal),
516 h,
517 &window_adapter,
518 &item_rc,
519 );
520 return (h_info.preferred_bounded(), h);
521 }
522 return (w, h);
523 }
524 (w, h)
525 };
526
527 core_layout::solve_flexbox_layout_with_measure(&data, ri, Some(&mut measure)).into()
528}
529
530fn flexbox_layout_direction(
531 flexbox_layout: &i_slint_compiler::layout::FlexboxLayout,
532 local_context: &EvalLocalContext,
533) -> FlexboxLayoutDirection {
534 flexbox_layout
535 .direction
536 .as_ref()
537 .and_then(|nr| {
538 let value =
539 eval::load_property(local_context.component_instance, &nr.element(), nr.name())
540 .ok()?;
541 if let Value::EnumerationValue(_, variant) = &value {
542 match variant.as_str() {
543 "row" => Some(FlexboxLayoutDirection::Row),
544 "row-reverse" => Some(FlexboxLayoutDirection::RowReverse),
545 "column" => Some(FlexboxLayoutDirection::Column),
546 "column-reverse" => Some(FlexboxLayoutDirection::ColumnReverse),
547 _ => None,
548 }
549 } else {
550 None
551 }
552 })
553 .unwrap_or(FlexboxLayoutDirection::Row)
554}
555
556pub(crate) fn compute_flexbox_layout_info(
557 flexbox_layout: &i_slint_compiler::layout::FlexboxLayout,
558 orientation: Orientation,
559 local_context: &mut EvalLocalContext,
560 cross_axis_size: Option<f32>,
561) -> Value {
562 let component = local_context.component_instance;
563 let expr_eval = |nr: &NamedReference| -> f32 {
564 eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
565 };
566
567 let (width_override, height_override) = match orientation {
572 Orientation::Vertical => (cross_axis_size, None),
573 Orientation::Horizontal => (None, cross_axis_size),
574 };
575 let width_override = width_override.map(|w| {
578 let (pad_h, _) =
579 padding_and_spacing(&flexbox_layout.geometry, Orientation::Horizontal, &expr_eval);
580 w - pad_h.begin - pad_h.end
581 });
582 let height_override = height_override.map(|h| {
583 let (pad_v, _) =
584 padding_and_spacing(&flexbox_layout.geometry, Orientation::Vertical, &expr_eval);
585 h - pad_v.begin - pad_v.end
586 });
587 let (cells_h, cells_v, flex_props, _repeated_indices) = flexbox_layout_data(
588 flexbox_layout,
589 component,
590 &expr_eval,
591 local_context,
592 width_override,
593 height_override,
594 );
595
596 let direction = flexbox_layout_direction(flexbox_layout, local_context);
598
599 let is_main_axis = matches!(
601 (direction, orientation),
602 (FlexboxLayoutDirection::Row | FlexboxLayoutDirection::RowReverse, Orientation::Horizontal)
603 | (
604 FlexboxLayoutDirection::Column | FlexboxLayoutDirection::ColumnReverse,
605 Orientation::Vertical
606 )
607 );
608
609 let (padding_h, spacing_h) =
610 padding_and_spacing(&flexbox_layout.geometry, Orientation::Horizontal, &expr_eval);
611 let (padding_v, spacing_v) =
612 padding_and_spacing(&flexbox_layout.geometry, Orientation::Vertical, &expr_eval);
613
614 let flex_wrap = flexbox_layout
615 .flex_wrap
616 .as_ref()
617 .map_or(i_slint_core::items::FlexboxLayoutWrap::default(), |nr| {
618 eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
619 });
620
621 if is_main_axis {
622 let (cells, spacing, padding) = match orientation {
623 Orientation::Horizontal => (&cells_h, spacing_h, &padding_h),
624 Orientation::Vertical => (&cells_v, spacing_v, &padding_v),
625 };
626 core_layout::flexbox_layout_info_main_axis(
627 Slice::from(cells.as_slice()),
628 Slice::from(flex_props.as_slice()),
629 spacing,
630 padding,
631 flex_wrap,
632 )
633 .into()
634 } else {
635 let constraint_size = cross_axis_size.unwrap_or_else(|| match orientation {
639 Orientation::Horizontal => {
640 let height_ref = &flexbox_layout.geometry.rect.height_reference;
641 height_ref.as_ref().map(&expr_eval).unwrap_or(0.)
642 }
643 Orientation::Vertical => {
644 let width_ref = &flexbox_layout.geometry.rect.width_reference;
645 width_ref.as_ref().map(&expr_eval).unwrap_or(0.)
646 }
647 });
648 core_layout::flexbox_layout_info_cross_axis(
649 Slice::from(cells_h.as_slice()),
650 Slice::from(cells_v.as_slice()),
651 Slice::from(flex_props.as_slice()),
652 spacing_h,
653 spacing_v,
654 &padding_h,
655 &padding_v,
656 direction,
657 flex_wrap,
658 constraint_size,
659 )
660 .into()
661 }
662}
663
664fn flexbox_layout_data(
665 flexbox_layout: &i_slint_compiler::layout::FlexboxLayout,
666 component: InstanceRef,
667 expr_eval: &impl Fn(&NamedReference) -> f32,
668 _local_context: &mut EvalLocalContext,
669 width_override: Option<f32>,
670 height_override: Option<f32>,
671) -> (
672 Vec<core_layout::LayoutItemInfo>,
673 Vec<core_layout::LayoutItemInfo>,
674 Vec<core_layout::FlexItemProps>,
675 Vec<u32>,
676) {
677 let window_adapter = component.window_adapter();
678 let mut cells_h = Vec::with_capacity(flexbox_layout.elems.len());
679 let mut cells_v = Vec::with_capacity(flexbox_layout.elems.len());
680 let mut repeated_indices = Vec::new();
681
682 let mut repeater_instance_vecs: Vec<Vec<crate::dynamic_item_tree::DynamicComponentVRc>> =
686 Vec::new();
687
688 for layout_elem in &flexbox_layout.elems {
689 if layout_elem.item.element.borrow().repeated.is_some() {
690 let component_vec = repeater_instances(component, &layout_elem.item.element);
691 repeated_indices.push(cells_h.len() as u32);
692 repeated_indices.push(component_vec.len() as u32);
693 cells_h.extend(component_vec.iter().map(|x| {
694 x.as_pin_ref().flexbox_layout_item_info(to_runtime(Orientation::Horizontal), None)
695 }));
696 let rep_root =
703 layout_elem.item.element.borrow().base_type.as_component().root_element.clone();
704 if rep_root.borrow().inherited_layout_info_v_with_constraint().is_some() {
705 cells_v.resize_with(cells_v.len() + component_vec.len(), Default::default);
706 } else {
707 cells_v.extend(component_vec.iter().map(|x| {
708 let info = x
709 .as_pin_ref()
710 .flexbox_layout_item_info(to_runtime(Orientation::Vertical), None);
711 core_layout::LayoutItemInfo { constraint: info.constraint }
712 }));
713 }
714 repeater_instance_vecs.push(component_vec);
715 } else {
716 let h_constraint = layout_elem
722 .item
723 .element
724 .borrow()
725 .inherited_layout_info_h_with_constraint()
726 .is_some()
727 .then(|| height_override.unwrap_or(f32::MAX));
728 let mut layout_info_h = get_layout_info_with_constraint(
729 &layout_elem.item.element,
730 component,
731 &window_adapter,
732 Orientation::Horizontal,
733 h_constraint,
734 );
735 fill_layout_info_constraints(
736 &mut layout_info_h,
737 &layout_elem.item.constraints,
738 Orientation::Horizontal,
739 expr_eval,
740 );
741 let flex_grow = layout_elem.flex_grow.as_ref().map(&expr_eval).unwrap_or(0.0);
745 let flex_shrink = layout_elem.flex_shrink.as_ref().map(&expr_eval).unwrap_or(1.0);
746 let flex_basis = layout_elem.flex_basis.as_ref().map(&expr_eval).unwrap_or(-1.0);
747 let align_self = layout_elem
748 .align_self
749 .as_ref()
750 .map(|nr| {
751 eval::load_property(component, &nr.element(), nr.name())
752 .unwrap()
753 .try_into()
754 .unwrap()
755 })
756 .unwrap_or(i_slint_core::items::FlexboxLayoutAlignSelf::default());
757 let order = layout_elem.order.as_ref().map(expr_eval).unwrap_or(0.0) as i32;
758 cells_h.push(core_layout::FlexboxLayoutItemInfo {
759 constraint: layout_info_h,
760 props: core_layout::FlexItemProps {
761 flex_grow,
762 flex_shrink,
763 flex_basis,
764 flex_align_self: align_self,
765 flex_order: order,
766 },
767 });
768 cells_v.push(core_layout::LayoutItemInfo::default());
770 }
771 }
772
773 let mut cell_idx = 0usize;
777 let mut repeater_idx = 0usize;
778 for layout_elem in &flexbox_layout.elems {
779 if layout_elem.item.element.borrow().repeated.is_some() {
780 let rep_root =
786 layout_elem.item.element.borrow().base_type.as_component().root_element.clone();
787 let is_height_for_width =
788 rep_root.borrow().inherited_layout_info_v_with_constraint().is_some();
789 let component_vec = &repeater_instance_vecs[repeater_idx];
790 repeater_idx += 1;
791 for instance in component_vec {
792 if is_height_for_width {
793 let width_constraint = width_override
794 .unwrap_or_else(|| cells_h[cell_idx].constraint.preferred_bounded());
795 generativity::make_guard!(guard);
796 let unerased = instance.unerase(guard);
797 let instance_ref = unerased.borrow_instance();
798 let mut layout_info_v = get_layout_info_with_constraint(
799 &rep_root,
800 instance_ref,
801 &window_adapter,
802 Orientation::Vertical,
803 Some(width_constraint),
804 );
805 let instance_expr_eval = |nr: &NamedReference| -> f32 {
809 eval::load_property(instance_ref, &nr.element(), nr.name())
810 .unwrap()
811 .try_into()
812 .unwrap()
813 };
814 let effective = layout_elem
820 .item
821 .constraints
822 .to_apply(&layout_elem.item.element, Orientation::Vertical);
823 fill_layout_info_constraints(
824 &mut layout_info_v,
825 &effective,
826 Orientation::Vertical,
827 &instance_expr_eval,
828 );
829 cells_v[cell_idx] = core_layout::LayoutItemInfo { constraint: layout_info_v };
832 }
833 cell_idx += 1;
834 }
835 } else {
836 let width_constraint =
837 width_override.unwrap_or_else(|| cells_h[cell_idx].constraint.preferred_bounded());
838 let mut layout_info_v = get_layout_info_with_constraint(
839 &layout_elem.item.element,
840 component,
841 &window_adapter,
842 Orientation::Vertical,
843 Some(width_constraint),
844 );
845 let effective = layout_elem
851 .item
852 .constraints
853 .to_apply(&layout_elem.item.element, Orientation::Vertical);
854 fill_layout_info_constraints(
855 &mut layout_info_v,
856 &effective,
857 Orientation::Vertical,
858 expr_eval,
859 );
860 cells_v[cell_idx] = core_layout::LayoutItemInfo { constraint: layout_info_v };
861 cell_idx += 1;
862 }
863 }
864
865 let flex_props = cells_h.iter().map(|c| c.props).collect();
868 let cells_h = cells_h
869 .into_iter()
870 .map(|c| core_layout::LayoutItemInfo { constraint: c.constraint })
871 .collect();
872 (cells_h, cells_v, flex_props, repeated_indices)
873}
874
875fn padding_and_spacing(
877 layout_geometry: &LayoutGeometry,
878 orientation: Orientation,
879 expr_eval: &impl Fn(&NamedReference) -> f32,
880) -> (core_layout::Padding, f32) {
881 let spacing = layout_geometry.spacing.orientation(orientation).map_or(0., expr_eval);
882 let (begin, end) = layout_geometry.padding.begin_end(orientation);
883 let padding =
884 core_layout::Padding { begin: begin.map_or(0., expr_eval), end: end.map_or(0., expr_eval) };
885 (padding, spacing)
886}
887
888fn repeater_instances(
889 component: InstanceRef,
890 elem: &ElementRc,
891) -> Vec<crate::dynamic_item_tree::DynamicComponentVRc> {
892 generativity::make_guard!(guard);
893 let rep =
894 crate::dynamic_item_tree::get_repeater_by_name(component, elem.borrow().id.as_str(), guard);
895 rep.0.as_ref().track_instance_changes();
896 rep.0.as_ref().instances_vec()
897}
898
899fn grid_layout_input_data(
900 grid_layout: &i_slint_compiler::layout::GridLayout,
901 ctx: &EvalLocalContext,
902 repeater_steps: &[u32],
903) -> Vec<GridLayoutInputData> {
904 let component = ctx.component_instance;
905 let mut result = Vec::with_capacity(grid_layout.elems.len());
906 let mut after_repeater_in_same_row = false;
907 let mut new_row = true;
908 let mut repeater_idx = 0usize;
909 for elem in grid_layout.elems.iter() {
910 let eval_or_default = |expr: &RowColExpr, component: InstanceRef| match expr {
911 RowColExpr::Literal(value) => *value as f32,
912 RowColExpr::Auto => i_slint_common::ROW_COL_AUTO,
913 RowColExpr::Named(nr) => {
914 eval::load_property(component, &nr.element(), nr.name())
916 .unwrap()
917 .try_into()
918 .unwrap()
919 }
920 };
921
922 let cell_new_row = elem.cell.borrow().new_row;
923 if cell_new_row {
924 after_repeater_in_same_row = false;
925 }
926 if elem.item.element.borrow().repeated.is_some() {
927 let component_vec = repeater_instances(component, &elem.item.element);
928 new_row = cell_new_row;
929 for erased_sub_comp in &component_vec {
930 generativity::make_guard!(guard);
932 let sub_comp = erased_sub_comp.as_pin_ref();
933 let sub_instance_ref =
934 unsafe { InstanceRef::from_pin_ref(sub_comp.borrow(), guard) };
935
936 if let Some(children) = elem.cell.borrow().child_items.as_ref() {
937 new_row = true;
939 let start_count = result.len();
940
941 for child_template in children {
947 match child_template {
948 i_slint_compiler::layout::RowChildTemplate::Static(child_item) => {
949 let (row_val, col_val, rowspan_val, colspan_val) = {
950 let element_ref = child_item.element.borrow();
951 let child_cell =
952 element_ref.grid_layout_cell.as_ref().unwrap().borrow();
953 (
954 eval_or_default(&child_cell.row_expr, sub_instance_ref),
955 eval_or_default(&child_cell.col_expr, sub_instance_ref),
956 eval_or_default(&child_cell.rowspan_expr, sub_instance_ref),
957 eval_or_default(&child_cell.colspan_expr, sub_instance_ref),
958 )
959 };
960 result.push(GridLayoutInputData {
961 new_row,
962 col: col_val,
963 row: row_val,
964 colspan: colspan_val,
965 rowspan: rowspan_val,
966 });
967 new_row = false;
968 }
969 i_slint_compiler::layout::RowChildTemplate::Repeated {
970 repeated_element,
971 ..
972 } => {
973 let inner_root = repeated_element
976 .borrow()
977 .base_type
978 .as_component()
979 .root_element
980 .clone();
981 let (rowspan_expr, colspan_expr) = {
982 let element_ref = inner_root.borrow();
983 let child_cell =
984 element_ref.grid_layout_cell.as_ref().unwrap().borrow();
985 (
986 child_cell.rowspan_expr.clone(),
987 child_cell.colspan_expr.clone(),
988 )
989 };
990 let inner_instances =
991 repeater_instances(sub_instance_ref, repeated_element);
992 for (i, erased_inner) in inner_instances.iter().enumerate() {
993 generativity::make_guard!(inner_guard);
994 let inner_comp = erased_inner.as_pin_ref();
995 let inner_instance_ref = unsafe {
996 InstanceRef::from_pin_ref(inner_comp.borrow(), inner_guard)
997 };
998 result.push(GridLayoutInputData {
999 new_row: i == 0 && new_row,
1000 rowspan: eval_or_default(&rowspan_expr, inner_instance_ref),
1001 colspan: eval_or_default(&colspan_expr, inner_instance_ref),
1002 ..Default::default()
1003 });
1004 }
1005 if !inner_instances.is_empty() {
1006 new_row = false;
1007 }
1008 }
1009 }
1010 }
1011 let cells_pushed = result.len() - start_count;
1013 let expected_step =
1014 repeater_steps.get(repeater_idx).copied().unwrap_or(0) as usize;
1015 for _ in cells_pushed..expected_step {
1016 result.push(GridLayoutInputData::default());
1017 }
1018 } else {
1019 let cell = elem.cell.borrow();
1021 let row = eval_or_default(&cell.row_expr, sub_instance_ref);
1022 let col = eval_or_default(&cell.col_expr, sub_instance_ref);
1023 let rowspan = eval_or_default(&cell.rowspan_expr, sub_instance_ref);
1024 let colspan = eval_or_default(&cell.colspan_expr, sub_instance_ref);
1025 result.push(GridLayoutInputData { new_row, col, row, colspan, rowspan });
1026 new_row = false;
1027 }
1028 }
1029 repeater_idx += 1;
1030 after_repeater_in_same_row = true;
1031 } else {
1032 let new_row =
1033 if cell_new_row || !after_repeater_in_same_row { cell_new_row } else { new_row };
1034 let row = eval_or_default(&elem.cell.borrow().row_expr, component);
1035 let col = eval_or_default(&elem.cell.borrow().col_expr, component);
1036 let rowspan = eval_or_default(&elem.cell.borrow().rowspan_expr, component);
1037 let colspan = eval_or_default(&elem.cell.borrow().colspan_expr, component);
1038 result.push(GridLayoutInputData { new_row, col, row, colspan, rowspan });
1039 }
1040 }
1041 result
1042}
1043
1044fn row_runtime_child_count(
1048 child_items: &[i_slint_compiler::layout::RowChildTemplate],
1049 sub_instance_ref: InstanceRef,
1050) -> usize {
1051 let mut count = 0;
1052 for child in child_items {
1053 if let Some(repeated_element) = child.repeated_element() {
1054 count += repeater_instances(sub_instance_ref, repeated_element).len();
1055 } else {
1056 count += 1;
1057 }
1058 }
1059 count
1060}
1061
1062fn grid_repeater_indices(
1063 grid_layout: &i_slint_compiler::layout::GridLayout,
1064 ctx: &mut EvalLocalContext,
1065 repeater_steps: &[u32],
1066) -> Vec<u32> {
1067 let component = ctx.component_instance;
1068 let mut repeater_indices = Vec::new();
1069 let mut num_cells = 0;
1070 let mut step_idx = 0;
1071 for elem in grid_layout.elems.iter() {
1072 if elem.item.element.borrow().repeated.is_some() {
1073 let component_vec = repeater_instances(component, &elem.item.element);
1074 repeater_indices.push(num_cells as _);
1075 repeater_indices.push(component_vec.len() as _);
1076 let item_count = repeater_steps[step_idx] as usize;
1077 num_cells += component_vec.len() * item_count;
1078 step_idx += 1;
1079 } else {
1080 num_cells += 1;
1081 }
1082 }
1083 repeater_indices
1084}
1085
1086fn grid_repeater_steps(
1087 grid_layout: &i_slint_compiler::layout::GridLayout,
1088 ctx: &mut EvalLocalContext,
1089) -> Vec<u32> {
1090 let component = ctx.component_instance;
1091 let mut repeater_steps = Vec::new();
1092 for elem in grid_layout.elems.iter() {
1093 if elem.item.element.borrow().repeated.is_some() {
1094 let item_count = match &elem.cell.borrow().child_items {
1095 Some(ci)
1096 if ci.iter().any(i_slint_compiler::layout::RowChildTemplate::is_repeated) =>
1097 {
1098 let component_vec = repeater_instances(component, &elem.item.element);
1100 component_vec
1101 .iter()
1102 .map(|sub| {
1103 generativity::make_guard!(guard);
1104 let sub_pin = sub.as_pin_ref();
1105 let sub_ref =
1106 unsafe { InstanceRef::from_pin_ref(sub_pin.borrow(), guard) };
1107 row_runtime_child_count(ci, sub_ref)
1108 })
1109 .max()
1110 .unwrap_or(0)
1111 }
1112 Some(ci) => ci.len(),
1113 None => 1,
1114 };
1115 repeater_steps.push(item_count as u32);
1116 }
1117 }
1118 repeater_steps
1119}
1120
1121fn grid_layout_constraints(
1122 grid_layout: &i_slint_compiler::layout::GridLayout,
1123 orientation: Orientation,
1124 ctx: &mut EvalLocalContext,
1125 repeater_steps: &[u32],
1126 cross_axis_size: Option<f32>,
1127) -> Vec<core_layout::LayoutItemInfo> {
1128 let component = ctx.component_instance;
1129 let expr_eval = |nr: &NamedReference| -> f32 {
1130 eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
1131 };
1132 let mut constraints = Vec::with_capacity(grid_layout.elems.len());
1133
1134 let mut repeater_idx = 0usize;
1135 for layout_elem in grid_layout.elems.iter() {
1136 if layout_elem.item.element.borrow().repeated.is_some() {
1137 let component_vec = repeater_instances(component, &layout_elem.item.element);
1138 let child_items = layout_elem.cell.borrow().child_items.clone();
1139 let has_children = child_items.is_some();
1140 if has_children {
1141 let ci = child_items.as_ref().unwrap();
1143 let step = repeater_steps.get(repeater_idx).copied().unwrap_or(0) as usize;
1144 for sub_comp in &component_vec {
1145 let per_instance_start = constraints.len();
1146 generativity::make_guard!(guard);
1148 let sub_pin = sub_comp.as_pin_ref();
1149 let sub_borrow = sub_pin.borrow();
1150 let sub_instance_ref = unsafe { InstanceRef::from_pin_ref(sub_borrow, guard) };
1151 let expr_eval = |nr: &NamedReference| -> f32 {
1152 eval::load_property(sub_instance_ref, &nr.element(), nr.name())
1153 .unwrap()
1154 .try_into()
1155 .unwrap()
1156 };
1157
1158 for child_template in ci.iter() {
1162 match child_template {
1163 i_slint_compiler::layout::RowChildTemplate::Static(child_item) => {
1164 let mut layout_info = crate::eval_layout::get_layout_info(
1165 &child_item.element,
1166 sub_instance_ref,
1167 &sub_instance_ref.window_adapter(),
1168 orientation,
1169 );
1170 fill_layout_info_constraints(
1171 &mut layout_info,
1172 &child_item.constraints,
1173 orientation,
1174 &expr_eval,
1175 );
1176 constraints
1177 .push(core_layout::LayoutItemInfo { constraint: layout_info });
1178 }
1179 i_slint_compiler::layout::RowChildTemplate::Repeated {
1180 item: child_item,
1181 repeated_element,
1182 } => {
1183 let inner_instances =
1185 repeater_instances(sub_instance_ref, repeated_element);
1186 for inner_comp in &inner_instances {
1187 let inner_pin = inner_comp.as_pin_ref();
1188 let mut layout_info =
1189 inner_pin.layout_item_info(to_runtime(orientation), None);
1190 generativity::make_guard!(inner_guard);
1193 let inner_borrow = inner_pin.borrow();
1194 let inner_instance_ref = unsafe {
1195 InstanceRef::from_pin_ref(inner_borrow, inner_guard)
1196 };
1197 let inner_expr_eval = |nr: &NamedReference| -> f32 {
1198 eval::load_property(
1199 inner_instance_ref,
1200 &nr.element(),
1201 nr.name(),
1202 )
1203 .unwrap()
1204 .try_into()
1205 .unwrap()
1206 };
1207 fill_layout_info_constraints(
1208 &mut layout_info.constraint,
1209 &child_item.constraints,
1210 orientation,
1211 &inner_expr_eval,
1212 );
1213 constraints.push(layout_info);
1214 }
1215 }
1216 }
1217 }
1218 let pushed = constraints.len() - per_instance_start;
1221 for _ in pushed..step {
1222 constraints.push(core_layout::LayoutItemInfo::default());
1223 }
1224 }
1225 } else {
1226 constraints.extend(
1228 component_vec
1229 .iter()
1230 .map(|x| x.as_pin_ref().layout_item_info(to_runtime(orientation), None)),
1231 );
1232 }
1233 repeater_idx += 1;
1234 } else {
1235 let cross_axis =
1236 cross_axis_size_for_cell(&layout_elem.item.element, orientation, cross_axis_size);
1237 let mut layout_info = get_layout_info_with_constraint(
1238 &layout_elem.item.element,
1239 component,
1240 &component.window_adapter(),
1241 orientation,
1242 cross_axis,
1243 );
1244 fill_layout_info_constraints(
1245 &mut layout_info,
1246 &layout_elem.item.constraints,
1247 orientation,
1248 &expr_eval,
1249 );
1250 constraints.push(core_layout::LayoutItemInfo { constraint: layout_info });
1251 }
1252 }
1253 constraints
1254}
1255
1256fn box_layout_data(
1258 box_layout: &i_slint_compiler::layout::BoxLayout,
1259 orientation: Orientation,
1260 component: InstanceRef,
1261 expr_eval: &impl Fn(&NamedReference) -> f32,
1262 mut repeater_indices: Option<&mut Vec<u32>>,
1263 cross_axis_size: Option<f32>,
1264 local_context: &mut EvalLocalContext,
1265 available_cross: Option<f32>,
1266) -> (Vec<core_layout::LayoutItemInfo>, i_slint_core::items::LayoutAlignment) {
1267 let window_adapter = component.window_adapter();
1268 let mut cells = Vec::with_capacity(box_layout.elems.len());
1269 for cell in &box_layout.elems {
1270 if cell.element.borrow().repeated.is_some() {
1271 let component_vec = repeater_instances(component, &cell.element);
1273 if let Some(ri) = repeater_indices.as_mut() {
1274 ri.push(cells.len() as _);
1275 ri.push(component_vec.len() as _);
1276 }
1277 cells.extend(
1278 component_vec
1279 .iter()
1280 .map(|x| x.as_pin_ref().layout_item_info(to_runtime(orientation), None)),
1281 );
1282 } else {
1283 let cross_axis = cross_axis_size_for_cell(&cell.element, orientation, cross_axis_size);
1285 let mut layout_info = get_layout_info_with_constraint(
1286 &cell.element,
1287 component,
1288 &window_adapter,
1289 orientation,
1290 cross_axis,
1291 );
1292 clamp_wrapping_flex_cross_preferred(
1293 &mut layout_info,
1294 &cell.element,
1295 box_layout,
1296 orientation,
1297 component,
1298 &expr_eval,
1299 local_context,
1300 available_cross,
1301 );
1302 fill_layout_info_constraints(
1303 &mut layout_info,
1304 &cell.constraints,
1305 orientation,
1306 &expr_eval,
1307 );
1308 cells.push(core_layout::LayoutItemInfo { constraint: layout_info });
1309 }
1310 }
1311 let alignment = box_layout
1312 .geometry
1313 .alignment
1314 .as_ref()
1315 .map(|nr| {
1316 eval::load_property(component, &nr.element(), nr.name())
1317 .unwrap()
1318 .try_into()
1319 .unwrap_or_default()
1320 })
1321 .unwrap_or_default();
1322 (cells, alignment)
1323}
1324
1325#[allow(clippy::too_many_arguments)]
1336fn clamp_wrapping_flex_cross_preferred(
1337 layout_info: &mut core_layout::LayoutInfo,
1338 elem: &ElementRc,
1339 box_layout: &i_slint_compiler::layout::BoxLayout,
1340 orientation: Orientation,
1341 component: InstanceRef,
1342 expr_eval: &impl Fn(&NamedReference) -> f32,
1343 local_context: &mut EvalLocalContext,
1344 available_cross: Option<f32>,
1345) {
1346 let Some(available) = available_cross else { return };
1347 if orientation == box_layout.orientation {
1348 return;
1349 }
1350 let Some(fl) = i_slint_compiler::layout::FlexboxLayout::from_element(elem) else { return };
1351
1352 let direction = flexbox_layout_direction(&fl, local_context);
1354 let main_is_cross = matches!(
1355 (direction, orientation),
1356 (FlexboxLayoutDirection::Row | FlexboxLayoutDirection::RowReverse, Orientation::Horizontal)
1357 | (
1358 FlexboxLayoutDirection::Column | FlexboxLayoutDirection::ColumnReverse,
1359 Orientation::Vertical
1360 )
1361 );
1362 if !main_is_cross {
1363 return;
1364 }
1365 let flex_wrap =
1366 fl.flex_wrap.as_ref().map_or(i_slint_core::items::FlexboxLayoutWrap::default(), |nr| {
1367 eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
1368 });
1369 if matches!(flex_wrap, i_slint_core::items::FlexboxLayoutWrap::NoWrap) {
1370 return;
1371 }
1372
1373 let (cells_h, cells_v, flex_props, _ri) =
1374 flexbox_layout_data(&fl, component, expr_eval, local_context, None, None);
1375 let (cells, padding, spacing) = match orientation {
1376 Orientation::Horizontal => {
1377 let (padding, spacing) =
1378 padding_and_spacing(&fl.geometry, Orientation::Horizontal, expr_eval);
1379 (cells_h, padding, spacing)
1380 }
1381 Orientation::Vertical => {
1382 let (padding, spacing) =
1383 padding_and_spacing(&fl.geometry, Orientation::Vertical, expr_eval);
1384 (cells_v, padding, spacing)
1385 }
1386 };
1387 let unwrapped = core_layout::flexbox_layout_unwrapped_main(
1388 Slice::from(cells.as_slice()),
1389 Slice::from(flex_props.as_slice()),
1390 spacing,
1391 &padding,
1392 );
1393 layout_info.preferred = available.min(unwrapped);
1394}
1395
1396pub(crate) fn fill_layout_info_constraints(
1397 layout_info: &mut core_layout::LayoutInfo,
1398 constraints: &LayoutConstraints,
1399 orientation: Orientation,
1400 expr_eval: &impl Fn(&NamedReference) -> f32,
1401) {
1402 let is_percent =
1403 |nr: &NamedReference| Expression::PropertyReference(nr.clone()).ty() == Type::Percent;
1404
1405 match orientation {
1406 Orientation::Horizontal => {
1407 if let Some(e) = constraints.min_width.as_ref() {
1408 if !is_percent(e) {
1409 layout_info.min = expr_eval(e)
1410 } else {
1411 layout_info.min_percent = expr_eval(e)
1412 }
1413 }
1414 if let Some(e) = constraints.max_width.as_ref() {
1415 if !is_percent(e) {
1416 layout_info.max = expr_eval(e)
1417 } else {
1418 layout_info.max_percent = expr_eval(e)
1419 }
1420 }
1421 if let Some(e) = constraints.preferred_width.as_ref() {
1422 layout_info.preferred = expr_eval(e);
1423 }
1424 if let Some(e) = constraints.horizontal_stretch.as_ref() {
1425 layout_info.stretch = expr_eval(e);
1426 }
1427 }
1428 Orientation::Vertical => {
1429 if let Some(e) = constraints.min_height.as_ref() {
1430 if !is_percent(e) {
1431 layout_info.min = expr_eval(e)
1432 } else {
1433 layout_info.min_percent = expr_eval(e)
1434 }
1435 }
1436 if let Some(e) = constraints.max_height.as_ref() {
1437 if !is_percent(e) {
1438 layout_info.max = expr_eval(e)
1439 } else {
1440 layout_info.max_percent = expr_eval(e)
1441 }
1442 }
1443 if let Some(e) = constraints.preferred_height.as_ref() {
1444 layout_info.preferred = expr_eval(e);
1445 }
1446 if let Some(e) = constraints.vertical_stretch.as_ref() {
1447 layout_info.stretch = expr_eval(e);
1448 }
1449 }
1450 }
1451}
1452
1453pub(crate) fn get_layout_info(
1455 elem: &ElementRc,
1456 component: InstanceRef,
1457 window_adapter: &Rc<dyn WindowAdapter>,
1458 orientation: Orientation,
1459) -> core_layout::LayoutInfo {
1460 get_layout_info_with_constraint(elem, component, window_adapter, orientation, None)
1461}
1462
1463pub(crate) fn get_layout_info_with_constraint(
1464 elem: &ElementRc,
1465 component: InstanceRef,
1466 window_adapter: &Rc<dyn WindowAdapter>,
1467 orientation: Orientation,
1468 cross_axis_constraint: Option<f32>,
1469) -> core_layout::LayoutInfo {
1470 let parameterized_nr = if cross_axis_constraint.is_some() {
1476 match orientation {
1477 Orientation::Vertical => elem.borrow().inherited_layout_info_v_with_constraint(),
1478 Orientation::Horizontal => elem.borrow().inherited_layout_info_h_with_constraint(),
1479 }
1480 } else {
1481 None
1482 };
1483 if let Some(nr) = parameterized_nr {
1484 let arg = cross_axis_constraint.unwrap();
1485 let v = eval::call_function(
1486 &eval::ComponentInstance::InstanceRef(component),
1487 &nr.element(),
1488 nr.name(),
1489 vec![Value::Number(arg as f64)],
1490 )
1491 .expect("layoutinfo-{h,v}-with-constraint is a synthesized pure function");
1492 return v.try_into().unwrap();
1493 }
1494
1495 let elem = elem.borrow();
1496 if let Some(nr) = elem.layout_info_prop(orientation) {
1497 eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
1498 } else {
1499 let item = &component
1500 .description
1501 .items
1502 .get(elem.id.as_str())
1503 .unwrap_or_else(|| panic!("Internal error: Item {} not found", elem.id));
1504 let item_comp = component.self_weak().get().unwrap().upgrade().unwrap();
1505
1506 unsafe {
1507 item.item_from_item_tree(component.as_ptr()).as_ref().layout_info(
1508 to_runtime(orientation),
1509 cross_axis_constraint.unwrap_or(-1.),
1510 window_adapter,
1511 &ItemRc::new(vtable::VRc::into_dyn(item_comp), item.item_index()),
1512 )
1513 }
1514 }
1515}
1516
1517fn cross_axis_size_for_cell(
1524 elem: &ElementRc,
1525 orientation: Orientation,
1526 parent_cross_axis_size: Option<f32>,
1527) -> Option<f32> {
1528 let cross = parent_cross_axis_size?;
1529 let elem_b = elem.borrow();
1530 if orientation == Orientation::Horizontal {
1531 return elem_b.inherited_layout_info_h_with_constraint().is_some().then_some(cross);
1536 }
1537 if elem_b.layout_info_v_with_constraint.is_some() {
1538 return Some(cross);
1539 }
1540 if elem_b.layout_info_prop(Orientation::Vertical).is_none() {
1545 return Some(cross);
1546 }
1547 None
1548}