Skip to main content

i_slint_core/
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
4// cSpell: ignore xffff unclipped subchildren subsubtree
5
6//! This module contains the ItemTree and code that helps navigating it
7
8use crate::SharedString;
9use crate::accessibility::{
10    AccessibilityAction, AccessibleStringProperty, SupportedAccessibilityAction,
11};
12use crate::items::{AccessibleRole, ItemRef, ItemVTable};
13use crate::layout::{LayoutInfo, Orientation};
14use crate::lengths::{ItemTransform, LogicalPoint, LogicalRect};
15use crate::slice::Slice;
16use crate::window::WindowAdapterRc;
17use alloc::vec::Vec;
18use core::ops::ControlFlow;
19use core::pin::Pin;
20use vtable::*;
21
22#[repr(C)]
23#[derive(Debug, Clone, Copy)]
24/// A range of indices
25pub struct IndexRange {
26    /// Start index
27    pub start: usize,
28    /// Index one past the last index
29    pub end: usize,
30}
31
32impl From<core::ops::Range<usize>> for IndexRange {
33    fn from(r: core::ops::Range<usize>) -> Self {
34        Self { start: r.start, end: r.end }
35    }
36}
37impl From<IndexRange> for core::ops::Range<usize> {
38    fn from(r: IndexRange) -> Self {
39        Self { start: r.start, end: r.end }
40    }
41}
42
43/// A ItemTree is representing an unit that is allocated together
44#[cfg_attr(not(feature = "ffi"), i_slint_core_macros::remove_extern)]
45#[vtable]
46#[repr(C)]
47pub struct ItemTreeVTable {
48    /// Visit the children of the item at index `index`.
49    /// Note that the root item is at index 0, so passing 0 would visit the item under root (the children of root).
50    /// If you want to visit the root item, you need to pass -1 as an index.
51    pub visit_children_item: extern "C" fn(
52        ::core::pin::Pin<VRef<ItemTreeVTable>>,
53        index: isize,
54        order: TraversalOrder,
55        visitor: VRefMut<ItemVisitorVTable>,
56    ) -> VisitChildrenResult,
57
58    /// Return a reference to an item using the given index
59    pub get_item_ref: extern "C" fn(
60        ::core::pin::Pin<VRef<ItemTreeVTable>>,
61        index: u32,
62    ) -> ::core::pin::Pin<VRef<ItemVTable>>,
63
64    /// Return the range of indices below the dynamic `ItemTreeNode` at `index`
65    pub get_subtree_range:
66        extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, index: u32) -> IndexRange,
67
68    /// Return the `ItemTreeRc` at `subindex` below the dynamic `ItemTreeNode` at `index`
69    pub get_subtree: extern "C" fn(
70        ::core::pin::Pin<VRef<ItemTreeVTable>>,
71        index: u32,
72        subindex: usize,
73        result: &mut vtable::VWeak<ItemTreeVTable, Dyn>,
74    ),
75
76    /// Return the item tree that is defined by this `ItemTree`.
77    pub get_item_tree: extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>) -> Slice<ItemTreeNode>,
78
79    /// Return the node this ItemTree is a part of in the parent ItemTree.
80    ///
81    /// The return value is an item weak because it can be null if there is no parent.
82    /// And the return value is passed by &mut because ItemWeak has a destructor
83    /// Note that the returned value will typically point to a repeater node, which is
84    /// strictly speaking not an Item at all!
85    ///
86    pub parent_node: extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, result: &mut ItemWeak),
87
88    /// This embeds this ItemTree into the item tree of another ItemTree
89    ///
90    /// Returns `true` if this ItemTree was embedded into the `parent`
91    /// at `parent_item_tree_index`.
92    pub embed_component: extern "C" fn(
93        ::core::pin::Pin<VRef<ItemTreeVTable>>,
94        parent: &VWeak<ItemTreeVTable>,
95        parent_item_tree_index: u32,
96    ) -> bool,
97
98    /// Return the index of the current subtree or usize::MAX if this is not a subtree
99    pub subtree_index: extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>) -> usize,
100
101    /// Returns the layout info for the root of the ItemTree
102    pub layout_info:
103        extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, Orientation) -> LayoutInfo,
104
105    /// Recursively materialize every Repeater, Conditional, and
106    /// ComponentContainer reachable from this ItemTree. Called at event-loop
107    /// boundaries so init code runs outside any in-flight property evaluation.
108    /// This is the "repeater instantiation pass".
109    /// Returns `true` if any instance was created or removed.
110    pub ensure_instantiated: extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>) -> bool,
111
112    /// Returns the item's geometry (relative to its parent item)
113    pub item_geometry:
114        extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, item_index: u32) -> LogicalRect,
115
116    /// Returns the accessible role for a given item
117    pub accessible_role:
118        extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, item_index: u32) -> AccessibleRole,
119
120    /// Returns the accessible property via the `result`. Returns true if such a property exists.
121    pub accessible_string_property: extern "C" fn(
122        ::core::pin::Pin<VRef<ItemTreeVTable>>,
123        item_index: u32,
124        what: AccessibleStringProperty,
125        result: &mut SharedString,
126    ) -> bool,
127
128    /// Executes an accessibility action.
129    pub accessibility_action: extern "C" fn(
130        ::core::pin::Pin<VRef<ItemTreeVTable>>,
131        item_index: u32,
132        action: &AccessibilityAction,
133    ),
134
135    /// Returns the supported accessibility actions.
136    pub supported_accessibility_actions: extern "C" fn(
137        ::core::pin::Pin<VRef<ItemTreeVTable>>,
138        item_index: u32,
139    ) -> SupportedAccessibilityAction,
140
141    /// Add the `ElementName::id` entries of the given item
142    pub item_element_infos: extern "C" fn(
143        ::core::pin::Pin<VRef<ItemTreeVTable>>,
144        item_index: u32,
145        result: &mut SharedString,
146    ) -> bool,
147
148    /// Returns a Window, creating a fresh one if `do_create` is true.
149    pub window_adapter: extern "C" fn(
150        ::core::pin::Pin<VRef<ItemTreeVTable>>,
151        do_create: bool,
152        result: &mut Option<WindowAdapterRc>,
153    ),
154
155    /// in-place destructor (for VRc)
156    pub drop_in_place: unsafe extern "C" fn(VRefMut<ItemTreeVTable>) -> vtable::Layout,
157
158    /// dealloc function (for VRc)
159    pub dealloc: unsafe extern "C" fn(&ItemTreeVTable, ptr: *mut u8, layout: vtable::Layout),
160}
161
162#[cfg(test)]
163pub(crate) use ItemTreeVTable_static;
164
165/// Alias for `vtable::VRef<ItemTreeVTable>` which represent a pointer to a `dyn ItemTree` with
166/// the associated vtable
167pub type ItemTreeRef<'a> = vtable::VRef<'a, ItemTreeVTable>;
168
169/// Type alias to the commonly used `Pin<VRef<ItemTreeVTable>>>`
170pub type ItemTreeRefPin<'a> = core::pin::Pin<ItemTreeRef<'a>>;
171
172/// Type alias to the commonly used VRc<ItemTreeVTable, Dyn>>
173pub type ItemTreeRc = vtable::VRc<ItemTreeVTable, Dyn>;
174/// Type alias to the commonly used VWeak<ItemTreeVTable, Dyn>>
175pub type ItemTreeWeak = vtable::VWeak<ItemTreeVTable, Dyn>;
176
177/// Ensure all repeaters and conditionals within the given item tree are
178/// instantiated. Call this before non-rendering tree walks that use
179/// `first_child` / `next_sibling`.
180/// Returns `true` if any instance was created or removed.
181pub fn ensure_item_tree_instantiated(item_tree: &vtable::VRc<ItemTreeVTable>) -> bool {
182    vtable::VRc::borrow_pin(item_tree).as_ref().ensure_instantiated()
183}
184
185/// Call init() on the ItemVTable for each item of the ItemTree.
186pub fn register_item_tree(item_tree_rc: &ItemTreeRc, window_adapter: Option<WindowAdapterRc>) {
187    let c = vtable::VRc::borrow_pin(item_tree_rc);
188    let item_tree = c.as_ref().get_item_tree();
189    item_tree.iter().enumerate().for_each(|(tree_index, node)| {
190        let tree_index = tree_index as u32;
191        if let ItemTreeNode::Item { .. } = &node {
192            let item = ItemRc::new(item_tree_rc.clone(), tree_index);
193            c.as_ref().get_item_ref(tree_index).as_ref().init(&item);
194        }
195    });
196    if let Some(adapter) = window_adapter.as_ref().and_then(|a| a.internal(crate::InternalToken)) {
197        adapter.register_item_tree(ItemTreeRc::borrow_pin(item_tree_rc));
198    }
199}
200
201/// Free the backend graphics resources allocated by the ItemTree's items.
202/// This will be called  if an sub-tree gets destroyed or a popup gets closed, ...
203/// It will be called only once not for every sub item
204///
205/// * `item_tree` - the item tree to unregister
206pub fn unregister_item_tree<Base>(
207    base: core::pin::Pin<&Base>,
208    item_tree: ItemTreeRef,
209    item_array: &[vtable::VOffset<Base, ItemVTable, vtable::AllowPin>],
210    window_adapter: &WindowAdapterRc,
211) {
212    item_array.iter().for_each(|item| {
213        item.apply_pin(base).as_ref().deinit(window_adapter);
214    });
215    window_adapter.renderer().free_graphics_resources(item_tree, &mut item_array.iter().map(|item| item.apply_pin(base))).expect(
216        "Fatal error encountered when freeing graphics resources while destroying Slint component",
217    );
218
219    if let Some(w) = window_adapter.internal(crate::InternalToken) {
220        w.unregister_item_tree(item_tree, &mut item_array.iter().map(|item| item.apply_pin(base)));
221    }
222
223    // Close popups that were part of a component that just got deleted
224    let window_inner = crate::window::WindowInner::from_pub(window_adapter.window());
225    let to_close_popups = window_inner
226        .active_popups()
227        .iter()
228        .filter_map(|p| p.parent_item.upgrade().is_none().then_some(p.popup_id))
229        .collect::<Vec<_>>();
230    for popup_id in to_close_popups {
231        window_inner.close_popup(popup_id);
232    }
233}
234
235fn find_sibling_outside_repeater(
236    component: &ItemTreeRc,
237    comp_ref_pin: Pin<VRef<ItemTreeVTable>>,
238    index: u32,
239    sibling_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
240    subtree_child: &dyn Fn(usize, usize) -> usize,
241) -> Option<ItemRc> {
242    assert_ne!(index, 0);
243
244    let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
245
246    let mut current_sibling = index;
247    loop {
248        current_sibling = sibling_step(&item_tree, current_sibling)?;
249
250        if let Some(node) = step_into_node(
251            component,
252            &comp_ref_pin,
253            current_sibling,
254            &item_tree,
255            subtree_child,
256            &core::convert::identity,
257        ) {
258            return Some(node);
259        }
260    }
261}
262
263fn step_into_node(
264    component: &ItemTreeRc,
265    comp_ref_pin: &Pin<VRef<ItemTreeVTable>>,
266    node_index: u32,
267    item_tree: &crate::item_tree::ItemTreeNodeArray,
268    subtree_child: &dyn Fn(usize, usize) -> usize,
269    wrap_around: &dyn Fn(ItemRc) -> ItemRc,
270) -> Option<ItemRc> {
271    match item_tree.get(node_index).expect("Invalid index passed to item tree") {
272        crate::item_tree::ItemTreeNode::Item { .. } => {
273            Some(ItemRc::new(component.clone(), node_index))
274        }
275        crate::item_tree::ItemTreeNode::DynamicTree { index, .. } => {
276            let range = comp_ref_pin.as_ref().get_subtree_range(*index);
277            let component_index = subtree_child(range.start, range.end);
278            let mut child_instance = Default::default();
279            comp_ref_pin.as_ref().get_subtree(*index, component_index, &mut child_instance);
280            child_instance
281                .upgrade()
282                .map(|child_instance| wrap_around(ItemRc::new_root(child_instance)))
283        }
284    }
285}
286
287pub enum ParentItemTraversalMode {
288    FindAllParents,
289    StopAtPopups,
290}
291
292/// A ItemRc is holding a reference to a ItemTree containing the item, and the index of this item
293#[repr(C)]
294#[derive(Clone)]
295pub struct ItemRc {
296    item_tree: vtable::VRc<ItemTreeVTable>,
297    index: u32,
298}
299
300impl core::fmt::Debug for ItemRc {
301    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
302        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
303        let mut debug = SharedString::new();
304        comp_ref_pin.as_ref().item_element_infos(self.index, &mut debug);
305
306        write!(f, "ItemRc{{ {:p}, {:?} {debug}}}", comp_ref_pin.as_ptr(), self.index)
307    }
308}
309
310impl ItemRc {
311    /// Create an ItemRc from a ItemTree and an index
312    pub fn new(item_tree: vtable::VRc<ItemTreeVTable>, index: u32) -> Self {
313        Self { item_tree, index }
314    }
315
316    pub fn new_root(item_tree: vtable::VRc<ItemTreeVTable>) -> Self {
317        Self { item_tree, index: Self::root_index() }
318    }
319
320    #[inline(always)]
321    pub const fn root_index() -> u32 {
322        0
323    }
324
325    #[inline(always)]
326    pub fn is_root(&self) -> bool {
327        self.index == Self::root_index()
328    }
329
330    /// Root within the self item tree and not considering dynamic items
331    pub fn is_root_item_of(&self, item_tree: &VRc<ItemTreeVTable>) -> bool {
332        self.is_root() && VRc::ptr_eq(&self.item_tree, item_tree)
333    }
334
335    /// Return a `Pin<ItemRef<'a>>`
336    pub fn borrow<'a>(&'a self) -> Pin<ItemRef<'a>> {
337        #![allow(unsafe_code)]
338        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
339        let result = comp_ref_pin.as_ref().get_item_ref(self.index);
340        // Safety: we can expand the lifetime of the ItemRef because we know it lives for at least the
341        // lifetime of the ItemTree, which is 'a.  Pin::as_ref removes the lifetime, but we can just put it back.
342        unsafe { core::mem::transmute::<Pin<ItemRef<'_>>, Pin<ItemRef<'a>>>(result) }
343    }
344
345    /// Returns a `VRcMapped` of this item, to conveniently access specialized item API.
346    pub fn downcast<T: HasStaticVTable<ItemVTable>>(&self) -> Option<VRcMapped<ItemTreeVTable, T>> {
347        #![allow(unsafe_code)]
348        let item = self.borrow();
349        ItemRef::downcast_pin::<T>(item)?;
350
351        Some(vtable::VRc::map_dyn(self.item_tree.clone(), |comp_ref_pin| {
352            let result = comp_ref_pin.as_ref().get_item_ref(self.index);
353            // Safety: we can expand the lifetime of the ItemRef because we know it lives for at least the
354            // lifetime of the ItemTree, which is 'a.  Pin::as_ref removes the lifetime, but we can just put it back.
355            let item =
356                unsafe { core::mem::transmute::<Pin<ItemRef<'_>>, Pin<ItemRef<'_>>>(result) };
357            ItemRef::downcast_pin::<T>(item).unwrap()
358        }))
359    }
360
361    pub fn downgrade(&self) -> ItemWeak {
362        ItemWeak { item_tree: VRc::downgrade(&self.item_tree), index: self.index }
363    }
364
365    /// Return the parent Item in the item tree.
366    ///
367    /// If the item is the root on its Window or PopupWindow, then the parent is None.
368    pub fn parent_item(&self, find_mode: ParentItemTraversalMode) -> Option<ItemRc> {
369        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
370        let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
371
372        if let Some(parent_index) = item_tree.parent(self.index) {
373            return Some(ItemRc::new(self.item_tree.clone(), parent_index));
374        }
375
376        // It is a root item so check if it is a dynamic tree object like a repeater or if a window/popup
377        let mut r = ItemWeak::default();
378        comp_ref_pin.as_ref().parent_node(&mut r);
379        let parent = r.upgrade()?;
380        let comp_ref_pin = vtable::VRc::borrow_pin(&parent.item_tree);
381        let item_tree_array = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
382        if let Some(ItemTreeNode::DynamicTree { parent_index, .. }) =
383            item_tree_array.get(parent.index())
384        {
385            // parent_node returns the repeater node, go up one more level!
386            Some(ItemRc::new(parent.item_tree.clone(), *parent_index))
387        } else {
388            // the Item was most likely a PopupWindow and we don't want to return the item for the purpose of this call
389            // (eg, focus/geometry/...)
390            match find_mode {
391                ParentItemTraversalMode::FindAllParents => Some(parent),
392                ParentItemTraversalMode::StopAtPopups => None,
393            }
394        }
395    }
396
397    /// Returns true if this item is visible from the root of the item tree. Note that this will return
398    /// false for `Clip` elements with the `clip` property evaluating to true.
399    pub fn is_visible(&self) -> bool {
400        let (clip, geometry) = self.absolute_clip_rect_and_geometry();
401        let clip = clip.to_box2d();
402        let geometry = geometry.to_box2d();
403        !clip.is_empty()
404            && clip.max.x >= geometry.min.x
405            && clip.max.y >= geometry.min.y
406            && clip.min.x <= geometry.max.x
407            && clip.min.y <= geometry.max.y
408    }
409
410    /// Returns true if this item is visible or only clipped away by a `Flickable`.
411    pub(crate) fn is_visible_or_clipped_by_flickable(&self) -> bool {
412        if self.is_visible() {
413            return true;
414        }
415
416        // The item is not visible. Walk toward the root and find the first
417        // clipping ancestor that actually hides the item: if it is a
418        // Flickable, scrolling can bring the item back into view.
419        let geometry = self.absolute_clip_rect_and_geometry().1.to_box2d();
420        let mut parent = self.parent_item(ParentItemTraversalMode::StopAtPopups);
421        while let Some(ancestor) = parent {
422            if ancestor.borrow().as_ref().clips_children() {
423                let (clip, ancestor_geo) = ancestor.absolute_clip_rect_and_geometry();
424                let clip = ancestor_geo.intersection(&clip).unwrap_or_default().to_box2d();
425                let item_in_clip = !clip.is_empty()
426                    && clip.max.x >= geometry.min.x
427                    && clip.max.y >= geometry.min.y
428                    && clip.min.x <= geometry.max.x
429                    && clip.min.y <= geometry.max.y;
430                if !item_in_clip {
431                    return ancestor.downcast::<crate::items::Flickable>().is_some()
432                        && ancestor.is_visible_or_clipped_by_flickable();
433                }
434            }
435            parent = ancestor.parent_item(ParentItemTraversalMode::StopAtPopups);
436        }
437
438        false
439    }
440
441    /// Returns the accumulated transform from this item's local coordinate space to window
442    /// coordinates, walking up the ancestor chain until `stop_condition` returns true.
443    ///
444    /// At each ancestor the ancestor's `children_transform` (scale/rotate) is composed first,
445    /// then its translation. This matches the traversal order used by
446    /// [`map_to_item_tree_impl`](Self::map_to_item_tree_impl) and the partial renderer's
447    /// `current_transform()`.
448    fn local_to_window_transform(&self, stop_condition: impl Fn(&Self) -> bool) -> ItemTransform {
449        let supports_transformations = self
450            .window_adapter()
451            .is_none_or(|adapter| adapter.renderer().supports_transformations());
452        let mut transform = ItemTransform::identity();
453        let mut current = self.clone();
454        while let Some(parent) = current.parent_item(ParentItemTraversalMode::StopAtPopups) {
455            if stop_condition(&parent) {
456                break;
457            }
458            if supports_transformations
459                && let Some(children_transform) = parent.children_transform()
460            {
461                transform = transform.then(&children_transform);
462            }
463            transform = transform.then_translate(parent.geometry().origin.to_vector().cast());
464            current = parent;
465        }
466        transform
467    }
468
469    /// Returns the clip rect that applies to this item (in window coordinates) as well as the
470    /// item's (unclipped) geometry (also in window coordinates).
471    fn absolute_clip_rect_and_geometry(&self) -> (LogicalRect, LogicalRect) {
472        let geometry = self
473            .local_to_window_transform(|_| false)
474            .outer_transformed_rect(&self.geometry().cast())
475            .cast();
476
477        // Intersect the clip rects contributed by all clipping ancestors.
478        let mut clip = LogicalRect::from_size((crate::Coord::MAX, crate::Coord::MAX).into());
479        let mut cur = self.parent_item(ParentItemTraversalMode::StopAtPopups);
480        while let Some(ref ancestor) = cur {
481            if ancestor.borrow().as_ref().clips_children() {
482                let (_, ancestor_geom) = ancestor.absolute_clip_rect_and_geometry();
483                clip = ancestor_geom.intersection(&clip).unwrap_or_default();
484            }
485            cur = ancestor.parent_item(ParentItemTraversalMode::StopAtPopups);
486        }
487
488        (clip, geometry)
489    }
490
491    pub fn is_accessible(&self) -> bool {
492        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
493        let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
494
495        if let Some(n) = &item_tree.get(self.index) {
496            match n {
497                ItemTreeNode::Item { is_accessible, .. } => *is_accessible,
498                ItemTreeNode::DynamicTree { .. } => false,
499            }
500        } else {
501            false
502        }
503    }
504
505    pub fn accessible_role(&self) -> crate::items::AccessibleRole {
506        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
507        comp_ref_pin.as_ref().accessible_role(self.index)
508    }
509
510    pub fn accessible_string_property(
511        &self,
512        what: crate::accessibility::AccessibleStringProperty,
513    ) -> Option<SharedString> {
514        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
515        let mut result = Default::default();
516        let ok = comp_ref_pin.as_ref().accessible_string_property(self.index, what, &mut result);
517        ok.then_some(result)
518    }
519
520    pub fn accessible_action(&self, action: &crate::accessibility::AccessibilityAction) {
521        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
522        comp_ref_pin.as_ref().accessibility_action(self.index, action);
523    }
524
525    pub fn supported_accessibility_actions(&self) -> SupportedAccessibilityAction {
526        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
527        comp_ref_pin.as_ref().supported_accessibility_actions(self.index)
528    }
529
530    /// Returns the raw element-info string for this item, if debug info is available.
531    fn raw_element_infos(&self) -> Option<SharedString> {
532        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
533        let mut result = SharedString::new();
534        comp_ref_pin.as_ref().item_element_infos(self.index, &mut result).then_some(result)
535    }
536
537    pub fn element_count(&self) -> Option<usize> {
538        self.raw_element_infos().map(|s| s.as_str().split("/").count())
539    }
540
541    pub fn element_type_names_and_ids(
542        &self,
543        element_index: usize,
544    ) -> Option<Vec<(SharedString, SharedString)>> {
545        self.raw_element_infos().map(|infos| {
546            infos
547                .as_str()
548                .split("/")
549                .nth(element_index)
550                .unwrap()
551                .split(";")
552                .map(|encoded_elem_info| {
553                    let mut decoder = encoded_elem_info.split(',');
554                    let type_name = decoder.next().unwrap().into();
555                    let id = decoder.next().map(Into::into).unwrap_or_default();
556                    (type_name, id)
557                })
558                .collect()
559        })
560    }
561
562    pub fn element_layout_kind(&self, element_index: usize) -> Option<SharedString> {
563        self.raw_element_infos().and_then(|infos| {
564            let first_debug_entry =
565                infos.as_str().split("/").nth(element_index)?.split(';').next()?;
566            let mut decoder = first_debug_entry.split(',');
567            let _type_name = decoder.next();
568            let _id = decoder.next();
569            decoder.next().filter(|s| !s.is_empty()).map(SharedString::from)
570        })
571    }
572
573    pub fn geometry(&self) -> LogicalRect {
574        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
575        comp_ref_pin.as_ref().item_geometry(self.index)
576    }
577
578    /// Returns the rendering bounding rect for that particular item in the parent's item coordinate
579    /// (same coordinate system as the geometry)
580    pub fn bounding_rect(
581        &self,
582        geometry: &LogicalRect,
583        window_adapter: &WindowAdapterRc,
584    ) -> LogicalRect {
585        self.borrow().as_ref().bounding_rect(window_adapter, self, *geometry)
586    }
587
588    /// Similar to `map_to_window` but considers also the popup location if the popup
589    /// is not a dedicated window but of type ChildWindow
590    /// Use this function if you wanna have the real absolute position
591    pub fn map_to_native_window(&self, p: LogicalPoint) -> LogicalPoint {
592        let mut pos = self.map_to_item_tree_impl(p, |_| false);
593        // If the component is in a popup of type ChildWindow we have to consider the location of that as well
594        if let Some(window_adapter) = self.window_adapter() {
595            let window_inner = crate::window::WindowInner::from_pub(window_adapter.window());
596            let active_popups = window_inner.active_popups();
597            for popup in active_popups.iter() {
598                if let crate::window::PopupWindowLocation::ChildWindow(location) = &popup.location {
599                    let popup_item = ItemRc::new_root(popup.component.clone());
600
601                    // Check if component is in a popup
602                    // We have to search through all trees recursively up and not only the current item tree
603                    if popup_item.is_root_item_of(self.item_tree()) {
604                        pos += location.to_vector();
605                    } else {
606                        let mut current = ItemRc::new_root(self.item_tree.clone());
607                        // is_root_item_of does not check the complete tree
608                        while let Some(parent) =
609                            current.parent_item(ParentItemTraversalMode::StopAtPopups)
610                        {
611                            if popup_item.is_root_item_of(parent.item_tree()) {
612                                pos += location.to_vector();
613                                break;
614                            }
615
616                            // We go to the root of the parent again to skip iterating over the complete item tree
617                            current = ItemRc::new_root(parent.item_tree);
618                        }
619                    }
620                }
621            }
622        }
623        pos
624    }
625
626    /// Returns an absolute position of `p` in the parent item coordinate system
627    /// (does not add this item's x and y)
628    pub fn map_to_window(&self, p: LogicalPoint) -> LogicalPoint {
629        self.map_to_item_tree_impl(p, |_| false)
630    }
631
632    /// Returns an absolute position of `p` in the `ItemTree`'s coordinate system
633    /// (does not add this item's x and y)
634    pub fn map_to_item_tree(
635        &self,
636        p: LogicalPoint,
637        item_tree: &vtable::VRc<ItemTreeVTable>,
638    ) -> LogicalPoint {
639        self.map_to_item_tree_impl(p, |current| current.is_root_item_of(item_tree))
640    }
641
642    /// Returns an absolute position of `p` in the `ancestor`'s coordinate system
643    /// (does not add this item's x and y)
644    /// Don't rely on any specific behavior if `self` isn't a descendant of `ancestor`.
645    fn map_to_ancestor(&self, p: LogicalPoint, ancestor: &Self) -> LogicalPoint {
646        self.map_to_item_tree_impl(p, |parent| parent == ancestor)
647    }
648
649    fn map_to_item_tree_impl(
650        &self,
651        p: LogicalPoint,
652        stop_condition: impl Fn(&Self) -> bool,
653    ) -> LogicalPoint {
654        if stop_condition(self) {
655            return p;
656        }
657        self.local_to_window_transform(stop_condition).transform_point(p.cast()).cast()
658    }
659
660    /// Return the index of the item within the ItemTree
661    pub fn index(&self) -> u32 {
662        self.index
663    }
664    /// Returns a reference to the ItemTree holding this item
665    pub fn item_tree(&self) -> &vtable::VRc<ItemTreeVTable> {
666        &self.item_tree
667    }
668
669    /// Returns a child based on the logic of `child_access`, `child_step` and `subtree_child`
670    fn find_child(
671        &self,
672        child_access: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
673        child_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
674        subtree_child: &dyn Fn(usize, usize) -> usize,
675    ) -> Option<Self> {
676        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
677        let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
678
679        let mut current_child_index = child_access(&item_tree, self.index())?;
680        loop {
681            if let Some(item) = step_into_node(
682                self.item_tree(),
683                &comp_ref_pin,
684                current_child_index,
685                &item_tree,
686                subtree_child,
687                &core::convert::identity,
688            ) {
689                return Some(item);
690            }
691            current_child_index = child_step(&item_tree, current_child_index)?;
692        }
693    }
694
695    /// The first child Item of this Item in this item tree
696    pub fn first_child(&self) -> Option<Self> {
697        self.find_child(
698            &|item_tree, index| item_tree.first_child(index),
699            &|item_tree, index| item_tree.next_sibling(index),
700            &|start, _| start,
701        )
702    }
703
704    /// The last child Item of this Item
705    pub fn last_child(&self) -> Option<Self> {
706        self.find_child(
707            &|item_tree, index| item_tree.last_child(index),
708            &|item_tree, index| item_tree.previous_sibling(index),
709            &|_, end| end.wrapping_sub(1),
710        )
711    }
712
713    fn find_sibling(
714        &self,
715        sibling_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
716        subtree_step: &dyn Fn(usize) -> usize,
717        subtree_child: &dyn Fn(usize, usize) -> usize,
718    ) -> Option<Self> {
719        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
720        if self.is_root() {
721            let mut parent_item = Default::default();
722            comp_ref_pin.as_ref().parent_node(&mut parent_item);
723            let current_component_subtree_index = comp_ref_pin.as_ref().subtree_index();
724            if let Some(parent_item) = parent_item.upgrade() {
725                let parent = parent_item.item_tree();
726                let parent_ref_pin = vtable::VRc::borrow_pin(parent);
727                let parent_item_index = parent_item.index();
728                let parent_item_tree = crate::item_tree::ItemTreeNodeArray::new(&parent_ref_pin);
729
730                let subtree_index = match parent_item_tree.get(parent_item_index)? {
731                    crate::item_tree::ItemTreeNode::Item { .. } => {
732                        // Popups can trigger this case!
733                        return None;
734                    }
735                    crate::item_tree::ItemTreeNode::DynamicTree { index, .. } => *index,
736                };
737
738                let next_subtree_index = subtree_step(current_component_subtree_index);
739
740                // Get next subtree from repeater!
741                let mut next_subtree_instance = Default::default();
742                parent_ref_pin.as_ref().get_subtree(
743                    subtree_index,
744                    next_subtree_index,
745                    &mut next_subtree_instance,
746                );
747                if let Some(next_subtree_instance) = next_subtree_instance.upgrade() {
748                    return Some(ItemRc::new_root(next_subtree_instance));
749                }
750
751                // We need to leave the repeater:
752                find_sibling_outside_repeater(
753                    parent,
754                    parent_ref_pin,
755                    parent_item_index,
756                    sibling_step,
757                    subtree_child,
758                )
759            } else {
760                None // At root if the item tree
761            }
762        } else {
763            find_sibling_outside_repeater(
764                self.item_tree(),
765                comp_ref_pin,
766                self.index(),
767                sibling_step,
768                subtree_child,
769            )
770        }
771    }
772
773    /// The previous sibling of this Item
774    pub fn previous_sibling(&self) -> Option<Self> {
775        self.find_sibling(
776            &|item_tree, index| item_tree.previous_sibling(index),
777            &|index| index.wrapping_sub(1),
778            &|_, end| end.wrapping_sub(1),
779        )
780    }
781
782    /// The next sibling of this Item
783    pub fn next_sibling(&self) -> Option<Self> {
784        self.find_sibling(
785            &|item_tree, index| item_tree.next_sibling(index),
786            &|index| index.saturating_add(1),
787            &|start, _| start,
788        )
789    }
790
791    fn move_focus(
792        &self,
793        focus_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
794        subtree_step: &dyn Fn(ItemRc) -> Option<ItemRc>,
795        subtree_child: &dyn Fn(usize, usize) -> usize,
796        step_in: &dyn Fn(ItemRc) -> ItemRc,
797        step_out: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
798    ) -> Self {
799        let mut component = self.item_tree().clone();
800        let mut comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
801        let mut item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
802
803        let mut to_focus = self.index();
804
805        'in_tree: loop {
806            if let Some(next) = focus_step(&item_tree, to_focus) {
807                if let Some(item) = step_into_node(
808                    &component,
809                    &comp_ref_pin,
810                    next,
811                    &item_tree,
812                    subtree_child,
813                    step_in,
814                ) {
815                    return item;
816                }
817                to_focus = next;
818                // Loop: We stepped into an empty repeater!
819            } else {
820                // Step out of this component:
821                let mut root = ItemRc::new_root(component);
822                if let Some(item) = subtree_step(root.clone()) {
823                    // Next component inside same repeater
824                    return step_in(item);
825                }
826
827                // Step out of the repeater
828                let root_component = root.item_tree();
829                let root_comp_ref = vtable::VRc::borrow_pin(root_component);
830                let mut parent_node = Default::default();
831                root_comp_ref.as_ref().parent_node(&mut parent_node);
832
833                while let Some(parent) = parent_node.upgrade() {
834                    // .. not at the root of the item tree:
835                    component = parent.item_tree().clone();
836                    comp_ref_pin = vtable::VRc::borrow_pin(&component);
837                    item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
838
839                    let index = parent.index();
840
841                    if !matches!(item_tree.get(index), Some(ItemTreeNode::DynamicTree { .. })) {
842                        // That was not a repeater (eg, a popup window)
843                        break;
844                    }
845
846                    if let Some(next) = step_out(&item_tree, index) {
847                        if let Some(item) = step_into_node(
848                            parent.item_tree(),
849                            &comp_ref_pin,
850                            next,
851                            &item_tree,
852                            subtree_child,
853                            step_in,
854                        ) {
855                            // Step into a dynamic node
856                            return item;
857                        } else {
858                            // The dynamic node was empty, proceed in normal tree
859                            to_focus = parent.index();
860                            continue 'in_tree; // Find a node in the current (parent!) tree
861                        }
862                    }
863
864                    root = ItemRc::new_root(component.clone());
865                    if let Some(item) = subtree_step(root.clone()) {
866                        return step_in(item);
867                    }
868
869                    // Go up one more level:
870                    let root_component = root.item_tree();
871                    let root_comp_ref = vtable::VRc::borrow_pin(root_component);
872                    parent_node = Default::default();
873                    root_comp_ref.as_ref().parent_node(&mut parent_node);
874                }
875
876                // Loop around after hitting the root node:
877                return step_in(root);
878            }
879        }
880    }
881
882    /// Move tab focus to the previous item:
883    pub fn previous_focus_item(&self) -> Self {
884        self.move_focus(
885            &|item_tree, index| {
886                crate::item_focus::default_previous_in_local_focus_chain(index, item_tree)
887            },
888            &|root| root.previous_sibling(),
889            &|_, end| end.wrapping_sub(1),
890            &|root| {
891                let mut current = root;
892                loop {
893                    if let Some(next) = current.last_child() {
894                        current = next;
895                    } else {
896                        return current;
897                    }
898                }
899            },
900            &|item_tree, index| item_tree.parent(index),
901        )
902    }
903
904    /// Move tab focus to the next item:
905    pub fn next_focus_item(&self) -> Self {
906        self.move_focus(
907            &|item_tree, index| {
908                crate::item_focus::default_next_in_local_focus_chain(index, item_tree)
909            },
910            &|root| root.next_sibling(),
911            &|start, _| start,
912            &core::convert::identity,
913            &|item_tree, index| crate::item_focus::step_out_of_node(index, item_tree),
914        )
915    }
916
917    pub fn window_adapter(&self) -> Option<WindowAdapterRc> {
918        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
919        let mut result = None;
920        comp_ref_pin.as_ref().window_adapter(false, &mut result);
921        result
922    }
923
924    /// Visit the children of this element and call the visitor to each of them, until the visitor returns [`ControlFlow::Break`].
925    /// When the visitor breaks, the function returns the value. If it doesn't break, the function returns None.
926    fn visit_descendants_impl<R>(
927        &self,
928        visitor: &mut impl FnMut(&ItemRc) -> ControlFlow<R>,
929    ) -> Option<R> {
930        let mut result = None;
931
932        let mut actual_visitor = |item_tree: &ItemTreeRc,
933                                  index: u32,
934                                  _item_pin: core::pin::Pin<ItemRef>|
935         -> VisitChildrenResult {
936            let item_rc = ItemRc::new(item_tree.clone(), index);
937
938            match visitor(&item_rc) {
939                ControlFlow::Continue(_) => {
940                    if let Some(x) = item_rc.visit_descendants_impl(visitor) {
941                        result = Some(x);
942                        return VisitChildrenResult::abort(index, 0);
943                    }
944                }
945                ControlFlow::Break(x) => {
946                    result = Some(x);
947                    return VisitChildrenResult::abort(index, 0);
948                }
949            }
950
951            VisitChildrenResult::CONTINUE
952        };
953        vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);
954
955        VRc::borrow_pin(self.item_tree()).as_ref().visit_children_item(
956            self.index() as isize,
957            TraversalOrder::BackToFront,
958            actual_visitor,
959        );
960
961        result
962    }
963
964    /// Visit the children of this element and call the visitor to each of them,
965    /// until the visitor returns [`ControlFlow::Break`].
966    /// When the visitor breaks, the function returns the value.
967    /// If it doesn't break, the function returns None.
968    ///
969    /// Runs [`ensure_item_tree_instantiated`] once before the walk so all
970    /// repeaters, conditionals, and component containers are materialized.
971    /// The recursive descent uses the private `visit_descendants_impl`,
972    /// which doesn't call it again.
973    pub fn visit_descendants<R>(
974        &self,
975        mut visitor: impl FnMut(&ItemRc) -> ControlFlow<R>,
976    ) -> Option<R> {
977        ensure_item_tree_instantiated(self.item_tree());
978        self.visit_descendants_impl(&mut visitor)
979    }
980
981    /// Returns the transform to apply to children to map them into the local coordinate space of this item.
982    /// Typically this is None, but rotation for example may return Some.
983    pub fn children_transform(&self) -> Option<ItemTransform> {
984        self.downcast::<crate::items::Transform>().map(|transform_item| {
985            let item = transform_item.as_pin_ref();
986            let origin = item.transform_origin().to_euclid().to_vector().cast::<f32>();
987            ItemTransform::translation(-origin.x, -origin.y)
988                .cast()
989                .then_scale(item.transform_scale_x(), item.transform_scale_y())
990                .then_rotate(euclid::Angle { radians: item.transform_rotation().to_radians() })
991                .then_translate(origin)
992        })
993    }
994
995    /// Returns the inverse of the children transform.
996    ///
997    /// None if children_transform is None or in the case of
998    /// non-invertible transforms (which should be extremely rare).
999    pub fn inverse_children_transform(&self) -> Option<ItemTransform> {
1000        self.children_transform()
1001            // Should practically always be possible.
1002            .and_then(|child_transform| child_transform.inverse())
1003    }
1004
1005    pub(crate) fn try_scroll_into_visible(&self) {
1006        let mut parent = self.parent_item(ParentItemTraversalMode::StopAtPopups);
1007        while let Some(item_rc) = parent.as_ref() {
1008            let item_ref = item_rc.borrow();
1009            if let Some(flickable) = vtable::VRef::downcast_pin::<crate::items::Flickable>(item_ref)
1010            {
1011                let geo = self.geometry();
1012
1013                flickable.reveal_points(
1014                    item_rc,
1015                    &[
1016                        self.map_to_ancestor(
1017                            LogicalPoint::new(
1018                                geo.origin.x - flickable.viewport_x().0,
1019                                geo.origin.y - flickable.viewport_y().0,
1020                            ),
1021                            item_rc,
1022                        ),
1023                        self.map_to_ancestor(
1024                            LogicalPoint::new(
1025                                geo.max_x() - flickable.viewport_x().0,
1026                                geo.max_y() - flickable.viewport_y().0,
1027                            ),
1028                            item_rc,
1029                        ),
1030                    ],
1031                );
1032            }
1033
1034            parent = item_rc.parent_item(ParentItemTraversalMode::StopAtPopups);
1035        }
1036    }
1037}
1038
1039impl PartialEq for ItemRc {
1040    fn eq(&self, other: &Self) -> bool {
1041        VRc::ptr_eq(&self.item_tree, &other.item_tree) && self.index == other.index
1042    }
1043}
1044
1045impl Eq for ItemRc {}
1046
1047/// A Weak reference to an item that can be constructed from an ItemRc.
1048#[derive(Clone, Default)]
1049#[repr(C)]
1050pub struct ItemWeak {
1051    item_tree: crate::item_tree::ItemTreeWeak,
1052    index: u32,
1053}
1054
1055impl ItemWeak {
1056    pub fn upgrade(&self) -> Option<ItemRc> {
1057        self.item_tree.upgrade().map(|c| ItemRc::new(c, self.index))
1058    }
1059}
1060
1061impl PartialEq for ItemWeak {
1062    fn eq(&self, other: &Self) -> bool {
1063        VWeak::ptr_eq(&self.item_tree, &other.item_tree) && self.index == other.index
1064    }
1065}
1066
1067impl Eq for ItemWeak {}
1068
1069#[repr(u8)]
1070#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1071pub enum TraversalOrder {
1072    BackToFront,
1073    FrontToBack,
1074}
1075
1076/// The return value of the ItemTree::visit_children_item function
1077///
1078/// Represents something like `enum { Continue, Aborted{aborted_at_item: isize} }`.
1079/// But this is just wrapping a int because it is easier to use ffi with isize than
1080/// complex enum.
1081///
1082/// -1 means the visitor will continue
1083/// otherwise this is the index of the item that aborted the visit.
1084#[repr(transparent)]
1085#[derive(Copy, Clone, Eq, PartialEq)]
1086pub struct VisitChildrenResult(u64);
1087impl VisitChildrenResult {
1088    /// The result used for a visitor that want to continue the visit
1089    pub const CONTINUE: Self = Self(u64::MAX);
1090
1091    /// Returns a result that means that the visitor must stop, and convey the item that caused the abort
1092    pub fn abort(item_index: u32, index_within_repeater: usize) -> Self {
1093        assert!(index_within_repeater < u32::MAX as usize);
1094        Self(item_index as u64 | (index_within_repeater as u64) << 32)
1095    }
1096    /// True if the visitor wants to abort the visit
1097    pub fn has_aborted(&self) -> bool {
1098        self.0 != Self::CONTINUE.0
1099    }
1100    pub fn aborted_index(&self) -> Option<usize> {
1101        if self.0 != Self::CONTINUE.0 { Some((self.0 & 0xffff_ffff) as usize) } else { None }
1102    }
1103    pub fn aborted_indexes(&self) -> Option<(usize, usize)> {
1104        if self.0 != Self::CONTINUE.0 {
1105            Some(((self.0 & 0xffff_ffff) as usize, (self.0 >> 32) as usize))
1106        } else {
1107            None
1108        }
1109    }
1110}
1111impl core::fmt::Debug for VisitChildrenResult {
1112    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1113        if self.0 == Self::CONTINUE.0 {
1114            write!(f, "CONTINUE")
1115        } else {
1116            write!(f, "({},{})", (self.0 & 0xffff_ffff) as usize, (self.0 >> 32) as usize)
1117        }
1118    }
1119}
1120
1121/// The item tree is an array of ItemTreeNode representing a static tree of items
1122/// within a ItemTree.
1123#[repr(u8)]
1124#[derive(Debug)]
1125pub enum ItemTreeNode {
1126    /// Static item
1127    Item {
1128        /// True when the item has accessibility properties attached
1129        is_accessible: bool,
1130
1131        /// number of children
1132        children_count: u32,
1133
1134        /// index of the first children within the item tree
1135        children_index: u32,
1136
1137        /// The index of the parent item (not valid for the root)
1138        parent_index: u32,
1139
1140        /// The index in the extra item_array
1141        item_array_index: u32,
1142    },
1143    /// A placeholder for many instance of item in their own ItemTree which
1144    /// are instantiated according to a model like repeaters
1145    DynamicTree {
1146        /// the index which is passed in the visit_dynamic callback.
1147        index: u32,
1148
1149        /// The index of the parent item (not valid for the root)
1150        parent_index: u32,
1151    },
1152}
1153
1154impl ItemTreeNode {
1155    pub fn parent_index(&self) -> u32 {
1156        match self {
1157            ItemTreeNode::Item { parent_index, .. } => *parent_index,
1158            ItemTreeNode::DynamicTree { parent_index, .. } => *parent_index,
1159        }
1160    }
1161}
1162
1163/// The `ItemTreeNodeArray` provides tree walking code for the physical ItemTree stored in
1164/// a `ItemTree` without stitching any inter-ItemTree links together!
1165pub struct ItemTreeNodeArray<'a> {
1166    node_array: &'a [ItemTreeNode],
1167}
1168
1169impl<'a> ItemTreeNodeArray<'a> {
1170    /// Create a new `ItemTree` from its raw data.
1171    pub fn new(comp_ref_pin: &'a Pin<VRef<'a, ItemTreeVTable>>) -> Self {
1172        Self { node_array: comp_ref_pin.as_ref().get_item_tree().as_slice() }
1173    }
1174
1175    /// Get a ItemTreeNode
1176    pub fn get(&self, index: u32) -> Option<&ItemTreeNode> {
1177        self.node_array.get(index as usize)
1178    }
1179
1180    /// Get the parent of a node, returns `None` if this is the root node of this item tree.
1181    pub fn parent(&self, index: u32) -> Option<u32> {
1182        let index = index as usize;
1183        (index < self.node_array.len() && index != ItemRc::root_index() as usize)
1184            .then(|| self.node_array[index].parent_index())
1185    }
1186
1187    /// Returns the next sibling or `None` if this is the last sibling.
1188    pub fn next_sibling(&self, index: u32) -> Option<u32> {
1189        if let Some(parent_index) = self.parent(index) {
1190            match self.node_array[parent_index as usize] {
1191                ItemTreeNode::Item { children_index, children_count, .. } => {
1192                    (index < (children_count + children_index - 1)).then_some(index + 1)
1193                }
1194                ItemTreeNode::DynamicTree { .. } => {
1195                    unreachable!("Parent in same item tree is a repeater.")
1196                }
1197            }
1198        } else {
1199            None // No parent, so we have no siblings either:-)
1200        }
1201    }
1202
1203    /// Returns the previous sibling or `None` if this is the first sibling.
1204    pub fn previous_sibling(&self, index: u32) -> Option<u32> {
1205        if let Some(parent_index) = self.parent(index) {
1206            match self.node_array[parent_index as usize] {
1207                ItemTreeNode::Item { children_index, .. } => {
1208                    (index > children_index).then_some(index - 1)
1209                }
1210                ItemTreeNode::DynamicTree { .. } => {
1211                    unreachable!("Parent in same item tree is a repeater.")
1212                }
1213            }
1214        } else {
1215            None // No parent, so we have no siblings either:-)
1216        }
1217    }
1218
1219    /// Returns the first child or `None` if there are no children or the `index`
1220    /// points to a `DynamicTree`.
1221    pub fn first_child(&self, index: u32) -> Option<u32> {
1222        match self.node_array.get(index as usize)? {
1223            ItemTreeNode::Item { children_index, children_count, .. } => {
1224                (*children_count != 0).then_some(*children_index as _)
1225            }
1226            ItemTreeNode::DynamicTree { .. } => None,
1227        }
1228    }
1229
1230    /// Returns the last child or `None` if this are no children or the `index`
1231    /// points to an `DynamicTree`.
1232    pub fn last_child(&self, index: u32) -> Option<u32> {
1233        match self.node_array.get(index as usize)? {
1234            ItemTreeNode::Item { children_index, children_count, .. } => {
1235                if *children_count != 0 {
1236                    Some(*children_index + *children_count - 1)
1237                } else {
1238                    None
1239                }
1240            }
1241            ItemTreeNode::DynamicTree { .. } => None,
1242        }
1243    }
1244
1245    /// Returns the number of nodes in the `ItemTreeNodeArray`
1246    pub fn node_count(&self) -> usize {
1247        self.node_array.len()
1248    }
1249}
1250
1251impl<'a> From<&'a [ItemTreeNode]> for ItemTreeNodeArray<'a> {
1252    fn from(item_tree: &'a [ItemTreeNode]) -> Self {
1253        Self { node_array: item_tree }
1254    }
1255}
1256
1257#[cfg_attr(not(feature = "ffi"), i_slint_core_macros::remove_extern)]
1258#[vtable]
1259#[repr(C)]
1260/// Object to be passed in visit_item_children method of the ItemTree.
1261pub struct ItemVisitorVTable {
1262    /// Called for each child of the visited item
1263    ///
1264    /// The `item_tree` parameter is the ItemTree in which the item live which might not be the same
1265    /// as the parent's ItemTree.
1266    /// `index` is to be used again in the visit_item_children function of the ItemTree (the one passed as parameter)
1267    /// and `item` is a reference to the item itself
1268    visit_item: extern "C" fn(
1269        VRefMut<ItemVisitorVTable>,
1270        item_tree: &VRc<ItemTreeVTable, vtable::Dyn>,
1271        index: u32,
1272        item: Pin<VRef<ItemVTable>>,
1273    ) -> VisitChildrenResult,
1274    /// Destructor
1275    drop: extern "C" fn(VRefMut<ItemVisitorVTable>),
1276}
1277
1278/// Type alias to `vtable::VRefMut<ItemVisitorVTable>`
1279pub type ItemVisitorRefMut<'a> = vtable::VRefMut<'a, ItemVisitorVTable>;
1280
1281impl<T: FnMut(&ItemTreeRc, u32, Pin<ItemRef>) -> VisitChildrenResult> ItemVisitor for T {
1282    fn visit_item(
1283        &mut self,
1284        item_tree: &ItemTreeRc,
1285        index: u32,
1286        item: Pin<ItemRef>,
1287    ) -> VisitChildrenResult {
1288        self(item_tree, index, item)
1289    }
1290}
1291pub enum ItemVisitorResult<State> {
1292    Continue(State),
1293    SkipChildren,
1294    Abort,
1295}
1296
1297/// Visit each items recursively
1298///
1299/// The state parameter returned by the visitor is passed to each child.
1300///
1301/// Returns the index of the item that cancelled, or -1 if nobody cancelled
1302pub fn visit_items<State>(
1303    item_tree: &ItemTreeRc,
1304    order: TraversalOrder,
1305    mut visitor: impl FnMut(&ItemTreeRc, Pin<ItemRef>, u32, &State) -> ItemVisitorResult<State>,
1306    state: State,
1307) -> VisitChildrenResult {
1308    visit_internal(item_tree, order, &mut visitor, -1, &state)
1309}
1310
1311fn visit_internal<State>(
1312    item_tree: &ItemTreeRc,
1313    order: TraversalOrder,
1314    visitor: &mut impl FnMut(&ItemTreeRc, Pin<ItemRef>, u32, &State) -> ItemVisitorResult<State>,
1315    index: isize,
1316    state: &State,
1317) -> VisitChildrenResult {
1318    let mut actual_visitor =
1319        |item_tree: &ItemTreeRc, index: u32, item: Pin<ItemRef>| -> VisitChildrenResult {
1320            match visitor(item_tree, item, index, state) {
1321                ItemVisitorResult::Continue(state) => {
1322                    visit_internal(item_tree, order, visitor, index as isize, &state)
1323                }
1324                ItemVisitorResult::SkipChildren => VisitChildrenResult::CONTINUE,
1325                ItemVisitorResult::Abort => VisitChildrenResult::abort(index, 0),
1326            }
1327        };
1328    vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);
1329    VRc::borrow_pin(item_tree).as_ref().visit_children_item(index, order, actual_visitor)
1330}
1331
1332/// Visit the children within an array of ItemTreeNode
1333///
1334/// The dynamic visitor is called for the dynamic nodes, its signature is
1335/// `fn(base: &Base, visitor: vtable::VRefMut<ItemVisitorVTable>, dyn_index: usize)`
1336///
1337/// FIXME: the design of this use lots of indirection and stack frame in recursive functions
1338/// Need to check if the compiler is able to optimize away some of it.
1339/// Possibly we should generate code that directly call the visitor instead
1340pub fn visit_item_tree<Base>(
1341    base: Pin<&Base>,
1342    item_tree: &ItemTreeRc,
1343    item_tree_array: &[ItemTreeNode],
1344    index: isize,
1345    order: TraversalOrder,
1346    mut visitor: vtable::VRefMut<ItemVisitorVTable>,
1347    visit_dynamic: impl Fn(
1348        Pin<&Base>,
1349        TraversalOrder,
1350        vtable::VRefMut<ItemVisitorVTable>,
1351        u32,
1352    ) -> VisitChildrenResult,
1353) -> VisitChildrenResult {
1354    let mut visit_at_index = |idx: u32| -> VisitChildrenResult {
1355        match &item_tree_array[idx as usize] {
1356            ItemTreeNode::Item { .. } => {
1357                let item = crate::items::ItemRc::new(item_tree.clone(), idx);
1358                visitor.visit_item(item_tree, idx, item.borrow())
1359            }
1360            ItemTreeNode::DynamicTree { index, .. } => {
1361                if let Some(sub_idx) =
1362                    visit_dynamic(base, order, visitor.borrow_mut(), *index).aborted_index()
1363                {
1364                    VisitChildrenResult::abort(idx, sub_idx)
1365                } else {
1366                    VisitChildrenResult::CONTINUE
1367                }
1368            }
1369        }
1370    };
1371    if index == -1 {
1372        visit_at_index(0)
1373    } else {
1374        match &item_tree_array[index as usize] {
1375            ItemTreeNode::Item { children_index, children_count, .. } => {
1376                for c in 0..*children_count {
1377                    let idx = match order {
1378                        TraversalOrder::BackToFront => *children_index + c,
1379                        TraversalOrder::FrontToBack => *children_index + *children_count - c - 1,
1380                    };
1381                    let maybe_abort_index = visit_at_index(idx);
1382                    if maybe_abort_index.has_aborted() {
1383                        return maybe_abort_index;
1384                    }
1385                }
1386            }
1387            ItemTreeNode::DynamicTree { .. } => panic!("should not be called with dynamic items"),
1388        };
1389        VisitChildrenResult::CONTINUE
1390    }
1391}
1392
1393#[cfg(feature = "ffi")]
1394pub(crate) mod ffi {
1395    #![allow(unsafe_code)]
1396
1397    use super::*;
1398    use core::ffi::c_void;
1399
1400    /// Call init() on the ItemVTable of each item in the item array.
1401    #[unsafe(no_mangle)]
1402    pub unsafe extern "C" fn slint_register_item_tree(
1403        item_tree_rc: &ItemTreeRc,
1404        window_handle: *const crate::window::ffi::WindowAdapterRcOpaque,
1405    ) {
1406        unsafe {
1407            let window_adapter = (window_handle as *const WindowAdapterRc).as_ref().cloned();
1408            super::register_item_tree(item_tree_rc, window_adapter)
1409        }
1410    }
1411
1412    /// Free the backend graphics resources allocated in the item array.
1413    #[unsafe(no_mangle)]
1414    pub unsafe extern "C" fn slint_unregister_item_tree(
1415        component: ItemTreeRefPin,
1416        item_array: Slice<vtable::VOffset<u8, ItemVTable, vtable::AllowPin>>,
1417        window_handle: *const crate::window::ffi::WindowAdapterRcOpaque,
1418    ) {
1419        unsafe {
1420            let window_adapter = &*(window_handle as *const WindowAdapterRc);
1421            super::unregister_item_tree(
1422                core::pin::Pin::new_unchecked(&*(component.as_ptr() as *const u8)),
1423                core::pin::Pin::into_inner(component),
1424                item_array.as_slice(),
1425                window_adapter,
1426            )
1427        }
1428    }
1429
1430    /// Expose `crate::item_tree::visit_item_tree` to C++
1431    ///
1432    /// Safety: Assume a correct implementation of the item_tree array
1433    #[unsafe(no_mangle)]
1434    pub unsafe extern "C" fn slint_visit_item_tree(
1435        item_tree: &ItemTreeRc,
1436        item_tree_array: Slice<ItemTreeNode>,
1437        index: isize,
1438        order: TraversalOrder,
1439        visitor: VRefMut<ItemVisitorVTable>,
1440        visit_dynamic: extern "C" fn(
1441            base: *const c_void,
1442            order: TraversalOrder,
1443            visitor: vtable::VRefMut<ItemVisitorVTable>,
1444            dyn_index: u32,
1445        ) -> VisitChildrenResult,
1446    ) -> VisitChildrenResult {
1447        crate::item_tree::visit_item_tree(
1448            VRc::as_pin_ref(item_tree),
1449            item_tree,
1450            item_tree_array.as_slice(),
1451            index,
1452            order,
1453            visitor,
1454            |a, b, c, d| visit_dynamic(a.get_ref() as *const vtable::Dyn as *const c_void, b, c, d),
1455        )
1456    }
1457}
1458
1459#[cfg(test)]
1460mod tests {
1461    use super::*;
1462    use crate::Property;
1463    use crate::api::LogicalPosition;
1464    use crate::api::Window;
1465    use crate::items::{Clip, Transform, WindowItem};
1466    use crate::lengths::LogicalLength;
1467    use crate::lengths::LogicalSize;
1468    use euclid::Point2D;
1469    use std::{rc::Rc, vec};
1470
1471    const GEOMETRY_POSITION_X: f32 = 6.;
1472    const GEOMETRY_POSITION_Y: f32 = 27.;
1473    const GEOMETRY_WIDTH: f32 = 33.;
1474    const GEOMETRY_HEIGHT: f32 = 42.;
1475
1476    #[derive(Default)]
1477    struct Renderer {
1478        supports_transformations: bool,
1479    }
1480
1481    struct WindowAdapter {
1482        renderer: Renderer,
1483        window: Window,
1484    }
1485
1486    impl WindowAdapter {
1487        fn new() -> Rc<Self> {
1488            Self::new_with_transformations(false)
1489        }
1490
1491        fn new_with_transformations(supports_transformations: bool) -> Rc<Self> {
1492            Rc::<Self>::new_cyclic(|w| Self {
1493                window: Window::new(w.clone()),
1494                renderer: Renderer { supports_transformations },
1495            })
1496        }
1497    }
1498
1499    impl crate::window::WindowAdapter for WindowAdapter {
1500        fn window(&self) -> &crate::api::Window {
1501            &self.window
1502        }
1503
1504        fn size(&self) -> crate::api::PhysicalSize {
1505            crate::api::PhysicalSize::new(100, 100)
1506        }
1507
1508        fn renderer(&self) -> &dyn crate::platform::Renderer {
1509            &self.renderer
1510        }
1511    }
1512
1513    struct TestItemTree {
1514        parent_component: Option<ItemTreeWeak>,
1515        /// First item is always the root, the next ones are the children and subchildren and so on
1516        item_tree: Vec<ItemTreeNode>,
1517        /// Contains the trees of the dynamic components
1518        subtrees: std::cell::RefCell<Vec<Vec<vtable::VRc<ItemTreeVTable, TestItemTree>>>>,
1519        subtree_index: usize,
1520
1521        window_adapter: std::rc::Weak<dyn crate::window::WindowAdapter>,
1522        window_item: Option<crate::items::WindowItem>,
1523    }
1524
1525    impl ItemTree for TestItemTree {
1526        fn visit_children_item(
1527            self: core::pin::Pin<&Self>,
1528            _1: isize,
1529            _2: crate::item_tree::TraversalOrder,
1530            _3: vtable::VRefMut<crate::item_tree::ItemVisitorVTable>,
1531        ) -> crate::item_tree::VisitChildrenResult {
1532            unimplemented!("Not needed for this test")
1533        }
1534
1535        fn get_item_ref(
1536            self: core::pin::Pin<&Self>,
1537            index: u32,
1538        ) -> core::pin::Pin<vtable::VRef<'_, super::ItemVTable>> {
1539            if index == 0 {
1540                return Pin::new(VRef::new(
1541                    self.get_ref().window_item.as_ref().expect("Not needed for this test"),
1542                ));
1543            }
1544            unimplemented!("Not needed for this test")
1545        }
1546
1547        fn get_item_tree(self: core::pin::Pin<&Self>) -> Slice<'_, ItemTreeNode> {
1548            Slice::from_slice(&self.get_ref().item_tree)
1549        }
1550
1551        fn parent_node(self: core::pin::Pin<&Self>, result: &mut ItemWeak) {
1552            if let Some(parent_item) = self.parent_component.as_ref().and_then(|w| w.upgrade()) {
1553                *result = ItemRc::new(parent_item, self.item_tree[0].parent_index()).downgrade();
1554            }
1555        }
1556
1557        fn embed_component(
1558            self: core::pin::Pin<&Self>,
1559            _parent_component: &ItemTreeWeak,
1560            _item_tree_index: u32,
1561        ) -> bool {
1562            false
1563        }
1564
1565        fn ensure_instantiated(self: core::pin::Pin<&Self>) -> bool {
1566            false
1567        }
1568
1569        fn layout_info(self: core::pin::Pin<&Self>, o: Orientation) -> LayoutInfo {
1570            if let Some(wi) = &self.window_item {
1571                match o {
1572                    Orientation::Horizontal => {
1573                        return LayoutInfo {
1574                            max: wi.width.get_internal().0,
1575                            max_percent: 100.,
1576                            min: wi.width.get_internal().0,
1577                            min_percent: 100.,
1578                            preferred: wi.width.get_internal().0,
1579                            stretch: 1.,
1580                        };
1581                    }
1582                    Orientation::Vertical => {
1583                        return LayoutInfo {
1584                            max: wi.height.get_internal().0,
1585                            max_percent: 100.,
1586                            min: wi.height.get_internal().0,
1587                            min_percent: 100.,
1588                            preferred: wi.height.get_internal().0,
1589                            stretch: 1.,
1590                        };
1591                    }
1592                }
1593            }
1594            unimplemented!("Not needed for this test")
1595        }
1596
1597        fn subtree_index(self: core::pin::Pin<&Self>) -> usize {
1598            self.subtree_index
1599        }
1600
1601        fn get_subtree_range(self: core::pin::Pin<&Self>, subtree_index: u32) -> IndexRange {
1602            (0..self.subtrees.borrow()[subtree_index as usize].len()).into()
1603        }
1604
1605        fn get_subtree(
1606            self: core::pin::Pin<&Self>,
1607            subtree_index: u32,
1608            component_index: usize,
1609            result: &mut ItemTreeWeak,
1610        ) {
1611            if let Some(vrc) = self.subtrees.borrow()[subtree_index as usize].get(component_index) {
1612                *result = vtable::VRc::downgrade(&vtable::VRc::into_dyn(vrc.clone()))
1613            }
1614        }
1615
1616        fn accessible_role(self: Pin<&Self>, _: u32) -> AccessibleRole {
1617            unimplemented!("Not needed for this test")
1618        }
1619
1620        fn accessible_string_property(
1621            self: Pin<&Self>,
1622            _: u32,
1623            _: AccessibleStringProperty,
1624            _: &mut SharedString,
1625        ) -> bool {
1626            false
1627        }
1628
1629        fn item_element_infos(self: Pin<&Self>, _: u32, _: &mut SharedString) -> bool {
1630            false
1631        }
1632
1633        fn window_adapter(
1634            self: Pin<&Self>,
1635            _do_create: bool,
1636            result: &mut Option<WindowAdapterRc>,
1637        ) {
1638            *result = self.window_adapter.upgrade()
1639        }
1640
1641        fn item_geometry(self: Pin<&Self>, _: u32) -> LogicalRect {
1642            LogicalRect::new(
1643                euclid::Point2D::new(GEOMETRY_POSITION_X, GEOMETRY_POSITION_Y),
1644                euclid::Size2D::new(GEOMETRY_WIDTH, GEOMETRY_HEIGHT),
1645            )
1646        }
1647
1648        fn accessibility_action(self: core::pin::Pin<&Self>, _: u32, _: &AccessibilityAction) {
1649            unimplemented!("Not needed for this test")
1650        }
1651
1652        fn supported_accessibility_actions(
1653            self: core::pin::Pin<&Self>,
1654            _: u32,
1655        ) -> SupportedAccessibilityAction {
1656            unimplemented!("Not needed for this test")
1657        }
1658    }
1659
1660    crate::item_tree::ItemTreeVTable_static!(static TEST_COMPONENT_VT for TestItemTree);
1661
1662    fn create_one_node_component(
1663        window_item: Option<WindowItem>,
1664    ) -> (std::rc::Rc<WindowAdapter>, VRc<ItemTreeVTable, vtable::Dyn>) {
1665        let window_adapter = WindowAdapter::new();
1666        let component = VRc::new(TestItemTree {
1667            parent_component: None,
1668            item_tree: vec![ItemTreeNode::Item {
1669                is_accessible: false,
1670                children_count: 0,
1671                children_index: 1,
1672                parent_index: 0,
1673                item_array_index: 0,
1674            }],
1675            subtrees: std::cell::RefCell::new(Vec::new()),
1676            subtree_index: usize::MAX,
1677
1678            window_adapter: Rc::downgrade(&window_adapter) as _,
1679            window_item,
1680        });
1681        (window_adapter, VRc::into_dyn(component))
1682    }
1683
1684    #[test]
1685    fn test_tree_traversal_one_node_structure() {
1686        let component = create_one_node_component(None).1;
1687
1688        let item = ItemRc::new_root(component.clone());
1689
1690        assert!(item.first_child().is_none());
1691        assert!(item.last_child().is_none());
1692        assert!(item.previous_sibling().is_none());
1693        assert!(item.next_sibling().is_none());
1694    }
1695
1696    #[test]
1697    fn test_tree_traversal_one_node_forward_focus() {
1698        let component = create_one_node_component(None).1;
1699
1700        let item = ItemRc::new_root(component.clone());
1701
1702        // Wrap the focus around:
1703        assert_eq!(item.next_focus_item(), item);
1704    }
1705
1706    #[test]
1707    fn test_tree_traversal_one_node_backward_focus() {
1708        let component = create_one_node_component(None).1;
1709
1710        let item = ItemRc::new_root(component.clone());
1711
1712        // Wrap the focus around:
1713        assert_eq!(item.previous_focus_item(), item);
1714    }
1715
1716    fn create_children_nodes() -> VRc<ItemTreeVTable, vtable::Dyn> {
1717        let component = VRc::new(TestItemTree {
1718            parent_component: None,
1719            item_tree: vec![
1720                // Root
1721                ItemTreeNode::Item {
1722                    is_accessible: false,
1723                    children_count: 3,
1724                    children_index: 1,
1725                    parent_index: 0,
1726                    item_array_index: 0, // Index in this array
1727                },
1728                // First child of the root
1729                ItemTreeNode::Item {
1730                    is_accessible: false,
1731                    children_count: 0,
1732                    children_index: 4, // Does not matter because children_count is zero
1733                    parent_index: 0,   // Root as parent
1734                    item_array_index: 1, // Index in this array
1735                },
1736                // Second child of the root
1737                ItemTreeNode::Item {
1738                    is_accessible: false,
1739                    children_count: 0,
1740                    children_index: 4, // Does not matter because children_count is zero
1741                    parent_index: 0,   // Root as parent
1742                    item_array_index: 2,
1743                },
1744                // Third child of the root
1745                ItemTreeNode::Item {
1746                    is_accessible: false,
1747                    children_count: 0,
1748                    children_index: 4, // Does not matter because children_count is zero
1749                    parent_index: 0,   // Root as parent
1750                    item_array_index: 3,
1751                },
1752            ],
1753            subtrees: std::cell::RefCell::new(Vec::new()),
1754            subtree_index: usize::MAX,
1755
1756            window_adapter: Rc::downgrade(&WindowAdapter::new()) as _,
1757            window_item: None,
1758        });
1759        VRc::into_dyn(component)
1760    }
1761
1762    #[test]
1763    fn test_tree_traversal_children_nodes_structure() {
1764        let component: VRc<ItemTreeVTable> = create_children_nodes();
1765
1766        // Examine root node:
1767        let item = ItemRc::new_root(component.clone());
1768        assert!(item.previous_sibling().is_none());
1769        assert!(item.next_sibling().is_none());
1770
1771        let fc = item.first_child().unwrap();
1772        assert_eq!(fc.index(), 1);
1773        assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
1774
1775        let fcn = fc.next_sibling().unwrap();
1776        assert_eq!(fcn.index(), 2);
1777
1778        let lc = item.last_child().unwrap();
1779        assert_eq!(lc.index(), 3);
1780        assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
1781
1782        let lcp = lc.previous_sibling().unwrap();
1783        assert!(VRc::ptr_eq(lcp.item_tree(), item.item_tree()));
1784        assert_eq!(lcp.index(), 2);
1785
1786        // Examine first child:
1787        assert!(fc.first_child().is_none());
1788        assert!(fc.last_child().is_none());
1789        assert!(fc.previous_sibling().is_none());
1790        assert_eq!(fc.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);
1791
1792        // Examine item between first and last child:
1793        assert_eq!(fcn, lcp);
1794        assert_eq!(lcp.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);
1795        assert_eq!(fcn.previous_sibling().unwrap(), fc);
1796        assert_eq!(fcn.next_sibling().unwrap(), lc);
1797
1798        // Examine last child:
1799        assert!(lc.first_child().is_none());
1800        assert!(lc.last_child().is_none());
1801        assert!(lc.next_sibling().is_none());
1802        assert_eq!(lc.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);
1803    }
1804
1805    #[test]
1806    fn test_tree_traversal_children_nodes_forward_focus() {
1807        let component = create_children_nodes();
1808
1809        let item = ItemRc::new_root(component.clone());
1810        let fc = item.first_child().unwrap();
1811        let fcn = fc.next_sibling().unwrap();
1812        let lc = item.last_child().unwrap();
1813
1814        let mut cursor = item.clone();
1815
1816        cursor = cursor.next_focus_item();
1817        assert_eq!(cursor, fc);
1818
1819        cursor = cursor.next_focus_item();
1820        assert_eq!(cursor, fcn);
1821
1822        cursor = cursor.next_focus_item();
1823        assert_eq!(cursor, lc);
1824
1825        cursor = cursor.next_focus_item();
1826        assert_eq!(cursor, item);
1827    }
1828
1829    #[test]
1830    fn test_tree_traversal_children_nodes_backward_focus() {
1831        let component = create_children_nodes();
1832
1833        let item = ItemRc::new_root(component.clone());
1834        let fc = item.first_child().unwrap();
1835        let fcn = fc.next_sibling().unwrap();
1836        let lc = item.last_child().unwrap();
1837
1838        let mut cursor = item.clone();
1839
1840        cursor = cursor.previous_focus_item();
1841        assert_eq!(cursor, lc);
1842
1843        cursor = cursor.previous_focus_item();
1844        assert_eq!(cursor, fcn);
1845
1846        cursor = cursor.previous_focus_item();
1847        assert_eq!(cursor, fc);
1848
1849        cursor = cursor.previous_focus_item();
1850        assert_eq!(cursor, item);
1851    }
1852
1853    fn create_empty_subtree() -> VRc<ItemTreeVTable, vtable::Dyn> {
1854        let component = vtable::VRc::new(TestItemTree {
1855            parent_component: None,
1856            item_tree: vec![
1857                ItemTreeNode::Item {
1858                    is_accessible: false,
1859                    children_count: 1,
1860                    children_index: 1,
1861                    parent_index: 0,
1862                    item_array_index: 0,
1863                },
1864                ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1865            ],
1866            subtrees: std::cell::RefCell::new(vec![Vec::new()]),
1867            subtree_index: usize::MAX,
1868
1869            window_adapter: Rc::downgrade(&WindowAdapter::new()) as _,
1870            window_item: None,
1871        });
1872        vtable::VRc::into_dyn(component)
1873    }
1874
1875    #[test]
1876    fn test_tree_traversal_empty_subtree_structure() {
1877        let component = create_empty_subtree();
1878
1879        // Examine root node:
1880        let item = ItemRc::new_root(component.clone());
1881        assert!(item.previous_sibling().is_none());
1882        assert!(item.next_sibling().is_none());
1883        assert!(item.first_child().is_none());
1884        assert!(item.last_child().is_none());
1885
1886        // Wrap the focus around:
1887        assert!(item.previous_focus_item() == item);
1888        assert!(item.next_focus_item() == item);
1889    }
1890
1891    #[test]
1892    fn test_tree_traversal_empty_subtree_forward_focus() {
1893        let component = create_empty_subtree();
1894
1895        // Examine root node:
1896        let item = ItemRc::new_root(component.clone());
1897
1898        assert!(item.next_focus_item() == item);
1899    }
1900
1901    #[test]
1902    fn test_tree_traversal_empty_subtree_backward_focus() {
1903        let component = create_empty_subtree();
1904
1905        // Examine root node:
1906        let item = ItemRc::new_root(component.clone());
1907
1908        assert!(item.previous_focus_item() == item);
1909    }
1910
1911    fn create_item_subtree_item() -> VRc<ItemTreeVTable, vtable::Dyn> {
1912        let window_adapter = WindowAdapter::new();
1913        let weak_adapter =
1914            Rc::downgrade(&window_adapter) as std::rc::Weak<dyn crate::window::WindowAdapter>;
1915        let component = VRc::new(TestItemTree {
1916            parent_component: None,
1917            item_tree: vec![
1918                // Root
1919                ItemTreeNode::Item {
1920                    is_accessible: false,
1921                    children_count: 3,
1922                    children_index: 1,
1923                    parent_index: 0,
1924                    item_array_index: 0,
1925                },
1926                // First child
1927                ItemTreeNode::Item {
1928                    is_accessible: false,
1929                    children_count: 0,
1930                    children_index: 4, // Does not matter because children_count is zero
1931                    parent_index: 0,   // Root as parent
1932                    item_array_index: 0,
1933                },
1934                ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1935                ItemTreeNode::Item {
1936                    is_accessible: false,
1937                    children_count: 0,
1938                    children_index: 4,
1939                    parent_index: 0, // Root as parent
1940                    item_array_index: 0,
1941                },
1942            ],
1943            subtrees: std::cell::RefCell::new(Vec::new()),
1944            subtree_index: usize::MAX,
1945
1946            window_adapter: weak_adapter.clone(),
1947            window_item: None,
1948        });
1949
1950        component.as_pin_ref().subtrees.replace(vec![vec![VRc::new(TestItemTree {
1951            parent_component: Some(VRc::downgrade(&VRc::into_dyn(component.clone()))),
1952            item_tree: vec![ItemTreeNode::Item {
1953                is_accessible: false,
1954                children_count: 0,
1955                children_index: 1,
1956                parent_index: 2,
1957                item_array_index: 0,
1958            }],
1959            subtrees: std::cell::RefCell::new(Vec::new()),
1960            subtree_index: 0,
1961
1962            window_adapter: weak_adapter,
1963            window_item: None,
1964        })]]);
1965
1966        VRc::into_dyn(component)
1967    }
1968
1969    #[test]
1970    fn test_tree_traversal_item_subtree_item_structure() {
1971        let component = create_item_subtree_item();
1972
1973        // Examine root node:
1974        let item = ItemRc::new_root(component.clone());
1975        assert!(item.previous_sibling().is_none());
1976        assert!(item.next_sibling().is_none());
1977
1978        let fc = item.first_child().unwrap();
1979        assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
1980        assert_eq!(fc.index(), 1);
1981
1982        let lc = item.last_child().unwrap();
1983        assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
1984        assert_eq!(lc.index(), 3);
1985
1986        let fcn = fc.next_sibling().unwrap();
1987        let lcp = lc.previous_sibling().unwrap();
1988
1989        assert_eq!(fcn, lcp);
1990        assert!(!VRc::ptr_eq(fcn.item_tree(), item.item_tree()));
1991
1992        let last = fcn.next_sibling().unwrap();
1993        assert_eq!(last, lc);
1994
1995        let first = lcp.previous_sibling().unwrap();
1996        assert_eq!(first, fc);
1997    }
1998
1999    #[test]
2000    fn test_tree_traversal_item_subtree_item_forward_focus() {
2001        let component = create_item_subtree_item();
2002
2003        let item = ItemRc::new_root(component.clone());
2004        let fc = item.first_child().unwrap();
2005        let lc = item.last_child().unwrap();
2006        let fcn = fc.next_sibling().unwrap();
2007
2008        let mut cursor = item.clone();
2009
2010        cursor = cursor.next_focus_item();
2011        assert_eq!(cursor, fc);
2012
2013        cursor = cursor.next_focus_item();
2014        assert_eq!(cursor, fcn);
2015
2016        cursor = cursor.next_focus_item();
2017        assert_eq!(cursor, lc);
2018
2019        cursor = cursor.next_focus_item();
2020        assert_eq!(cursor, item);
2021    }
2022
2023    #[test]
2024    fn test_tree_traversal_item_subtree_item_backward_focus() {
2025        let component = create_item_subtree_item();
2026
2027        let item = ItemRc::new_root(component.clone());
2028        let fc = item.first_child().unwrap();
2029        let lc = item.last_child().unwrap();
2030        let fcn = fc.next_sibling().unwrap();
2031
2032        let mut cursor = item.clone();
2033
2034        cursor = cursor.previous_focus_item();
2035        assert_eq!(cursor, lc);
2036
2037        cursor = cursor.previous_focus_item();
2038        assert_eq!(cursor, fcn);
2039
2040        cursor = cursor.previous_focus_item();
2041        assert_eq!(cursor, fc);
2042
2043        cursor = cursor.previous_focus_item();
2044        assert_eq!(cursor, item);
2045    }
2046
2047    fn create_nested_subtrees() -> VRc<ItemTreeVTable, vtable::Dyn> {
2048        // Nesting the subtrees
2049        // sub_component2 as subtree of sub_component1
2050        // sub_component1 as subtree of the main component
2051
2052        let window_adapter = WindowAdapter::new();
2053        let weak_adapter =
2054            Rc::downgrade(&window_adapter) as std::rc::Weak<dyn crate::window::WindowAdapter>;
2055
2056        let component = VRc::new(TestItemTree {
2057            parent_component: None,
2058            item_tree: vec![
2059                // Root
2060                ItemTreeNode::Item {
2061                    is_accessible: false,
2062                    children_count: 3,
2063                    children_index: 1,
2064                    parent_index: 0,
2065                    item_array_index: 0,
2066                },
2067                // First child
2068                ItemTreeNode::Item {
2069                    is_accessible: false,
2070                    children_count: 0,
2071                    children_index: 4,
2072                    parent_index: 0,
2073                    item_array_index: 0,
2074                },
2075                // Second child
2076                // Relates to the first subtree in this component (sub_component1, added below)
2077                ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
2078                // Third child
2079                ItemTreeNode::Item {
2080                    is_accessible: false,
2081                    children_count: 0,
2082                    children_index: 4,
2083                    parent_index: 0,
2084                    item_array_index: 0,
2085                },
2086            ],
2087            subtrees: std::cell::RefCell::new(Vec::new()),
2088            subtree_index: usize::MAX,
2089
2090            window_adapter: weak_adapter.clone(),
2091            window_item: None,
2092        });
2093
2094        let sub_component1 = VRc::new(TestItemTree {
2095            parent_component: Some(VRc::downgrade(&VRc::into_dyn(component.clone()))),
2096            item_tree: vec![
2097                // Root
2098                ItemTreeNode::Item {
2099                    is_accessible: false,
2100                    children_count: 1,
2101                    children_index: 1,
2102                    parent_index: 2,
2103                    item_array_index: 0,
2104                },
2105                // First child
2106                // Relates to the first subtree in this component (sub_component2, added below)
2107                ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
2108            ],
2109            subtrees: std::cell::RefCell::new(Vec::new()),
2110            subtree_index: usize::MAX,
2111
2112            window_adapter: weak_adapter.clone(),
2113            window_item: None,
2114        });
2115        let sub_component2 = VRc::new(TestItemTree {
2116            parent_component: Some(VRc::downgrade(&VRc::into_dyn(sub_component1.clone()))),
2117            item_tree: vec![
2118                ItemTreeNode::Item {
2119                    is_accessible: false,
2120                    children_count: 1,
2121                    children_index: 1,
2122                    parent_index: 1,
2123                    item_array_index: 0,
2124                },
2125                ItemTreeNode::Item {
2126                    is_accessible: false,
2127                    children_count: 0,
2128                    children_index: 2,
2129                    parent_index: 0,
2130                    item_array_index: 0,
2131                },
2132            ],
2133            subtrees: std::cell::RefCell::new(Vec::new()),
2134            subtree_index: usize::MAX,
2135
2136            window_adapter: weak_adapter,
2137            window_item: None,
2138        });
2139
2140        sub_component1.as_pin_ref().subtrees.replace(vec![vec![sub_component2]]);
2141        component.as_pin_ref().subtrees.replace(vec![vec![sub_component1]]);
2142
2143        VRc::into_dyn(component)
2144    }
2145
2146    #[test]
2147    fn test_tree_traversal_nested_subtrees_structure() {
2148        let component = create_nested_subtrees();
2149
2150        // Examine root node:
2151        let item = ItemRc::new_root(component.clone());
2152        assert!(item.previous_sibling().is_none());
2153        assert!(item.next_sibling().is_none());
2154
2155        let fc = item.first_child().unwrap();
2156        assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
2157        assert_eq!(fc.index(), 1);
2158
2159        let lc = item.last_child().unwrap();
2160        assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
2161        assert_eq!(lc.index(), 3);
2162
2163        let fcn = fc.next_sibling().unwrap();
2164        let lcp = lc.previous_sibling().unwrap();
2165
2166        assert_eq!(fcn, lcp);
2167        assert!(!VRc::ptr_eq(fcn.item_tree(), item.item_tree()));
2168
2169        let last = fcn.next_sibling().unwrap();
2170        assert_eq!(last, lc);
2171
2172        let first = lcp.previous_sibling().unwrap();
2173        assert_eq!(first, fc);
2174
2175        // Nested component:
2176        let nested_root = fcn.first_child().unwrap();
2177        assert_eq!(nested_root, fcn.last_child().unwrap());
2178        assert!(nested_root.next_sibling().is_none());
2179        assert!(nested_root.previous_sibling().is_none());
2180        assert!(!VRc::ptr_eq(nested_root.item_tree(), item.item_tree()));
2181        assert!(!VRc::ptr_eq(nested_root.item_tree(), fcn.item_tree()));
2182
2183        let nested_child = nested_root.first_child().unwrap();
2184        assert_eq!(nested_child, nested_root.last_child().unwrap());
2185        assert!(VRc::ptr_eq(nested_root.item_tree(), nested_child.item_tree()));
2186    }
2187
2188    #[test]
2189    fn test_tree_traversal_nested_subtrees_forward_focus() {
2190        let component = create_nested_subtrees();
2191
2192        // Examine root node:
2193        let item = ItemRc::new_root(component.clone());
2194        let fc = item.first_child().unwrap();
2195        let fcn = fc.next_sibling().unwrap();
2196        let lc = item.last_child().unwrap();
2197        let nested_root = fcn.first_child().unwrap();
2198        let nested_child = nested_root.first_child().unwrap();
2199
2200        // Focus traversal:
2201        let mut cursor = item.clone();
2202
2203        cursor = cursor.next_focus_item();
2204        assert_eq!(cursor, fc);
2205
2206        cursor = cursor.next_focus_item();
2207        assert_eq!(cursor, fcn);
2208
2209        cursor = cursor.next_focus_item();
2210        assert_eq!(cursor, nested_root);
2211
2212        cursor = cursor.next_focus_item();
2213        assert_eq!(cursor, nested_child);
2214
2215        cursor = cursor.next_focus_item();
2216        assert_eq!(cursor, lc);
2217
2218        cursor = cursor.next_focus_item();
2219        assert_eq!(cursor, item);
2220    }
2221
2222    #[test]
2223    fn test_tree_traversal_nested_subtrees_backward_focus() {
2224        let component = create_nested_subtrees();
2225
2226        // Examine root node:
2227        let item = ItemRc::new_root(component.clone());
2228        let fc = item.first_child().unwrap();
2229        let fcn = fc.next_sibling().unwrap();
2230        let lc = item.last_child().unwrap();
2231        let nested_root = fcn.first_child().unwrap();
2232        let nested_child = nested_root.first_child().unwrap();
2233
2234        // Focus traversal:
2235        let mut cursor = item.clone();
2236
2237        cursor = cursor.previous_focus_item();
2238        assert_eq!(cursor, lc);
2239
2240        cursor = cursor.previous_focus_item();
2241        assert_eq!(cursor, nested_child);
2242
2243        cursor = cursor.previous_focus_item();
2244        assert_eq!(cursor, nested_root);
2245
2246        cursor = cursor.previous_focus_item();
2247        assert_eq!(cursor, fcn);
2248
2249        cursor = cursor.previous_focus_item();
2250        assert_eq!(cursor, fc);
2251
2252        cursor = cursor.previous_focus_item();
2253        assert_eq!(cursor, item);
2254    }
2255
2256    fn create_subtrees_item() -> VRc<ItemTreeVTable, vtable::Dyn> {
2257        let window_adapter = WindowAdapter::new();
2258        let weak_adapter =
2259            Rc::downgrade(&window_adapter) as std::rc::Weak<dyn crate::window::WindowAdapter>;
2260
2261        let component = VRc::new(TestItemTree {
2262            parent_component: None,
2263            item_tree: vec![
2264                ItemTreeNode::Item {
2265                    is_accessible: false,
2266                    children_count: 2,
2267                    children_index: 1,
2268                    parent_index: 0,
2269                    item_array_index: 0,
2270                },
2271                ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
2272                ItemTreeNode::Item {
2273                    is_accessible: false,
2274                    children_count: 0,
2275                    children_index: 4,
2276                    parent_index: 0,
2277                    item_array_index: 0,
2278                },
2279            ],
2280            subtrees: std::cell::RefCell::new(Vec::new()),
2281            subtree_index: usize::MAX,
2282
2283            window_adapter: weak_adapter.clone(),
2284            window_item: None,
2285        });
2286
2287        component.as_pin_ref().subtrees.replace(vec![vec![
2288            VRc::new(TestItemTree {
2289                parent_component: Some(VRc::downgrade(&VRc::into_dyn(component.clone()))),
2290                item_tree: vec![ItemTreeNode::Item {
2291                    is_accessible: false,
2292                    children_count: 0,
2293                    children_index: 1,
2294                    parent_index: 1,
2295                    item_array_index: 0,
2296                }],
2297                subtrees: std::cell::RefCell::new(Vec::new()),
2298                subtree_index: 0,
2299
2300                window_adapter: weak_adapter.clone(),
2301                window_item: None,
2302            }),
2303            VRc::new(TestItemTree {
2304                parent_component: Some(VRc::downgrade(&VRc::into_dyn(component.clone()))),
2305                item_tree: vec![ItemTreeNode::Item {
2306                    is_accessible: false,
2307                    children_count: 0,
2308                    children_index: 1,
2309                    parent_index: 1,
2310                    item_array_index: 0,
2311                }],
2312                subtrees: std::cell::RefCell::new(Vec::new()),
2313                subtree_index: 1,
2314
2315                window_adapter: weak_adapter.clone(),
2316                window_item: None,
2317            }),
2318            VRc::new(TestItemTree {
2319                parent_component: Some(VRc::downgrade(&VRc::into_dyn(component.clone()))),
2320                item_tree: vec![ItemTreeNode::Item {
2321                    is_accessible: false,
2322                    children_count: 0,
2323                    children_index: 1,
2324                    parent_index: 1,
2325                    item_array_index: 0,
2326                }],
2327                subtrees: std::cell::RefCell::new(Vec::new()),
2328                subtree_index: 2,
2329
2330                window_adapter: weak_adapter,
2331                window_item: None,
2332            }),
2333        ]]);
2334
2335        VRc::into_dyn(component)
2336    }
2337
2338    #[test]
2339    fn test_tree_traversal_subtrees_item_structure() {
2340        let component = create_subtrees_item();
2341
2342        // Examine root node:
2343        let item = ItemRc::new_root(component.clone());
2344        assert!(item.previous_sibling().is_none());
2345        assert!(item.next_sibling().is_none());
2346
2347        let sub1 = item.first_child().unwrap();
2348        assert_eq!(sub1.index(), 0);
2349        assert!(!VRc::ptr_eq(sub1.item_tree(), item.item_tree()));
2350
2351        // assert!(sub1.previous_sibling().is_none());
2352
2353        let sub2 = sub1.next_sibling().unwrap();
2354        assert_eq!(sub2.index(), 0);
2355        assert!(!VRc::ptr_eq(sub1.item_tree(), sub2.item_tree()));
2356        assert!(!VRc::ptr_eq(item.item_tree(), sub2.item_tree()));
2357
2358        assert!(sub2.previous_sibling() == Some(sub1.clone()));
2359
2360        let sub3 = sub2.next_sibling().unwrap();
2361        assert_eq!(sub3.index(), 0);
2362        assert!(!VRc::ptr_eq(sub1.item_tree(), sub2.item_tree()));
2363        assert!(!VRc::ptr_eq(sub2.item_tree(), sub3.item_tree()));
2364        assert!(!VRc::ptr_eq(item.item_tree(), sub3.item_tree()));
2365
2366        assert_eq!(sub3.previous_sibling().unwrap(), sub2.clone());
2367    }
2368
2369    #[test]
2370    fn test_component_item_tree_root_only() {
2371        let nodes = vec![ItemTreeNode::Item {
2372            is_accessible: false,
2373            children_count: 0,
2374            children_index: 1,
2375            parent_index: 0,
2376            item_array_index: 0,
2377        }];
2378
2379        let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
2380
2381        assert_eq!(tree.first_child(0), None);
2382        assert_eq!(tree.last_child(0), None);
2383        assert_eq!(tree.previous_sibling(0), None);
2384        assert_eq!(tree.next_sibling(0), None);
2385        assert_eq!(tree.parent(0), None);
2386    }
2387
2388    #[test]
2389    fn test_component_item_tree_one_child() {
2390        let nodes = vec![
2391            ItemTreeNode::Item {
2392                is_accessible: false,
2393                children_count: 1,
2394                children_index: 1,
2395                parent_index: 0,
2396                item_array_index: 0,
2397            },
2398            ItemTreeNode::Item {
2399                is_accessible: false,
2400                children_count: 0,
2401                children_index: 2,
2402                parent_index: 0,
2403                item_array_index: 0,
2404            },
2405        ];
2406
2407        let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
2408
2409        assert_eq!(tree.first_child(0), Some(1));
2410        assert_eq!(tree.last_child(0), Some(1));
2411        assert_eq!(tree.previous_sibling(0), None);
2412        assert_eq!(tree.next_sibling(0), None);
2413        assert_eq!(tree.parent(0), None);
2414        assert_eq!(tree.previous_sibling(1), None);
2415        assert_eq!(tree.next_sibling(1), None);
2416        assert_eq!(tree.parent(1), Some(0));
2417    }
2418
2419    #[test]
2420    fn test_component_item_tree_tree_children() {
2421        let nodes = vec![
2422            ItemTreeNode::Item {
2423                is_accessible: false,
2424                children_count: 3,
2425                children_index: 1,
2426                parent_index: 0,
2427                item_array_index: 0,
2428            },
2429            ItemTreeNode::Item {
2430                is_accessible: false,
2431                children_count: 0,
2432                children_index: 4,
2433                parent_index: 0,
2434                item_array_index: 0,
2435            },
2436            ItemTreeNode::Item {
2437                is_accessible: false,
2438                children_count: 0,
2439                children_index: 4,
2440                parent_index: 0,
2441                item_array_index: 0,
2442            },
2443            ItemTreeNode::Item {
2444                is_accessible: false,
2445                children_count: 0,
2446                children_index: 4,
2447                parent_index: 0,
2448                item_array_index: 0,
2449            },
2450        ];
2451
2452        let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
2453
2454        assert_eq!(tree.first_child(0), Some(1));
2455        assert_eq!(tree.last_child(0), Some(3));
2456        assert_eq!(tree.previous_sibling(0), None);
2457        assert_eq!(tree.next_sibling(0), None);
2458        assert_eq!(tree.parent(0), None);
2459
2460        assert_eq!(tree.previous_sibling(1), None);
2461        assert_eq!(tree.next_sibling(1), Some(2));
2462        assert_eq!(tree.parent(1), Some(0));
2463
2464        assert_eq!(tree.previous_sibling(2), Some(1));
2465        assert_eq!(tree.next_sibling(2), Some(3));
2466        assert_eq!(tree.parent(2), Some(0));
2467
2468        assert_eq!(tree.previous_sibling(3), Some(2));
2469        assert_eq!(tree.next_sibling(3), None);
2470        assert_eq!(tree.parent(3), Some(0));
2471    }
2472
2473    // It does not contain any dynamic elements
2474    fn create_subsubtree_items(
2475        window_adapter: Option<std::rc::Rc<WindowAdapter>>,
2476    ) -> (std::rc::Rc<WindowAdapter>, VRc<ItemTreeVTable>) {
2477        let window_adapter = window_adapter.unwrap_or(WindowAdapter::new());
2478        let mut window_item = WindowItem::default();
2479        window_item.width = Property::new(LogicalLength::new(30.));
2480        window_item.height = Property::new(LogicalLength::new(30.));
2481        (
2482            window_adapter.clone(),
2483            VRc::into_dyn(VRc::new(TestItemTree {
2484                parent_component: None,
2485                item_tree: vec![
2486                    // Root
2487                    ItemTreeNode::Item {
2488                        is_accessible: false,
2489                        children_count: 1,
2490                        children_index: 1,
2491                        parent_index: 0,
2492                        item_array_index: 0,
2493                    },
2494                    // First child
2495                    ItemTreeNode::Item {
2496                        is_accessible: false,
2497                        children_count: 1,
2498                        children_index: 2, // Monotonic increasing
2499                        parent_index: 0,
2500                        item_array_index: 1,
2501                    },
2502                    // First child of the first child of the root
2503                    ItemTreeNode::Item {
2504                        is_accessible: false,
2505                        children_count: 0,
2506                        children_index: 3, // Not relevant because it has no children
2507                        parent_index: 1,
2508                        item_array_index: 2,
2509                    },
2510                ],
2511                subtrees: std::cell::RefCell::new(Vec::new()),
2512                subtree_index: usize::MAX,
2513                window_adapter: Rc::downgrade(&window_adapter) as _,
2514                window_item: Some(window_item),
2515            })),
2516        )
2517    }
2518
2519    struct TransformTestItemTree {
2520        item_tree: Vec<ItemTreeNode>,
2521        geometries: Vec<LogicalRect>,
2522        window_adapter: std::rc::Weak<dyn crate::window::WindowAdapter>,
2523        root: WindowItem,
2524        transform: Transform,
2525        clip: Clip,
2526        leaf: WindowItem,
2527    }
2528
2529    impl ItemTree for TransformTestItemTree {
2530        fn visit_children_item(
2531            self: Pin<&Self>,
2532            _index: isize,
2533            _order: TraversalOrder,
2534            _visitor: vtable::VRefMut<ItemVisitorVTable>,
2535        ) -> VisitChildrenResult {
2536            unimplemented!("Not needed for this test")
2537        }
2538
2539        fn get_item_ref(self: Pin<&Self>, index: u32) -> Pin<VRef<'_, ItemVTable>> {
2540            let this = self.get_ref();
2541            match index {
2542                0 => Pin::new(VRef::new(&this.root)),
2543                1 => Pin::new(VRef::new(&this.transform)),
2544                2 => Pin::new(VRef::new(&this.clip)),
2545                3 => Pin::new(VRef::new(&this.leaf)),
2546                _ => unimplemented!("Not needed for this test"),
2547            }
2548        }
2549
2550        fn get_item_tree(self: Pin<&Self>) -> Slice<'_, ItemTreeNode> {
2551            Slice::from_slice(&self.get_ref().item_tree)
2552        }
2553
2554        fn parent_node(self: Pin<&Self>, _result: &mut ItemWeak) {}
2555
2556        fn embed_component(
2557            self: Pin<&Self>,
2558            _parent_component: &ItemTreeWeak,
2559            _item_tree_index: u32,
2560        ) -> bool {
2561            false
2562        }
2563
2564        fn layout_info(self: Pin<&Self>, _orientation: Orientation) -> LayoutInfo {
2565            unimplemented!("Not needed for this test")
2566        }
2567
2568        fn subtree_index(self: Pin<&Self>) -> usize {
2569            usize::MAX
2570        }
2571
2572        fn get_subtree_range(self: Pin<&Self>, _subtree_index: u32) -> IndexRange {
2573            (0..0).into()
2574        }
2575
2576        fn get_subtree(
2577            self: Pin<&Self>,
2578            _subtree_index: u32,
2579            _component_index: usize,
2580            _result: &mut ItemTreeWeak,
2581        ) {
2582            unimplemented!("Not needed for this test")
2583        }
2584
2585        fn accessible_role(self: Pin<&Self>, _index: u32) -> AccessibleRole {
2586            unimplemented!("Not needed for this test")
2587        }
2588
2589        fn accessible_string_property(
2590            self: Pin<&Self>,
2591            _index: u32,
2592            _what: AccessibleStringProperty,
2593            _result: &mut SharedString,
2594        ) -> bool {
2595            false
2596        }
2597
2598        fn item_element_infos(self: Pin<&Self>, _index: u32, _result: &mut SharedString) -> bool {
2599            false
2600        }
2601
2602        fn ensure_instantiated(self: Pin<&Self>) -> bool {
2603            false
2604        }
2605
2606        fn window_adapter(
2607            self: Pin<&Self>,
2608            _do_create: bool,
2609            result: &mut Option<WindowAdapterRc>,
2610        ) {
2611            *result = self.window_adapter.upgrade()
2612        }
2613
2614        fn item_geometry(self: Pin<&Self>, index: u32) -> LogicalRect {
2615            self.geometries[index as usize]
2616        }
2617
2618        fn accessibility_action(self: Pin<&Self>, _index: u32, _action: &AccessibilityAction) {
2619            unimplemented!("Not needed for this test")
2620        }
2621
2622        fn supported_accessibility_actions(
2623            self: Pin<&Self>,
2624            _index: u32,
2625        ) -> SupportedAccessibilityAction {
2626            unimplemented!("Not needed for this test")
2627        }
2628    }
2629
2630    crate::item_tree::ItemTreeVTable_static!(static TRANSFORM_TEST_COMPONENT_VT for TransformTestItemTree);
2631
2632    fn create_transform_test_items() -> (std::rc::Rc<WindowAdapter>, VRc<ItemTreeVTable>) {
2633        let window_adapter = WindowAdapter::new_with_transformations(true);
2634
2635        let mut transform = Transform::default();
2636        transform.transform_scale_x = Property::new(2.);
2637        transform.transform_scale_y = Property::new(3.);
2638        transform.transform_rotation = Property::new(0.);
2639        transform.transform_origin = Property::new(LogicalPosition::new(0., 0.));
2640
2641        let mut clip = Clip::default();
2642        clip.clip = Property::new(true);
2643
2644        (
2645            window_adapter.clone(),
2646            VRc::into_dyn(VRc::new(TransformTestItemTree {
2647                item_tree: vec![
2648                    ItemTreeNode::Item {
2649                        is_accessible: false,
2650                        children_count: 1,
2651                        children_index: 1,
2652                        parent_index: 0,
2653                        item_array_index: 0,
2654                    },
2655                    ItemTreeNode::Item {
2656                        is_accessible: false,
2657                        children_count: 1,
2658                        children_index: 2,
2659                        parent_index: 0,
2660                        item_array_index: 1,
2661                    },
2662                    ItemTreeNode::Item {
2663                        is_accessible: false,
2664                        children_count: 1,
2665                        children_index: 3,
2666                        parent_index: 1,
2667                        item_array_index: 2,
2668                    },
2669                    ItemTreeNode::Item {
2670                        is_accessible: false,
2671                        children_count: 0,
2672                        children_index: 4,
2673                        parent_index: 2,
2674                        item_array_index: 3,
2675                    },
2676                ],
2677                geometries: vec![
2678                    LogicalRect::new(Point2D::new(0., 0.), LogicalSize::new(100., 100.)),
2679                    LogicalRect::new(Point2D::new(10., 20.), LogicalSize::new(40., 40.)),
2680                    LogicalRect::new(Point2D::new(5., 6.), LogicalSize::new(20., 20.)),
2681                    LogicalRect::new(Point2D::new(8., 4.), LogicalSize::new(10., 10.)),
2682                ],
2683                window_adapter: Rc::downgrade(&window_adapter) as _,
2684                root: WindowItem::default(),
2685                transform,
2686                clip,
2687                leaf: WindowItem::default(),
2688            })),
2689        )
2690    }
2691
2692    fn assert_point_approx_eq(actual: LogicalPoint, expected: LogicalPoint) {
2693        const EPSILON: f32 = 0.0001;
2694        assert!(
2695            (actual.x - expected.x).abs() < EPSILON,
2696            "actual x {}, expected x {}",
2697            actual.x,
2698            expected.x
2699        );
2700        assert!(
2701            (actual.y - expected.y).abs() < EPSILON,
2702            "actual y {}, expected y {}",
2703            actual.y,
2704            expected.y
2705        );
2706    }
2707
2708    #[test]
2709    fn test_map_to_ancestor() {
2710        let (_window_adapter, item_tree) = create_subsubtree_items(None);
2711        let root = ItemRc::new_root(item_tree);
2712        let first_child = root.first_child().unwrap();
2713        let first_child_of_first_child = first_child.first_child().unwrap();
2714
2715        {
2716            let point = first_child.map_to_ancestor(Point2D::new(6., 19.), &root);
2717            assert_eq!(point.x, 6.);
2718            assert_eq!(point.y, 19.);
2719        }
2720
2721        {
2722            let point =
2723                first_child_of_first_child.map_to_ancestor(Point2D::new(27., -10.), &first_child);
2724            assert_eq!(point.x, 27.);
2725            assert_eq!(point.y, -10.);
2726        }
2727
2728        {
2729            // Position of the parent must be added
2730            let point = first_child_of_first_child.map_to_ancestor(Point2D::new(27., -10.), &root);
2731            // Position of          first child
2732            assert_eq!(point.x, GEOMETRY_POSITION_X + 27.);
2733            assert_eq!(point.y, GEOMETRY_POSITION_Y - 10.);
2734        }
2735    }
2736
2737    #[test]
2738    fn test_map_to_window() {
2739        let (_window_adapter, item_tree) = create_subsubtree_items(None);
2740        let root = ItemRc::new_root(item_tree);
2741        let first_child = root.first_child().unwrap();
2742        let first_child_of_first_child = first_child.first_child().unwrap();
2743
2744        let point = first_child_of_first_child.map_to_window(Point2D::new(-5., 7.));
2745        // Position of position of first_child  + first_child_of_first_child
2746        assert_eq!(point.x, GEOMETRY_POSITION_X + GEOMETRY_POSITION_X - 5.);
2747        assert_eq!(point.y, GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y + 7.);
2748    }
2749
2750    #[test]
2751    fn test_map_to_window_through_transform_roundtrip() {
2752        let (_window_adapter, item_tree) = create_transform_test_items();
2753        let root = ItemRc::new_root(item_tree);
2754        let transform = root.first_child().unwrap();
2755        let clip = transform.first_child().unwrap();
2756        let leaf = clip.first_child().unwrap();
2757
2758        let local_point = Point2D::new(4., 5.);
2759        let window_point = leaf.map_to_window(local_point);
2760        assert_point_approx_eq(window_point, Point2D::new(28., 53.));
2761    }
2762
2763    #[test]
2764    fn test_visibility_with_clip_under_transform() {
2765        let (_window_adapter, item_tree) = create_transform_test_items();
2766        let root = ItemRc::new_root(item_tree);
2767        let transform = root.first_child().unwrap();
2768        let clip = transform.first_child().unwrap();
2769        let leaf = clip.first_child().unwrap();
2770
2771        assert!(leaf.is_visible());
2772
2773        let hidden_point = leaf.map_to_window(Point2D::new(25., 25.));
2774        let (clip_rect, leaf_geometry) = leaf.absolute_clip_rect_and_geometry();
2775        assert!(clip_rect.intersection(&leaf_geometry).is_some());
2776        assert!(!clip_rect.contains(hidden_point));
2777    }
2778
2779    #[test]
2780    fn test_map_to_native_window_popup() {
2781        const POPUP_LOCATION: LogicalPosition = LogicalPosition::new(20., 33.);
2782        let mut window_item = WindowItem::default();
2783        window_item.width = Property::new(LogicalLength::new(30.));
2784        window_item.height = Property::new(LogicalLength::new(30.));
2785        // A popup has it's own ItemTreeVTable
2786        let (window_adapter, parent) = create_one_node_component(Some(window_item));
2787        let popup_component = create_subsubtree_items(Some(window_adapter.clone())).1;
2788        window_adapter.window.0.show_popup(
2789            &popup_component,
2790            alloc::boxed::Box::new(move || POPUP_LOCATION),
2791            crate::items::PopupClosePolicy::NoAutoClose,
2792            &ItemRc::new_root(parent.clone()),
2793            crate::window::WindowKind::Popup,
2794            alloc::boxed::Box::new(|_| {}),
2795        );
2796
2797        let root = ItemRc::new_root(popup_component);
2798        let first_child = root.first_child().unwrap();
2799        let first_child_of_first_child = first_child.first_child().unwrap();
2800
2801        // Check that we have a ChildWindow popup
2802        let active_popups = window_adapter.window.0.active_popups();
2803        assert_eq!(active_popups.len(), 1);
2804        let popup = active_popups.first().unwrap();
2805        assert!(matches!(popup.location, crate::window::PopupWindowLocation::ChildWindow { .. }));
2806
2807        // The popup is not a real window and therefore it does not have it's own coordinate system
2808        // So map_to_window is really absolute to the window not to the popup window
2809        let point = first_child_of_first_child.map_to_native_window(Point2D::new(3., -82.));
2810        assert_eq!(
2811            point.x,
2812            // ------------- Popup --------------- +     root.x          + first_child.x       + 3
2813            POPUP_LOCATION.x + GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + 3.
2814        );
2815        assert_eq!(
2816            point.y,
2817            POPUP_LOCATION.y + GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y
2818                - 82.
2819        );
2820    }
2821
2822    #[test]
2823    fn test_map_to_window_popup() {
2824        const POPUP_LOCATION: LogicalPosition = LogicalPosition::new(20., 33.);
2825        let (window_adapter, item_tree) = create_subsubtree_items(None);
2826        window_adapter.window.0.show_popup(
2827            &item_tree,
2828            alloc::boxed::Box::new(move || POPUP_LOCATION),
2829            crate::items::PopupClosePolicy::NoAutoClose,
2830            &ItemRc::new_root(item_tree.clone()),
2831            crate::window::WindowKind::Popup,
2832            alloc::boxed::Box::new(|_| {}),
2833        );
2834
2835        let root = ItemRc::new_root(item_tree);
2836        let first_child = root.first_child().unwrap();
2837        let first_child_of_first_child = first_child.first_child().unwrap();
2838
2839        // Check that we have a ChildWindow popup
2840        let active_popups = window_adapter.window.0.active_popups();
2841        assert_eq!(active_popups.len(), 1);
2842        let popup = active_popups.first().unwrap();
2843        assert!(matches!(popup.location, crate::window::PopupWindowLocation::ChildWindow { .. }));
2844
2845        // The popup is not a real window and therefore it does not have it's own coordinate system
2846        // So map_to_window is really absolute to the window not to the popup window
2847        let point = first_child_of_first_child.map_to_window(Point2D::new(3., -82.));
2848        // Does not consider the popup location
2849        //                         Root.x       +     first_child.x   + 3
2850        assert_eq!(point.x, GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + 3.);
2851        assert_eq!(point.y, GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y - 82.);
2852    }
2853
2854    // Includes also dynamic elements
2855    fn create_subsubtree_items_dynamic_elements(
2856        window_adapter: Rc<WindowAdapter>,
2857    ) -> VRc<ItemTreeVTable> {
2858        let weak_adapter =
2859            Rc::downgrade(&window_adapter) as std::rc::Weak<dyn crate::window::WindowAdapter>;
2860        let mut window_item = WindowItem::default();
2861        window_item.width = Property::new(LogicalLength::new(30.));
2862        window_item.height = Property::new(LogicalLength::new(30.));
2863
2864        let item_tree = VRc::new(TestItemTree {
2865            parent_component: None,
2866            item_tree: vec![
2867                // Root
2868                ItemTreeNode::Item {
2869                    is_accessible: false,
2870                    children_count: 1,
2871                    children_index: 1,
2872                    parent_index: 0,
2873                    item_array_index: 0,
2874                },
2875                // First child
2876                ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
2877            ],
2878            subtrees: std::cell::RefCell::new(Vec::new()),
2879            subtree_index: usize::MAX,
2880            window_adapter: weak_adapter.clone(),
2881            window_item: Some(window_item),
2882        });
2883
2884        item_tree.as_pin_ref().subtrees.replace(vec![vec![VRc::new(TestItemTree {
2885            parent_component: Some(VRc::downgrade(&VRc::into_dyn(item_tree.clone()))),
2886            item_tree: vec![
2887                // Root
2888                ItemTreeNode::Item {
2889                    is_accessible: false,
2890                    children_count: 1,
2891                    children_index: 1,
2892                    parent_index: 1, // The index in the parent item tree
2893                    item_array_index: 0,
2894                },
2895                // First child
2896                ItemTreeNode::Item {
2897                    is_accessible: false,
2898                    children_count: 0,
2899                    children_index: 0,
2900                    parent_index: 0,
2901                    item_array_index: 1,
2902                },
2903            ],
2904            subtrees: std::cell::RefCell::new(Vec::new()),
2905            subtree_index: 0,
2906
2907            window_adapter: weak_adapter,
2908            window_item: None,
2909        })]]);
2910
2911        VRc::into_dyn(item_tree)
2912    }
2913
2914    // This time the element is a child of a dynamic element with a different item tree
2915    // Therefore we have to make sure we go up recursively
2916    #[test]
2917    fn test_map_to_native_window_popup_dynamic_element() {
2918        const POPUP_LOCATION: LogicalPosition = LogicalPosition::new(20., 33.);
2919
2920        let mut window_item = WindowItem::default();
2921        window_item.width = Property::new(LogicalLength::new(30.));
2922        window_item.height = Property::new(LogicalLength::new(30.));
2923
2924        // A popup has it's own ItemTreeVTable
2925        let (window_adapter, parent) = create_one_node_component(Some(window_item));
2926        let popup_component = create_subsubtree_items_dynamic_elements(window_adapter.clone());
2927        window_adapter.window.0.show_popup(
2928            &popup_component,
2929            alloc::boxed::Box::new(move || POPUP_LOCATION),
2930            crate::items::PopupClosePolicy::NoAutoClose,
2931            &ItemRc::new_root(parent.clone()),
2932            crate::window::WindowKind::Popup,
2933            alloc::boxed::Box::new(|_| {}),
2934        );
2935
2936        // Check that we have a ChildWindow popup, otherwise the popup has its own coordinate system
2937        let active_popups = window_adapter.window.0.active_popups();
2938        assert_eq!(active_popups.len(), 1);
2939        let popup = active_popups.first().unwrap();
2940        assert!(matches!(popup.location, crate::window::PopupWindowLocation::ChildWindow { .. }));
2941
2942        let root = ItemRc::new_root(popup_component);
2943        let first_child = root.first_child().unwrap();
2944        // Check if the first item is a dynamic tree!
2945        let comp_ref_pin = vtable::VRc::borrow_pin(&root.item_tree);
2946        let item_tree_array = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
2947        assert!(matches!(
2948            item_tree_array.get(1).expect("Must be one element"),
2949            ItemTreeNode::DynamicTree { .. }
2950        ));
2951        // Because of the dynamic tree, the item tree is not the same as for the root
2952        let first_child_of_first_child = first_child.first_child().expect("We have one child");
2953
2954        // The popup is not a real window and therefore it does not have it's own coordinate system
2955        // So map_to_window is really absolute to the window not to the popup window
2956        let point = first_child_of_first_child.map_to_native_window(Point2D::new(3., -82.));
2957        assert_eq!(
2958            point.x,
2959            // ------------- Popup --------------- +     root.x          + first_child.x       + 3
2960            POPUP_LOCATION.x + GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + 3.
2961        );
2962        assert_eq!(
2963            point.y,
2964            POPUP_LOCATION.y + GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y
2965                - 82.
2966        );
2967    }
2968
2969    impl crate::renderer::RendererSealed for Renderer {
2970        fn char_size(
2971            &self,
2972            _text_item: Pin<&dyn crate::item_rendering::HasFont>,
2973            _item_rc: &crate::item_tree::ItemRc,
2974            _ch: char,
2975        ) -> LogicalSize {
2976            LogicalSize::new(5., 10.)
2977        }
2978
2979        fn font_metrics(
2980            &self,
2981            _font_request: crate::graphics::FontRequest,
2982        ) -> crate::items::FontMetrics {
2983            crate::items::FontMetrics { ..Default::default() }
2984        }
2985
2986        fn free_graphics_resources(
2987            &self,
2988            _component: ItemTreeRef,
2989            _items: &mut dyn Iterator<Item = Pin<crate::items::ItemRef<'_>>>,
2990        ) -> Result<(), crate::platform::PlatformError> {
2991            Ok(())
2992        }
2993
2994        fn mark_dirty_region(&self, _region: crate::partial_renderer::DirtyRegion) {
2995            // Will be called when showing a popup to mark the previous position dirty
2996        }
2997
2998        fn register_bitmap_font(&self, _font_data: &'static crate::graphics::BitmapFont) {
2999            unimplemented!("Not required in this test");
3000        }
3001
3002        fn register_font_from_memory(
3003            &self,
3004            _data: &'static [u8],
3005        ) -> Result<(), std::prelude::v1::Box<dyn std::error::Error>> {
3006            unimplemented!("Not required in this test");
3007        }
3008
3009        fn register_font_from_path(
3010            &self,
3011            _path: &std::path::Path,
3012        ) -> Result<(), std::prelude::v1::Box<dyn std::error::Error>> {
3013            unimplemented!("Not required in this test");
3014        }
3015
3016        fn resize(&self, _size: crate::api::PhysicalSize) -> Result<(), crate::api::PlatformError> {
3017            Ok(())
3018        }
3019
3020        fn scale_factor(&self) -> Option<crate::lengths::ScaleFactor> {
3021            None
3022        }
3023
3024        fn set_rendering_notifier(
3025            &self,
3026            _callback: std::prelude::v1::Box<dyn crate::api::RenderingNotifier>,
3027        ) -> Result<(), crate::api::SetRenderingNotifierError> {
3028            Ok(())
3029        }
3030
3031        fn set_window_adapter(
3032            &self,
3033            _window_adapter: &std::rc::Rc<dyn crate::window::WindowAdapter>,
3034        ) {
3035            unimplemented!("Not required in this test");
3036        }
3037
3038        fn slint_context(&self) -> Option<crate::SlintContext> {
3039            None
3040        }
3041
3042        fn supports_transformations(&self) -> bool {
3043            self.supports_transformations
3044        }
3045
3046        fn take_snapshot(
3047            &self,
3048        ) -> Result<crate::api::SharedPixelBuffer<crate::api::Rgba8Pixel>, crate::api::PlatformError>
3049        {
3050            unimplemented!("Not required in this test");
3051        }
3052
3053        fn text_input_byte_offset_for_position(
3054            &self,
3055            _text_input: Pin<&crate::items::TextInput>,
3056            _item_rc: &ItemRc,
3057            _pos: LogicalPoint,
3058        ) -> usize {
3059            unimplemented!("Not required in this test");
3060        }
3061
3062        fn text_input_cursor_rect_for_byte_offset(
3063            &self,
3064            _text_input: Pin<&crate::items::TextInput>,
3065            _item_rc: &ItemRc,
3066            _byte_offset: usize,
3067        ) -> LogicalRect {
3068            unimplemented!("Not required in this test");
3069        }
3070
3071        fn text_size(
3072            &self,
3073            _text_item: Pin<&dyn crate::item_rendering::RenderString>,
3074            _item_rc: &crate::item_tree::ItemRc,
3075            _max_width: Option<crate::lengths::LogicalLength>,
3076            _text_wrap: crate::items::TextWrap,
3077        ) -> crate::lengths::LogicalSize {
3078            unimplemented!("Not required in this test");
3079        }
3080
3081        fn window_adapter(&self) -> Option<std::rc::Rc<dyn crate::window::WindowAdapter>> {
3082            unimplemented!("Not required in this test");
3083        }
3084    }
3085}