i_slint_compiler/passes/
z_order.rs1use std::rc::Rc;
9
10use crate::diagnostics::BuildDiagnostics;
11use crate::expression_tree::{Expression, Unit};
12use crate::langtype::ElementType;
13use crate::object_tree::{Component, ElementRc};
14
15pub fn reorder_by_z_order(root_component: &Rc<Component>, diag: &mut BuildDiagnostics) {
16 crate::object_tree::recurse_elem_including_sub_components(
17 root_component,
18 &(),
19 &mut |elem: &ElementRc, _| {
20 reorder_children_by_zorder(elem, diag);
21 },
22 )
23}
24
25fn reorder_children_by_zorder(
26 elem: &Rc<std::cell::RefCell<crate::object_tree::Element>>,
27 diag: &mut BuildDiagnostics,
28) {
29 let mut children_z_order = Vec::new();
31 for (idx, child_elm) in elem.borrow().children.iter().enumerate() {
32 let z = child_elm
33 .borrow_mut()
34 .bindings
35 .remove("z")
36 .and_then(|e| eval_const_expr(&e.borrow().expression, "z", &*e.borrow(), diag));
37 let z =
38 z.or_else(|| {
39 child_elm.borrow().repeated.as_ref()?;
40 if let ElementType::Component(c) = &child_elm.borrow().base_type {
41 c.root_element.borrow_mut().bindings.remove("z").and_then(|e| {
42 eval_const_expr(&e.borrow().expression, "z", &*e.borrow(), diag)
43 })
44 } else {
45 None
46 }
47 });
48
49 if let Some(z) = z {
50 if children_z_order.is_empty() {
51 for i in 0..idx {
52 children_z_order.push((i, 0.));
53 }
54 }
55 children_z_order.push((idx, z));
56 } else if !children_z_order.is_empty() {
57 children_z_order.push((idx, 0.));
58 }
59 }
60
61 if !children_z_order.is_empty() {
62 children_z_order.sort_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap());
63
64 let new_children = children_z_order
65 .into_iter()
66 .map(|(idx, _)| elem.borrow().children[idx].clone())
67 .collect();
68 elem.borrow_mut().children = new_children;
69 }
70}
71
72fn eval_const_expr(
73 expression: &Expression,
74 name: &str,
75 span: &dyn crate::diagnostics::Spanned,
76 diag: &mut BuildDiagnostics,
77) -> Option<f64> {
78 match super::ignore_debug_hooks(expression) {
79 Expression::NumberLiteral(v, Unit::None) => Some(*v),
80 Expression::Cast { from, .. } => eval_const_expr(from, name, span, diag),
81 Expression::UnaryOp { sub, op: '-' } => eval_const_expr(sub, name, span, diag).map(|v| -v),
82 Expression::UnaryOp { sub, op: '+' } => eval_const_expr(sub, name, span, diag),
83 _ => {
84 diag.push_error(format!("'{name}' must be an number literal"), span);
85 None
86 }
87 }
88}