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;
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 |elem, _| {
22 let is_listview = match &elem.borrow().repeated {
23 Some(r) => r.is_listview.clone(),
24 None => return,
25 };
26 let parent_element = Rc::downgrade(elem);
27 let mut elem = elem.borrow_mut();
28
29 if matches!(&elem.base_type, ElementType::Component(c) if c.parent_element.upgrade().is_some())
30 {
31 debug_assert!(std::rc::Weak::ptr_eq(
32 &parent_element,
33 &elem.base_type.as_component().parent_element
34 ));
35 return;
37 }
38
39 let comp = Rc::new(Component {
40 root_element: Rc::new(RefCell::new(Element {
41 id: elem.id.clone(),
42 base_type: std::mem::take(&mut elem.base_type),
43 bindings: std::mem::take(&mut elem.bindings),
44 change_callbacks: std::mem::take(&mut elem.change_callbacks),
45 property_analysis: std::mem::take(&mut elem.property_analysis),
46 children: std::mem::take(&mut elem.children),
47 property_declarations: std::mem::take(&mut elem.property_declarations),
48 named_references: Default::default(),
49 repeated: None,
50 is_component_placeholder: false,
51 debug: elem.debug.clone(),
52 enclosing_component: Default::default(),
53 states: std::mem::take(&mut elem.states),
54 transitions: std::mem::take(&mut elem.transitions),
55 child_of_layout: elem.child_of_layout || is_listview.is_some(),
56 layout_info_prop: elem.layout_info_prop.take(),
57 default_fill_parent: elem.default_fill_parent,
58 accessibility_props: std::mem::take(&mut elem.accessibility_props),
59 geometry_props: elem.geometry_props.clone(),
60 is_flickable_viewport: elem.is_flickable_viewport,
61 has_popup_child: elem.has_popup_child,
62 item_index: Default::default(), item_index_of_first_children: Default::default(),
64 is_legacy_syntax: elem.is_legacy_syntax,
65 inline_depth: 0,
66 grid_layout_cell: elem.grid_layout_cell.clone(),
67 })),
68 parent_element,
69 ..Component::default()
70 });
71
72 if let Some(listview) = is_listview {
73 if !comp.root_element.borrow().is_binding_set("height", false) {
74 let preferred = Expression::PropertyReference(NamedReference::new(
75 &comp.root_element,
76 SmolStr::new_static("preferred-height"),
77 ));
78 comp.root_element
79 .borrow_mut()
80 .bindings
81 .insert("height".into(), RefCell::new(preferred.into()));
82 }
83 if !comp.root_element.borrow().is_binding_set("width", false) {
84 comp.root_element.borrow_mut().bindings.insert(
85 "width".into(),
86 RefCell::new(Expression::PropertyReference(listview.listview_width).into()),
87 );
88 }
89 }
90
91 let weak = Rc::downgrade(&comp);
92 recurse_elem(&comp.root_element, &(), &mut |e, _| {
93 e.borrow_mut().enclosing_component = weak.clone()
94 });
95
96 component.menu_item_tree.borrow_mut().retain(|x| {
99 if x.parent_element
100 .upgrade()
101 .unwrap()
102 .try_borrow() .ok()
104 .is_none_or(|parent| std::rc::Weak::ptr_eq(&parent.enclosing_component, &weak))
105 {
106 comp.menu_item_tree.borrow_mut().push(x.clone());
107 false
108 } else {
109 true
110 }
111 });
112
113 create_repeater_components(&comp);
114 elem.base_type = ElementType::Component(comp);
115 });
116
117 for p in component.popup_windows.borrow().iter() {
118 create_repeater_components(&p.component);
119 }
120 for c in component.menu_item_tree.borrow().iter() {
121 create_repeater_components(c);
122 }
123}
124
125pub fn adjust_references(comp: &Rc<Component>) {
128 visit_all_named_references(comp, &mut |nr| {
129 if nr.name() == "$model" {
130 return;
131 }
132 let e = nr.element();
133 if e.borrow().repeated.is_some()
134 && let ElementType::Component(c) = e.borrow().base_type.clone()
135 {
136 *nr = NamedReference::new(&c.root_element, nr.name().clone())
137 };
138 });
139 visit_all_expressions(comp, |expr, _| {
141 expr.visit_recursive_mut(&mut |expr| {
142 if let Expression::ElementReference(element_ref) = expr
143 && let Some(repeater_element) =
144 element_ref.upgrade().filter(|e| e.borrow().repeated.is_some())
145 {
146 let inner_element =
147 repeater_element.borrow().base_type.as_component().root_element.clone();
148 *element_ref = Rc::downgrade(&inner_element);
149 }
150 })
151 });
152}