Skip to main content

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// cSpell: ignore zorder
5/*! re-order the children by their z-order
6*/
7
8use 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    // maps indexes to their z order
30    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}