i_slint_compiler/passes/
clip.rs1use smol_str::{format_smolstr, SmolStr};
7use std::cell::RefCell;
8use std::rc::Rc;
9
10use crate::diagnostics::{BuildDiagnostics, Spanned};
11use crate::expression_tree::{BindingExpression, Expression, NamedReference};
12use crate::langtype::NativeClass;
13use crate::object_tree::{Component, Element, ElementRc};
14use crate::typeregister::TypeRegister;
15
16pub fn handle_clip(
17 component: &Rc<Component>,
18 type_register: &TypeRegister,
19 diag: &mut BuildDiagnostics,
20) {
21 let native_clip =
22 type_register.lookup_builtin_element("Clip").unwrap().as_builtin().native_class.clone();
23
24 crate::object_tree::recurse_elem_including_sub_components(
25 component,
26 &(),
27 &mut |elem_rc: &ElementRc, _| {
28 let elem = elem_rc.borrow();
29 if elem.native_class().is_some_and(|n| Rc::ptr_eq(&n, &native_clip)) {
30 return;
31 }
32 if elem.bindings.contains_key("clip")
33 || elem
34 .property_analysis
35 .borrow()
36 .get("clip")
37 .is_some_and(|a| a.is_set || a.is_linked)
38 {
39 match elem.builtin_type().as_ref().map(|ty| ty.name.as_str()) {
40 Some("Rectangle") => {}
41 Some("Path") => {
42 return;
44 }
45 _ => {
46 diag.push_error(
47 "The 'clip' property can only be applied to a Rectangle or a Path for now".into(),
48 &elem.bindings.get("clip").and_then(|x| x.borrow().span.clone()).unwrap_or_else(|| elem.to_source_location()),
49 );
50 return;
51 }
52 }
53 drop(elem);
54 create_clip_element(elem_rc, &native_clip);
55 }
56 },
57 );
58}
59
60fn create_clip_element(parent_elem: &ElementRc, native_clip: &Rc<NativeClass>) {
61 let mut parent = parent_elem.borrow_mut();
62 let clip = Element::make_rc(Element {
63 id: format_smolstr!("{}-clip", parent.id),
64 base_type: crate::langtype::ElementType::Native(native_clip.clone()),
65 children: std::mem::take(&mut parent.children),
66 enclosing_component: parent.enclosing_component.clone(),
67 ..Element::default()
68 });
69
70 parent.children.push(clip.clone());
71 drop(parent); clip.borrow_mut().bindings = ["width", "height"]
73 .iter()
74 .map(|prop| {
75 (
76 SmolStr::new_static(prop),
77 RefCell::new(
78 Expression::PropertyReference(NamedReference::new(
79 parent_elem,
80 SmolStr::new_static(prop),
81 ))
82 .into(),
83 ),
84 )
85 })
86 .collect();
87
88 copy_optional_binding(parent_elem, "border-width", &clip);
89 if super::border_radius::BORDER_RADIUS_PROPERTIES
90 .iter()
91 .any(|property_name| parent_elem.borrow().is_binding_set(property_name, true))
92 {
93 for optional_binding in super::border_radius::BORDER_RADIUS_PROPERTIES.iter() {
94 copy_optional_binding(parent_elem, optional_binding, &clip);
95 }
96 } else if parent_elem.borrow().bindings.contains_key("border-radius") {
97 for prop in super::border_radius::BORDER_RADIUS_PROPERTIES.iter() {
98 clip.borrow_mut().bindings.insert(
99 SmolStr::new(prop),
100 RefCell::new(
101 Expression::PropertyReference(NamedReference::new(
102 parent_elem,
103 SmolStr::new_static("border-radius"),
104 ))
105 .into(),
106 ),
107 );
108 }
109 }
110 clip.borrow_mut().bindings.insert(
111 SmolStr::new_static("clip"),
112 BindingExpression::new_two_way(NamedReference::new(
113 parent_elem,
114 SmolStr::new_static("clip"),
115 ))
116 .into(),
117 );
118}
119
120fn copy_optional_binding(
121 parent_elem: &ElementRc,
122 optional_binding: &'static str,
123 clip: &ElementRc,
124) {
125 if parent_elem.borrow().bindings.contains_key(optional_binding) {
126 clip.borrow_mut().bindings.insert(
127 optional_binding.into(),
128 RefCell::new(
129 Expression::PropertyReference(NamedReference::new(
130 parent_elem,
131 SmolStr::new_static(optional_binding),
132 ))
133 .into(),
134 ),
135 );
136 }
137}