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}