i_slint_compiler/passes/
clip.rs1use smol_str::{SmolStr, format_smolstr};
7use std::rc::Rc;
8use std::sync::Arc;
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| Arc::ptr_eq(&n, &native_clip)) {
30 return;
31 }
32 if elem.binding("clip").is_some()
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.binding("clip").and_then(|binding| binding.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: &Arc<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); for prop in ["width", "height"] {
73 clip.borrow_mut().set_binding(
74 SmolStr::new_static(prop),
75 Expression::PropertyReference(NamedReference::new(
76 parent_elem,
77 SmolStr::new_static(prop),
78 ))
79 .into(),
80 );
81 }
82
83 copy_optional_binding(parent_elem, "border-width", &clip);
84 if super::border_radius::BORDER_RADIUS_PROPERTIES
85 .iter()
86 .any(|property_name| parent_elem.borrow().is_binding_set(property_name, true))
87 {
88 for optional_binding in super::border_radius::BORDER_RADIUS_PROPERTIES.iter() {
89 copy_optional_binding(parent_elem, optional_binding, &clip);
90 }
91 } else if parent_elem.borrow().binding("border-radius").is_some() {
92 for prop in super::border_radius::BORDER_RADIUS_PROPERTIES.iter() {
93 clip.borrow_mut().set_binding(
94 SmolStr::new(prop),
95 Expression::PropertyReference(NamedReference::new(
96 parent_elem,
97 SmolStr::new_static("border-radius"),
98 ))
99 .into(),
100 );
101 }
102 }
103 clip.borrow_mut().set_binding(
104 SmolStr::new_static("clip"),
105 BindingExpression::new_two_way(
106 NamedReference::new(parent_elem, SmolStr::new_static("clip")).into(),
107 ),
108 );
109}
110
111fn copy_optional_binding(
112 parent_elem: &ElementRc,
113 optional_binding: &'static str,
114 clip: &ElementRc,
115) {
116 if parent_elem.borrow().binding(optional_binding).is_some() {
117 clip.borrow_mut().set_binding(
118 optional_binding.into(),
119 Expression::PropertyReference(NamedReference::new(
120 parent_elem,
121 SmolStr::new_static(optional_binding),
122 ))
123 .into(),
124 );
125 }
126}