Skip to main content

i_slint_compiler/llr/
item_tree.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
4use super::{EvaluationContext, Expression, ParentScope};
5use crate::langtype::{NativeClass, Type};
6use derive_more::{From, Into};
7use smol_str::SmolStr;
8use std::cell::{Cell, RefCell};
9use std::collections::{BTreeMap, HashMap};
10use std::rc::Rc;
11use typed_index_collections::TiVec;
12
13#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq, PartialOrd, Ord)]
14pub struct PropertyIdx(usize);
15#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq, PartialOrd, Ord)]
16pub struct FunctionIdx(usize);
17#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq, PartialOrd, Ord)]
18pub struct CallbackIdx(usize);
19#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq)]
20pub struct SubComponentIdx(usize);
21#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq)]
22pub struct GlobalIdx(usize);
23#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq)]
24pub struct SubComponentInstanceIdx(usize);
25#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq, PartialOrd, Ord)]
26pub struct ItemInstanceIdx(usize);
27#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq)]
28pub struct RepeatedElementIdx(usize);
29#[derive(Debug, Clone, Copy, Into, From, Hash, PartialEq, Eq)]
30pub struct GridLayoutChildIdx(usize);
31
32/// Describes one child in a repeated Row template.
33/// Used by code generators to handle any number of interleaved static children and
34/// inner repeaters within a repeated Row in a GridLayout.
35#[derive(Debug, Clone)]
36pub enum RowChildTemplateInfo {
37    /// A static child. `child_index` is an index into `SubComponent::grid_layout_children`.
38    Static { child_index: GridLayoutChildIdx },
39    /// An inner repeated child.
40    Repeated { repeater_index: RepeatedElementIdx },
41}
42
43/// Returns `true` if the optional template list contains at least one inner repeater.
44pub fn has_inner_repeaters(templates: &Option<Vec<RowChildTemplateInfo>>) -> bool {
45    templates
46        .as_ref()
47        .is_some_and(|t| t.iter().any(|e| matches!(e, RowChildTemplateInfo::Repeated { .. })))
48}
49
50/// Count the static children in a template list.
51pub fn static_child_count(templates: &[RowChildTemplateInfo]) -> usize {
52    templates.iter().filter(|e| matches!(e, RowChildTemplateInfo::Static { .. })).count()
53}
54
55#[derive(Debug, Clone)]
56pub struct LayoutRepeatedElement {
57    pub repeater_index: RepeatedElementIdx,
58    /// Template of children for a repeated Row (statics and inner repeaters in declaration order).
59    /// `None` means a single child per repeater entry (no Row with multiple children).
60    pub row_child_templates: Option<Vec<RowChildTemplateInfo>>,
61}
62
63#[derive(Debug, Clone)]
64pub struct GridLayoutRepeatedElement {
65    pub new_row: bool,
66    pub repeater_index: RepeatedElementIdx,
67    /// Template of children for a repeated Row (statics and inner repeaters in declaration order).
68    /// `None` means a single child per repeater entry (no Row with multiple children).
69    pub row_child_templates: Option<Vec<RowChildTemplateInfo>>,
70}
71
72impl PropertyIdx {
73    pub const REPEATER_DATA: Self = Self(0);
74    pub const REPEATER_INDEX: Self = Self(1);
75}
76
77/// Layout info (constraints) for a direct child of a repeated Row in a GridLayout.
78/// Used to generate `layout_item_info` which returns layout info for a specific child.
79#[derive(Debug, Clone)]
80pub struct GridLayoutChildLayoutInfo {
81    pub layout_info_h: MutExpression,
82    pub layout_info_v: MutExpression,
83}
84
85#[derive(Debug, Clone, derive_more::Deref, derive_more::DerefMut)]
86pub struct MutExpression(RefCell<Expression>);
87
88impl From<Expression> for MutExpression {
89    fn from(e: Expression) -> Self {
90        Self(e.into())
91    }
92}
93
94impl MutExpression {
95    pub fn ty(&self, ctx: &dyn super::TypeResolutionContext) -> Type {
96        self.0.borrow().ty(ctx)
97    }
98}
99
100#[derive(Debug, Clone)]
101pub enum Animation {
102    /// The expression is a Struct with the animation fields
103    Static(Expression),
104    Transition(Expression),
105}
106
107#[derive(Debug, Clone)]
108pub struct BindingExpression {
109    pub expression: MutExpression,
110    pub animation: Option<Animation>,
111    /// When true, we can initialize the property with `set` otherwise, `set_binding` must be used
112    pub is_constant: bool,
113    /// When true, the expression is a "state binding".  Despite the type of the expression being a integer
114    /// the property is of type StateInfo and the `set_state_binding` need to be used on the property
115    pub is_state_info: bool,
116
117    /// The amount of time this binding is used
118    /// This property is only valid after the [`count_property_use`](super::optim_passes::count_property_use) pass
119    pub use_count: Cell<usize>,
120}
121
122#[derive(Debug)]
123pub struct GlobalComponent {
124    pub name: SmolStr,
125    pub properties: TiVec<PropertyIdx, Property>,
126    pub callbacks: TiVec<CallbackIdx, Callback>,
127    pub functions: TiVec<FunctionIdx, Function>,
128    /// One entry per property
129    pub init_values: BTreeMap<LocalMemberIndex, BindingExpression>,
130    // maps property to its changed callback
131    pub change_callbacks: BTreeMap<PropertyIdx, MutExpression>,
132    pub const_properties: TiVec<PropertyIdx, bool>,
133    pub public_properties: PublicProperties,
134    pub private_properties: PrivateProperties,
135    /// true if we should expose the global in the generated API
136    pub exported: bool,
137    /// The extra names under which this component should be accessible
138    /// if it is exported several time.
139    pub aliases: Vec<SmolStr>,
140    /// True when this is a built-in global that does not need to be generated
141    pub is_builtin: bool,
142    /// True if this component is imported from an external library
143    pub from_library: bool,
144    /// Analysis for each properties
145    pub prop_analysis: TiVec<PropertyIdx, crate::object_tree::PropertyAnalysis>,
146}
147
148impl GlobalComponent {
149    pub fn must_generate(&self) -> bool {
150        !self.from_library
151            && (self.exported
152                || !self.functions.is_empty()
153                || self.properties.iter().any(|p| p.use_count.get() > 0)
154                || self.callbacks.iter().any(|c| c.use_count.get() > 0))
155    }
156}
157
158#[derive(Clone, Debug, Hash, PartialEq, Eq, From, PartialOrd, Ord)]
159pub enum LocalMemberIndex {
160    #[from]
161    Property(PropertyIdx),
162    #[from]
163    Function(FunctionIdx),
164    #[from]
165    Callback(CallbackIdx),
166    Native {
167        item_index: ItemInstanceIdx,
168        prop_name: SmolStr,
169    },
170}
171impl LocalMemberIndex {
172    pub fn property(&self) -> Option<PropertyIdx> {
173        if let LocalMemberIndex::Property(p) = self { Some(*p) } else { None }
174    }
175}
176
177/// A reference to a property, callback, or function, in the context of a SubComponent
178#[derive(Clone, Debug, Hash, PartialEq, Eq)]
179pub enum MemberReference {
180    /// The property or callback is withing a global
181    Global { global_index: GlobalIdx, member: LocalMemberIndex },
182
183    /// The reference is relative to the current SubComponent
184    Relative {
185        /// Go up so many level to reach the parent
186        parent_level: usize,
187        local_reference: LocalMemberReference,
188    },
189}
190impl MemberReference {
191    /// this is only valid for relative local reference
192    #[track_caller]
193    pub fn local(&self) -> LocalMemberReference {
194        match self {
195            MemberReference::Relative { parent_level: 0, local_reference, .. } => {
196                local_reference.clone()
197            }
198            _ => panic!("not a local reference"),
199        }
200    }
201
202    pub fn is_function(&self) -> bool {
203        matches!(
204            self,
205            MemberReference::Global { member: LocalMemberIndex::Function(..), .. }
206                | MemberReference::Relative {
207                    local_reference: LocalMemberReference {
208                        reference: LocalMemberIndex::Function(..),
209                        ..
210                    },
211                    ..
212                }
213        )
214    }
215}
216
217impl From<LocalMemberReference> for MemberReference {
218    fn from(local_reference: LocalMemberReference) -> Self {
219        MemberReference::Relative { parent_level: 0, local_reference }
220    }
221}
222
223/// A reference to something within an ItemTree
224#[derive(Debug, Clone, PartialEq, Eq, Hash)]
225pub struct LocalMemberReference {
226    pub sub_component_path: Vec<SubComponentInstanceIdx>,
227    pub reference: LocalMemberIndex,
228}
229
230impl<T: Into<LocalMemberIndex>> From<T> for LocalMemberReference {
231    fn from(reference: T) -> Self {
232        Self { sub_component_path: Vec::new(), reference: reference.into() }
233    }
234}
235
236#[derive(Debug, Clone)]
237pub struct TwoWayBinding {
238    pub prop1: LocalMemberReference,
239    pub prop2: MemberReference,
240    /// `Some` when the binding targets a model row. `prop2` is then the
241    /// `model_data` property of the enclosing `for`'s body sub-component,
242    /// and this index is the `model_index` property in the same sub-component.
243    pub is_model: Option<PropertyIdx>,
244    /// Field path applied to `prop2`, when `prop2` is a struct.
245    pub field_access: Vec<SmolStr>,
246}
247
248/// Resolved view of a model two-way binding, used by code generators to
249/// avoid re-deriving the parent walk and the data/index/repeater references.
250pub struct ResolvedModelTwoWayBinding<'a> {
251    /// Number of `parent` hops up to the body sub-component.
252    pub parent_level: usize,
253    pub body_sub_component: SubComponentIdx,
254    pub data_prop: PropertyIdx,
255    /// Type of `data_prop`, i.e. the starting type of [`TwoWayBinding::field_access`].
256    pub data_prop_ty: &'a Type,
257    pub index_prop: PropertyIdx,
258    pub parent_sub_component: SubComponentIdx,
259    pub repeater_index: RepeatedElementIdx,
260}
261
262impl TwoWayBinding {
263    /// Resolve the parent walk and the data/index/repeater references of a
264    /// model two-way binding. Returns `None` for regular property bindings.
265    pub fn resolve_model<'a, T>(
266        &self,
267        ctx: &EvaluationContext<'a, T>,
268    ) -> Option<ResolvedModelTwoWayBinding<'a>> {
269        let index_prop = self.is_model?;
270        let MemberReference::Relative { parent_level, local_reference } = &self.prop2 else {
271            unreachable!("model two-way binding's prop2 is always a Relative reference")
272        };
273        debug_assert!(local_reference.sub_component_path.is_empty());
274        let LocalMemberIndex::Property(data_prop) = local_reference.reference else {
275            unreachable!("model two-way binding's prop2 always references a property")
276        };
277        let super::EvaluationScope::SubComponent(mut sc, mut par) = ctx.current_scope else {
278            unreachable!("model two-way binding cannot be in a global")
279        };
280        for _ in 0..*parent_level {
281            let x = par.expect("parent_level should be valid");
282            par = x.parent;
283            sc = x.sub_component;
284        }
285        let par = par.expect("repeated item_tree must have a parent");
286        let data_prop_ty = &ctx.compilation_unit.sub_components[sc].properties[data_prop].ty;
287        Some(ResolvedModelTwoWayBinding {
288            parent_level: *parent_level,
289            body_sub_component: sc,
290            data_prop,
291            data_prop_ty,
292            index_prop,
293            parent_sub_component: par.sub_component,
294            repeater_index: par.repeater_index.expect("repeated parent has a repeater_index"),
295        })
296    }
297}
298
299#[derive(Debug, Default)]
300pub struct Property {
301    pub name: SmolStr,
302    pub ty: Type,
303    /// The amount of time this property is used of another property
304    /// This property is only valid after the [`count_property_use`](super::optim_passes::count_property_use) pass
305    pub use_count: Cell<usize>,
306}
307
308#[derive(Debug, Default)]
309pub struct Callback {
310    pub name: SmolStr,
311    pub ret_ty: Type,
312    pub args: Vec<Type>,
313
314    /// The Type::Callback
315    /// (This shouldn't be needed but it is because we call property_ty that returns a &Type)
316    pub ty: Type,
317
318    /// Same as for Property::use_count
319    pub use_count: Cell<usize>,
320
321    /// Whether this callback needs a change tracker `Property<()>` so that
322    /// setting a new handler from native code triggers re-evaluation of
323    /// property bindings that invoke this callback.
324    pub needs_tracker: bool,
325}
326
327#[derive(Debug)]
328pub struct Function {
329    pub name: SmolStr,
330    pub ret_ty: Type,
331    pub args: Vec<Type>,
332    pub code: Expression,
333}
334
335#[derive(Debug, Clone)]
336/// The property references might be either in the parent context, or in the
337/// repeated's component context
338pub struct ListViewInfo {
339    pub viewport_y: MemberReference,
340    pub viewport_height: MemberReference,
341    pub viewport_width: MemberReference,
342    /// The ListView's inner visible height (not counting eventual scrollbar)
343    pub listview_height: MemberReference,
344    /// The ListView's inner visible width (not counting eventual scrollbar)
345    pub listview_width: MemberReference,
346
347    // In the repeated component context
348    pub prop_y: MemberReference,
349    // In the repeated component context
350    pub prop_height: MemberReference,
351}
352
353#[derive(Debug)]
354pub struct RepeatedElement {
355    pub model: MutExpression,
356    /// Within the sub_tree's root component. None for `if`
357    pub index_prop: Option<PropertyIdx>,
358    /// Within the sub_tree's root component. None for `if`
359    pub data_prop: Option<PropertyIdx>,
360    pub sub_tree: ItemTree,
361    /// The index of the item node in the parent tree
362    pub index_in_tree: u32,
363
364    pub listview: Option<ListViewInfo>,
365
366    /// Access through this in case of the element being a `is_component_placeholder`
367    pub container_item_index: Option<ItemInstanceIdx>,
368}
369
370#[derive(Debug)]
371pub struct ComponentContainerElement {
372    /// The index of the `ComponentContainer` in the enclosing components `item_tree` array
373    pub component_container_item_tree_index: u32,
374    /// The index of the `ComponentContainer` item in the enclosing components `items` array
375    pub component_container_items_index: ItemInstanceIdx,
376    /// The index to a dynamic tree node where the component is supposed to be embedded at
377    pub component_placeholder_item_tree_index: u32,
378}
379
380pub struct Item {
381    pub ty: Rc<NativeClass>,
382    pub name: SmolStr,
383    /// Index in the item tree array
384    pub index_in_tree: u32,
385}
386
387impl std::fmt::Debug for Item {
388    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
389        f.debug_struct("Item")
390            .field("ty", &self.ty.class_name)
391            .field("name", &self.name)
392            .field("index_in_tree", &self.index_in_tree)
393            .finish()
394    }
395}
396
397#[derive(Debug)]
398pub struct TreeNode {
399    pub sub_component_path: Vec<SubComponentInstanceIdx>,
400    /// Either an index in the items, or the local dynamic index for repeater or component container
401    pub item_index: itertools::Either<ItemInstanceIdx, u32>,
402    pub children: Vec<TreeNode>,
403    pub is_accessible: bool,
404}
405
406impl TreeNode {
407    fn children_count(&self) -> usize {
408        let mut count = self.children.len();
409        for c in &self.children {
410            count += c.children_count();
411        }
412        count
413    }
414
415    /// Visit this, and the children.
416    /// `children_offset` must be set to `1` for the root
417    pub fn visit_in_array(
418        &self,
419        visitor: &mut dyn FnMut(
420            &TreeNode,
421            /*children_offset: */ usize,
422            /*parent_index: */ usize,
423        ),
424    ) {
425        visitor(self, 1, 0);
426        visit_in_array_recursive(self, 1, 0, visitor);
427
428        fn visit_in_array_recursive(
429            node: &TreeNode,
430            children_offset: usize,
431            current_index: usize,
432            visitor: &mut dyn FnMut(&TreeNode, usize, usize),
433        ) {
434            let mut offset = children_offset + node.children.len();
435            for c in &node.children {
436                visitor(c, offset, current_index);
437                offset += c.children_count();
438            }
439
440            let mut offset = children_offset + node.children.len();
441            for (i, c) in node.children.iter().enumerate() {
442                visit_in_array_recursive(c, offset, children_offset + i, visitor);
443                offset += c.children_count();
444            }
445        }
446    }
447}
448
449#[derive(Debug)]
450pub struct SubComponent {
451    pub name: SmolStr,
452    pub properties: TiVec<PropertyIdx, Property>,
453    pub callbacks: TiVec<CallbackIdx, Callback>,
454    pub functions: TiVec<FunctionIdx, Function>,
455    pub items: TiVec<ItemInstanceIdx, Item>,
456    pub repeated: TiVec<RepeatedElementIdx, RepeatedElement>,
457    pub component_containers: Vec<ComponentContainerElement>,
458    pub popup_windows: Vec<PopupWindow>,
459    /// The MenuItem trees. The index is stored in a Expression::NumberLiteral in the arguments of BuiltinFunction::ShowPopupMenu and BuiltinFunction::SetupMenuBar
460    pub menu_item_trees: Vec<ItemTree>,
461    pub timers: Vec<Timer>,
462    pub sub_components: TiVec<SubComponentInstanceIdx, SubComponentInstance>,
463    /// The initial value or binding for properties.
464    /// This is ordered in the order they must be set.
465    pub property_init: Vec<(MemberReference, BindingExpression)>,
466    pub change_callbacks: Vec<(MemberReference, MutExpression)>,
467    /// The animation for properties which are animated
468    pub animations: HashMap<LocalMemberReference, Expression>,
469    /// The two way bindings that map the first property to the second wih optional field access
470    pub two_way_bindings: Vec<TwoWayBinding>,
471    pub const_properties: Vec<LocalMemberReference>,
472    /// Code run at the start of the constructor, before the property initialization.
473    /// Custom font registration uses this, so fonts are ready before a property needs them.
474    pub pre_init_code: Vec<MutExpression>,
475    /// Code that is run in the sub component constructor, after property initializations
476    pub init_code: Vec<MutExpression>,
477
478    /// For each node, an expression that returns a `{x: length, y: length, width: length, height: length}`
479    pub geometries: Vec<Option<MutExpression>>,
480
481    pub layout_info_h: MutExpression,
482    pub layout_info_v: MutExpression,
483    pub child_of_layout: bool,
484    pub grid_layout_input_for_repeated: Option<MutExpression>,
485    /// Expression that builds a FlexboxLayoutItemInfo for a repeated element in a FlexboxLayout.
486    /// Contains property references to flex-grow, flex-shrink, flex-basis, align-self, order.
487    pub flexbox_layout_item_info_for_repeated: Option<MutExpression>,
488    /// True when this is a repeated Row in a GridLayout, meaning layout_item_info
489    /// needs to be able to return layout info for individual children
490    pub is_repeated_row: bool,
491    /// The list of direct grid layout children for a repeated Row.
492    /// Used to generate `layout_item_info` which returns layout info for a specific child.
493    pub grid_layout_children: TiVec<GridLayoutChildIdx, GridLayoutChildLayoutInfo>,
494    /// For repeated Rows with children: template of children in declaration order
495    /// (statics and inner repeaters). Used by code generators to produce
496    /// `grid_layout_input_data` and `layout_item_info`.
497    pub row_child_templates: Option<Vec<RowChildTemplateInfo>>,
498
499    /// Maps (item_index, property) to an expression
500    pub accessible_prop: BTreeMap<(u32, String), MutExpression>,
501
502    /// Maps item index to a list of encoded element infos of the element  (type name, qualified ids).
503    pub element_infos: BTreeMap<u32, String>,
504
505    pub prop_analysis: HashMap<MemberReference, PropAnalysis>,
506}
507
508#[derive(Debug)]
509pub struct PopupWindow {
510    pub item_tree: ItemTree,
511    pub position: MutExpression,
512    pub is_tooltip: bool,
513}
514
515#[derive(Debug)]
516pub struct PopupMenu {
517    pub item_tree: ItemTree,
518    pub sub_menu: MemberReference,
519    pub activated: MemberReference,
520    pub close: MemberReference,
521    pub entries: MemberReference,
522}
523
524#[derive(Debug)]
525pub struct Timer {
526    pub interval: MutExpression,
527    pub running: MutExpression,
528    pub triggered: MutExpression,
529}
530
531#[derive(Debug, Clone)]
532pub struct PropAnalysis {
533    /// Index in SubComponent::property_init for this property
534    pub property_init: Option<usize>,
535    pub analysis: crate::object_tree::PropertyAnalysis,
536}
537
538impl SubComponent {
539    /// total count of repeater, including in sub components
540    pub fn repeater_count(&self, cu: &CompilationUnit) -> u32 {
541        let mut count = (self.repeated.len() + self.component_containers.len()) as u32;
542        for x in self.sub_components.iter() {
543            count += cu.sub_components[x.ty].repeater_count(cu);
544        }
545        count
546    }
547
548    /// total count of items, including in sub components
549    pub fn child_item_count(&self, cu: &CompilationUnit) -> u32 {
550        let mut count = self.items.len() as u32;
551        for x in self.sub_components.iter() {
552            count += cu.sub_components[x.ty].child_item_count(cu);
553        }
554        count
555    }
556}
557
558#[derive(Debug)]
559pub struct SubComponentInstance {
560    pub ty: SubComponentIdx,
561    pub name: SmolStr,
562    pub index_in_tree: u32,
563    pub index_of_first_child_in_tree: u32,
564    pub repeater_offset: u32,
565}
566
567#[derive(Debug)]
568pub struct ItemTree {
569    pub root: SubComponentIdx,
570    pub tree: TreeNode,
571}
572
573/// What top-level role an exported component plays. Drives whether the
574/// generated public API is `slint::Window`-shaped (a `ComponentHandle` impl
575/// with `show`/`hide`/`run`/`window`) or something else.
576#[derive(Debug, Clone, Copy, PartialEq, Eq)]
577pub enum TopLevelComponentType {
578    Window,
579    SystemTrayIcon,
580}
581
582#[derive(Debug)]
583pub struct PublicComponent {
584    pub public_properties: PublicProperties,
585    pub private_properties: PrivateProperties,
586    pub item_tree: ItemTree,
587    pub name: SmolStr,
588    pub top_level_type: TopLevelComponentType,
589}
590
591#[derive(Debug)]
592pub struct CompilationUnit {
593    pub public_components: Vec<PublicComponent>,
594    /// Storage for all sub-components
595    pub sub_components: TiVec<SubComponentIdx, SubComponent>,
596    /// The sub-components that are not item-tree root
597    pub used_sub_components: Vec<SubComponentIdx>,
598    pub globals: TiVec<GlobalIdx, GlobalComponent>,
599    pub popup_menu: Option<PopupMenu>,
600    pub has_debug_info: bool,
601    #[cfg(feature = "bundle-translations")]
602    pub translations: Option<crate::translations::Translations>,
603}
604
605impl CompilationUnit {
606    pub fn needs_window_adapter(&self) -> bool {
607        self.public_components.iter().any(|p| p.top_level_type == TopLevelComponentType::Window)
608            || self.popup_menu.is_some()
609    }
610
611    pub fn for_each_sub_components<'a>(
612        &'a self,
613        visitor: &mut dyn FnMut(&'a SubComponent, &EvaluationContext<'_>),
614    ) {
615        fn visit_component<'a>(
616            root: &'a CompilationUnit,
617            c: SubComponentIdx,
618            visitor: &mut dyn FnMut(&'a SubComponent, &EvaluationContext<'_>),
619            parent: Option<&ParentScope<'_>>,
620        ) {
621            let ctx = EvaluationContext::new_sub_component(root, c, (), parent);
622            let sc = &root.sub_components[c];
623            visitor(sc, &ctx);
624            for (idx, r) in sc.repeated.iter_enumerated() {
625                visit_component(
626                    root,
627                    r.sub_tree.root,
628                    visitor,
629                    Some(&ParentScope::new(&ctx, Some(idx))),
630                );
631            }
632            for popup in &sc.popup_windows {
633                visit_component(
634                    root,
635                    popup.item_tree.root,
636                    visitor,
637                    Some(&ParentScope::new(&ctx, None)),
638                );
639            }
640            for menu_tree in &sc.menu_item_trees {
641                visit_component(root, menu_tree.root, visitor, Some(&ParentScope::new(&ctx, None)));
642            }
643        }
644        for c in &self.used_sub_components {
645            visit_component(self, *c, visitor, None);
646        }
647        for p in &self.public_components {
648            visit_component(self, p.item_tree.root, visitor, None);
649        }
650        if let Some(p) = &self.popup_menu {
651            visit_component(self, p.item_tree.root, visitor, None);
652        }
653    }
654
655    pub fn for_each_expression<'a>(
656        &'a self,
657        visitor: &mut dyn FnMut(&'a super::MutExpression, &EvaluationContext<'_>),
658    ) {
659        self.for_each_sub_components(&mut |sc, ctx| {
660            for e in &sc.pre_init_code {
661                visitor(e, ctx);
662            }
663            for e in &sc.init_code {
664                visitor(e, ctx);
665            }
666            for (_, e) in &sc.property_init {
667                visitor(&e.expression, ctx);
668            }
669            visitor(&sc.layout_info_h, ctx);
670            visitor(&sc.layout_info_v, ctx);
671            if let Some(e) = &sc.grid_layout_input_for_repeated {
672                visitor(e, ctx);
673            }
674            if let Some(e) = &sc.flexbox_layout_item_info_for_repeated {
675                visitor(e, ctx);
676            }
677            for e in sc.accessible_prop.values() {
678                visitor(e, ctx);
679            }
680            for i in sc.geometries.iter().flatten() {
681                visitor(i, ctx);
682            }
683            for (_, e) in sc.change_callbacks.iter() {
684                visitor(e, ctx);
685            }
686        });
687        for (idx, g) in self.globals.iter_enumerated() {
688            let ctx = EvaluationContext::new_global(self, idx, ());
689            for e in g.init_values.values() {
690                visitor(&e.expression, &ctx)
691            }
692            for e in g.change_callbacks.values() {
693                visitor(e, &ctx)
694            }
695        }
696    }
697}
698
699/// Depending on the type, this can also be a Callback or a Function
700#[derive(Debug, Clone)]
701pub struct PublicProperty {
702    pub name: SmolStr,
703    pub ty: Type,
704    pub prop: MemberReference,
705    pub read_only: bool,
706}
707pub type PublicProperties = Vec<PublicProperty>;
708pub type PrivateProperties = Vec<(SmolStr, Type)>;