1use std::collections::BTreeMap;
5use std::rc::Rc;
6
7use itertools::Either;
8use smol_str::SmolStr;
9
10use super::lower_to_item_tree::LoweredElement;
11use super::{GridLayoutRepeatedElement, LayoutRepeatedElement};
12use crate::langtype::{BuiltinStruct, EnumerationValue, Struct, Type};
13use crate::layout::{GridLayoutCell, Orientation, RowColExpr};
14use crate::llr::ArrayOutput as llr_ArrayOutput;
15use crate::llr::Expression as llr_Expression;
16use crate::namedreference::NamedReference;
17use crate::object_tree::ElementRc;
18
19use super::lower_expression::{ExpressionLoweringCtx, make_struct};
20
21fn empty_int32_slice() -> llr_Expression {
22 llr_Expression::Array {
23 element_ty: Type::Int32,
24 values: Vec::new(),
25 output: llr_ArrayOutput::Slice,
26 }
27}
28
29pub(super) fn compute_grid_layout_info(
30 layout_organized_data_prop: &NamedReference,
31 layout: &crate::layout::GridLayout,
32 o: Orientation,
33 ctx: &mut ExpressionLoweringCtx,
34 cross_axis_size_override: Option<&crate::expression_tree::Expression>,
35) -> llr_Expression {
36 let (padding, spacing) = generate_layout_padding_and_spacing(&layout.geometry, o, ctx);
37 let organized_cells = ctx.map_property_reference(layout_organized_data_prop);
38 let constraints_result = grid_layout_cell_constraints(layout, o, ctx, cross_axis_size_override);
39 let orientation_literal = llr_Expression::EnumerationValue(EnumerationValue {
40 value: o as _,
41 enumeration: crate::typeregister::BUILTIN.with(|b| b.enums.Orientation.clone()),
42 });
43
44 let sub_expression = llr_Expression::ExtraBuiltinFunctionCall {
45 function: "grid_layout_info".into(),
46 arguments: vec![
47 llr_Expression::PropertyReference(organized_cells),
48 constraints_result.cells,
49 if constraints_result.compute_cells.is_none() {
50 empty_int32_slice()
51 } else {
52 llr_Expression::ReadLocalVariable {
53 name: "repeated_indices".into(),
54 ty: Type::Array(Type::Int32.into()),
55 }
56 },
57 if constraints_result.compute_cells.is_none() {
58 empty_int32_slice()
59 } else {
60 llr_Expression::ReadLocalVariable {
61 name: "repeater_steps".into(),
62 ty: Type::Array(Type::Int32.into()),
63 }
64 },
65 spacing,
66 padding,
67 orientation_literal,
68 ],
69 return_ty: crate::typeregister::layout_info_type().into(),
70 };
71 match constraints_result.compute_cells {
72 Some((cells_variable, elements)) => llr_Expression::WithLayoutItemInfo {
73 cells_variable,
74 repeater_indices_var_name: Some("repeated_indices".into()),
75 repeater_steps_var_name: Some("repeater_steps".into()),
76 elements,
77 orientation: o,
78 sub_expression: Box::new(sub_expression),
79 },
80 None => sub_expression,
81 }
82}
83
84pub(super) fn compute_box_layout_info(
85 layout: &crate::layout::BoxLayout,
86 o: Orientation,
87 ctx: &mut ExpressionLoweringCtx,
88 cross_axis_size_override: Option<&crate::expression_tree::Expression>,
89) -> llr_Expression {
90 let (padding, spacing) = generate_layout_padding_and_spacing(&layout.geometry, o, ctx);
91 let bld = box_layout_data(layout, o, ctx, cross_axis_size_override);
92 let sub_expression = if o == layout.orientation {
93 llr_Expression::ExtraBuiltinFunctionCall {
94 function: "box_layout_info".into(),
95 arguments: vec![bld.cells, spacing, padding, bld.alignment],
96 return_ty: crate::typeregister::layout_info_type().into(),
97 }
98 } else {
99 llr_Expression::ExtraBuiltinFunctionCall {
100 function: "box_layout_info_ortho".into(),
101 arguments: vec![bld.cells, padding],
102 return_ty: crate::typeregister::layout_info_type().into(),
103 }
104 };
105 match bld.compute_cells {
106 Some((cells_variable, elements)) => llr_Expression::WithLayoutItemInfo {
107 cells_variable,
108 repeater_indices_var_name: None,
109 repeater_steps_var_name: None,
110 elements,
111 orientation: o,
112 sub_expression: Box::new(sub_expression),
113 },
114 None => sub_expression,
115 }
116}
117
118pub(super) fn organize_grid_layout(
119 layout: &crate::layout::GridLayout,
120 ctx: &mut ExpressionLoweringCtx,
121) -> llr_Expression {
122 let input_data = grid_layout_input_data(layout, ctx);
123
124 if let Some(button_roles) = &layout.dialog_button_roles {
125 let e = crate::typeregister::BUILTIN.with(|e| e.enums.DialogButtonRole.clone());
126 let roles = button_roles
127 .iter()
128 .map(|r| {
129 llr_Expression::EnumerationValue(EnumerationValue {
130 value: e.values.iter().position(|x| x == r).unwrap() as _,
131 enumeration: e.clone(),
132 })
133 })
134 .collect();
135 let roles_expr = llr_Expression::Array {
136 element_ty: Type::Enumeration(e),
137 values: roles,
138 output: llr_ArrayOutput::Slice,
139 };
140 llr_Expression::ExtraBuiltinFunctionCall {
141 function: "organize_dialog_button_layout".into(),
142 arguments: vec![input_data.cells, roles_expr],
143 return_ty: Type::Array(Type::Int32.into()),
144 }
145 } else {
146 let sub_expression = llr_Expression::ExtraBuiltinFunctionCall {
147 function: "organize_grid_layout".into(),
148 arguments: vec![
149 input_data.cells,
150 if input_data.compute_cells.is_none() {
151 empty_int32_slice()
152 } else {
153 llr_Expression::ReadLocalVariable {
154 name: SmolStr::new_static("repeated_indices"),
155 ty: Type::Array(Type::Int32.into()),
156 }
157 },
158 if input_data.compute_cells.is_none() {
159 empty_int32_slice()
160 } else {
161 llr_Expression::ReadLocalVariable {
162 name: SmolStr::new_static("repeater_steps"),
163 ty: Type::Array(Type::Int32.into()),
164 }
165 },
166 ],
167 return_ty: Type::Array(Type::Int32.into()),
168 };
169 if let Some((cells_variable, elements)) = input_data.compute_cells {
170 llr_Expression::WithGridInputData {
171 cells_variable,
172 repeater_indices_var_name: SmolStr::new_static("repeated_indices"),
173 repeater_steps_var_name: SmolStr::new_static("repeater_steps"),
174 elements,
175 sub_expression: Box::new(sub_expression),
176 }
177 } else {
178 sub_expression
179 }
180 }
181}
182
183pub(super) fn solve_grid_layout(
184 layout_organized_data_prop: &NamedReference,
185 layout: &crate::layout::GridLayout,
186 o: Orientation,
187 ctx: &mut ExpressionLoweringCtx,
188) -> llr_Expression {
189 let (padding, spacing) = generate_layout_padding_and_spacing(&layout.geometry, o, ctx);
190 let cells = ctx.map_property_reference(layout_organized_data_prop);
191 let size = layout_geometry_size(&layout.geometry.rect, o, ctx);
192 let orientation_expr = llr_Expression::EnumerationValue(EnumerationValue {
193 value: o as _,
194 enumeration: crate::typeregister::BUILTIN.with(|b| b.enums.Orientation.clone()),
195 });
196 let data = make_struct(
197 BuiltinStruct::GridLayoutData,
198 [
199 ("size", Type::Float32, size),
200 ("spacing", Type::Float32, spacing),
201 ("padding", padding.ty(ctx), padding),
202 ("organized_data", Type::ArrayOfU16, llr_Expression::PropertyReference(cells)),
203 ],
204 );
205 let constraints_result = grid_layout_cell_constraints(layout, o, ctx, None);
206
207 match constraints_result.compute_cells {
208 Some((cells_variable, elements)) => llr_Expression::WithLayoutItemInfo {
209 cells_variable: cells_variable.clone(),
210 repeater_indices_var_name: Some("repeated_indices".into()),
211 repeater_steps_var_name: Some("repeater_steps".into()),
212 elements,
213 orientation: o,
214 sub_expression: Box::new(llr_Expression::ExtraBuiltinFunctionCall {
215 function: "solve_grid_layout".into(),
216 arguments: vec![
217 data,
218 llr_Expression::ReadLocalVariable {
219 name: cells_variable.into(),
220 ty: constraints_result.cells.ty(ctx),
221 },
222 orientation_expr,
223 llr_Expression::ReadLocalVariable {
224 name: "repeated_indices".into(),
225 ty: Type::Array(Type::Int32.into()),
226 },
227 llr_Expression::ReadLocalVariable {
228 name: "repeater_steps".into(),
229 ty: Type::Array(Type::Int32.into()),
230 },
231 ],
232 return_ty: Type::LayoutCache,
233 }),
234 },
235 None => llr_Expression::ExtraBuiltinFunctionCall {
236 function: "solve_grid_layout".into(),
237 arguments: vec![
238 data,
239 constraints_result.cells,
240 orientation_expr,
241 empty_int32_slice(),
242 empty_int32_slice(),
243 ],
244 return_ty: Type::LayoutCache,
245 },
246 }
247}
248
249pub(super) fn solve_box_layout(
250 layout: &crate::layout::BoxLayout,
251 o: Orientation,
252 ctx: &mut ExpressionLoweringCtx,
253) -> llr_Expression {
254 let (padding, spacing) = generate_layout_padding_and_spacing(&layout.geometry, o, ctx);
255 let cross_override = (o == layout.orientation && o == Orientation::Horizontal)
260 .then(|| layout_cross_content_size(layout))
261 .flatten();
262 let bld = box_layout_data(layout, o, ctx, cross_override.as_ref());
263 let size = layout_geometry_size(&layout.geometry.rect, o, ctx);
264 let (data, function) = if o == layout.orientation {
265 let data = make_struct(
266 BuiltinStruct::BoxLayoutData,
267 [
268 ("size", Type::Float32, size),
269 ("spacing", Type::Float32, spacing),
270 ("padding", padding.ty(ctx), padding),
271 (
272 "alignment",
273 crate::typeregister::BUILTIN
274 .with(|e| Type::Enumeration(e.enums.LayoutAlignment.clone())),
275 bld.alignment,
276 ),
277 ("cells", bld.cells.ty(ctx), bld.cells),
278 ],
279 );
280 (data, "solve_box_layout")
281 } else {
282 let cross_axis_alignment_ty = crate::typeregister::BUILTIN
283 .with(|e| Type::Enumeration(e.enums.CrossAxisAlignment.clone()));
284 let cross_axis_alignment = if let Some(nr) = &layout.cross_alignment {
285 llr_Expression::PropertyReference(ctx.map_property_reference(nr))
286 } else {
287 let e = crate::typeregister::BUILTIN.with(|e| e.enums.CrossAxisAlignment.clone());
288 llr_Expression::EnumerationValue(EnumerationValue {
289 value: e.default_value,
290 enumeration: e,
291 })
292 };
293 let data = make_struct(
294 BuiltinStruct::BoxLayoutOrthoData,
295 [
296 ("size", Type::Float32, size),
297 ("padding", padding.ty(ctx), padding),
298 ("cross_axis_alignment", cross_axis_alignment_ty, cross_axis_alignment),
299 ("cells", bld.cells.ty(ctx), bld.cells),
300 ],
301 );
302 (data, "solve_box_layout_ortho")
303 };
304 match bld.compute_cells {
305 Some((cells_variable, elements)) => llr_Expression::WithLayoutItemInfo {
306 cells_variable,
307 repeater_indices_var_name: Some("repeated_indices".into()),
308 repeater_steps_var_name: None,
309 elements,
310 orientation: o,
311 sub_expression: Box::new(llr_Expression::ExtraBuiltinFunctionCall {
312 function: function.into(),
313 arguments: vec![
314 data,
315 llr_Expression::ReadLocalVariable {
316 name: "repeated_indices".into(),
317 ty: Type::Array(Type::Int32.into()),
318 },
319 ],
320 return_ty: Type::LayoutCache,
321 }),
322 },
323 None => llr_Expression::ExtraBuiltinFunctionCall {
324 function: function.into(),
325 arguments: vec![data, empty_int32_slice()],
326 return_ty: Type::LayoutCache,
327 },
328 }
329}
330
331pub(super) fn solve_flexbox_layout(
332 layout: &crate::layout::FlexboxLayout,
333 ctx: &mut ExpressionLoweringCtx,
334) -> llr_Expression {
335 let (padding_h, spacing_h) =
336 generate_layout_padding_and_spacing(&layout.geometry, Orientation::Horizontal, ctx);
337 let (padding_v, spacing_v) =
338 generate_layout_padding_and_spacing(&layout.geometry, Orientation::Vertical, ctx);
339 let container_width_for_cells = if matches!(
344 layout.axis_relation(Orientation::Vertical),
345 crate::layout::FlexboxAxisRelation::MainAxis
346 ) {
347 layout
348 .geometry
349 .rect
350 .width_reference
351 .as_ref()
352 .map(|nr| crate::expression_tree::Expression::PropertyReference(nr.clone()))
353 } else {
354 None
355 };
356 let fld = flexbox_layout_data(layout, ctx, container_width_for_cells.as_ref(), None);
357 let width = layout_geometry_size(&layout.geometry.rect, Orientation::Horizontal, ctx);
358 let height = layout_geometry_size(&layout.geometry.rect, Orientation::Vertical, ctx);
359 let data = make_struct(
360 BuiltinStruct::FlexboxLayoutData,
361 [
362 ("width", Type::Float32, width),
363 ("height", Type::Float32, height),
364 ("spacing_h", Type::Float32, spacing_h),
365 ("spacing_v", Type::Float32, spacing_v),
366 ("padding_h", padding_h.ty(ctx), padding_h),
367 ("padding_v", padding_v.ty(ctx), padding_v),
368 (
369 "alignment",
370 crate::typeregister::BUILTIN
371 .with(|e| Type::Enumeration(e.enums.LayoutAlignment.clone())),
372 fld.alignment,
373 ),
374 (
375 "direction",
376 crate::typeregister::BUILTIN
377 .with(|e| Type::Enumeration(e.enums.FlexboxLayoutDirection.clone())),
378 fld.direction,
379 ),
380 (
381 "align_content",
382 crate::typeregister::BUILTIN
383 .with(|e| Type::Enumeration(e.enums.FlexboxLayoutAlignContent.clone())),
384 fld.align_content,
385 ),
386 (
387 "cross_axis_alignment",
388 crate::typeregister::BUILTIN
389 .with(|e| Type::Enumeration(e.enums.CrossAxisAlignment.clone())),
390 fld.cross_axis_alignment,
391 ),
392 (
393 "flex_wrap",
394 crate::typeregister::BUILTIN
395 .with(|e| Type::Enumeration(e.enums.FlexboxLayoutWrap.clone())),
396 fld.flex_wrap,
397 ),
398 ("cells_h", fld.cells_h.ty(ctx), fld.cells_h),
399 ("cells_v", fld.cells_v.ty(ctx), fld.cells_v),
400 ],
401 );
402 match fld.compute_cells {
403 Some((cells_h_var, cells_v_var, elements)) => llr_Expression::WithFlexboxLayoutItemInfo {
404 cells_h_variable: cells_h_var,
405 cells_v_variable: cells_v_var,
406 repeater_indices_var_name: Some("repeated_indices".into()),
407 elements,
408 sub_expression: Box::new(llr_Expression::ExtraBuiltinFunctionCall {
409 function: "solve_flexbox_layout".into(),
410 arguments: vec![
411 data,
412 llr_Expression::ReadLocalVariable {
413 name: "repeated_indices".into(),
414 ty: Type::Array(Type::Int32.into()),
415 },
416 ],
417 return_ty: Type::LayoutCache,
418 }),
419 },
420 None => {
421 let needs_measure = layout.elems.iter().any(|li| {
424 let elem = &li.item.element;
425 is_height_for_width_cell(elem)
426 || elem.borrow().inherited_layout_info_h_with_constraint().is_some()
427 });
428 if !needs_measure {
429 return llr_Expression::ExtraBuiltinFunctionCall {
430 function: "solve_flexbox_layout".into(),
431 arguments: vec![data, empty_int32_slice()],
432 return_ty: Type::LayoutCache,
433 };
434 }
435 let measure_cells = layout
440 .elems
441 .iter()
442 .map(|li| {
443 let elem = &li.item.element;
444 let v_constraint = is_height_for_width_cell(elem).then(|| {
445 crate::expression_tree::Expression::ReadLocalVariable {
446 name: "measure_known_w".into(),
447 ty: Type::LogicalLength,
448 }
449 });
450 let v_info = get_layout_info(
451 elem,
452 ctx,
453 &li.item.constraints,
454 Orientation::Vertical,
455 v_constraint,
456 );
457 let h_constraint =
458 elem.borrow().inherited_layout_info_h_with_constraint().is_some().then(
459 || crate::expression_tree::Expression::ReadLocalVariable {
460 name: "measure_known_h".into(),
461 ty: Type::LogicalLength,
462 },
463 );
464 let h_info = get_layout_info(
465 elem,
466 ctx,
467 &li.item.constraints,
468 Orientation::Horizontal,
469 h_constraint,
470 );
471 Either::Left((h_info, v_info))
472 })
473 .collect();
474 let default_cells = layout
479 .elems
480 .iter()
481 .map(|li| {
482 let elem = &li.item.element;
483 let v_constraint = if is_height_for_width_cell(elem) {
484 default_cross_axis_constraint(elem)
485 } else {
486 None
487 };
488 let v_info = get_layout_info(
489 elem,
490 ctx,
491 &li.item.constraints,
492 Orientation::Vertical,
493 v_constraint,
494 );
495 let h_constraint =
496 elem.borrow().inherited_layout_info_h_with_constraint().is_some().then(
497 || {
498 crate::expression_tree::Expression::NumberLiteral(
499 f32::MAX as f64,
500 crate::expression_tree::Unit::Px,
501 )
502 },
503 );
504 let h_info = get_layout_info(
505 elem,
506 ctx,
507 &li.item.constraints,
508 Orientation::Horizontal,
509 h_constraint,
510 );
511 Either::Left((h_info, v_info))
512 })
513 .collect();
514 llr_Expression::SolveFlexboxLayoutWithMeasure {
515 data: Box::new(data),
516 repeater_indices: Box::new(empty_int32_slice()),
517 measure_cells,
518 default_cells,
519 }
520 }
521 }
522}
523
524pub(super) fn compute_flexbox_layout_info(
525 layout: &crate::layout::FlexboxLayout,
526 orientation: Orientation,
527 ctx: &mut ExpressionLoweringCtx,
528 cross_axis_size_override: Option<&crate::expression_tree::Expression>,
529) -> llr_Expression {
530 let (width_override, height_override) = match orientation {
535 Orientation::Vertical => (cross_axis_size_override, None),
536 Orientation::Horizontal => (None, cross_axis_size_override),
537 };
538 let fld = flexbox_layout_data(layout, ctx, width_override, height_override);
539
540 match layout.axis_relation(orientation) {
541 crate::layout::FlexboxAxisRelation::MainAxis => {
542 compute_flexbox_layout_info_for_direction(layout, orientation, false, fld, ctx, None)
543 }
544 crate::layout::FlexboxAxisRelation::CrossAxis => compute_flexbox_layout_info_for_direction(
545 layout,
546 orientation,
547 true,
548 fld,
549 ctx,
550 cross_axis_size_override,
551 ),
552 crate::layout::FlexboxAxisRelation::Unknown => {
553 let row_expr = compute_flexbox_layout_info_for_direction(
556 layout,
557 orientation,
558 orientation == Orientation::Vertical, fld.clone(),
560 ctx,
561 cross_axis_size_override,
562 );
563 let col_expr = compute_flexbox_layout_info_for_direction(
564 layout,
565 orientation,
566 orientation == Orientation::Horizontal, fld,
568 ctx,
569 cross_axis_size_override,
570 );
571
572 let direction_enum =
574 crate::typeregister::BUILTIN.with(|e| e.enums.FlexboxLayoutDirection.clone());
575 let direction_ref = llr_Expression::PropertyReference(
576 ctx.map_property_reference(layout.direction.as_ref().unwrap()),
577 );
578
579 let is_row_condition = llr_Expression::BinaryExpression {
580 lhs: Box::new(llr_Expression::BinaryExpression {
581 lhs: Box::new(direction_ref.clone()),
582 rhs: Box::new(llr_Expression::EnumerationValue(EnumerationValue {
583 value: 0, enumeration: direction_enum.clone(),
585 })),
586 op: '=',
587 }),
588 rhs: Box::new(llr_Expression::BinaryExpression {
589 lhs: Box::new(direction_ref),
590 rhs: Box::new(llr_Expression::EnumerationValue(EnumerationValue {
591 value: 1, enumeration: direction_enum,
593 })),
594 op: '=',
595 }),
596 op: '|',
597 };
598
599 llr_Expression::Condition {
600 condition: Box::new(is_row_condition),
601 true_expr: Box::new(row_expr),
602 false_expr: Box::new(col_expr),
603 }
604 }
605 }
606}
607
608fn compute_flexbox_layout_info_for_direction(
609 layout: &crate::layout::FlexboxLayout,
610 orientation: Orientation,
611 is_cross_axis: bool,
612 fld: FlexboxLayoutDataResult,
613 ctx: &mut ExpressionLoweringCtx,
614 cross_axis_size_override: Option<&crate::expression_tree::Expression>,
615) -> llr_Expression {
616 let (padding_h, spacing_h) =
617 generate_layout_padding_and_spacing(&layout.geometry, Orientation::Horizontal, ctx);
618 let (padding_v, spacing_v) =
619 generate_layout_padding_and_spacing(&layout.geometry, Orientation::Vertical, ctx);
620
621 if is_cross_axis {
622 let constraint_size = if let Some(override_expr) = cross_axis_size_override {
627 super::lower_expression::lower_expression(override_expr, ctx)
628 } else {
629 match orientation {
630 Orientation::Horizontal => {
631 layout_geometry_size(&layout.geometry.rect, Orientation::Vertical, ctx)
632 }
633 Orientation::Vertical => {
634 layout_geometry_size(&layout.geometry.rect, Orientation::Horizontal, ctx)
635 }
636 }
637 };
638
639 let arguments = vec![
640 fld.cells_h,
641 fld.cells_v,
642 spacing_h,
643 spacing_v,
644 padding_h,
645 padding_v,
646 fld.direction,
647 fld.flex_wrap,
648 constraint_size,
649 ];
650
651 match fld.compute_cells {
652 Some((cells_h_var, cells_v_var, elements)) => {
653 llr_Expression::WithFlexboxLayoutItemInfo {
654 cells_h_variable: cells_h_var,
655 cells_v_variable: cells_v_var,
656 repeater_indices_var_name: None,
657 elements,
658 sub_expression: Box::new(llr_Expression::ExtraBuiltinFunctionCall {
659 function: "flexbox_layout_info_cross_axis".into(),
660 arguments,
661 return_ty: crate::typeregister::layout_info_type().into(),
662 }),
663 }
664 }
665 None => llr_Expression::ExtraBuiltinFunctionCall {
666 function: "flexbox_layout_info_cross_axis".into(),
667 arguments,
668 return_ty: crate::typeregister::layout_info_type().into(),
669 },
670 }
671 } else {
672 let (cells, spacing, padding) = match orientation {
674 Orientation::Horizontal => (fld.cells_h, spacing_h, padding_h),
675 Orientation::Vertical => (fld.cells_v, spacing_v, padding_v),
676 };
677
678 match fld.compute_cells {
679 Some((cells_h_var, cells_v_var, elements)) => {
680 let cells_var = match orientation {
681 Orientation::Horizontal => cells_h_var.clone(),
682 Orientation::Vertical => cells_v_var.clone(),
683 };
684 llr_Expression::WithFlexboxLayoutItemInfo {
685 cells_h_variable: cells_h_var,
686 cells_v_variable: cells_v_var,
687 repeater_indices_var_name: None,
688 elements,
689 sub_expression: Box::new(llr_Expression::ExtraBuiltinFunctionCall {
690 function: "flexbox_layout_info_main_axis".into(),
691 arguments: vec![
692 llr_Expression::ReadLocalVariable {
693 name: cells_var.into(),
694 ty: Type::Array(Rc::new(
695 crate::typeregister::flexbox_layout_item_info_type(),
696 )),
697 },
698 spacing,
699 padding,
700 fld.flex_wrap,
701 ],
702 return_ty: crate::typeregister::layout_info_type().into(),
703 }),
704 }
705 }
706 None => llr_Expression::ExtraBuiltinFunctionCall {
707 function: "flexbox_layout_info_main_axis".into(),
708 arguments: vec![cells, spacing, padding, fld.flex_wrap],
709 return_ty: crate::typeregister::layout_info_type().into(),
710 },
711 }
712 }
713}
714
715#[derive(Clone)]
716struct FlexboxLayoutDataResult {
717 alignment: llr_Expression,
718 direction: llr_Expression,
719 align_content: llr_Expression,
720 cross_axis_alignment: llr_Expression,
721 flex_wrap: llr_Expression,
722 cells_h: llr_Expression,
723 cells_v: llr_Expression,
724 compute_cells: Option<(
727 String,
728 String,
729 Vec<Either<(llr_Expression, llr_Expression), LayoutRepeatedElement>>,
730 )>,
731}
732
733fn flexbox_layout_data(
734 layout: &crate::layout::FlexboxLayout,
735 ctx: &mut ExpressionLoweringCtx,
736 width_override: Option<&crate::expression_tree::Expression>,
737 height_override: Option<&crate::expression_tree::Expression>,
738) -> FlexboxLayoutDataResult {
739 let alignment = if let Some(expr) = &layout.geometry.alignment {
740 llr_Expression::PropertyReference(ctx.map_property_reference(expr))
741 } else {
742 let e = crate::typeregister::BUILTIN.with(|e| e.enums.LayoutAlignment.clone());
743 llr_Expression::EnumerationValue(EnumerationValue {
744 value: e.default_value,
745 enumeration: e,
746 })
747 };
748
749 let direction = if let Some(expr) = &layout.direction {
750 llr_Expression::PropertyReference(ctx.map_property_reference(expr))
751 } else {
752 let e = crate::typeregister::BUILTIN.with(|e| e.enums.FlexboxLayoutDirection.clone());
753 llr_Expression::EnumerationValue(EnumerationValue {
754 value: e.default_value,
755 enumeration: e,
756 })
757 };
758
759 let align_content = if let Some(expr) = &layout.align_content {
760 llr_Expression::PropertyReference(ctx.map_property_reference(expr))
761 } else {
762 let e = crate::typeregister::BUILTIN.with(|e| e.enums.FlexboxLayoutAlignContent.clone());
763 llr_Expression::EnumerationValue(EnumerationValue {
764 value: e.default_value,
765 enumeration: e,
766 })
767 };
768
769 let cross_axis_alignment = if let Some(expr) = &layout.cross_axis_alignment {
770 llr_Expression::PropertyReference(ctx.map_property_reference(expr))
771 } else {
772 let e = crate::typeregister::BUILTIN.with(|e| e.enums.CrossAxisAlignment.clone());
773 llr_Expression::EnumerationValue(EnumerationValue {
774 value: e.default_value,
775 enumeration: e,
776 })
777 };
778
779 let flex_wrap = if let Some(expr) = &layout.flex_wrap {
780 llr_Expression::PropertyReference(ctx.map_property_reference(expr))
781 } else {
782 let e = crate::typeregister::BUILTIN.with(|e| e.enums.FlexboxLayoutWrap.clone());
783 llr_Expression::EnumerationValue(EnumerationValue {
784 value: e.default_value,
785 enumeration: e,
786 })
787 };
788
789 let repeater_count =
790 layout.elems.iter().filter(|i| i.item.element.borrow().repeated.is_some()).count();
791
792 let element_ty = crate::typeregister::flexbox_layout_item_info_type();
793
794 let flex_prop =
795 |li: &crate::layout::FlexboxLayoutItem, ctx: &mut ExpressionLoweringCtx| -> FlexItemProps {
796 FlexItemProps {
797 grow: li
798 .flex_grow
799 .as_ref()
800 .map(|nr| llr_Expression::PropertyReference(ctx.map_property_reference(nr)))
801 .unwrap_or(llr_Expression::NumberLiteral(0.0)),
802 shrink: li
803 .flex_shrink
804 .as_ref()
805 .map(|nr| llr_Expression::PropertyReference(ctx.map_property_reference(nr)))
806 .unwrap_or(llr_Expression::NumberLiteral(0.0)),
807 basis: li
808 .flex_basis
809 .as_ref()
810 .map(|nr| llr_Expression::PropertyReference(ctx.map_property_reference(nr)))
811 .unwrap_or(llr_Expression::NumberLiteral(-1.0)),
812 align_self: li
813 .align_self
814 .as_ref()
815 .map(|nr| llr_Expression::PropertyReference(ctx.map_property_reference(nr)))
816 .unwrap_or(default_align_self().1),
817 order: li
818 .order
819 .as_ref()
820 .map(|nr| llr_Expression::PropertyReference(ctx.map_property_reference(nr)))
821 .unwrap_or(llr_Expression::NumberLiteral(0.0)),
822 }
823 };
824
825 let cell_v_constraint = |elem: &ElementRc| -> Option<crate::expression_tree::Expression> {
831 if !is_height_for_width_cell(elem) {
832 return None;
833 }
834 width_override.cloned().or_else(|| default_cross_axis_constraint(elem))
835 };
836 let cell_h_constraint = |elem: &ElementRc| -> Option<crate::expression_tree::Expression> {
843 if elem.borrow().inherited_layout_info_h_with_constraint().is_some() {
844 Some(height_override.cloned().unwrap_or_else(|| {
845 crate::expression_tree::Expression::NumberLiteral(
846 f32::MAX as f64,
847 crate::expression_tree::Unit::Px,
848 )
849 }))
850 } else {
851 None
852 }
853 };
854
855 if repeater_count == 0 {
856 let cells_h = llr_Expression::Array {
857 values: layout
858 .elems
859 .iter()
860 .map(|li| {
861 let constraint = cell_h_constraint(&li.item.element);
862 let layout_info_h = get_layout_info(
863 &li.item.element,
864 ctx,
865 &li.item.constraints,
866 Orientation::Horizontal,
867 constraint,
868 );
869 let flex_props = flex_prop(li, ctx);
870 make_flexbox_cell_data_struct(layout_info_h, flex_props)
871 })
872 .collect(),
873 element_ty: element_ty.clone(),
874 output: llr_ArrayOutput::Slice,
875 };
876 let cells_v = llr_Expression::Array {
881 values: layout
882 .elems
883 .iter()
884 .map(|li| {
885 let constraint = cell_v_constraint(&li.item.element);
886 let layout_info_v = get_layout_info(
887 &li.item.element,
888 ctx,
889 &li.item.constraints,
890 Orientation::Vertical,
891 constraint,
892 );
893 let flex_props = flex_prop(li, ctx);
894 make_flexbox_cell_data_struct(layout_info_v, flex_props)
895 })
896 .collect(),
897 element_ty,
898 output: llr_ArrayOutput::Slice,
899 };
900 FlexboxLayoutDataResult {
901 alignment,
902 direction,
903 align_content,
904 cross_axis_alignment,
905 flex_wrap,
906 cells_h,
907 cells_v,
908 compute_cells: None,
909 }
910 } else {
911 let mut elements = Vec::new();
912 for item in &layout.elems {
913 if item.item.element.borrow().repeated.is_some() {
914 let repeater_index = match ctx
915 .mapping
916 .element_mapping
917 .get(&item.item.element.clone().into())
918 .unwrap()
919 {
920 LoweredElement::Repeated { repeated_index } => *repeated_index,
921 _ => panic!(),
922 };
923 elements.push(Either::Right(LayoutRepeatedElement {
924 repeater_index,
925 row_child_templates: None,
926 }))
927 } else {
928 let h_constraint = cell_h_constraint(&item.item.element);
930 let layout_info_h = get_layout_info(
931 &item.item.element,
932 ctx,
933 &item.item.constraints,
934 Orientation::Horizontal,
935 h_constraint,
936 );
937 let constraint = cell_v_constraint(&item.item.element);
938 let layout_info_v = get_layout_info(
939 &item.item.element,
940 ctx,
941 &item.item.constraints,
942 Orientation::Vertical,
943 constraint,
944 );
945 let flex_props = flex_prop(item, ctx);
946 elements.push(Either::Left((
947 make_flexbox_cell_data_struct(layout_info_h, flex_props.clone()),
948 make_flexbox_cell_data_struct(layout_info_v, flex_props),
949 )));
950 }
951 }
952 let cells_h = llr_Expression::ReadLocalVariable {
953 name: "cells_h".into(),
954 ty: Type::Array(Rc::new(crate::typeregister::flexbox_layout_item_info_type())),
955 };
956 let cells_v = llr_Expression::ReadLocalVariable {
957 name: "cells_v".into(),
958 ty: Type::Array(Rc::new(crate::typeregister::flexbox_layout_item_info_type())),
959 };
960 FlexboxLayoutDataResult {
961 alignment,
962 direction,
963 align_content,
964 cross_axis_alignment,
965 flex_wrap,
966 cells_h,
967 cells_v,
968 compute_cells: Some(("cells_h".into(), "cells_v".into(), elements)),
969 }
970 }
971}
972
973struct BoxLayoutDataResult {
974 alignment: llr_Expression,
975 cells: llr_Expression,
976 compute_cells: Option<(String, Vec<Either<llr_Expression, LayoutRepeatedElement>>)>,
979}
980
981fn default_align_self() -> (Type, llr_Expression) {
982 let e = crate::typeregister::BUILTIN.with(|e| e.enums.FlexboxLayoutAlignSelf.clone());
983 (
984 Type::Enumeration(e.clone()),
985 llr_Expression::EnumerationValue(EnumerationValue {
986 value: e.default_value,
987 enumeration: e,
988 }),
989 )
990}
991
992fn make_layout_cell_data_struct(layout_info: llr_Expression) -> llr_Expression {
993 make_struct(
994 BuiltinStruct::LayoutItemInfo,
995 [("constraint", crate::typeregister::layout_info_type().into(), layout_info)],
996 )
997}
998
999#[derive(Clone)]
1000struct FlexItemProps {
1001 grow: llr_Expression,
1002 shrink: llr_Expression,
1003 basis: llr_Expression,
1004 align_self: llr_Expression,
1005 order: llr_Expression,
1006}
1007
1008fn make_flexbox_cell_data_struct(layout_info: llr_Expression, fp: FlexItemProps) -> llr_Expression {
1009 let (align_self_ty, _) = default_align_self();
1010 make_struct(
1011 BuiltinStruct::FlexboxLayoutItemInfo,
1012 [
1013 ("constraint", crate::typeregister::layout_info_type().into(), layout_info),
1014 ("flex-grow", Type::Float32, fp.grow),
1015 ("flex-shrink", Type::Float32, fp.shrink),
1016 ("flex-basis", Type::Float32, fp.basis),
1017 ("flex-align-self", align_self_ty, fp.align_self),
1018 ("flex-order", Type::Int32, fp.order),
1019 ],
1020 )
1021}
1022
1023fn box_layout_data(
1024 layout: &crate::layout::BoxLayout,
1025 orientation: Orientation,
1026 ctx: &mut ExpressionLoweringCtx,
1027 cross_axis_size_override: Option<&crate::expression_tree::Expression>,
1028) -> BoxLayoutDataResult {
1029 let alignment = if let Some(expr) = &layout.geometry.alignment {
1030 llr_Expression::PropertyReference(ctx.map_property_reference(expr))
1031 } else {
1032 let e = crate::typeregister::BUILTIN.with(|e| e.enums.LayoutAlignment.clone());
1033 llr_Expression::EnumerationValue(EnumerationValue {
1034 value: e.default_value,
1035 enumeration: e,
1036 })
1037 };
1038
1039 let repeater_count =
1040 layout.elems.iter().filter(|i| i.element.borrow().repeated.is_some()).count();
1041
1042 let element_ty = crate::typeregister::layout_item_info_type();
1043
1044 if repeater_count == 0 {
1045 let cells = llr_Expression::Array {
1046 values: layout
1047 .elems
1048 .iter()
1049 .map(|li| {
1050 let layout_info = cell_layout_info(
1051 &li.element,
1052 &li.constraints,
1053 ctx,
1054 orientation,
1055 cross_axis_size_override,
1056 );
1057 make_layout_cell_data_struct(layout_info)
1058 })
1059 .collect(),
1060 element_ty,
1061 output: llr_ArrayOutput::Slice,
1062 };
1063 BoxLayoutDataResult { alignment, cells, compute_cells: None }
1064 } else {
1065 let mut elements = Vec::new();
1066 for item in &layout.elems {
1067 if item.element.borrow().repeated.is_some() {
1068 let repeater_index =
1069 match ctx.mapping.element_mapping.get(&item.element.clone().into()).unwrap() {
1070 LoweredElement::Repeated { repeated_index } => *repeated_index,
1071 _ => panic!(),
1072 };
1073 elements.push(Either::Right(LayoutRepeatedElement {
1074 repeater_index,
1075 row_child_templates: None,
1076 }))
1077 } else {
1078 let layout_info = cell_layout_info(
1079 &item.element,
1080 &item.constraints,
1081 ctx,
1082 orientation,
1083 cross_axis_size_override,
1084 );
1085 elements.push(Either::Left(make_layout_cell_data_struct(layout_info)));
1086 }
1087 }
1088 let cells = llr_Expression::ReadLocalVariable {
1089 name: "cells".into(),
1090 ty: Type::Array(Rc::new(crate::typeregister::layout_info_type().into())),
1091 };
1092 BoxLayoutDataResult { alignment, cells, compute_cells: Some(("cells".into(), elements)) }
1093 }
1094}
1095
1096fn cell_layout_info(
1097 elem: &ElementRc,
1098 constraints: &crate::layout::LayoutConstraints,
1099 ctx: &mut ExpressionLoweringCtx,
1100 orientation: Orientation,
1101 cross_axis_size_override: Option<&crate::expression_tree::Expression>,
1102) -> llr_Expression {
1103 let constraint = match orientation {
1104 Orientation::Vertical => {
1105 cross_axis_size_override.filter(|_| is_height_for_width_cell(elem)).cloned()
1106 }
1107 Orientation::Horizontal => {
1108 if elem.borrow().inherited_layout_info_h_with_constraint().is_some() {
1114 Some(cross_axis_size_override.cloned().unwrap_or_else(|| {
1115 crate::expression_tree::Expression::NumberLiteral(
1116 f32::MAX as f64,
1117 crate::expression_tree::Unit::Px,
1118 )
1119 }))
1120 } else {
1121 None
1122 }
1123 }
1124 };
1125 get_layout_info(elem, ctx, constraints, orientation, constraint)
1126}
1127
1128struct GridLayoutCellConstraintsResult {
1129 cells: llr_Expression,
1130 compute_cells: Option<(String, Vec<Either<llr_Expression, LayoutRepeatedElement>>)>,
1133}
1134
1135fn grid_layout_cell_constraints(
1136 layout: &crate::layout::GridLayout,
1137 orientation: Orientation,
1138 ctx: &mut ExpressionLoweringCtx,
1139 cross_axis_size_override: Option<&crate::expression_tree::Expression>,
1140) -> GridLayoutCellConstraintsResult {
1141 let repeater_count =
1142 layout.elems.iter().filter(|i| i.item.element.borrow().repeated.is_some()).count();
1143
1144 let element_ty = crate::typeregister::layout_item_info_type();
1145
1146 if repeater_count == 0 {
1147 let cells = llr_Expression::Array {
1148 element_ty,
1149 values: layout
1150 .elems
1151 .iter()
1152 .map(|li| {
1153 let layout_info = cell_layout_info(
1154 &li.item.element,
1155 &li.item.constraints,
1156 ctx,
1157 orientation,
1158 cross_axis_size_override,
1159 );
1160 make_layout_cell_data_struct(layout_info)
1161 })
1162 .collect(),
1163 output: llr_ArrayOutput::Slice,
1164 };
1165 GridLayoutCellConstraintsResult { cells, compute_cells: None }
1166 } else {
1167 let mut elements = Vec::new();
1168 for item in &layout.elems {
1169 if item.item.element.borrow().repeated.is_some() {
1170 let repeater_index = match ctx
1171 .mapping
1172 .element_mapping
1173 .get(&item.item.element.clone().into())
1174 .unwrap()
1175 {
1176 LoweredElement::Repeated { repeated_index } => *repeated_index,
1177 _ => panic!(),
1178 };
1179 let row_child_templates = get_row_child_templates(&item.item.element, ctx);
1180 elements.push(Either::Right(LayoutRepeatedElement {
1181 repeater_index,
1182 row_child_templates,
1183 }));
1184 } else {
1185 let layout_info = cell_layout_info(
1186 &item.item.element,
1187 &item.item.constraints,
1188 ctx,
1189 orientation,
1190 cross_axis_size_override,
1191 );
1192 elements.push(Either::Left(make_layout_cell_data_struct(layout_info)));
1193 }
1194 }
1195 let cells = llr_Expression::ReadLocalVariable {
1196 name: "cells".into(),
1197 ty: Type::Array(Rc::new(crate::typeregister::layout_info_type().into())),
1198 };
1199 GridLayoutCellConstraintsResult { cells, compute_cells: Some(("cells".into(), elements)) }
1200 }
1201}
1202
1203struct GridLayoutInputDataResult {
1204 cells: llr_Expression,
1205 compute_cells: Option<(String, Vec<Either<llr_Expression, GridLayoutRepeatedElement>>)>,
1208}
1209
1210fn grid_layout_input_data(
1212 layout: &crate::layout::GridLayout,
1213 ctx: &mut ExpressionLoweringCtx,
1214) -> GridLayoutInputDataResult {
1215 let propref = |named_ref: &RowColExpr| match named_ref {
1216 RowColExpr::Literal(n) => llr_Expression::NumberLiteral((*n).into()),
1217 RowColExpr::Named(nr) => llr_Expression::PropertyReference(ctx.map_property_reference(nr)),
1218 RowColExpr::Auto => llr_Expression::NumberLiteral(i_slint_common::ROW_COL_AUTO as _),
1219 };
1220 let input_data_for_cell = |elem: &crate::layout::GridLayoutElement,
1221 new_row_expr: llr_Expression| {
1222 let row_expr = propref(&elem.cell.borrow().row_expr);
1223 let col_expr = propref(&elem.cell.borrow().col_expr);
1224 let rowspan_expr = propref(&elem.cell.borrow().rowspan_expr);
1225 let colspan_expr = propref(&elem.cell.borrow().colspan_expr);
1226
1227 make_struct(
1228 BuiltinStruct::GridLayoutInputData,
1229 [
1230 ("new_row", Type::Bool, new_row_expr),
1231 ("row", Type::Float32, row_expr),
1232 ("col", Type::Float32, col_expr),
1233 ("rowspan", Type::Float32, rowspan_expr),
1234 ("colspan", Type::Float32, colspan_expr),
1235 ],
1236 )
1237 };
1238 let repeater_count =
1239 layout.elems.iter().filter(|i| i.item.element.borrow().repeated.is_some()).count();
1240
1241 let element_ty = grid_layout_input_data_ty();
1242
1243 if repeater_count == 0 {
1244 let cells = llr_Expression::Array {
1245 element_ty,
1246 values: layout
1247 .elems
1248 .iter()
1249 .map(|elem| {
1250 input_data_for_cell(
1251 elem,
1252 llr_Expression::BoolLiteral(elem.cell.borrow().new_row),
1253 )
1254 })
1255 .collect(),
1256 output: llr_ArrayOutput::Slice,
1257 };
1258 GridLayoutInputDataResult { cells, compute_cells: None }
1259 } else {
1260 let mut elements = Vec::new();
1261 let mut after_repeater_in_same_row = false;
1262 for item in &layout.elems {
1263 let new_row = item.cell.borrow().new_row;
1264 if new_row {
1265 after_repeater_in_same_row = false;
1266 }
1267 if item.item.element.borrow().repeated.is_some() {
1268 let repeater_index = match ctx
1269 .mapping
1270 .element_mapping
1271 .get(&item.item.element.clone().into())
1272 .unwrap()
1273 {
1274 LoweredElement::Repeated { repeated_index } => *repeated_index,
1275 _ => panic!(),
1276 };
1277 let row_child_templates = get_row_child_templates(&item.item.element, ctx);
1278 let repeated_element =
1279 GridLayoutRepeatedElement { new_row, repeater_index, row_child_templates };
1280 elements.push(Either::Right(repeated_element));
1281 after_repeater_in_same_row = true;
1282 } else {
1283 let new_row_expr = if new_row || !after_repeater_in_same_row {
1284 llr_Expression::BoolLiteral(new_row)
1285 } else {
1286 llr_Expression::ReadLocalVariable {
1287 name: SmolStr::new_static("new_row"),
1288 ty: Type::Bool,
1289 }
1290 };
1291 elements.push(Either::Left(input_data_for_cell(item, new_row_expr)));
1292 }
1293 }
1294 let cells = llr_Expression::ReadLocalVariable {
1295 name: "cells".into(),
1296 ty: Type::Array(Rc::new(element_ty)),
1297 };
1298 GridLayoutInputDataResult { cells, compute_cells: Some(("cells".into(), elements)) }
1299 }
1300}
1301
1302pub(super) fn grid_layout_input_data_ty() -> Type {
1303 Type::Struct(Rc::new(Struct {
1304 fields: IntoIterator::into_iter([
1305 (SmolStr::new_static("new_row"), Type::Bool),
1306 (SmolStr::new_static("row"), Type::Int32),
1307 (SmolStr::new_static("col"), Type::Int32),
1308 (SmolStr::new_static("rowspan"), Type::Int32),
1309 (SmolStr::new_static("colspan"), Type::Int32),
1310 ])
1311 .collect(),
1312 name: BuiltinStruct::GridLayoutInputData.into(),
1313 }))
1314}
1315
1316fn generate_layout_padding_and_spacing(
1317 layout_geometry: &crate::layout::LayoutGeometry,
1318 orientation: Orientation,
1319 ctx: &ExpressionLoweringCtx,
1320) -> (llr_Expression, llr_Expression) {
1321 let padding_prop = |expr| {
1322 if let Some(expr) = expr {
1323 llr_Expression::PropertyReference(ctx.map_property_reference(expr))
1324 } else {
1325 llr_Expression::NumberLiteral(0.)
1326 }
1327 };
1328 let spacing = padding_prop(layout_geometry.spacing.orientation(orientation));
1329 let (begin, end) = layout_geometry.padding.begin_end(orientation);
1330
1331 let padding = make_struct(
1332 BuiltinStruct::Padding,
1333 [("begin", Type::Float32, padding_prop(begin)), ("end", Type::Float32, padding_prop(end))],
1334 );
1335
1336 (padding, spacing)
1337}
1338
1339fn is_height_for_width_cell(elem: &ElementRc) -> bool {
1349 let elem_b = elem.borrow();
1350
1351 let has_constrained_layoutinfo_v = elem_b.layout_info_v_with_constraint.is_some()
1354 || matches!(
1355 &elem_b.base_type,
1356 crate::langtype::ElementType::Component(base_comp)
1357 if base_comp.root_element.borrow().layout_info_v_with_constraint.is_some()
1358 );
1359 if has_constrained_layoutinfo_v {
1360 return true;
1361 }
1362
1363 if elem_b.layout_info_prop(Orientation::Vertical).is_some() {
1364 return false;
1365 }
1366 drop(elem_b);
1367
1368 matches!(
1370 crate::layout::implicit_layout_info_call(
1371 elem,
1372 Orientation::Vertical,
1373 crate::layout::BuiltinFilter::All,
1374 None,
1375 ),
1376 Some(crate::expression_tree::Expression::FunctionCall { .. })
1377 )
1378}
1379
1380fn default_cross_axis_constraint(elem: &ElementRc) -> Option<crate::expression_tree::Expression> {
1394 let elem_b = elem.borrow();
1395
1396 if let Some(constrained_nr) = elem_b.inherited_layout_info_h_with_constraint() {
1405 let call = crate::expression_tree::Expression::FunctionCall {
1406 function: crate::expression_tree::Callable::Function(constrained_nr),
1407 arguments: vec![crate::expression_tree::Expression::NumberLiteral(
1408 f32::MAX as f64,
1409 crate::expression_tree::Unit::Px,
1410 )],
1411 source_location: None,
1412 };
1413 return Some(crate::expression_tree::Expression::StructFieldAccess {
1414 base: Box::new(call),
1415 name: "preferred".into(),
1416 });
1417 }
1418
1419 if let Some((h_nr, _v_nr)) = elem_b.layout_info_prop.as_ref() {
1421 return Some(crate::expression_tree::Expression::StructFieldAccess {
1422 base: Box::new(crate::expression_tree::Expression::PropertyReference(h_nr.clone())),
1423 name: "preferred".into(),
1424 });
1425 }
1426 drop(elem_b);
1427
1428 crate::layout::implicit_layout_info_call(
1430 elem,
1431 Orientation::Horizontal,
1432 crate::layout::BuiltinFilter::All,
1433 None,
1434 )
1435 .map(|expr| crate::expression_tree::Expression::StructFieldAccess {
1436 base: Box::new(expr),
1437 name: "preferred".into(),
1438 })
1439}
1440
1441fn layout_cross_content_size(
1444 layout: &crate::layout::BoxLayout,
1445) -> Option<crate::expression_tree::Expression> {
1446 use crate::expression_tree::Expression;
1447 let cross = layout.orientation.orthogonal();
1448 let size_nr = layout.geometry.rect.size_reference(cross)?.clone();
1449 let mut expr = Expression::PropertyReference(size_nr);
1450 let pads = match cross {
1451 Orientation::Horizontal => [&layout.geometry.padding.left, &layout.geometry.padding.right],
1452 Orientation::Vertical => [&layout.geometry.padding.top, &layout.geometry.padding.bottom],
1453 };
1454 for p in pads.into_iter().flatten() {
1455 expr = Expression::BinaryExpression {
1456 lhs: Box::new(expr),
1457 rhs: Box::new(Expression::PropertyReference(p.clone())),
1458 op: '-',
1459 };
1460 }
1461 Some(expr)
1462}
1463
1464fn layout_geometry_size(
1465 rect: &crate::layout::LayoutRect,
1466 orientation: Orientation,
1467 ctx: &ExpressionLoweringCtx,
1468) -> llr_Expression {
1469 match rect.size_reference(orientation) {
1470 Some(nr) => llr_Expression::PropertyReference(ctx.map_property_reference(nr)),
1471 None => llr_Expression::NumberLiteral(0.),
1472 }
1473}
1474
1475pub fn get_layout_info(
1476 elem: &ElementRc,
1477 ctx: &mut ExpressionLoweringCtx,
1478 constraints: &crate::layout::LayoutConstraints,
1479 orientation: Orientation,
1480 constraint: Option<crate::expression_tree::Expression>,
1481) -> llr_Expression {
1482 let layout_info = if let Some(c) = &constraint
1487 && let Some(parameterized_nr) = (match orientation {
1488 Orientation::Vertical => elem.borrow().layout_info_v_with_constraint.clone(),
1489 Orientation::Horizontal => elem.borrow().layout_info_h_with_constraint.clone(),
1490 }) {
1491 let call = crate::expression_tree::Expression::FunctionCall {
1492 function: crate::expression_tree::Callable::Function(parameterized_nr),
1493 arguments: vec![c.clone()],
1494 source_location: None,
1495 };
1496 super::lower_expression::lower_expression(&call, ctx)
1497 } else if let Some(layout_info_prop) = &elem.borrow().layout_info_prop(orientation) {
1498 llr_Expression::PropertyReference(ctx.map_property_reference(layout_info_prop))
1499 } else {
1500 super::lower_expression::lower_expression(
1501 &crate::layout::implicit_layout_info_call(
1502 elem,
1503 orientation,
1504 crate::layout::BuiltinFilter::All,
1505 constraint,
1506 )
1507 .unwrap(),
1508 ctx,
1509 )
1510 };
1511
1512 if constraints.has_explicit_restrictions(orientation) {
1513 let store = llr_Expression::StoreLocalVariable {
1514 name: "layout_info".into(),
1515 value: layout_info.into(),
1516 };
1517 let ty = crate::typeregister::layout_info_type();
1518 let mut values = ty
1519 .fields
1520 .keys()
1521 .map(|p| {
1522 (
1523 p.clone(),
1524 llr_Expression::StructFieldAccess {
1525 base: llr_Expression::ReadLocalVariable {
1526 name: "layout_info".into(),
1527 ty: ty.clone().into(),
1528 }
1529 .into(),
1530 name: p.clone(),
1531 },
1532 )
1533 })
1534 .collect::<BTreeMap<_, _>>();
1535
1536 for (nr, s) in constraints.for_each_restrictions(orientation) {
1537 values.insert(
1538 s.into(),
1539 llr_Expression::PropertyReference(ctx.map_property_reference(nr)),
1540 );
1541 }
1542 llr_Expression::CodeBlock([store, llr_Expression::Struct { ty, values }].into())
1543 } else {
1544 layout_info
1545 }
1546}
1547
1548pub fn get_grid_layout_input_for_repeated(
1550 ctx: &mut ExpressionLoweringCtx,
1551 grid_cell: &GridLayoutCell,
1552) -> llr_Expression {
1553 let mut assignments = Vec::new();
1554
1555 fn convert_row_col_expr(expr: &RowColExpr, ctx: &ExpressionLoweringCtx) -> llr_Expression {
1556 match expr {
1557 RowColExpr::Literal(n) => llr_Expression::NumberLiteral((*n).into()),
1558 RowColExpr::Named(nr) => {
1559 llr_Expression::PropertyReference(ctx.map_property_reference(nr))
1560 }
1561 RowColExpr::Auto => llr_Expression::NumberLiteral(i_slint_common::ROW_COL_AUTO as _),
1562 }
1563 }
1564
1565 let mut push_assignment =
1567 |i: usize, new_row_expr: &llr_Expression, grid_cell: &GridLayoutCell| {
1568 let row = convert_row_col_expr(&grid_cell.row_expr, &*ctx);
1569 let col = convert_row_col_expr(&grid_cell.col_expr, &*ctx);
1570 let rowspan = convert_row_col_expr(&grid_cell.rowspan_expr, &*ctx);
1571 let colspan = convert_row_col_expr(&grid_cell.colspan_expr, &*ctx);
1572 let value = make_struct(
1573 BuiltinStruct::GridLayoutInputData,
1574 [
1575 ("new_row", Type::Bool, new_row_expr.clone()),
1576 ("row", Type::Float32, row),
1577 ("col", Type::Float32, col),
1578 ("rowspan", Type::Float32, rowspan),
1579 ("colspan", Type::Float32, colspan),
1580 ],
1581 );
1582 assignments.push(llr_Expression::SliceIndexAssignment {
1583 slice_name: SmolStr::new_static("result"),
1584 index: i,
1585 value: value.into(),
1586 });
1587 };
1588
1589 if let Some(child_items) = grid_cell.child_items.as_ref() {
1590 let mut new_row_expr = llr_Expression::BoolLiteral(true);
1593 let mut i = 0;
1594 for child_item in child_items.iter() {
1595 match child_item {
1596 crate::layout::RowChildTemplate::Static(layout_item) => {
1597 let child_element = layout_item.element.borrow();
1598 let child_cell = child_element.grid_layout_cell.as_ref().unwrap().borrow();
1599 push_assignment(i, &new_row_expr, &child_cell);
1600 new_row_expr = llr_Expression::BoolLiteral(false);
1601 i += 1;
1602 }
1603 crate::layout::RowChildTemplate::Repeated { .. } => {
1604 }
1606 }
1607 }
1608 } else {
1609 let new_row_expr = llr_Expression::ReadLocalVariable {
1615 name: SmolStr::new_static("new_row"),
1616 ty: Type::Bool,
1617 };
1618 push_assignment(0, &new_row_expr, grid_cell);
1619 }
1620
1621 llr_Expression::CodeBlock(assignments)
1622}
1623
1624fn get_row_child_templates(
1633 outer_element: &ElementRc,
1634 ctx: &ExpressionLoweringCtx,
1635) -> Option<Vec<super::RowChildTemplateInfo>> {
1636 let comp = outer_element.borrow().base_type.as_component().clone();
1637 ctx.state.row_child_templates(&comp)
1638}
1639
1640pub fn get_flexbox_layout_item_info_for_repeated(
1643 ctx: &mut ExpressionLoweringCtx,
1644 element: &ElementRc,
1645) -> llr_Expression {
1646 let prop_ref = |name: &'static str| -> Option<llr_Expression> {
1647 crate::layout::binding_reference(element, name)
1648 .map(|nr| llr_Expression::PropertyReference(ctx.map_property_reference(&nr)))
1649 };
1650
1651 let (align_self_ty, align_self_default) = default_align_self();
1652
1653 let grow = prop_ref("flex-grow").unwrap_or(llr_Expression::NumberLiteral(0.0));
1654 let shrink = prop_ref("flex-shrink").unwrap_or(llr_Expression::NumberLiteral(1.0));
1655 let basis = prop_ref("flex-basis").unwrap_or(llr_Expression::NumberLiteral(-1.0));
1656 let align_self = prop_ref("flex-align-self").unwrap_or(align_self_default);
1657 let order = prop_ref("flex-order").unwrap_or(llr_Expression::NumberLiteral(0.0));
1658
1659 make_struct(
1660 BuiltinStruct::FlexboxLayoutItemInfo,
1661 [
1662 (
1663 "constraint",
1664 crate::typeregister::layout_info_type().into(),
1665 llr_Expression::default_value_for_type(
1666 &crate::typeregister::layout_info_type().into(),
1667 )
1668 .unwrap(),
1669 ),
1670 ("flex-grow", Type::Float32, grow),
1671 ("flex-shrink", Type::Float32, shrink),
1672 ("flex-basis", Type::Float32, basis),
1673 ("flex-align-self", align_self_ty, align_self),
1674 ("flex-order", Type::Int32, order),
1675 ],
1676 )
1677}