i_slint_compiler/passes/
repeater_component.rs1use crate::expression_tree::{Expression, NamedReference};
9use crate::langtype::ElementType;
10use crate::object_tree::*;
11use smol_str::SmolStr;
12use std::cell::RefCell;
13use std::rc::{Rc, Weak};
14
15pub fn process_repeater_components(component: &Rc<Component>) {
16 create_repeater_components(component);
17 adjust_references(component);
18}
19
20fn create_repeater_components(component: &Rc<Component>) {
21 recurse_elem(&component.root_element, &(), &mut |original_elem_rc, _| {
22 let is_listview = match &original_elem_rc.borrow().repeated {
23 Some(r) => r.is_listview.clone(),
24 None => return,
25 };
26 let original_elem_as_weak = Rc::downgrade(original_elem_rc);
27 let mut original_elem = original_elem_rc.borrow_mut();
28
29 if matches!(&original_elem.base_type, ElementType::Component(c) if c.parent_element().is_some())
30 {
31 debug_assert!(std::rc::Weak::ptr_eq(
32 &original_elem_as_weak,
33 &*original_elem.base_type.as_component().parent_element.borrow()
34 ));
35 return;
37 }
38
39 let repeated_component = Rc::new(Component {
40 root_element: Rc::new(RefCell::new(Element {
41 id: original_elem.id.clone(),
42 base_type: std::mem::take(&mut original_elem.base_type),
43 bindings: std::mem::take(&mut original_elem.bindings),
44 change_callbacks: std::mem::take(&mut original_elem.change_callbacks),
45 property_analysis: std::mem::take(&mut original_elem.property_analysis),
46 children: std::mem::take(&mut original_elem.children),
47 property_declarations: std::mem::take(&mut original_elem.property_declarations),
48 named_references: Default::default(),
49 repeated: None,
50 is_component_placeholder: false,
51 debug: original_elem.debug.clone(),
52 enclosing_component: Default::default(),
53 states: std::mem::take(&mut original_elem.states),
54 transitions: std::mem::take(&mut original_elem.transitions),
55 child_of_layout: original_elem.child_of_layout || is_listview.is_some(),
56 layout_info_prop: original_elem.layout_info_prop.take(),
57 default_fill_parent: original_elem.default_fill_parent,
58 accessibility_props: std::mem::take(&mut original_elem.accessibility_props),
59 geometry_props: original_elem.geometry_props.clone(),
60 is_flickable_viewport: original_elem.is_flickable_viewport,
61 has_popup_child: original_elem.has_popup_child,
62 item_index: Default::default(), item_index_of_first_children: Default::default(),
64 is_legacy_syntax: original_elem.is_legacy_syntax,
65 inline_depth: 0,
66 grid_layout_cell: original_elem.grid_layout_cell.clone(),
67 })),
68 parent_element: RefCell::new(Weak::clone(&original_elem_as_weak)),
69 ..Component::default()
70 });
71
72 if let Some(listview) = is_listview {
73 if !repeated_component.root_element.borrow().is_binding_set("height", false) {
74 let preferred = Expression::PropertyReference(NamedReference::new(
75 &repeated_component.root_element,
76 SmolStr::new_static("preferred-height"),
77 ));
78 repeated_component
79 .root_element
80 .borrow_mut()
81 .bindings
82 .insert("height".into(), RefCell::new(preferred.into()));
83 }
84 if !repeated_component.root_element.borrow().is_binding_set("width", false) {
85 repeated_component.root_element.borrow_mut().bindings.insert(
86 "width".into(),
87 RefCell::new(Expression::PropertyReference(listview.listview_width).into()),
88 );
89 }
90 }
91
92 let repeated_component_weak = Rc::downgrade(&repeated_component);
93 recurse_elem(&repeated_component.root_element, &(), &mut |e, _| {
94 e.borrow_mut().enclosing_component = repeated_component_weak.clone()
95 });
96 drop(original_elem);
98
99 component.menu_item_tree.borrow_mut().retain(|menu_item| {
102 let mut parent_elem = menu_item.parent_element.borrow_mut();
103
104 if Weak::ptr_eq(&parent_elem, &original_elem_as_weak) {
107 *parent_elem = Rc::downgrade(&repeated_component.root_element);
108 }
109
110 let enclosing_component =
111 parent_elem.upgrade().unwrap().borrow().enclosing_component.clone();
112 let should_move = Weak::ptr_eq(&enclosing_component, &repeated_component_weak);
113 if should_move {
114 repeated_component.menu_item_tree.borrow_mut().push(menu_item.clone());
115 false
116 } else {
117 true
118 }
119 });
120
121 create_repeater_components(&repeated_component);
122 original_elem_rc.borrow_mut().base_type = ElementType::Component(repeated_component);
123 });
124
125 for p in component.popup_windows.borrow().iter() {
126 create_repeater_components(&p.component);
127 }
128 for c in component.menu_item_tree.borrow().iter() {
129 create_repeater_components(c);
130 }
131}
132
133pub fn adjust_references(component: &Rc<Component>) {
136 visit_all_named_references(component, &mut |reference| {
137 if reference.name() == "$model" {
138 return;
139 }
140 let referred_element = reference.element();
141 if referred_element.borrow().repeated.is_some()
142 && let ElementType::Component(created_component) =
143 referred_element.borrow().base_type.clone()
144 {
145 *reference =
146 NamedReference::new(&created_component.root_element, reference.name().clone())
147 };
148 });
149 visit_all_expressions(component, |expr, _| {
151 expr.visit_recursive_mut(&mut |expr| {
152 if let Expression::ElementReference(element_ref) = expr
153 && let Some(repeater_element) =
154 element_ref.upgrade().filter(|e| e.borrow().repeated.is_some())
155 {
156 let inner_element =
157 repeater_element.borrow().base_type.as_component().root_element.clone();
158 *element_ref = Rc::downgrade(&inner_element);
159 }
160 })
161 });
162}