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 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 x.as_pin_ref().flexbox_layout_item_info(to_runtime(Orientation::Vertical), None)
709 }));
710 }
711 static_children.resize_with(static_children.len() + component_vec.len(), || None);
712 repeater_instance_vecs.push(component_vec);
713 } else {
714 let h_constraint = layout_elem
720 .item
721 .element
722 .borrow()
723 .inherited_layout_info_h_with_constraint()
724 .is_some()
725 .then(|| height_override.unwrap_or(f32::MAX));
726 let mut layout_info_h = get_layout_info_with_constraint(
727 &layout_elem.item.element,
728 component,
729 &window_adapter,
730 Orientation::Horizontal,
731 h_constraint,
732 );
733 fill_layout_info_constraints(
734 &mut layout_info_h,
735 &layout_elem.item.constraints,
736 Orientation::Horizontal,
737 expr_eval,
738 );
739 let flex_grow = layout_elem.flex_grow.as_ref().map(&expr_eval).unwrap_or(0.0);
743 let flex_shrink = layout_elem.flex_shrink.as_ref().map(&expr_eval).unwrap_or(1.0);
744 let flex_basis = layout_elem.flex_basis.as_ref().map(&expr_eval).unwrap_or(-1.0);
745 let align_self = layout_elem
746 .align_self
747 .as_ref()
748 .map(|nr| {
749 eval::load_property(component, &nr.element(), nr.name())
750 .unwrap()
751 .try_into()
752 .unwrap()
753 })
754 .unwrap_or(i_slint_core::items::FlexboxLayoutAlignSelf::default());
755 let order = layout_elem.order.as_ref().map(expr_eval).unwrap_or(0.0) as i32;
756 cells_h.push(core_layout::FlexboxLayoutItemInfo {
757 constraint: layout_info_h,
758 flex_grow,
759 flex_shrink,
760 flex_basis,
761 flex_align_self: align_self,
762 flex_order: order,
763 });
764 cells_v.push(core_layout::FlexboxLayoutItemInfo::default());
766 static_children.push(Some(ChildInfo {
767 flex_grow,
768 flex_shrink,
769 flex_basis,
770 flex_align_self: align_self,
771 flex_order: order,
772 }));
773 }
774 }
775
776 let mut cell_idx = 0usize;
780 let mut repeater_idx = 0usize;
781 for layout_elem in &flexbox_layout.elems {
782 if layout_elem.item.element.borrow().repeated.is_some() {
783 let rep_root =
789 layout_elem.item.element.borrow().base_type.as_component().root_element.clone();
790 let is_height_for_width =
791 rep_root.borrow().inherited_layout_info_v_with_constraint().is_some();
792 let component_vec = &repeater_instance_vecs[repeater_idx];
793 repeater_idx += 1;
794 for instance in component_vec {
795 if is_height_for_width {
796 let width_constraint = width_override
797 .unwrap_or_else(|| cells_h[cell_idx].constraint.preferred_bounded());
798 generativity::make_guard!(guard);
799 let unerased = instance.unerase(guard);
800 let instance_ref = unerased.borrow_instance();
801 let mut layout_info_v = get_layout_info_with_constraint(
802 &rep_root,
803 instance_ref,
804 &window_adapter,
805 Orientation::Vertical,
806 Some(width_constraint),
807 );
808 let instance_expr_eval = |nr: &NamedReference| -> f32 {
812 eval::load_property(instance_ref, &nr.element(), nr.name())
813 .unwrap()
814 .try_into()
815 .unwrap()
816 };
817 let effective = layout_elem
823 .item
824 .constraints
825 .to_apply(&layout_elem.item.element, Orientation::Vertical);
826 fill_layout_info_constraints(
827 &mut layout_info_v,
828 &effective,
829 Orientation::Vertical,
830 &instance_expr_eval,
831 );
832 cells_v[cell_idx] = core_layout::FlexboxLayoutItemInfo {
835 constraint: layout_info_v,
836 flex_grow: cells_h[cell_idx].flex_grow,
837 flex_shrink: cells_h[cell_idx].flex_shrink,
838 flex_basis: cells_h[cell_idx].flex_basis,
839 flex_align_self: cells_h[cell_idx].flex_align_self,
840 flex_order: cells_h[cell_idx].flex_order,
841 };
842 }
843 cell_idx += 1;
844 }
845 } else {
846 let width_constraint =
847 width_override.unwrap_or_else(|| cells_h[cell_idx].constraint.preferred_bounded());
848 let mut layout_info_v = get_layout_info_with_constraint(
849 &layout_elem.item.element,
850 component,
851 &window_adapter,
852 Orientation::Vertical,
853 Some(width_constraint),
854 );
855 let effective = layout_elem
861 .item
862 .constraints
863 .to_apply(&layout_elem.item.element, Orientation::Vertical);
864 fill_layout_info_constraints(
865 &mut layout_info_v,
866 &effective,
867 Orientation::Vertical,
868 expr_eval,
869 );
870 if let Some(info) = &static_children[cell_idx] {
871 cells_v[cell_idx] = core_layout::FlexboxLayoutItemInfo {
872 constraint: layout_info_v,
873 flex_grow: info.flex_grow,
874 flex_shrink: info.flex_shrink,
875 flex_basis: info.flex_basis,
876 flex_align_self: info.flex_align_self,
877 flex_order: info.flex_order,
878 };
879 }
880 cell_idx += 1;
881 }
882 }
883
884 (cells_h, cells_v, repeated_indices)
885}
886
887fn padding_and_spacing(
889 layout_geometry: &LayoutGeometry,
890 orientation: Orientation,
891 expr_eval: &impl Fn(&NamedReference) -> f32,
892) -> (core_layout::Padding, f32) {
893 let spacing = layout_geometry.spacing.orientation(orientation).map_or(0., expr_eval);
894 let (begin, end) = layout_geometry.padding.begin_end(orientation);
895 let padding =
896 core_layout::Padding { begin: begin.map_or(0., expr_eval), end: end.map_or(0., expr_eval) };
897 (padding, spacing)
898}
899
900fn repeater_instances(
901 component: InstanceRef,
902 elem: &ElementRc,
903) -> Vec<crate::dynamic_item_tree::DynamicComponentVRc> {
904 generativity::make_guard!(guard);
905 let rep =
906 crate::dynamic_item_tree::get_repeater_by_name(component, elem.borrow().id.as_str(), guard);
907 rep.0.as_ref().track_instance_changes();
908 rep.0.as_ref().instances_vec()
909}
910
911fn grid_layout_input_data(
912 grid_layout: &i_slint_compiler::layout::GridLayout,
913 ctx: &EvalLocalContext,
914 repeater_steps: &[u32],
915) -> Vec<GridLayoutInputData> {
916 let component = ctx.component_instance;
917 let mut result = Vec::with_capacity(grid_layout.elems.len());
918 let mut after_repeater_in_same_row = false;
919 let mut new_row = true;
920 let mut repeater_idx = 0usize;
921 for elem in grid_layout.elems.iter() {
922 let eval_or_default = |expr: &RowColExpr, component: InstanceRef| match expr {
923 RowColExpr::Literal(value) => *value as f32,
924 RowColExpr::Auto => i_slint_common::ROW_COL_AUTO,
925 RowColExpr::Named(nr) => {
926 eval::load_property(component, &nr.element(), nr.name())
928 .unwrap()
929 .try_into()
930 .unwrap()
931 }
932 };
933
934 let cell_new_row = elem.cell.borrow().new_row;
935 if cell_new_row {
936 after_repeater_in_same_row = false;
937 }
938 if elem.item.element.borrow().repeated.is_some() {
939 let component_vec = repeater_instances(component, &elem.item.element);
940 new_row = cell_new_row;
941 for erased_sub_comp in &component_vec {
942 generativity::make_guard!(guard);
944 let sub_comp = erased_sub_comp.as_pin_ref();
945 let sub_instance_ref =
946 unsafe { InstanceRef::from_pin_ref(sub_comp.borrow(), guard) };
947
948 if let Some(children) = elem.cell.borrow().child_items.as_ref() {
949 new_row = true;
951 let start_count = result.len();
952
953 for child_template in children {
959 match child_template {
960 i_slint_compiler::layout::RowChildTemplate::Static(child_item) => {
961 let (row_val, col_val, rowspan_val, colspan_val) = {
962 let element_ref = child_item.element.borrow();
963 let child_cell =
964 element_ref.grid_layout_cell.as_ref().unwrap().borrow();
965 (
966 eval_or_default(&child_cell.row_expr, sub_instance_ref),
967 eval_or_default(&child_cell.col_expr, sub_instance_ref),
968 eval_or_default(&child_cell.rowspan_expr, sub_instance_ref),
969 eval_or_default(&child_cell.colspan_expr, sub_instance_ref),
970 )
971 };
972 result.push(GridLayoutInputData {
973 new_row,
974 col: col_val,
975 row: row_val,
976 colspan: colspan_val,
977 rowspan: rowspan_val,
978 });
979 new_row = false;
980 }
981 i_slint_compiler::layout::RowChildTemplate::Repeated {
982 repeated_element,
983 ..
984 } => {
985 let inner_root = repeated_element
988 .borrow()
989 .base_type
990 .as_component()
991 .root_element
992 .clone();
993 let (rowspan_expr, colspan_expr) = {
994 let element_ref = inner_root.borrow();
995 let child_cell =
996 element_ref.grid_layout_cell.as_ref().unwrap().borrow();
997 (
998 child_cell.rowspan_expr.clone(),
999 child_cell.colspan_expr.clone(),
1000 )
1001 };
1002 let inner_instances =
1003 repeater_instances(sub_instance_ref, repeated_element);
1004 for (i, erased_inner) in inner_instances.iter().enumerate() {
1005 generativity::make_guard!(inner_guard);
1006 let inner_comp = erased_inner.as_pin_ref();
1007 let inner_instance_ref = unsafe {
1008 InstanceRef::from_pin_ref(inner_comp.borrow(), inner_guard)
1009 };
1010 result.push(GridLayoutInputData {
1011 new_row: i == 0 && new_row,
1012 rowspan: eval_or_default(&rowspan_expr, inner_instance_ref),
1013 colspan: eval_or_default(&colspan_expr, inner_instance_ref),
1014 ..Default::default()
1015 });
1016 }
1017 if !inner_instances.is_empty() {
1018 new_row = false;
1019 }
1020 }
1021 }
1022 }
1023 let cells_pushed = result.len() - start_count;
1025 let expected_step =
1026 repeater_steps.get(repeater_idx).copied().unwrap_or(0) as usize;
1027 for _ in cells_pushed..expected_step {
1028 result.push(GridLayoutInputData::default());
1029 }
1030 } else {
1031 let cell = elem.cell.borrow();
1033 let row = eval_or_default(&cell.row_expr, sub_instance_ref);
1034 let col = eval_or_default(&cell.col_expr, sub_instance_ref);
1035 let rowspan = eval_or_default(&cell.rowspan_expr, sub_instance_ref);
1036 let colspan = eval_or_default(&cell.colspan_expr, sub_instance_ref);
1037 result.push(GridLayoutInputData { new_row, col, row, colspan, rowspan });
1038 new_row = false;
1039 }
1040 }
1041 repeater_idx += 1;
1042 after_repeater_in_same_row = true;
1043 } else {
1044 let new_row =
1045 if cell_new_row || !after_repeater_in_same_row { cell_new_row } else { new_row };
1046 let row = eval_or_default(&elem.cell.borrow().row_expr, component);
1047 let col = eval_or_default(&elem.cell.borrow().col_expr, component);
1048 let rowspan = eval_or_default(&elem.cell.borrow().rowspan_expr, component);
1049 let colspan = eval_or_default(&elem.cell.borrow().colspan_expr, component);
1050 result.push(GridLayoutInputData { new_row, col, row, colspan, rowspan });
1051 }
1052 }
1053 result
1054}
1055
1056fn row_runtime_child_count(
1060 child_items: &[i_slint_compiler::layout::RowChildTemplate],
1061 sub_instance_ref: InstanceRef,
1062) -> usize {
1063 let mut count = 0;
1064 for child in child_items {
1065 if let Some(repeated_element) = child.repeated_element() {
1066 count += repeater_instances(sub_instance_ref, repeated_element).len();
1067 } else {
1068 count += 1;
1069 }
1070 }
1071 count
1072}
1073
1074fn grid_repeater_indices(
1075 grid_layout: &i_slint_compiler::layout::GridLayout,
1076 ctx: &mut EvalLocalContext,
1077 repeater_steps: &[u32],
1078) -> Vec<u32> {
1079 let component = ctx.component_instance;
1080 let mut repeater_indices = Vec::new();
1081 let mut num_cells = 0;
1082 let mut step_idx = 0;
1083 for elem in grid_layout.elems.iter() {
1084 if elem.item.element.borrow().repeated.is_some() {
1085 let component_vec = repeater_instances(component, &elem.item.element);
1086 repeater_indices.push(num_cells as _);
1087 repeater_indices.push(component_vec.len() as _);
1088 let item_count = repeater_steps[step_idx] as usize;
1089 num_cells += component_vec.len() * item_count;
1090 step_idx += 1;
1091 } else {
1092 num_cells += 1;
1093 }
1094 }
1095 repeater_indices
1096}
1097
1098fn grid_repeater_steps(
1099 grid_layout: &i_slint_compiler::layout::GridLayout,
1100 ctx: &mut EvalLocalContext,
1101) -> Vec<u32> {
1102 let component = ctx.component_instance;
1103 let mut repeater_steps = Vec::new();
1104 for elem in grid_layout.elems.iter() {
1105 if elem.item.element.borrow().repeated.is_some() {
1106 let item_count = match &elem.cell.borrow().child_items {
1107 Some(ci)
1108 if ci.iter().any(i_slint_compiler::layout::RowChildTemplate::is_repeated) =>
1109 {
1110 let component_vec = repeater_instances(component, &elem.item.element);
1112 component_vec
1113 .iter()
1114 .map(|sub| {
1115 generativity::make_guard!(guard);
1116 let sub_pin = sub.as_pin_ref();
1117 let sub_ref =
1118 unsafe { InstanceRef::from_pin_ref(sub_pin.borrow(), guard) };
1119 row_runtime_child_count(ci, sub_ref)
1120 })
1121 .max()
1122 .unwrap_or(0)
1123 }
1124 Some(ci) => ci.len(),
1125 None => 1,
1126 };
1127 repeater_steps.push(item_count as u32);
1128 }
1129 }
1130 repeater_steps
1131}
1132
1133fn grid_layout_constraints(
1134 grid_layout: &i_slint_compiler::layout::GridLayout,
1135 orientation: Orientation,
1136 ctx: &mut EvalLocalContext,
1137 repeater_steps: &[u32],
1138 cross_axis_size: Option<f32>,
1139) -> Vec<core_layout::LayoutItemInfo> {
1140 let component = ctx.component_instance;
1141 let expr_eval = |nr: &NamedReference| -> f32 {
1142 eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
1143 };
1144 let mut constraints = Vec::with_capacity(grid_layout.elems.len());
1145
1146 let mut repeater_idx = 0usize;
1147 for layout_elem in grid_layout.elems.iter() {
1148 if layout_elem.item.element.borrow().repeated.is_some() {
1149 let component_vec = repeater_instances(component, &layout_elem.item.element);
1150 let child_items = layout_elem.cell.borrow().child_items.clone();
1151 let has_children = child_items.is_some();
1152 if has_children {
1153 let ci = child_items.as_ref().unwrap();
1155 let step = repeater_steps.get(repeater_idx).copied().unwrap_or(0) as usize;
1156 for sub_comp in &component_vec {
1157 let per_instance_start = constraints.len();
1158 generativity::make_guard!(guard);
1160 let sub_pin = sub_comp.as_pin_ref();
1161 let sub_borrow = sub_pin.borrow();
1162 let sub_instance_ref = unsafe { InstanceRef::from_pin_ref(sub_borrow, guard) };
1163 let expr_eval = |nr: &NamedReference| -> f32 {
1164 eval::load_property(sub_instance_ref, &nr.element(), nr.name())
1165 .unwrap()
1166 .try_into()
1167 .unwrap()
1168 };
1169
1170 for child_template in ci.iter() {
1174 match child_template {
1175 i_slint_compiler::layout::RowChildTemplate::Static(child_item) => {
1176 let mut layout_info = crate::eval_layout::get_layout_info(
1177 &child_item.element,
1178 sub_instance_ref,
1179 &sub_instance_ref.window_adapter(),
1180 orientation,
1181 );
1182 fill_layout_info_constraints(
1183 &mut layout_info,
1184 &child_item.constraints,
1185 orientation,
1186 &expr_eval,
1187 );
1188 constraints
1189 .push(core_layout::LayoutItemInfo { constraint: layout_info });
1190 }
1191 i_slint_compiler::layout::RowChildTemplate::Repeated {
1192 item: child_item,
1193 repeated_element,
1194 } => {
1195 let inner_instances =
1197 repeater_instances(sub_instance_ref, repeated_element);
1198 for inner_comp in &inner_instances {
1199 let inner_pin = inner_comp.as_pin_ref();
1200 let mut layout_info =
1201 inner_pin.layout_item_info(to_runtime(orientation), None);
1202 generativity::make_guard!(inner_guard);
1205 let inner_borrow = inner_pin.borrow();
1206 let inner_instance_ref = unsafe {
1207 InstanceRef::from_pin_ref(inner_borrow, inner_guard)
1208 };
1209 let inner_expr_eval = |nr: &NamedReference| -> f32 {
1210 eval::load_property(
1211 inner_instance_ref,
1212 &nr.element(),
1213 nr.name(),
1214 )
1215 .unwrap()
1216 .try_into()
1217 .unwrap()
1218 };
1219 fill_layout_info_constraints(
1220 &mut layout_info.constraint,
1221 &child_item.constraints,
1222 orientation,
1223 &inner_expr_eval,
1224 );
1225 constraints.push(layout_info);
1226 }
1227 }
1228 }
1229 }
1230 let pushed = constraints.len() - per_instance_start;
1233 for _ in pushed..step {
1234 constraints.push(core_layout::LayoutItemInfo::default());
1235 }
1236 }
1237 } else {
1238 constraints.extend(
1240 component_vec
1241 .iter()
1242 .map(|x| x.as_pin_ref().layout_item_info(to_runtime(orientation), None)),
1243 );
1244 }
1245 repeater_idx += 1;
1246 } else {
1247 let cross_axis =
1248 cross_axis_size_for_cell(&layout_elem.item.element, orientation, cross_axis_size);
1249 let mut layout_info = get_layout_info_with_constraint(
1250 &layout_elem.item.element,
1251 component,
1252 &component.window_adapter(),
1253 orientation,
1254 cross_axis,
1255 );
1256 fill_layout_info_constraints(
1257 &mut layout_info,
1258 &layout_elem.item.constraints,
1259 orientation,
1260 &expr_eval,
1261 );
1262 constraints.push(core_layout::LayoutItemInfo { constraint: layout_info });
1263 }
1264 }
1265 constraints
1266}
1267
1268fn box_layout_data(
1270 box_layout: &i_slint_compiler::layout::BoxLayout,
1271 orientation: Orientation,
1272 component: InstanceRef,
1273 expr_eval: &impl Fn(&NamedReference) -> f32,
1274 mut repeater_indices: Option<&mut Vec<u32>>,
1275 cross_axis_size: Option<f32>,
1276 local_context: &mut EvalLocalContext,
1277 available_cross: Option<f32>,
1278) -> (Vec<core_layout::LayoutItemInfo>, i_slint_core::items::LayoutAlignment) {
1279 let window_adapter = component.window_adapter();
1280 let mut cells = Vec::with_capacity(box_layout.elems.len());
1281 for cell in &box_layout.elems {
1282 if cell.element.borrow().repeated.is_some() {
1283 let component_vec = repeater_instances(component, &cell.element);
1285 if let Some(ri) = repeater_indices.as_mut() {
1286 ri.push(cells.len() as _);
1287 ri.push(component_vec.len() as _);
1288 }
1289 cells.extend(
1290 component_vec
1291 .iter()
1292 .map(|x| x.as_pin_ref().layout_item_info(to_runtime(orientation), None)),
1293 );
1294 } else {
1295 let cross_axis = cross_axis_size_for_cell(&cell.element, orientation, cross_axis_size);
1297 let mut layout_info = get_layout_info_with_constraint(
1298 &cell.element,
1299 component,
1300 &window_adapter,
1301 orientation,
1302 cross_axis,
1303 );
1304 clamp_wrapping_flex_cross_preferred(
1305 &mut layout_info,
1306 &cell.element,
1307 box_layout,
1308 orientation,
1309 component,
1310 &expr_eval,
1311 local_context,
1312 available_cross,
1313 );
1314 fill_layout_info_constraints(
1315 &mut layout_info,
1316 &cell.constraints,
1317 orientation,
1318 &expr_eval,
1319 );
1320 cells.push(core_layout::LayoutItemInfo { constraint: layout_info });
1321 }
1322 }
1323 let alignment = box_layout
1324 .geometry
1325 .alignment
1326 .as_ref()
1327 .map(|nr| {
1328 eval::load_property(component, &nr.element(), nr.name())
1329 .unwrap()
1330 .try_into()
1331 .unwrap_or_default()
1332 })
1333 .unwrap_or_default();
1334 (cells, alignment)
1335}
1336
1337#[allow(clippy::too_many_arguments)]
1348fn clamp_wrapping_flex_cross_preferred(
1349 layout_info: &mut core_layout::LayoutInfo,
1350 elem: &ElementRc,
1351 box_layout: &i_slint_compiler::layout::BoxLayout,
1352 orientation: Orientation,
1353 component: InstanceRef,
1354 expr_eval: &impl Fn(&NamedReference) -> f32,
1355 local_context: &mut EvalLocalContext,
1356 available_cross: Option<f32>,
1357) {
1358 let Some(available) = available_cross else { return };
1359 if orientation == box_layout.orientation {
1360 return;
1361 }
1362 let Some(fl) = i_slint_compiler::layout::FlexboxLayout::from_element(elem) else { return };
1363
1364 let direction = flexbox_layout_direction(&fl, local_context);
1366 let main_is_cross = matches!(
1367 (direction, orientation),
1368 (FlexboxLayoutDirection::Row | FlexboxLayoutDirection::RowReverse, Orientation::Horizontal)
1369 | (
1370 FlexboxLayoutDirection::Column | FlexboxLayoutDirection::ColumnReverse,
1371 Orientation::Vertical
1372 )
1373 );
1374 if !main_is_cross {
1375 return;
1376 }
1377 let flex_wrap =
1378 fl.flex_wrap.as_ref().map_or(i_slint_core::items::FlexboxLayoutWrap::default(), |nr| {
1379 eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
1380 });
1381 if matches!(flex_wrap, i_slint_core::items::FlexboxLayoutWrap::NoWrap) {
1382 return;
1383 }
1384
1385 let (cells_h, cells_v, _ri) =
1386 flexbox_layout_data(&fl, component, expr_eval, local_context, None, None);
1387 let (cells, padding, spacing) = match orientation {
1388 Orientation::Horizontal => {
1389 let (padding, spacing) =
1390 padding_and_spacing(&fl.geometry, Orientation::Horizontal, expr_eval);
1391 (cells_h, padding, spacing)
1392 }
1393 Orientation::Vertical => {
1394 let (padding, spacing) =
1395 padding_and_spacing(&fl.geometry, Orientation::Vertical, expr_eval);
1396 (cells_v, padding, spacing)
1397 }
1398 };
1399 let unwrapped = core_layout::flexbox_layout_unwrapped_main(
1400 Slice::from(cells.as_slice()),
1401 spacing,
1402 &padding,
1403 );
1404 layout_info.preferred = available.min(unwrapped);
1405}
1406
1407pub(crate) fn fill_layout_info_constraints(
1408 layout_info: &mut core_layout::LayoutInfo,
1409 constraints: &LayoutConstraints,
1410 orientation: Orientation,
1411 expr_eval: &impl Fn(&NamedReference) -> f32,
1412) {
1413 let is_percent =
1414 |nr: &NamedReference| Expression::PropertyReference(nr.clone()).ty() == Type::Percent;
1415
1416 match orientation {
1417 Orientation::Horizontal => {
1418 if let Some(e) = constraints.min_width.as_ref() {
1419 if !is_percent(e) {
1420 layout_info.min = expr_eval(e)
1421 } else {
1422 layout_info.min_percent = expr_eval(e)
1423 }
1424 }
1425 if let Some(e) = constraints.max_width.as_ref() {
1426 if !is_percent(e) {
1427 layout_info.max = expr_eval(e)
1428 } else {
1429 layout_info.max_percent = expr_eval(e)
1430 }
1431 }
1432 if let Some(e) = constraints.preferred_width.as_ref() {
1433 layout_info.preferred = expr_eval(e);
1434 }
1435 if let Some(e) = constraints.horizontal_stretch.as_ref() {
1436 layout_info.stretch = expr_eval(e);
1437 }
1438 }
1439 Orientation::Vertical => {
1440 if let Some(e) = constraints.min_height.as_ref() {
1441 if !is_percent(e) {
1442 layout_info.min = expr_eval(e)
1443 } else {
1444 layout_info.min_percent = expr_eval(e)
1445 }
1446 }
1447 if let Some(e) = constraints.max_height.as_ref() {
1448 if !is_percent(e) {
1449 layout_info.max = expr_eval(e)
1450 } else {
1451 layout_info.max_percent = expr_eval(e)
1452 }
1453 }
1454 if let Some(e) = constraints.preferred_height.as_ref() {
1455 layout_info.preferred = expr_eval(e);
1456 }
1457 if let Some(e) = constraints.vertical_stretch.as_ref() {
1458 layout_info.stretch = expr_eval(e);
1459 }
1460 }
1461 }
1462}
1463
1464pub(crate) fn get_layout_info(
1466 elem: &ElementRc,
1467 component: InstanceRef,
1468 window_adapter: &Rc<dyn WindowAdapter>,
1469 orientation: Orientation,
1470) -> core_layout::LayoutInfo {
1471 get_layout_info_with_constraint(elem, component, window_adapter, orientation, None)
1472}
1473
1474pub(crate) fn get_layout_info_with_constraint(
1475 elem: &ElementRc,
1476 component: InstanceRef,
1477 window_adapter: &Rc<dyn WindowAdapter>,
1478 orientation: Orientation,
1479 cross_axis_constraint: Option<f32>,
1480) -> core_layout::LayoutInfo {
1481 let parameterized_nr = if cross_axis_constraint.is_some() {
1487 match orientation {
1488 Orientation::Vertical => elem.borrow().inherited_layout_info_v_with_constraint(),
1489 Orientation::Horizontal => elem.borrow().inherited_layout_info_h_with_constraint(),
1490 }
1491 } else {
1492 None
1493 };
1494 if let Some(nr) = parameterized_nr {
1495 let arg = cross_axis_constraint.unwrap();
1496 let v = eval::call_function(
1497 &eval::ComponentInstance::InstanceRef(component),
1498 &nr.element(),
1499 nr.name(),
1500 vec![Value::Number(arg as f64)],
1501 )
1502 .expect("layoutinfo-{h,v}-with-constraint is a synthesized pure function");
1503 return v.try_into().unwrap();
1504 }
1505
1506 let elem = elem.borrow();
1507 if let Some(nr) = elem.layout_info_prop(orientation) {
1508 eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
1509 } else {
1510 let item = &component
1511 .description
1512 .items
1513 .get(elem.id.as_str())
1514 .unwrap_or_else(|| panic!("Internal error: Item {} not found", elem.id));
1515 let item_comp = component.self_weak().get().unwrap().upgrade().unwrap();
1516
1517 unsafe {
1518 item.item_from_item_tree(component.as_ptr()).as_ref().layout_info(
1519 to_runtime(orientation),
1520 cross_axis_constraint.unwrap_or(-1.),
1521 window_adapter,
1522 &ItemRc::new(vtable::VRc::into_dyn(item_comp), item.item_index()),
1523 )
1524 }
1525 }
1526}
1527
1528fn cross_axis_size_for_cell(
1535 elem: &ElementRc,
1536 orientation: Orientation,
1537 parent_cross_axis_size: Option<f32>,
1538) -> Option<f32> {
1539 let cross = parent_cross_axis_size?;
1540 let elem_b = elem.borrow();
1541 if orientation == Orientation::Horizontal {
1542 return elem_b.inherited_layout_info_h_with_constraint().is_some().then_some(cross);
1547 }
1548 if elem_b.layout_info_v_with_constraint.is_some() {
1549 return Some(cross);
1550 }
1551 if elem_b.layout_info_prop(Orientation::Vertical).is_none() {
1556 return Some(cross);
1557 }
1558 None
1559}