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