i_slint_compiler/passes/
visible.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//! Pass that lowers synthetic `visible` properties to Clip element
5
6use smol_str::{format_smolstr, SmolStr};
7use std::cell::RefCell;
8use std::rc::Rc;
9
10use crate::diagnostics::BuildDiagnostics;
11use crate::expression_tree::{Expression, NamedReference};
12use crate::langtype::{ElementType, NativeClass, Type};
13use crate::object_tree::{self, Component, Element, ElementRc};
14use crate::typeregister::TypeRegister;
15
16pub fn handle_visible(
17    component: &Rc<Component>,
18    type_register: &TypeRegister,
19    diag: &mut BuildDiagnostics,
20) {
21    if let Some(b) = component.root_element.borrow().bindings.get("visible") {
22        diag.push_warning(
23            "The visible property cannot be used on the root element, it will not be applied"
24                .into(),
25            &*b.borrow(),
26        );
27    }
28
29    let native_clip =
30        type_register.lookup_builtin_element("Clip").unwrap().as_builtin().native_class.clone();
31
32    crate::object_tree::recurse_elem_including_sub_components(
33        component,
34        &(),
35        &mut |elem: &ElementRc, _| {
36            let is_lowered_from_visible_property = elem.borrow().native_class().is_some_and(|n| {
37                Rc::ptr_eq(&n, &native_clip) && elem.borrow().id.ends_with("-visibility")
38            });
39            if is_lowered_from_visible_property {
40                // This is the element we just created. Skip it.
41                return;
42            }
43
44            let old_children = {
45                let mut elem = elem.borrow_mut();
46                let new_children = Vec::with_capacity(elem.children.len());
47                std::mem::replace(&mut elem.children, new_children)
48            };
49
50            let has_visible_binding = |e: &ElementRc| {
51                e.borrow().base_type.lookup_property("visible").property_type != Type::Invalid
52                    && (e.borrow().bindings.contains_key("visible")
53                        || e.borrow()
54                            .property_analysis
55                            .borrow()
56                            .get("visible")
57                            .is_some_and(|a| a.is_set || a.is_linked))
58            };
59
60            for mut child in old_children {
61                if child.borrow().repeated.is_some() {
62                    let root_elem = child.borrow().base_type.as_component().root_element.clone();
63                    if has_visible_binding(&root_elem) {
64                        let clip_elem = create_visibility_element(&root_elem, &native_clip);
65                        object_tree::inject_element_as_repeated_element(&child, clip_elem.clone());
66                        // The width and the height must be null
67                        let d = NamedReference::new(&clip_elem, SmolStr::new_static("dummy"));
68                        clip_elem.borrow_mut().geometry_props.as_mut().unwrap().width = d.clone();
69                        clip_elem.borrow_mut().geometry_props.as_mut().unwrap().height = d;
70                    }
71                } else if has_visible_binding(&child) {
72                    let new_child = create_visibility_element(&child, &native_clip);
73                    new_child.borrow_mut().children.push(child);
74                    child = new_child;
75                }
76
77                elem.borrow_mut().children.push(child);
78            }
79        },
80    );
81}
82
83fn create_visibility_element(child: &ElementRc, native_clip: &Rc<NativeClass>) -> ElementRc {
84    let element = Element {
85        id: format_smolstr!("{}-visibility", child.borrow().id),
86        base_type: ElementType::Native(native_clip.clone()),
87        enclosing_component: child.borrow().enclosing_component.clone(),
88        bindings: std::iter::once((
89            SmolStr::new_static("clip"),
90            RefCell::new(
91                Expression::UnaryOp {
92                    sub: Box::new(Expression::PropertyReference(NamedReference::new(
93                        child,
94                        SmolStr::new_static("visible"),
95                    ))),
96                    op: '!',
97                }
98                .into(),
99            ),
100        ))
101        .collect(),
102        ..Default::default()
103    };
104    Element::make_rc(element)
105}