sixtyfps_compilerlib/llr/
item_tree.rs

1// Copyright © SixtyFPS GmbH <info@sixtyfps.io>
2// SPDX-License-Identifier: (GPL-3.0-only OR LicenseRef-SixtyFPS-commercial)
3
4use super::Expression;
5use crate::langtype::{NativeClass, Type};
6use std::collections::{BTreeMap, HashMap};
7use std::num::NonZeroUsize;
8use std::rc::Rc;
9
10// Index in the `SubComponent::properties`
11pub type PropertyIndex = usize;
12
13#[derive(Debug, Clone)]
14pub enum Animation {
15    /// The expression is a Struct with the animation fields
16    Static(Expression),
17    Transition(Expression),
18}
19
20#[derive(Debug, Clone)]
21pub struct BindingExpression {
22    pub expression: Expression,
23    pub animation: Option<Animation>,
24    /// When true, we can initialize the property with `set` otherwise, `set_binding` must be used
25    pub is_constant: bool,
26}
27
28#[derive(Debug)]
29pub struct GlobalComponent {
30    pub name: String,
31    pub properties: Vec<Property>,
32    /// One entry per property
33    pub init_values: Vec<Option<BindingExpression>>,
34    pub const_properties: Vec<bool>,
35    pub public_properties: PublicProperties,
36    /// true if we should expose the global in the generated API
37    pub exported: bool,
38    /// The extra names under which this component should be accessible
39    /// if it is exported several time.
40    pub aliases: Vec<String>,
41    /// True when this is a built-in global that does not need to be generated
42    pub is_builtin: bool,
43}
44
45/// a Reference to a property, in the context of a SubComponent
46#[derive(Clone, Debug, Hash, PartialEq, Eq)]
47pub enum PropertyReference {
48    /// A property relative to this SubComponent
49    Local { sub_component_path: Vec<usize>, property_index: PropertyIndex },
50    /// A property in a Native item
51    InNativeItem { sub_component_path: Vec<usize>, item_index: usize, prop_name: String },
52    /// The properties is a property relative to a parent ItemTree (`level` level deep)
53    InParent { level: NonZeroUsize, parent_reference: Box<PropertyReference> },
54    /// The property within a GlobalComponent
55    Global { global_index: usize, property_index: usize },
56}
57
58#[derive(Debug)]
59pub struct Property {
60    pub name: String,
61    pub ty: Type,
62}
63
64#[derive(Debug, Clone)]
65/// The property references might be either in the parent context, or in the
66/// repeated's component context
67pub struct ListViewInfo {
68    pub viewport_y: PropertyReference,
69    pub viewport_height: PropertyReference,
70    pub viewport_width: PropertyReference,
71    /// The ListView's inner visible height (not counting eventual scrollbar)
72    pub listview_height: PropertyReference,
73    /// The ListView's inner visible width (not counting eventual scrollbar)
74    pub listview_width: PropertyReference,
75
76    // In the repeated component context
77    pub prop_y: PropertyReference,
78    // In the repeated component context
79    pub prop_width: PropertyReference,
80    // In the repeated component context
81    pub prop_height: PropertyReference,
82}
83
84#[derive(Debug)]
85pub struct RepeatedElement {
86    pub model: Expression,
87    /// Within the sub_tree's root component
88    pub index_prop: Option<PropertyIndex>,
89    /// Within the sub_tree's root component
90    pub data_prop: Option<PropertyIndex>,
91    pub sub_tree: ItemTree,
92    /// The index of the item node in the parent tree
93    pub index_in_tree: usize,
94
95    pub listview: Option<ListViewInfo>,
96}
97
98pub struct Item {
99    pub ty: Rc<NativeClass>,
100    pub name: String,
101    /// Index in the item tree array
102    pub index_in_tree: usize,
103    /// When this is true, this item does not need to be created because it is
104    /// already in the flickable.
105    /// The Item::name is the same as the flickable, and ty is Rectangle
106    pub is_flickable_viewport: bool,
107}
108
109impl std::fmt::Debug for Item {
110    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111        f.debug_struct("Item")
112            .field("ty", &self.ty.class_name)
113            .field("name", &self.name)
114            .field("index_in_tree", &self.index_in_tree)
115            .field("is_flickable_viewport", &self.is_flickable_viewport)
116            .finish()
117    }
118}
119
120#[derive(Debug)]
121pub struct TreeNode {
122    pub sub_component_path: Vec<usize>,
123    /// Either an index in the items or repeater, depending on repeated
124    pub item_index: usize,
125    pub repeated: bool,
126    pub children: Vec<TreeNode>,
127}
128
129impl TreeNode {
130    fn children_count(&self) -> usize {
131        let mut count = self.children.len();
132        for c in &self.children {
133            count += c.children_count();
134        }
135        count
136    }
137
138    /// Visit this, and the children. passes
139    /// children_offset must be set to `1` for the root
140    pub fn visit_in_array(
141        &self,
142        visitor: &mut dyn FnMut(
143            &TreeNode,
144            /*children_offset: */ usize,
145            /*parent_index: */ usize,
146        ),
147    ) {
148        visitor(self, 1, 0);
149        visit_in_array_recursive(self, 1, 0, visitor);
150
151        fn visit_in_array_recursive(
152            node: &TreeNode,
153            children_offset: usize,
154            current_index: usize,
155            visitor: &mut dyn FnMut(&TreeNode, usize, usize),
156        ) {
157            let mut offset = children_offset + node.children.len();
158            for c in &node.children {
159                visitor(c, offset, current_index);
160                offset += c.children_count();
161            }
162
163            let mut offset = children_offset + node.children.len();
164            for (i, c) in node.children.iter().enumerate() {
165                visit_in_array_recursive(c, offset, children_offset + i, visitor);
166                offset += c.children_count();
167            }
168        }
169    }
170}
171
172#[derive(Debug)]
173pub struct SubComponent {
174    pub name: String,
175    pub properties: Vec<Property>,
176    pub items: Vec<Item>,
177    pub repeated: Vec<RepeatedElement>,
178    pub popup_windows: Vec<ItemTree>,
179    pub sub_components: Vec<SubComponentInstance>,
180    /// The initial value or binding for properties.
181    /// This is ordered in the order they must be set.
182    pub property_init: Vec<(PropertyReference, BindingExpression)>,
183    /// The animation for properties which are animated
184    pub animations: HashMap<PropertyReference, Expression>,
185    pub two_way_bindings: Vec<(PropertyReference, PropertyReference)>,
186    pub const_properties: Vec<PropertyReference>,
187    // Code that is run in the sub component constructor, after property initializations
188    pub init_code: Vec<Expression>,
189
190    pub layout_info_h: Expression,
191    pub layout_info_v: Expression,
192}
193
194impl SubComponent {
195    /// total count of repeater, including in sub components
196    pub fn repeater_count(&self) -> usize {
197        let mut count = self.repeated.len();
198        for x in self.sub_components.iter() {
199            count += x.ty.repeater_count();
200        }
201        count
202    }
203}
204
205pub struct SubComponentInstance {
206    pub ty: Rc<SubComponent>,
207    pub name: String,
208    pub index_in_tree: usize,
209    pub index_of_first_child_in_tree: usize,
210    pub repeater_offset: usize,
211}
212
213impl std::fmt::Debug for SubComponentInstance {
214    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
215        f.debug_struct("SubComponentInstance")
216            // only dump ty.name, not the whole structure
217            .field("ty", &self.ty.name)
218            .field("name", &self.name)
219            .field("index_in_tree", &self.index_in_tree)
220            .field("index_of_first_child_in_tree", &self.index_of_first_child_in_tree)
221            .field("repeater_offset", &self.repeater_offset)
222            .finish()
223    }
224}
225
226#[derive(Debug)]
227pub struct ItemTree {
228    pub root: SubComponent,
229    pub tree: TreeNode,
230    /// This tree has a parent. e.g: it is a Repeater or a PopupMenu whose property can access
231    /// the parent ItemTree.
232    /// The String is the type of the parent ItemTree
233    pub parent_context: Option<String>,
234}
235
236#[derive(Debug)]
237pub struct PublicComponent {
238    pub public_properties: PublicProperties,
239    pub item_tree: ItemTree,
240    pub sub_components: Vec<Rc<SubComponent>>,
241    pub globals: Vec<GlobalComponent>,
242}
243
244pub type PublicProperties = BTreeMap<String, (Type, PropertyReference)>;