i_slint_compiler/passes/
deprecated_rotation_origin.rs1use crate::diagnostics::{BuildDiagnostics, Spanned};
7use crate::expression_tree::Expression;
8use crate::langtype::ElementType;
9use crate::namedreference::NamedReference;
10use crate::object_tree::{Component, Element, ElementRc};
11use core::cell::RefCell;
12use smol_str::SmolStr;
13
14pub fn handle_rotation_origin(component: &Component, diag: &mut BuildDiagnostics) {
15 let transform_origin = crate::typeregister::transform_origin_property();
16
17 crate::object_tree::recurse_elem_including_sub_components_no_borrow(
18 component,
19 &(),
20 &mut |elem, _| {
21 let mut must_materialize = false;
22 let mut seen = false;
23 for (prop, _) in crate::typeregister::DEPRECATED_ROTATION_ORIGIN_PROPERTIES {
24 if is_property_set(&elem.borrow(), prop) {
25 let span = match elem
26 .borrow()
27 .bindings
28 .get(prop)
29 .and_then(|b| b.borrow().span.clone())
30 {
31 Some(span) => span,
32 None => {
33 if seen {
34 return;
35 }
36 elem.borrow().to_source_location()
37 }
38 };
39
40 seen = true;
41
42 if !is_image_or_text(elem) {
43 diag.push_error(format!("'{prop}' cannot be set on this element"), &span);
44 } else {
45 diag.push_property_deprecation_warning(prop, transform_origin.0, &span);
46 must_materialize = true;
47 }
48 }
49 }
50 if !must_materialize {
51 return;
52 }
53
54 let expr = Expression::Struct {
55 ty: transform_origin.1.clone(),
56 values: crate::typeregister::DEPRECATED_ROTATION_ORIGIN_PROPERTIES
57 .iter()
58 .map(|(prop, _)| {
59 (
60 SmolStr::new_static(&prop[prop.len() - 1..]),
61 Expression::PropertyReference(NamedReference::new(
62 elem,
63 SmolStr::new_static(prop),
64 )),
65 )
66 })
67 .collect(),
68 };
69
70 match elem.borrow_mut().bindings.entry(transform_origin.0.into()) {
71 std::collections::btree_map::Entry::Occupied(occupied_entry) => {
72 diag.push_error(
73 "Can't specify transform-origin if rotation-origin-x or rotation-origin-y is used on this element".into(),
74 &occupied_entry.get().borrow().span
75 );
76 }
77 std::collections::btree_map::Entry::Vacant(vacant_entry) => {
78 vacant_entry.insert(RefCell::new(expr.into()));
79 }
80 }
81 },
82 );
83}
84
85fn is_image_or_text(e: &ElementRc) -> bool {
87 e.borrow().builtin_type().is_some_and(|bt| matches!(bt.name.as_str(), "Image" | "Text"))
88}
89
90fn is_property_set(e: &Element, property_name: &str) -> bool {
92 e.bindings.contains_key(property_name)
93 || e.property_analysis.borrow().get(property_name).is_some_and(|a| a.is_set || a.is_linked)
94 || matches!(&e.base_type, ElementType::Component(base) if is_property_set(&base.root_element.borrow(), property_name))
95}