i_slint_compiler/passes/
z_order.rs

1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4/*! re-order the children by their z-order
5*/
6
7use 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    // maps indexes to their z order
29    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}