i_slint_compiler/passes/
move_declarations.rs1use crate::expression_tree::{Expression, NamedReference};
7use crate::langtype::ElementType;
8use crate::object_tree::*;
9use core::cell::RefCell;
10use smol_str::{SmolStr, format_smolstr};
11use std::collections::{BTreeMap, HashMap};
12use std::rc::Rc;
13
14struct Declarations {
15 property_declarations: BTreeMap<SmolStr, PropertyDeclaration>,
16}
17impl Declarations {
18 fn take_from_element(e: &mut Element) -> Self {
19 Declarations { property_declarations: core::mem::take(&mut e.property_declarations) }
20 }
21}
22
23pub fn move_declarations(component: &Rc<Component>) {
24 simplify_optimized_items_recursive(component);
25 do_move_declarations(component);
26}
27
28fn do_move_declarations(component: &Rc<Component>) {
29 let mut decl = Declarations::take_from_element(&mut component.root_element.borrow_mut());
30 component.popup_windows.borrow().iter().for_each(|f| do_move_declarations(&f.component));
31 component.menu_item_tree.borrow().iter().for_each(do_move_declarations);
32
33 let mut new_root_bindings = HashMap::new();
34 let mut new_root_change_callbacks = HashMap::new();
35 let mut new_root_property_analysis = HashMap::new();
36
37 let move_bindings_and_animations = &mut |elem: &ElementRc| {
38 visit_all_named_references_in_element(elem, fixup_reference);
39
40 if elem.borrow().repeated.is_some() {
41 if let ElementType::Component(base) = &elem.borrow().base_type {
42 do_move_declarations(base);
43 } else {
44 panic!(
45 "Repeated element should have a component as base because of the repeater_component.rs pass"
46 )
47 }
48 debug_assert!(
49 elem.borrow().property_declarations.is_empty() && elem.borrow().children.is_empty(),
50 "Repeated element should be empty because of the repeater_component.rs pass"
51 );
52 return;
53 }
54
55 let bindings = core::mem::take(&mut elem.borrow_mut().bindings);
57 let mut new_bindings = BindingsMap::default();
58 for (k, e) in bindings {
59 let will_be_moved = elem.borrow().property_declarations.contains_key(&k);
60 if will_be_moved {
61 new_root_bindings.insert(map_name(elem, &k), e);
62 } else {
63 new_bindings.insert(k, e);
64 }
65 }
66 elem.borrow_mut().bindings = new_bindings;
67
68 let property_analysis = elem.borrow().property_analysis.take();
69 let mut new_property_analysis = HashMap::with_capacity(property_analysis.len());
70 for (prop, a) in property_analysis {
71 let will_be_moved = elem.borrow().property_declarations.contains_key(&prop);
72 if will_be_moved {
73 new_root_property_analysis.insert(map_name(elem, &prop), a);
74 } else {
75 new_property_analysis.insert(prop, a);
76 }
77 }
78 *elem.borrow().property_analysis.borrow_mut() = new_property_analysis;
79
80 let change_callbacks = core::mem::take(&mut elem.borrow_mut().change_callbacks);
82 let mut new_change_callbacks = BTreeMap::<SmolStr, RefCell<Vec<Expression>>>::default();
83 for (k, e) in change_callbacks {
84 let will_be_moved = elem.borrow().property_declarations.contains_key(&k);
85 if will_be_moved {
86 new_root_change_callbacks.insert(map_name(elem, &k), e);
87 } else {
88 new_change_callbacks.insert(k, e);
89 }
90 }
91 elem.borrow_mut().change_callbacks = new_change_callbacks;
92 };
93
94 component.optimized_elements.borrow().iter().for_each(&mut *move_bindings_and_animations);
95 recurse_elem(&component.root_element, &(), &mut |e, _| move_bindings_and_animations(e));
96
97 component.root_constraints.borrow_mut().visit_named_references(&mut fixup_reference);
98 component.popup_windows.borrow_mut().iter_mut().for_each(|p| {
99 fixup_reference(&mut p.x);
100 fixup_reference(&mut p.y);
101 visit_all_named_references(&p.component, &mut fixup_reference)
102 });
103 component.timers.borrow_mut().iter_mut().for_each(|t| {
104 fixup_reference(&mut t.interval);
105 fixup_reference(&mut t.running);
106 fixup_reference(&mut t.triggered);
107 });
108 component.menu_item_tree.borrow_mut().iter_mut().for_each(|c| {
109 visit_all_named_references(c, &mut fixup_reference);
110 });
111 component.init_code.borrow_mut().iter_mut().for_each(|expr| {
112 visit_named_references_in_expression(expr, &mut fixup_reference);
113 });
114 for pd in decl.property_declarations.values_mut() {
115 pd.is_alias.as_mut().map(fixup_reference);
116 }
117
118 let move_properties = &mut |elem: &ElementRc| {
119 let elem_decl = Declarations::take_from_element(&mut elem.borrow_mut());
120 decl.property_declarations.extend(
121 elem_decl.property_declarations.into_iter().map(|(p, d)| (map_name(elem, &p), d)),
122 );
123 };
124
125 recurse_elem(&component.root_element, &(), &mut |elem, _| move_properties(elem));
126
127 component.optimized_elements.borrow().iter().for_each(move_properties);
128
129 {
130 let mut r = component.root_element.borrow_mut();
131 r.property_declarations = decl.property_declarations;
132 r.bindings.extend(new_root_bindings);
133 r.property_analysis.borrow_mut().extend(new_root_property_analysis);
134 r.change_callbacks.extend(new_root_change_callbacks);
135 }
136}
137
138fn fixup_reference(nr: &mut NamedReference) {
139 let e = nr.element();
140 let component = e.borrow().enclosing_component.upgrade().unwrap();
141 if !Rc::ptr_eq(&e, &component.root_element)
142 && e.borrow().property_declarations.contains_key(nr.name())
143 {
144 *nr = NamedReference::new(&component.root_element, map_name(&e, nr.name()));
145 }
146}
147
148fn map_name(e: &ElementRc, s: &SmolStr) -> SmolStr {
149 format_smolstr!("{}-{}", e.borrow().id, s)
150}
151
152fn simplify_optimized_items_recursive(component: &Rc<Component>) {
153 simplify_optimized_items(component.optimized_elements.borrow().as_slice());
154 component
155 .popup_windows
156 .borrow()
157 .iter()
158 .for_each(|f| simplify_optimized_items_recursive(&f.component));
159 recurse_elem(&component.root_element, &(), &mut |elem, _| {
160 if elem.borrow().repeated.is_some()
161 && let ElementType::Component(base) = &elem.borrow().base_type
162 {
163 simplify_optimized_items_recursive(base);
164 }
165 });
166}
167
168fn simplify_optimized_items(items: &[ElementRc]) {
172 for elem in items {
173 recurse_elem(elem, &(), &mut |elem, _| {
174 let base = core::mem::take(&mut elem.borrow_mut().base_type);
175 if let ElementType::Builtin(c) = base {
176 elem.borrow_mut().property_declarations.extend(c.properties.iter().map(
178 |(k, v)| {
179 (
180 k.clone(),
181 PropertyDeclaration {
182 property_type: v.ty.clone(),
183 ..Default::default()
184 },
185 )
186 },
187 ));
188 } else {
189 unreachable!("Only builtin items should be optimized")
190 }
191 })
192 }
193}