i_slint_compiler/passes/generate_item_indices.rs
1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4//! Assign the Element::item_index on each elements
5
6use std::rc::Rc;
7
8use crate::object_tree::{Component, ElementRc};
9
10/// The item indices are generated and assigned to the ElementRc's item_index for each
11/// element in the component. The indices are local to the component.
12///
13/// For sub-components the structure of the tree becomes a little complicated, which is best
14/// illustrated using an example:
15/// ```slint
16/// SubCompo := Rectangle { Image {} }
17/// MainCompo := Window {
18/// TouchArea {}
19/// SubCompo {}
20/// Text {
21/// Path {}
22/// }
23/// }
24/// ```
25/// The item tree for `MainCompo` with its local indices is as follows:
26/// 0: Window (children: 3, children_offset: 1, parent_index: 0)
27/// 1: TouchArea (children: 0, children_offset: X, parent_index: 0)
28/// 2: Rectangle (children: 1, children_offset: 4, parent_index: 0) // SubCompo's root element
29/// 3: Text (children: 1, children_offset: 5, parent_index: 0)
30/// 4: Image (children: 0, children_offset: X, parent_index: 2) // SubCompo's child(ren)
31/// 5: Path (children: 0, children_offset: X, parent_index: 3)
32pub fn generate_item_indices(component: &Rc<Component>) {
33 // In order to create the local indices like in the above example (0-5) we use the same function
34 // that is also used for building the item tree. It recurses into all sub-components, but we skip
35 // them, by checking if the SubComponentState is true.
36 // The immediate children of for example the Window element are emitted first. When a sub-component
37 // is encountered (like `SubCompo`) the root element is emitted, but the children later. This simulates
38 // the structure as if the SubCompo was inlined, but it also means that the local item indices must be
39 // counted continuously.
40 crate::generator::build_item_tree(component, &false, &mut Helper { current_item_index: 0 });
41 for p in component.popup_windows.borrow().iter() {
42 generate_item_indices(&p.component)
43 }
44 for c in component.menu_item_tree.borrow().iter() {
45 generate_item_indices(c);
46 }
47}
48
49struct Helper {
50 current_item_index: u32,
51}
52impl crate::generator::ItemTreeBuilder for Helper {
53 // true when not at the root
54 type SubComponentState = bool;
55
56 fn push_repeated_item(
57 &mut self,
58 item: &ElementRc,
59 _repeater_count: u32,
60 _parent_index: u32,
61 component_state: &Self::SubComponentState,
62 ) {
63 if !component_state {
64 item.borrow().item_index.set(self.current_item_index).unwrap();
65 if let crate::langtype::ElementType::Component(c) = &item.borrow().base_type {
66 generate_item_indices(c);
67 }
68 }
69 self.current_item_index += 1;
70 }
71
72 fn push_native_item(
73 &mut self,
74 item: &ElementRc,
75 children_offset: u32,
76 _parent_index: u32,
77 component_state: &Self::SubComponentState,
78 ) {
79 if !component_state {
80 item.borrow().item_index.set(self.current_item_index).unwrap();
81 item.borrow().item_index_of_first_children.set(children_offset as _).unwrap();
82 }
83 self.current_item_index += 1;
84 }
85
86 fn enter_component(
87 &mut self,
88 item: &ElementRc,
89 _sub_component: &Rc<Component>,
90 children_offset: u32,
91 component_state: &Self::SubComponentState,
92 ) -> Self::SubComponentState {
93 if !component_state {
94 item.borrow().item_index.set(self.current_item_index).unwrap();
95 item.borrow().item_index_of_first_children.set(children_offset as _).unwrap();
96 }
97 true
98 }
99
100 fn enter_component_children(
101 &mut self,
102 _item: &ElementRc,
103 _repeater_count: u32,
104 _component_state: &Self::SubComponentState,
105 _sub_component_state: &Self::SubComponentState,
106 ) {
107 }
108}