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, 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 align_content = flexbox_layout
303 .align_content
304 .as_ref()
305 .map_or(i_slint_core::items::FlexboxLayoutAlignContent::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 align_content,
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 };
341 let ri = Slice::from(repeated_indices.as_slice());
342
343 let window_adapter = component.window_adapter();
344
345 struct ChildElem {
355 elem: ElementRc,
356 has_constrained_layoutinfo_v: bool,
357 has_constrained_layoutinfo_h: bool,
358 has_aggregated_info: bool,
365 repeated_instance: Option<crate::dynamic_item_tree::DynamicComponentVRc>,
369 }
370 let mut child_elems: Vec<Option<ChildElem>> = Vec::new();
371 for layout_elem in &flexbox_layout.elems {
372 let placeholder = layout_elem.item.element.borrow();
373 let repeated = placeholder.repeated.is_some();
374 let query_elem = if repeated {
379 placeholder.base_type.as_component().root_element.clone()
380 } else {
381 layout_elem.item.element.clone()
382 };
383 drop(placeholder);
384 let qe = query_elem.borrow();
385 let has_constrained_layoutinfo_v = qe.inherited_layout_info_v_with_constraint().is_some();
386 let has_constrained_layoutinfo_h = qe.inherited_layout_info_h_with_constraint().is_some();
387 let has_aggregated_info = qe.layout_info_prop.is_some();
388 drop(qe);
389 if repeated {
390 let component_vec = repeater_instances(component, &layout_elem.item.element);
393 for instance in component_vec {
394 child_elems.push(Some(ChildElem {
395 elem: query_elem.clone(),
396 has_constrained_layoutinfo_v,
397 has_constrained_layoutinfo_h,
398 has_aggregated_info,
399 repeated_instance: Some(instance),
400 }));
401 }
402 } else {
403 child_elems.push(Some(ChildElem {
404 elem: query_elem,
405 has_constrained_layoutinfo_v,
406 has_constrained_layoutinfo_h,
407 has_aggregated_info,
408 repeated_instance: None,
409 }));
410 }
411 }
412
413 let mut measure = |child_index: usize,
414 known_w: Option<f32>,
415 known_h: Option<f32>|
416 -> (f32, f32) {
417 let default_w = cells_h.get(child_index).map_or(0., |c| c.constraint.preferred_bounded());
418 let default_h = cells_v.get(child_index).map_or(0., |c| c.constraint.preferred_bounded());
419 let w = known_w.unwrap_or(default_w);
420 let h = known_h.unwrap_or(default_h);
421
422 let ce = match child_elems.get(child_index) {
423 Some(Some(c)) => c,
424 _ => return (w, h),
425 };
426
427 let use_property_lookup = ce.has_aggregated_info
433 || ce.has_constrained_layoutinfo_v
434 || ce.has_constrained_layoutinfo_h;
435
436 let query = |orientation, constraint: Option<f32>| -> core_layout::LayoutInfo {
441 match &ce.repeated_instance {
442 Some(instance) => {
443 generativity::make_guard!(guard);
444 let unerased = instance.unerase(guard);
445 get_layout_info_with_constraint(
446 &ce.elem,
447 unerased.borrow_instance(),
448 &window_adapter,
449 orientation,
450 constraint,
451 )
452 }
453 None => get_layout_info_with_constraint(
454 &ce.elem,
455 component,
456 &window_adapter,
457 orientation,
458 constraint,
459 ),
460 }
461 };
462
463 if known_w.is_some() && known_h.is_none() {
464 if use_property_lookup {
465 let v_info =
466 query(Orientation::Vertical, ce.has_constrained_layoutinfo_v.then_some(w));
467 return (w, v_info.preferred_bounded());
468 }
469 if let Some(item_within) = ce
476 .repeated_instance
477 .is_none()
478 .then(|| component.description.items.get(ce.elem.borrow().id.as_str()))
479 .flatten()
480 {
481 let item_comp = component.self_weak().get().unwrap().upgrade().unwrap();
482 let item_rc =
483 ItemRc::new(vtable::VRc::into_dyn(item_comp), item_within.item_index());
484 let item = unsafe { item_within.item_from_item_tree(component.as_ptr()) };
485 let v_info = item.as_ref().layout_info(
486 to_runtime(Orientation::Vertical),
487 w,
488 &window_adapter,
489 &item_rc,
490 );
491 return (w, v_info.preferred_bounded());
492 }
493 return (w, h);
494 }
495 if known_h.is_some() && known_w.is_none() {
496 if use_property_lookup {
497 let h_info =
498 query(Orientation::Horizontal, ce.has_constrained_layoutinfo_h.then_some(h));
499 return (h_info.preferred_bounded(), h);
500 }
501 if let Some(item_within) = ce
504 .repeated_instance
505 .is_none()
506 .then(|| component.description.items.get(ce.elem.borrow().id.as_str()))
507 .flatten()
508 {
509 let item_comp = component.self_weak().get().unwrap().upgrade().unwrap();
510 let item_rc =
511 ItemRc::new(vtable::VRc::into_dyn(item_comp), item_within.item_index());
512 let item = unsafe { item_within.item_from_item_tree(component.as_ptr()) };
513 let h_info = item.as_ref().layout_info(
514 to_runtime(Orientation::Horizontal),
515 h,
516 &window_adapter,
517 &item_rc,
518 );
519 return (h_info.preferred_bounded(), h);
520 }
521 return (w, h);
522 }
523 (w, h)
524 };
525
526 core_layout::solve_flexbox_layout_with_measure(&data, ri, Some(&mut measure)).into()
527}
528
529fn flexbox_layout_direction(
530 flexbox_layout: &i_slint_compiler::layout::FlexboxLayout,
531 local_context: &EvalLocalContext,
532) -> FlexboxLayoutDirection {
533 flexbox_layout
534 .direction
535 .as_ref()
536 .and_then(|nr| {
537 let value =
538 eval::load_property(local_context.component_instance, &nr.element(), nr.name())
539 .ok()?;
540 if let Value::EnumerationValue(_, variant) = &value {
541 match variant.as_str() {
542 "row" => Some(FlexboxLayoutDirection::Row),
543 "row-reverse" => Some(FlexboxLayoutDirection::RowReverse),
544 "column" => Some(FlexboxLayoutDirection::Column),
545 "column-reverse" => Some(FlexboxLayoutDirection::ColumnReverse),
546 _ => None,
547 }
548 } else {
549 None
550 }
551 })
552 .unwrap_or(FlexboxLayoutDirection::Row)
553}
554
555pub(crate) fn compute_flexbox_layout_info(
556 flexbox_layout: &i_slint_compiler::layout::FlexboxLayout,
557 orientation: Orientation,
558 local_context: &mut EvalLocalContext,
559 cross_axis_size: Option<f32>,
560) -> Value {
561 let component = local_context.component_instance;
562 let expr_eval = |nr: &NamedReference| -> f32 {
563 eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
564 };
565
566 let (width_override, height_override) = match orientation {
571 Orientation::Vertical => (cross_axis_size, None),
572 Orientation::Horizontal => (None, cross_axis_size),
573 };
574 let width_override = width_override.map(|w| {
577 let (pad_h, _) =
578 padding_and_spacing(&flexbox_layout.geometry, Orientation::Horizontal, &expr_eval);
579 w - pad_h.begin - pad_h.end
580 });
581 let height_override = height_override.map(|h| {
582 let (pad_v, _) =
583 padding_and_spacing(&flexbox_layout.geometry, Orientation::Vertical, &expr_eval);
584 h - pad_v.begin - pad_v.end
585 });
586 let (cells_h, cells_v, _repeated_indices) = flexbox_layout_data(
587 flexbox_layout,
588 component,
589 &expr_eval,
590 local_context,
591 width_override,
592 height_override,
593 );
594
595 let direction = flexbox_layout_direction(flexbox_layout, local_context);
597
598 let is_main_axis = matches!(
600 (direction, orientation),
601 (FlexboxLayoutDirection::Row | FlexboxLayoutDirection::RowReverse, Orientation::Horizontal)
602 | (
603 FlexboxLayoutDirection::Column | FlexboxLayoutDirection::ColumnReverse,
604 Orientation::Vertical
605 )
606 );
607
608 let (padding_h, spacing_h) =
609 padding_and_spacing(&flexbox_layout.geometry, Orientation::Horizontal, &expr_eval);
610 let (padding_v, spacing_v) =
611 padding_and_spacing(&flexbox_layout.geometry, Orientation::Vertical, &expr_eval);
612
613 let flex_wrap = flexbox_layout
614 .flex_wrap
615 .as_ref()
616 .map_or(i_slint_core::items::FlexboxLayoutWrap::default(), |nr| {
617 eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
618 });
619
620 if is_main_axis {
621 let (cells, spacing, padding) = match orientation {
622 Orientation::Horizontal => (&cells_h, spacing_h, &padding_h),
623 Orientation::Vertical => (&cells_v, spacing_v, &padding_v),
624 };
625 core_layout::flexbox_layout_info_main_axis(
626 Slice::from(cells.as_slice()),
627 spacing,
628 padding,
629 flex_wrap,
630 )
631 .into()
632 } else {
633 let constraint_size = cross_axis_size.unwrap_or_else(|| match orientation {
637 Orientation::Horizontal => {
638 let height_ref = &flexbox_layout.geometry.rect.height_reference;
639 height_ref.as_ref().map(&expr_eval).unwrap_or(0.)
640 }
641 Orientation::Vertical => {
642 let width_ref = &flexbox_layout.geometry.rect.width_reference;
643 width_ref.as_ref().map(&expr_eval).unwrap_or(0.)
644 }
645 });
646 core_layout::flexbox_layout_info_cross_axis(
647 Slice::from(cells_h.as_slice()),
648 Slice::from(cells_v.as_slice()),
649 spacing_h,
650 spacing_v,
651 &padding_h,
652 &padding_v,
653 direction,
654 flex_wrap,
655 constraint_size,
656 )
657 .into()
658 }
659}
660
661fn flexbox_layout_data(
662 flexbox_layout: &i_slint_compiler::layout::FlexboxLayout,
663 component: InstanceRef,
664 expr_eval: &impl Fn(&NamedReference) -> f32,
665 _local_context: &mut EvalLocalContext,
666 width_override: Option<f32>,
667 height_override: Option<f32>,
668) -> (Vec<core_layout::FlexboxLayoutItemInfo>, Vec<core_layout::FlexboxLayoutItemInfo>, Vec<u32>) {
669 let window_adapter = component.window_adapter();
670 let mut cells_h = Vec::with_capacity(flexbox_layout.elems.len());
671 let mut cells_v = Vec::with_capacity(flexbox_layout.elems.len());
672 let mut repeated_indices = Vec::new();
673
674 struct ChildInfo {
677 flex_grow: f32,
678 flex_shrink: f32,
679 flex_basis: f32,
680 flex_align_self: i_slint_core::items::FlexboxLayoutAlignSelf,
681 flex_order: i32,
682 }
683 let mut static_children: Vec<Option<ChildInfo>> = Vec::new(); 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 cells_v.extend(component_vec.iter().map(|x| {
697 x.as_pin_ref().flexbox_layout_item_info(to_runtime(Orientation::Vertical), None)
698 }));
699 static_children.resize_with(static_children.len() + component_vec.len(), || None);
700 repeater_instance_vecs.push(component_vec);
701 } else {
702 let h_constraint = layout_elem
708 .item
709 .element
710 .borrow()
711 .inherited_layout_info_h_with_constraint()
712 .is_some()
713 .then(|| height_override.unwrap_or(f32::MAX));
714 let mut layout_info_h = get_layout_info_with_constraint(
715 &layout_elem.item.element,
716 component,
717 &window_adapter,
718 Orientation::Horizontal,
719 h_constraint,
720 );
721 fill_layout_info_constraints(
722 &mut layout_info_h,
723 &layout_elem.item.constraints,
724 Orientation::Horizontal,
725 expr_eval,
726 );
727 let flex_grow = layout_elem.flex_grow.as_ref().map(&expr_eval).unwrap_or(0.0);
731 let flex_shrink = layout_elem.flex_shrink.as_ref().map(&expr_eval).unwrap_or(1.0);
732 let flex_basis = layout_elem.flex_basis.as_ref().map(&expr_eval).unwrap_or(-1.0);
733 let align_self = layout_elem
734 .align_self
735 .as_ref()
736 .map(|nr| {
737 eval::load_property(component, &nr.element(), nr.name())
738 .unwrap()
739 .try_into()
740 .unwrap()
741 })
742 .unwrap_or(i_slint_core::items::FlexboxLayoutAlignSelf::default());
743 let order = layout_elem.order.as_ref().map(expr_eval).unwrap_or(0.0) as i32;
744 cells_h.push(core_layout::FlexboxLayoutItemInfo {
745 constraint: layout_info_h,
746 flex_grow,
747 flex_shrink,
748 flex_basis,
749 flex_align_self: align_self,
750 flex_order: order,
751 });
752 cells_v.push(core_layout::FlexboxLayoutItemInfo::default());
754 static_children.push(Some(ChildInfo {
755 flex_grow,
756 flex_shrink,
757 flex_basis,
758 flex_align_self: align_self,
759 flex_order: order,
760 }));
761 }
762 }
763
764 let mut cell_idx = 0usize;
768 let mut repeater_idx = 0usize;
769 for layout_elem in &flexbox_layout.elems {
770 if layout_elem.item.element.borrow().repeated.is_some() {
771 let rep_root =
777 layout_elem.item.element.borrow().base_type.as_component().root_element.clone();
778 let is_height_for_width =
779 rep_root.borrow().inherited_layout_info_v_with_constraint().is_some();
780 let component_vec = &repeater_instance_vecs[repeater_idx];
781 repeater_idx += 1;
782 for instance in component_vec {
783 if is_height_for_width {
784 let width_constraint = width_override
785 .unwrap_or_else(|| cells_h[cell_idx].constraint.preferred_bounded());
786 generativity::make_guard!(guard);
787 let unerased = instance.unerase(guard);
788 let instance_ref = unerased.borrow_instance();
789 let mut layout_info_v = get_layout_info_with_constraint(
790 &rep_root,
791 instance_ref,
792 &window_adapter,
793 Orientation::Vertical,
794 Some(width_constraint),
795 );
796 let instance_expr_eval = |nr: &NamedReference| -> f32 {
800 eval::load_property(instance_ref, &nr.element(), nr.name())
801 .unwrap()
802 .try_into()
803 .unwrap()
804 };
805 fill_layout_info_constraints(
806 &mut layout_info_v,
807 &layout_elem.item.constraints,
808 Orientation::Vertical,
809 &instance_expr_eval,
810 );
811 cells_v[cell_idx].constraint = layout_info_v;
812 }
813 cell_idx += 1;
814 }
815 } else {
816 let width_constraint =
817 width_override.unwrap_or_else(|| cells_h[cell_idx].constraint.preferred_bounded());
818 let mut layout_info_v = get_layout_info_with_constraint(
819 &layout_elem.item.element,
820 component,
821 &window_adapter,
822 Orientation::Vertical,
823 Some(width_constraint),
824 );
825 fill_layout_info_constraints(
826 &mut layout_info_v,
827 &layout_elem.item.constraints,
828 Orientation::Vertical,
829 expr_eval,
830 );
831 if let Some(info) = &static_children[cell_idx] {
832 cells_v[cell_idx] = core_layout::FlexboxLayoutItemInfo {
833 constraint: layout_info_v,
834 flex_grow: info.flex_grow,
835 flex_shrink: info.flex_shrink,
836 flex_basis: info.flex_basis,
837 flex_align_self: info.flex_align_self,
838 flex_order: info.flex_order,
839 };
840 }
841 cell_idx += 1;
842 }
843 }
844
845 (cells_h, cells_v, repeated_indices)
846}
847
848fn padding_and_spacing(
850 layout_geometry: &LayoutGeometry,
851 orientation: Orientation,
852 expr_eval: &impl Fn(&NamedReference) -> f32,
853) -> (core_layout::Padding, f32) {
854 let spacing = layout_geometry.spacing.orientation(orientation).map_or(0., expr_eval);
855 let (begin, end) = layout_geometry.padding.begin_end(orientation);
856 let padding =
857 core_layout::Padding { begin: begin.map_or(0., expr_eval), end: end.map_or(0., expr_eval) };
858 (padding, spacing)
859}
860
861fn repeater_instances(
862 component: InstanceRef,
863 elem: &ElementRc,
864) -> Vec<crate::dynamic_item_tree::DynamicComponentVRc> {
865 generativity::make_guard!(guard);
866 let rep =
867 crate::dynamic_item_tree::get_repeater_by_name(component, elem.borrow().id.as_str(), guard);
868 rep.0.as_ref().track_instance_changes();
869 rep.0.as_ref().instances_vec()
870}
871
872fn grid_layout_input_data(
873 grid_layout: &i_slint_compiler::layout::GridLayout,
874 ctx: &EvalLocalContext,
875 repeater_steps: &[u32],
876) -> Vec<GridLayoutInputData> {
877 let component = ctx.component_instance;
878 let mut result = Vec::with_capacity(grid_layout.elems.len());
879 let mut after_repeater_in_same_row = false;
880 let mut new_row = true;
881 let mut repeater_idx = 0usize;
882 for elem in grid_layout.elems.iter() {
883 let eval_or_default = |expr: &RowColExpr, component: InstanceRef| match expr {
884 RowColExpr::Literal(value) => *value as f32,
885 RowColExpr::Auto => i_slint_common::ROW_COL_AUTO,
886 RowColExpr::Named(nr) => {
887 eval::load_property(component, &nr.element(), nr.name())
889 .unwrap()
890 .try_into()
891 .unwrap()
892 }
893 };
894
895 let cell_new_row = elem.cell.borrow().new_row;
896 if cell_new_row {
897 after_repeater_in_same_row = false;
898 }
899 if elem.item.element.borrow().repeated.is_some() {
900 let component_vec = repeater_instances(component, &elem.item.element);
901 new_row = cell_new_row;
902 for erased_sub_comp in &component_vec {
903 generativity::make_guard!(guard);
905 let sub_comp = erased_sub_comp.as_pin_ref();
906 let sub_instance_ref =
907 unsafe { InstanceRef::from_pin_ref(sub_comp.borrow(), guard) };
908
909 if let Some(children) = elem.cell.borrow().child_items.as_ref() {
910 new_row = true;
912 let start_count = result.len();
913
914 for child_template in children {
920 match child_template {
921 i_slint_compiler::layout::RowChildTemplate::Static(child_item) => {
922 let (row_val, col_val, rowspan_val, colspan_val) = {
923 let element_ref = child_item.element.borrow();
924 let child_cell =
925 element_ref.grid_layout_cell.as_ref().unwrap().borrow();
926 (
927 eval_or_default(&child_cell.row_expr, sub_instance_ref),
928 eval_or_default(&child_cell.col_expr, sub_instance_ref),
929 eval_or_default(&child_cell.rowspan_expr, sub_instance_ref),
930 eval_or_default(&child_cell.colspan_expr, sub_instance_ref),
931 )
932 };
933 result.push(GridLayoutInputData {
934 new_row,
935 col: col_val,
936 row: row_val,
937 colspan: colspan_val,
938 rowspan: rowspan_val,
939 });
940 new_row = false;
941 }
942 i_slint_compiler::layout::RowChildTemplate::Repeated {
943 repeated_element,
944 ..
945 } => {
946 let inner_root = repeated_element
949 .borrow()
950 .base_type
951 .as_component()
952 .root_element
953 .clone();
954 let (rowspan_expr, colspan_expr) = {
955 let element_ref = inner_root.borrow();
956 let child_cell =
957 element_ref.grid_layout_cell.as_ref().unwrap().borrow();
958 (
959 child_cell.rowspan_expr.clone(),
960 child_cell.colspan_expr.clone(),
961 )
962 };
963 let inner_instances =
964 repeater_instances(sub_instance_ref, repeated_element);
965 for (i, erased_inner) in inner_instances.iter().enumerate() {
966 generativity::make_guard!(inner_guard);
967 let inner_comp = erased_inner.as_pin_ref();
968 let inner_instance_ref = unsafe {
969 InstanceRef::from_pin_ref(inner_comp.borrow(), inner_guard)
970 };
971 result.push(GridLayoutInputData {
972 new_row: i == 0 && new_row,
973 rowspan: eval_or_default(&rowspan_expr, inner_instance_ref),
974 colspan: eval_or_default(&colspan_expr, inner_instance_ref),
975 ..Default::default()
976 });
977 }
978 if !inner_instances.is_empty() {
979 new_row = false;
980 }
981 }
982 }
983 }
984 let cells_pushed = result.len() - start_count;
986 let expected_step =
987 repeater_steps.get(repeater_idx).copied().unwrap_or(0) as usize;
988 for _ in cells_pushed..expected_step {
989 result.push(GridLayoutInputData::default());
990 }
991 } else {
992 let cell = elem.cell.borrow();
994 let row = eval_or_default(&cell.row_expr, sub_instance_ref);
995 let col = eval_or_default(&cell.col_expr, sub_instance_ref);
996 let rowspan = eval_or_default(&cell.rowspan_expr, sub_instance_ref);
997 let colspan = eval_or_default(&cell.colspan_expr, sub_instance_ref);
998 result.push(GridLayoutInputData { new_row, col, row, colspan, rowspan });
999 new_row = false;
1000 }
1001 }
1002 repeater_idx += 1;
1003 after_repeater_in_same_row = true;
1004 } else {
1005 let new_row =
1006 if cell_new_row || !after_repeater_in_same_row { cell_new_row } else { new_row };
1007 let row = eval_or_default(&elem.cell.borrow().row_expr, component);
1008 let col = eval_or_default(&elem.cell.borrow().col_expr, component);
1009 let rowspan = eval_or_default(&elem.cell.borrow().rowspan_expr, component);
1010 let colspan = eval_or_default(&elem.cell.borrow().colspan_expr, component);
1011 result.push(GridLayoutInputData { new_row, col, row, colspan, rowspan });
1012 }
1013 }
1014 result
1015}
1016
1017fn row_runtime_child_count(
1021 child_items: &[i_slint_compiler::layout::RowChildTemplate],
1022 sub_instance_ref: InstanceRef,
1023) -> usize {
1024 let mut count = 0;
1025 for child in child_items {
1026 if let Some(repeated_element) = child.repeated_element() {
1027 count += repeater_instances(sub_instance_ref, repeated_element).len();
1028 } else {
1029 count += 1;
1030 }
1031 }
1032 count
1033}
1034
1035fn grid_repeater_indices(
1036 grid_layout: &i_slint_compiler::layout::GridLayout,
1037 ctx: &mut EvalLocalContext,
1038 repeater_steps: &[u32],
1039) -> Vec<u32> {
1040 let component = ctx.component_instance;
1041 let mut repeater_indices = Vec::new();
1042 let mut num_cells = 0;
1043 let mut step_idx = 0;
1044 for elem in grid_layout.elems.iter() {
1045 if elem.item.element.borrow().repeated.is_some() {
1046 let component_vec = repeater_instances(component, &elem.item.element);
1047 repeater_indices.push(num_cells as _);
1048 repeater_indices.push(component_vec.len() as _);
1049 let item_count = repeater_steps[step_idx] as usize;
1050 num_cells += component_vec.len() * item_count;
1051 step_idx += 1;
1052 } else {
1053 num_cells += 1;
1054 }
1055 }
1056 repeater_indices
1057}
1058
1059fn grid_repeater_steps(
1060 grid_layout: &i_slint_compiler::layout::GridLayout,
1061 ctx: &mut EvalLocalContext,
1062) -> Vec<u32> {
1063 let component = ctx.component_instance;
1064 let mut repeater_steps = Vec::new();
1065 for elem in grid_layout.elems.iter() {
1066 if elem.item.element.borrow().repeated.is_some() {
1067 let item_count = match &elem.cell.borrow().child_items {
1068 Some(ci)
1069 if ci.iter().any(i_slint_compiler::layout::RowChildTemplate::is_repeated) =>
1070 {
1071 let component_vec = repeater_instances(component, &elem.item.element);
1073 component_vec
1074 .iter()
1075 .map(|sub| {
1076 generativity::make_guard!(guard);
1077 let sub_pin = sub.as_pin_ref();
1078 let sub_ref =
1079 unsafe { InstanceRef::from_pin_ref(sub_pin.borrow(), guard) };
1080 row_runtime_child_count(ci, sub_ref)
1081 })
1082 .max()
1083 .unwrap_or(0)
1084 }
1085 Some(ci) => ci.len(),
1086 None => 1,
1087 };
1088 repeater_steps.push(item_count as u32);
1089 }
1090 }
1091 repeater_steps
1092}
1093
1094fn grid_layout_constraints(
1095 grid_layout: &i_slint_compiler::layout::GridLayout,
1096 orientation: Orientation,
1097 ctx: &mut EvalLocalContext,
1098 repeater_steps: &[u32],
1099 cross_axis_size: Option<f32>,
1100) -> Vec<core_layout::LayoutItemInfo> {
1101 let component = ctx.component_instance;
1102 let expr_eval = |nr: &NamedReference| -> f32 {
1103 eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
1104 };
1105 let mut constraints = Vec::with_capacity(grid_layout.elems.len());
1106
1107 let mut repeater_idx = 0usize;
1108 for layout_elem in grid_layout.elems.iter() {
1109 if layout_elem.item.element.borrow().repeated.is_some() {
1110 let component_vec = repeater_instances(component, &layout_elem.item.element);
1111 let child_items = layout_elem.cell.borrow().child_items.clone();
1112 let has_children = child_items.is_some();
1113 if has_children {
1114 let ci = child_items.as_ref().unwrap();
1116 let step = repeater_steps.get(repeater_idx).copied().unwrap_or(0) as usize;
1117 for sub_comp in &component_vec {
1118 let per_instance_start = constraints.len();
1119 generativity::make_guard!(guard);
1121 let sub_pin = sub_comp.as_pin_ref();
1122 let sub_borrow = sub_pin.borrow();
1123 let sub_instance_ref = unsafe { InstanceRef::from_pin_ref(sub_borrow, guard) };
1124 let expr_eval = |nr: &NamedReference| -> f32 {
1125 eval::load_property(sub_instance_ref, &nr.element(), nr.name())
1126 .unwrap()
1127 .try_into()
1128 .unwrap()
1129 };
1130
1131 for child_template in ci.iter() {
1135 match child_template {
1136 i_slint_compiler::layout::RowChildTemplate::Static(child_item) => {
1137 let mut layout_info = crate::eval_layout::get_layout_info(
1138 &child_item.element,
1139 sub_instance_ref,
1140 &sub_instance_ref.window_adapter(),
1141 orientation,
1142 );
1143 fill_layout_info_constraints(
1144 &mut layout_info,
1145 &child_item.constraints,
1146 orientation,
1147 &expr_eval,
1148 );
1149 constraints
1150 .push(core_layout::LayoutItemInfo { constraint: layout_info });
1151 }
1152 i_slint_compiler::layout::RowChildTemplate::Repeated {
1153 item: child_item,
1154 repeated_element,
1155 } => {
1156 let inner_instances =
1158 repeater_instances(sub_instance_ref, repeated_element);
1159 for inner_comp in &inner_instances {
1160 let inner_pin = inner_comp.as_pin_ref();
1161 let mut layout_info =
1162 inner_pin.layout_item_info(to_runtime(orientation), None);
1163 generativity::make_guard!(inner_guard);
1166 let inner_borrow = inner_pin.borrow();
1167 let inner_instance_ref = unsafe {
1168 InstanceRef::from_pin_ref(inner_borrow, inner_guard)
1169 };
1170 let inner_expr_eval = |nr: &NamedReference| -> f32 {
1171 eval::load_property(
1172 inner_instance_ref,
1173 &nr.element(),
1174 nr.name(),
1175 )
1176 .unwrap()
1177 .try_into()
1178 .unwrap()
1179 };
1180 fill_layout_info_constraints(
1181 &mut layout_info.constraint,
1182 &child_item.constraints,
1183 orientation,
1184 &inner_expr_eval,
1185 );
1186 constraints.push(layout_info);
1187 }
1188 }
1189 }
1190 }
1191 let pushed = constraints.len() - per_instance_start;
1194 for _ in pushed..step {
1195 constraints.push(core_layout::LayoutItemInfo::default());
1196 }
1197 }
1198 } else {
1199 constraints.extend(
1201 component_vec
1202 .iter()
1203 .map(|x| x.as_pin_ref().layout_item_info(to_runtime(orientation), None)),
1204 );
1205 }
1206 repeater_idx += 1;
1207 } else {
1208 let cross_axis =
1209 cross_axis_size_for_cell(&layout_elem.item.element, orientation, cross_axis_size);
1210 let mut layout_info = get_layout_info_with_constraint(
1211 &layout_elem.item.element,
1212 component,
1213 &component.window_adapter(),
1214 orientation,
1215 cross_axis,
1216 );
1217 fill_layout_info_constraints(
1218 &mut layout_info,
1219 &layout_elem.item.constraints,
1220 orientation,
1221 &expr_eval,
1222 );
1223 constraints.push(core_layout::LayoutItemInfo { constraint: layout_info });
1224 }
1225 }
1226 constraints
1227}
1228
1229fn box_layout_data(
1231 box_layout: &i_slint_compiler::layout::BoxLayout,
1232 orientation: Orientation,
1233 component: InstanceRef,
1234 expr_eval: &impl Fn(&NamedReference) -> f32,
1235 mut repeater_indices: Option<&mut Vec<u32>>,
1236 cross_axis_size: Option<f32>,
1237 local_context: &mut EvalLocalContext,
1238 available_cross: Option<f32>,
1239) -> (Vec<core_layout::LayoutItemInfo>, i_slint_core::items::LayoutAlignment) {
1240 let window_adapter = component.window_adapter();
1241 let mut cells = Vec::with_capacity(box_layout.elems.len());
1242 for cell in &box_layout.elems {
1243 if cell.element.borrow().repeated.is_some() {
1244 let component_vec = repeater_instances(component, &cell.element);
1246 if let Some(ri) = repeater_indices.as_mut() {
1247 ri.push(cells.len() as _);
1248 ri.push(component_vec.len() as _);
1249 }
1250 cells.extend(
1251 component_vec
1252 .iter()
1253 .map(|x| x.as_pin_ref().layout_item_info(to_runtime(orientation), None)),
1254 );
1255 } else {
1256 let cross_axis = cross_axis_size_for_cell(&cell.element, orientation, cross_axis_size);
1258 let mut layout_info = get_layout_info_with_constraint(
1259 &cell.element,
1260 component,
1261 &window_adapter,
1262 orientation,
1263 cross_axis,
1264 );
1265 clamp_wrapping_flex_cross_preferred(
1266 &mut layout_info,
1267 &cell.element,
1268 box_layout,
1269 orientation,
1270 component,
1271 &expr_eval,
1272 local_context,
1273 available_cross,
1274 );
1275 fill_layout_info_constraints(
1276 &mut layout_info,
1277 &cell.constraints,
1278 orientation,
1279 &expr_eval,
1280 );
1281 cells.push(core_layout::LayoutItemInfo { constraint: layout_info });
1282 }
1283 }
1284 let alignment = box_layout
1285 .geometry
1286 .alignment
1287 .as_ref()
1288 .map(|nr| {
1289 eval::load_property(component, &nr.element(), nr.name())
1290 .unwrap()
1291 .try_into()
1292 .unwrap_or_default()
1293 })
1294 .unwrap_or_default();
1295 (cells, alignment)
1296}
1297
1298#[allow(clippy::too_many_arguments)]
1309fn clamp_wrapping_flex_cross_preferred(
1310 layout_info: &mut core_layout::LayoutInfo,
1311 elem: &ElementRc,
1312 box_layout: &i_slint_compiler::layout::BoxLayout,
1313 orientation: Orientation,
1314 component: InstanceRef,
1315 expr_eval: &impl Fn(&NamedReference) -> f32,
1316 local_context: &mut EvalLocalContext,
1317 available_cross: Option<f32>,
1318) {
1319 let Some(available) = available_cross else { return };
1320 if orientation == box_layout.orientation {
1321 return;
1322 }
1323 let Some(fl) = i_slint_compiler::layout::FlexboxLayout::from_element(elem) else { return };
1324
1325 let direction = flexbox_layout_direction(&fl, local_context);
1327 let main_is_cross = matches!(
1328 (direction, orientation),
1329 (FlexboxLayoutDirection::Row | FlexboxLayoutDirection::RowReverse, Orientation::Horizontal)
1330 | (
1331 FlexboxLayoutDirection::Column | FlexboxLayoutDirection::ColumnReverse,
1332 Orientation::Vertical
1333 )
1334 );
1335 if !main_is_cross {
1336 return;
1337 }
1338 let flex_wrap =
1339 fl.flex_wrap.as_ref().map_or(i_slint_core::items::FlexboxLayoutWrap::default(), |nr| {
1340 eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
1341 });
1342 if matches!(flex_wrap, i_slint_core::items::FlexboxLayoutWrap::NoWrap) {
1343 return;
1344 }
1345
1346 let (cells_h, cells_v, _ri) =
1347 flexbox_layout_data(&fl, component, expr_eval, local_context, None, None);
1348 let (cells, padding, spacing) = match orientation {
1349 Orientation::Horizontal => {
1350 let (padding, spacing) =
1351 padding_and_spacing(&fl.geometry, Orientation::Horizontal, expr_eval);
1352 (cells_h, padding, spacing)
1353 }
1354 Orientation::Vertical => {
1355 let (padding, spacing) =
1356 padding_and_spacing(&fl.geometry, Orientation::Vertical, expr_eval);
1357 (cells_v, padding, spacing)
1358 }
1359 };
1360 let unwrapped = core_layout::flexbox_layout_unwrapped_main(
1361 Slice::from(cells.as_slice()),
1362 spacing,
1363 &padding,
1364 );
1365 layout_info.preferred = available.min(unwrapped);
1366}
1367
1368pub(crate) fn fill_layout_info_constraints(
1369 layout_info: &mut core_layout::LayoutInfo,
1370 constraints: &LayoutConstraints,
1371 orientation: Orientation,
1372 expr_eval: &impl Fn(&NamedReference) -> f32,
1373) {
1374 let is_percent =
1375 |nr: &NamedReference| Expression::PropertyReference(nr.clone()).ty() == Type::Percent;
1376
1377 match orientation {
1378 Orientation::Horizontal => {
1379 if let Some(e) = constraints.min_width.as_ref() {
1380 if !is_percent(e) {
1381 layout_info.min = expr_eval(e)
1382 } else {
1383 layout_info.min_percent = expr_eval(e)
1384 }
1385 }
1386 if let Some(e) = constraints.max_width.as_ref() {
1387 if !is_percent(e) {
1388 layout_info.max = expr_eval(e)
1389 } else {
1390 layout_info.max_percent = expr_eval(e)
1391 }
1392 }
1393 if let Some(e) = constraints.preferred_width.as_ref() {
1394 layout_info.preferred = expr_eval(e);
1395 }
1396 if let Some(e) = constraints.horizontal_stretch.as_ref() {
1397 layout_info.stretch = expr_eval(e);
1398 }
1399 }
1400 Orientation::Vertical => {
1401 if let Some(e) = constraints.min_height.as_ref() {
1402 if !is_percent(e) {
1403 layout_info.min = expr_eval(e)
1404 } else {
1405 layout_info.min_percent = expr_eval(e)
1406 }
1407 }
1408 if let Some(e) = constraints.max_height.as_ref() {
1409 if !is_percent(e) {
1410 layout_info.max = expr_eval(e)
1411 } else {
1412 layout_info.max_percent = expr_eval(e)
1413 }
1414 }
1415 if let Some(e) = constraints.preferred_height.as_ref() {
1416 layout_info.preferred = expr_eval(e);
1417 }
1418 if let Some(e) = constraints.vertical_stretch.as_ref() {
1419 layout_info.stretch = expr_eval(e);
1420 }
1421 }
1422 }
1423}
1424
1425pub(crate) fn get_layout_info(
1427 elem: &ElementRc,
1428 component: InstanceRef,
1429 window_adapter: &Rc<dyn WindowAdapter>,
1430 orientation: Orientation,
1431) -> core_layout::LayoutInfo {
1432 get_layout_info_with_constraint(elem, component, window_adapter, orientation, None)
1433}
1434
1435pub(crate) fn get_layout_info_with_constraint(
1436 elem: &ElementRc,
1437 component: InstanceRef,
1438 window_adapter: &Rc<dyn WindowAdapter>,
1439 orientation: Orientation,
1440 cross_axis_constraint: Option<f32>,
1441) -> core_layout::LayoutInfo {
1442 let parameterized_nr = if cross_axis_constraint.is_some() {
1448 match orientation {
1449 Orientation::Vertical => elem.borrow().inherited_layout_info_v_with_constraint(),
1450 Orientation::Horizontal => elem.borrow().inherited_layout_info_h_with_constraint(),
1451 }
1452 } else {
1453 None
1454 };
1455 if let Some(nr) = parameterized_nr {
1456 let arg = cross_axis_constraint.unwrap();
1457 let v = eval::call_function(
1458 &eval::ComponentInstance::InstanceRef(component),
1459 &nr.element(),
1460 nr.name(),
1461 vec![Value::Number(arg as f64)],
1462 )
1463 .expect("layoutinfo-{h,v}-with-constraint is a synthesized pure function");
1464 return v.try_into().unwrap();
1465 }
1466
1467 let elem = elem.borrow();
1468 if let Some(nr) = elem.layout_info_prop(orientation) {
1469 eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
1470 } else {
1471 let item = &component
1472 .description
1473 .items
1474 .get(elem.id.as_str())
1475 .unwrap_or_else(|| panic!("Internal error: Item {} not found", elem.id));
1476 let item_comp = component.self_weak().get().unwrap().upgrade().unwrap();
1477
1478 unsafe {
1479 item.item_from_item_tree(component.as_ptr()).as_ref().layout_info(
1480 to_runtime(orientation),
1481 cross_axis_constraint.unwrap_or(-1.),
1482 window_adapter,
1483 &ItemRc::new(vtable::VRc::into_dyn(item_comp), item.item_index()),
1484 )
1485 }
1486 }
1487}
1488
1489fn cross_axis_size_for_cell(
1496 elem: &ElementRc,
1497 orientation: Orientation,
1498 parent_cross_axis_size: Option<f32>,
1499) -> Option<f32> {
1500 let cross = parent_cross_axis_size?;
1501 let elem_b = elem.borrow();
1502 if orientation == Orientation::Horizontal {
1503 return elem_b.inherited_layout_info_h_with_constraint().is_some().then_some(cross);
1508 }
1509 if elem_b.layout_info_v_with_constraint.is_some() {
1510 return Some(cross);
1511 }
1512 if elem_b.layout_info_prop(Orientation::Vertical).is_none() {
1517 return Some(cross);
1518 }
1519 None
1520}