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
5
6//! This module contains the ItemTree and code that helps navigating it
7
8use crate::accessibility::{
9    AccessibilityAction, AccessibleStringProperty, SupportedAccessibilityAction,
10};
11use crate::items::{AccessibleRole, ItemRef, ItemVTable};
12use crate::layout::{LayoutInfo, Orientation};
13use crate::lengths::{ItemTransform, LogicalPoint, LogicalRect};
14use crate::slice::Slice;
15use crate::window::WindowAdapterRc;
16use crate::SharedString;
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    /// Returns the item's geometry (relative to its parent item)
106    pub item_geometry:
107        extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, item_index: u32) -> LogicalRect,
108
109    /// Returns the accessible role for a given item
110    pub accessible_role:
111        extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, item_index: u32) -> AccessibleRole,
112
113    /// Returns the accessible property via the `result`. Returns true if such a property exists.
114    pub accessible_string_property: extern "C" fn(
115        ::core::pin::Pin<VRef<ItemTreeVTable>>,
116        item_index: u32,
117        what: AccessibleStringProperty,
118        result: &mut SharedString,
119    ) -> bool,
120
121    /// Executes an accessibility action.
122    pub accessibility_action: extern "C" fn(
123        ::core::pin::Pin<VRef<ItemTreeVTable>>,
124        item_index: u32,
125        action: &AccessibilityAction,
126    ),
127
128    /// Returns the supported accessibility actions.
129    pub supported_accessibility_actions: extern "C" fn(
130        ::core::pin::Pin<VRef<ItemTreeVTable>>,
131        item_index: u32,
132    ) -> SupportedAccessibilityAction,
133
134    /// Add the `ElementName::id` entries of the given item
135    pub item_element_infos: extern "C" fn(
136        ::core::pin::Pin<VRef<ItemTreeVTable>>,
137        item_index: u32,
138        result: &mut SharedString,
139    ) -> bool,
140
141    /// Returns a Window, creating a fresh one if `do_create` is true.
142    pub window_adapter: extern "C" fn(
143        ::core::pin::Pin<VRef<ItemTreeVTable>>,
144        do_create: bool,
145        result: &mut Option<WindowAdapterRc>,
146    ),
147
148    /// in-place destructor (for VRc)
149    pub drop_in_place: unsafe extern "C" fn(VRefMut<ItemTreeVTable>) -> vtable::Layout,
150
151    /// dealloc function (for VRc)
152    pub dealloc: unsafe extern "C" fn(&ItemTreeVTable, ptr: *mut u8, layout: vtable::Layout),
153}
154
155#[cfg(test)]
156pub(crate) use ItemTreeVTable_static;
157
158/// Alias for `vtable::VRef<ItemTreeVTable>` which represent a pointer to a `dyn ItemTree` with
159/// the associated vtable
160pub type ItemTreeRef<'a> = vtable::VRef<'a, ItemTreeVTable>;
161
162/// Type alias to the commonly used `Pin<VRef<ItemTreeVTable>>>`
163pub type ItemTreeRefPin<'a> = core::pin::Pin<ItemTreeRef<'a>>;
164
165/// Type alias to the commonly used VRc<ItemTreeVTable, Dyn>>
166pub type ItemTreeRc = vtable::VRc<ItemTreeVTable, Dyn>;
167/// Type alias to the commonly used VWeak<ItemTreeVTable, Dyn>>
168pub type ItemTreeWeak = vtable::VWeak<ItemTreeVTable, Dyn>;
169
170/// Call init() on the ItemVTable for each item of the ItemTree.
171pub fn register_item_tree(item_tree_rc: &ItemTreeRc, window_adapter: Option<WindowAdapterRc>) {
172    let c = vtable::VRc::borrow_pin(item_tree_rc);
173    let item_tree = c.as_ref().get_item_tree();
174    item_tree.iter().enumerate().for_each(|(tree_index, node)| {
175        let tree_index = tree_index as u32;
176        if let ItemTreeNode::Item { .. } = &node {
177            let item = ItemRc::new(item_tree_rc.clone(), tree_index);
178            c.as_ref().get_item_ref(tree_index).as_ref().init(&item);
179        }
180    });
181    if let Some(adapter) = window_adapter.as_ref().and_then(|a| a.internal(crate::InternalToken)) {
182        adapter.register_item_tree();
183    }
184}
185
186/// Free the backend graphics resources allocated by the ItemTree's items.
187pub fn unregister_item_tree<Base>(
188    base: core::pin::Pin<&Base>,
189    item_tree: ItemTreeRef,
190    item_array: &[vtable::VOffset<Base, ItemVTable, vtable::AllowPin>],
191    window_adapter: &WindowAdapterRc,
192) {
193    window_adapter.renderer().free_graphics_resources(
194        item_tree,
195        &mut item_array.iter().map(|item| item.apply_pin(base)),
196    ).expect("Fatal error encountered when freeing graphics resources while destroying Slint component");
197    if let Some(w) = window_adapter.internal(crate::InternalToken) {
198        w.unregister_item_tree(item_tree, &mut item_array.iter().map(|item| item.apply_pin(base)));
199    }
200
201    // Close popups that were part of a component that just got deleted
202    let window_inner = crate::window::WindowInner::from_pub(window_adapter.window());
203    let to_close_popups = window_inner
204        .active_popups()
205        .iter()
206        .filter_map(|p| p.parent_item.upgrade().is_none().then_some(p.popup_id))
207        .collect::<Vec<_>>();
208    for popup_id in to_close_popups {
209        window_inner.close_popup(popup_id);
210    }
211}
212
213fn find_sibling_outside_repeater(
214    component: &ItemTreeRc,
215    comp_ref_pin: Pin<VRef<ItemTreeVTable>>,
216    index: u32,
217    sibling_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
218    subtree_child: &dyn Fn(usize, usize) -> usize,
219) -> Option<ItemRc> {
220    assert_ne!(index, 0);
221
222    let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
223
224    let mut current_sibling = index;
225    loop {
226        current_sibling = sibling_step(&item_tree, current_sibling)?;
227
228        if let Some(node) = step_into_node(
229            component,
230            &comp_ref_pin,
231            current_sibling,
232            &item_tree,
233            subtree_child,
234            &core::convert::identity,
235        ) {
236            return Some(node);
237        }
238    }
239}
240
241fn step_into_node(
242    component: &ItemTreeRc,
243    comp_ref_pin: &Pin<VRef<ItemTreeVTable>>,
244    node_index: u32,
245    item_tree: &crate::item_tree::ItemTreeNodeArray,
246    subtree_child: &dyn Fn(usize, usize) -> usize,
247    wrap_around: &dyn Fn(ItemRc) -> ItemRc,
248) -> Option<ItemRc> {
249    match item_tree.get(node_index).expect("Invalid index passed to item tree") {
250        crate::item_tree::ItemTreeNode::Item { .. } => {
251            Some(ItemRc::new(component.clone(), node_index))
252        }
253        crate::item_tree::ItemTreeNode::DynamicTree { index, .. } => {
254            let range = comp_ref_pin.as_ref().get_subtree_range(*index);
255            let component_index = subtree_child(range.start, range.end);
256            let mut child_instance = Default::default();
257            comp_ref_pin.as_ref().get_subtree(*index, component_index, &mut child_instance);
258            child_instance
259                .upgrade()
260                .map(|child_instance| wrap_around(ItemRc::new(child_instance, 0)))
261        }
262    }
263}
264
265pub enum ParentItemTraversalMode {
266    FindAllParents,
267    StopAtPopups,
268}
269
270/// A ItemRc is holding a reference to a ItemTree containing the item, and the index of this item
271#[repr(C)]
272#[derive(Clone, Debug)]
273pub struct ItemRc {
274    item_tree: vtable::VRc<ItemTreeVTable>,
275    index: u32,
276}
277
278impl ItemRc {
279    /// Create an ItemRc from a ItemTree and an index
280    pub fn new(item_tree: vtable::VRc<ItemTreeVTable>, index: u32) -> Self {
281        Self { item_tree, index }
282    }
283
284    pub fn is_root_item_of(&self, item_tree: &VRc<ItemTreeVTable>) -> bool {
285        self.index == 0 && VRc::ptr_eq(&self.item_tree, item_tree)
286    }
287
288    /// Return a `Pin<ItemRef<'a>>`
289    pub fn borrow<'a>(&'a self) -> Pin<ItemRef<'a>> {
290        #![allow(unsafe_code)]
291        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
292        let result = comp_ref_pin.as_ref().get_item_ref(self.index);
293        // Safety: we can expand the lifetime of the ItemRef because we know it lives for at least the
294        // lifetime of the ItemTree, which is 'a.  Pin::as_ref removes the lifetime, but we can just put it back.
295        unsafe { core::mem::transmute::<Pin<ItemRef<'_>>, Pin<ItemRef<'a>>>(result) }
296    }
297
298    /// Returns a `VRcMapped` of this item, to conveniently access specialized item API.
299    pub fn downcast<T: HasStaticVTable<ItemVTable>>(&self) -> Option<VRcMapped<ItemTreeVTable, T>> {
300        #![allow(unsafe_code)]
301        let item = self.borrow();
302        ItemRef::downcast_pin::<T>(item)?;
303
304        Some(vtable::VRc::map_dyn(self.item_tree.clone(), |comp_ref_pin| {
305            let result = comp_ref_pin.as_ref().get_item_ref(self.index);
306            // Safety: we can expand the lifetime of the ItemRef because we know it lives for at least the
307            // lifetime of the ItemTree, which is 'a.  Pin::as_ref removes the lifetime, but we can just put it back.
308            let item =
309                unsafe { core::mem::transmute::<Pin<ItemRef<'_>>, Pin<ItemRef<'_>>>(result) };
310            ItemRef::downcast_pin::<T>(item).unwrap()
311        }))
312    }
313
314    pub fn downgrade(&self) -> ItemWeak {
315        ItemWeak { item_tree: VRc::downgrade(&self.item_tree), index: self.index }
316    }
317
318    /// Return the parent Item in the item tree.
319    ///
320    /// If the item is a the root on its Window or PopupWindow, then the parent is None.
321    pub fn parent_item(&self, find_mode: ParentItemTraversalMode) -> Option<ItemRc> {
322        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
323        let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
324
325        if let Some(parent_index) = item_tree.parent(self.index) {
326            return Some(ItemRc::new(self.item_tree.clone(), parent_index));
327        }
328
329        let mut r = ItemWeak::default();
330        comp_ref_pin.as_ref().parent_node(&mut r);
331        let parent = r.upgrade()?;
332        let comp_ref_pin = vtable::VRc::borrow_pin(&parent.item_tree);
333        let item_tree_array = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
334        if let Some(ItemTreeNode::DynamicTree { parent_index, .. }) =
335            item_tree_array.get(parent.index())
336        {
337            // parent_node returns the repeater node, go up one more level!
338            Some(ItemRc::new(parent.item_tree.clone(), *parent_index))
339        } else {
340            // the Item was most likely a PopupWindow and we don't want to return the item for the purpose of this call
341            // (eg, focus/geometry/...)
342            match find_mode {
343                ParentItemTraversalMode::FindAllParents => Some(parent),
344                ParentItemTraversalMode::StopAtPopups => None,
345            }
346        }
347    }
348
349    /// Returns true if this item is visible from the root of the item tree. Note that this will return
350    /// false for `Clip` elements with the `clip` property evaluating to true.
351    pub fn is_visible(&self) -> bool {
352        let (clip, geometry) = self.absolute_clip_rect_and_geometry();
353        let clip = clip.to_box2d();
354        let geometry = geometry.to_box2d();
355        !clip.is_empty()
356            && clip.max.x >= geometry.min.x
357            && clip.max.y >= geometry.min.y
358            && clip.min.x <= geometry.max.x
359            && clip.min.y <= geometry.max.y
360    }
361
362    /// Returns the clip rect that applies to this item (in window coordinates) as well as the
363    /// item's (unclipped) geometry (also in window coordinates).
364    fn absolute_clip_rect_and_geometry(&self) -> (LogicalRect, LogicalRect) {
365        let (mut clip, parent_geometry) =
366            self.parent_item(ParentItemTraversalMode::StopAtPopups).map_or_else(
367                || {
368                    (
369                        LogicalRect::from_size((crate::Coord::MAX, crate::Coord::MAX).into()),
370                        Default::default(),
371                    )
372                },
373                |parent| parent.absolute_clip_rect_and_geometry(),
374            );
375
376        let geometry = self.geometry().translate(parent_geometry.origin.to_vector());
377
378        let item = self.borrow();
379        if item.as_ref().clips_children() {
380            clip = geometry.intersection(&clip).unwrap_or_default();
381        }
382
383        (clip, geometry)
384    }
385
386    pub fn is_accessible(&self) -> bool {
387        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
388        let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
389
390        if let Some(n) = &item_tree.get(self.index) {
391            match n {
392                ItemTreeNode::Item { is_accessible, .. } => *is_accessible,
393                ItemTreeNode::DynamicTree { .. } => false,
394            }
395        } else {
396            false
397        }
398    }
399
400    pub fn accessible_role(&self) -> crate::items::AccessibleRole {
401        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
402        comp_ref_pin.as_ref().accessible_role(self.index)
403    }
404
405    pub fn accessible_string_property(
406        &self,
407        what: crate::accessibility::AccessibleStringProperty,
408    ) -> Option<SharedString> {
409        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
410        let mut result = Default::default();
411        let ok = comp_ref_pin.as_ref().accessible_string_property(self.index, what, &mut result);
412        ok.then_some(result)
413    }
414
415    pub fn accessible_action(&self, action: &crate::accessibility::AccessibilityAction) {
416        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
417        comp_ref_pin.as_ref().accessibility_action(self.index, action);
418    }
419
420    pub fn supported_accessibility_actions(&self) -> SupportedAccessibilityAction {
421        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
422        comp_ref_pin.as_ref().supported_accessibility_actions(self.index)
423    }
424
425    pub fn element_count(&self) -> Option<usize> {
426        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
427        let mut result = SharedString::new();
428        comp_ref_pin
429            .as_ref()
430            .item_element_infos(self.index, &mut result)
431            .then(|| result.as_str().split("/").count())
432    }
433
434    pub fn element_type_names_and_ids(
435        &self,
436        element_index: usize,
437    ) -> Option<Vec<(SharedString, SharedString)>> {
438        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
439        let mut result = SharedString::new();
440        comp_ref_pin.as_ref().item_element_infos(self.index, &mut result).then(|| {
441            result
442                .as_str()
443                .split("/")
444                .nth(element_index)
445                .unwrap()
446                .split(";")
447                .map(|encoded_elem_info| {
448                    let mut decoder = encoded_elem_info.split(',');
449                    let type_name = decoder.next().unwrap().into();
450                    let id = decoder.next().map(Into::into).unwrap_or_default();
451                    (type_name, id)
452                })
453                .collect()
454        })
455    }
456
457    pub fn geometry(&self) -> LogicalRect {
458        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
459        comp_ref_pin.as_ref().item_geometry(self.index)
460    }
461
462    pub fn bounding_rect(
463        &self,
464        geometry: &LogicalRect,
465        window_adapter: &WindowAdapterRc,
466    ) -> LogicalRect {
467        self.borrow().as_ref().bounding_rect(window_adapter, self, *geometry)
468    }
469
470    /// Returns an absolute position of `p` in the parent item coordinate system
471    /// (does not add this item's x and y)
472    pub fn map_to_window(&self, p: LogicalPoint) -> LogicalPoint {
473        let mut current = self.clone();
474        let mut result = p;
475        let supports_transformations = self
476            .window_adapter()
477            .map(|adapter| adapter.renderer().supports_transformations())
478            .unwrap_or(true);
479        while let Some(parent) = current.parent_item(ParentItemTraversalMode::StopAtPopups) {
480            let geometry = parent.geometry();
481            if supports_transformations {
482                if let Some(transform) = parent.children_transform() {
483                    result = transform.transform_point(result.cast()).cast();
484                }
485            }
486            result += geometry.origin.to_vector();
487            current = parent.clone();
488        }
489        result
490    }
491
492    /// Returns an absolute position of `p` in the `ItemTree`'s coordinate system
493    /// (does not add this item's x and y)
494    pub fn map_to_item_tree(
495        &self,
496        p: LogicalPoint,
497        item_tree: &vtable::VRc<ItemTreeVTable>,
498    ) -> LogicalPoint {
499        let mut current = self.clone();
500        let mut result = p;
501        if current.is_root_item_of(item_tree) {
502            return result;
503        }
504        let supports_transformations = self
505            .window_adapter()
506            .map(|adapter| adapter.renderer().supports_transformations())
507            .unwrap_or(true);
508        while let Some(parent) = current.parent_item(ParentItemTraversalMode::StopAtPopups) {
509            if parent.is_root_item_of(item_tree) {
510                break;
511            }
512            let geometry = parent.geometry();
513            if supports_transformations {
514                if let Some(transform) = parent.children_transform() {
515                    result = transform.transform_point(result.cast()).cast();
516                }
517            }
518            result += geometry.origin.to_vector();
519            current = parent.clone();
520        }
521        result
522    }
523
524    /// Return the index of the item within the ItemTree
525    pub fn index(&self) -> u32 {
526        self.index
527    }
528    /// Returns a reference to the ItemTree holding this item
529    pub fn item_tree(&self) -> &vtable::VRc<ItemTreeVTable> {
530        &self.item_tree
531    }
532
533    fn find_child(
534        &self,
535        child_access: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
536        child_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
537        subtree_child: &dyn Fn(usize, usize) -> usize,
538    ) -> Option<Self> {
539        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
540        let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
541
542        let mut current_child_index = child_access(&item_tree, self.index())?;
543        loop {
544            if let Some(item) = step_into_node(
545                self.item_tree(),
546                &comp_ref_pin,
547                current_child_index,
548                &item_tree,
549                subtree_child,
550                &core::convert::identity,
551            ) {
552                return Some(item);
553            }
554            current_child_index = child_step(&item_tree, current_child_index)?;
555        }
556    }
557
558    /// The first child Item of this Item
559    pub fn first_child(&self) -> Option<Self> {
560        self.find_child(
561            &|item_tree, index| item_tree.first_child(index),
562            &|item_tree, index| item_tree.next_sibling(index),
563            &|start, _| start,
564        )
565    }
566
567    /// The last child Item of this Item
568    pub fn last_child(&self) -> Option<Self> {
569        self.find_child(
570            &|item_tree, index| item_tree.last_child(index),
571            &|item_tree, index| item_tree.previous_sibling(index),
572            &|_, end| end.wrapping_sub(1),
573        )
574    }
575
576    fn find_sibling(
577        &self,
578        sibling_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
579        subtree_step: &dyn Fn(usize) -> usize,
580        subtree_child: &dyn Fn(usize, usize) -> usize,
581    ) -> Option<Self> {
582        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
583        if self.index == 0 {
584            let mut parent_item = Default::default();
585            comp_ref_pin.as_ref().parent_node(&mut parent_item);
586            let current_component_subtree_index = comp_ref_pin.as_ref().subtree_index();
587            if let Some(parent_item) = parent_item.upgrade() {
588                let parent = parent_item.item_tree();
589                let parent_ref_pin = vtable::VRc::borrow_pin(parent);
590                let parent_item_index = parent_item.index();
591                let parent_item_tree = crate::item_tree::ItemTreeNodeArray::new(&parent_ref_pin);
592
593                let subtree_index = match parent_item_tree.get(parent_item_index)? {
594                    crate::item_tree::ItemTreeNode::Item { .. } => {
595                        // Popups can trigger this case!
596                        return None;
597                    }
598                    crate::item_tree::ItemTreeNode::DynamicTree { index, .. } => *index,
599                };
600
601                let next_subtree_index = subtree_step(current_component_subtree_index);
602
603                // Get next subtree from repeater!
604                let mut next_subtree_instance = Default::default();
605                parent_ref_pin.as_ref().get_subtree(
606                    subtree_index,
607                    next_subtree_index,
608                    &mut next_subtree_instance,
609                );
610                if let Some(next_subtree_instance) = next_subtree_instance.upgrade() {
611                    return Some(ItemRc::new(next_subtree_instance, 0));
612                }
613
614                // We need to leave the repeater:
615                find_sibling_outside_repeater(
616                    parent,
617                    parent_ref_pin,
618                    parent_item_index,
619                    sibling_step,
620                    subtree_child,
621                )
622            } else {
623                None // At root if the item tree
624            }
625        } else {
626            find_sibling_outside_repeater(
627                self.item_tree(),
628                comp_ref_pin,
629                self.index(),
630                sibling_step,
631                subtree_child,
632            )
633        }
634    }
635
636    /// The previous sibling of this Item
637    pub fn previous_sibling(&self) -> Option<Self> {
638        self.find_sibling(
639            &|item_tree, index| item_tree.previous_sibling(index),
640            &|index| index.wrapping_sub(1),
641            &|_, end| end.wrapping_sub(1),
642        )
643    }
644
645    /// The next sibling of this Item
646    pub fn next_sibling(&self) -> Option<Self> {
647        self.find_sibling(
648            &|item_tree, index| item_tree.next_sibling(index),
649            &|index| index.saturating_add(1),
650            &|start, _| start,
651        )
652    }
653
654    fn move_focus(
655        &self,
656        focus_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
657        subtree_step: &dyn Fn(ItemRc) -> Option<ItemRc>,
658        subtree_child: &dyn Fn(usize, usize) -> usize,
659        step_in: &dyn Fn(ItemRc) -> ItemRc,
660        step_out: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
661    ) -> Self {
662        let mut component = self.item_tree().clone();
663        let mut comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
664        let mut item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
665
666        let mut to_focus = self.index();
667
668        'in_tree: loop {
669            if let Some(next) = focus_step(&item_tree, to_focus) {
670                if let Some(item) = step_into_node(
671                    &component,
672                    &comp_ref_pin,
673                    next,
674                    &item_tree,
675                    subtree_child,
676                    step_in,
677                ) {
678                    return item;
679                }
680                to_focus = next;
681                // Loop: We stepped into an empty repeater!
682            } else {
683                // Step out of this component:
684                let mut root = ItemRc::new(component, 0);
685                if let Some(item) = subtree_step(root.clone()) {
686                    // Next component inside same repeater
687                    return step_in(item);
688                }
689
690                // Step out of the repeater
691                let root_component = root.item_tree();
692                let root_comp_ref = vtable::VRc::borrow_pin(root_component);
693                let mut parent_node = Default::default();
694                root_comp_ref.as_ref().parent_node(&mut parent_node);
695
696                while let Some(parent) = parent_node.upgrade() {
697                    // .. not at the root of the item tree:
698                    component = parent.item_tree().clone();
699                    comp_ref_pin = vtable::VRc::borrow_pin(&component);
700                    item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
701
702                    let index = parent.index();
703
704                    if !matches!(item_tree.get(index), Some(ItemTreeNode::DynamicTree { .. })) {
705                        // That was not a repeater (eg, a popup window)
706                        break;
707                    }
708
709                    if let Some(next) = step_out(&item_tree, index) {
710                        if let Some(item) = step_into_node(
711                            parent.item_tree(),
712                            &comp_ref_pin,
713                            next,
714                            &item_tree,
715                            subtree_child,
716                            step_in,
717                        ) {
718                            // Step into a dynamic node
719                            return item;
720                        } else {
721                            // The dynamic node was empty, proceed in normal tree
722                            to_focus = parent.index();
723                            continue 'in_tree; // Find a node in the current (parent!) tree
724                        }
725                    }
726
727                    root = ItemRc::new(component.clone(), 0);
728                    if let Some(item) = subtree_step(root.clone()) {
729                        return step_in(item);
730                    }
731
732                    // Go up one more level:
733                    let root_component = root.item_tree();
734                    let root_comp_ref = vtable::VRc::borrow_pin(root_component);
735                    parent_node = Default::default();
736                    root_comp_ref.as_ref().parent_node(&mut parent_node);
737                }
738
739                // Loop around after hitting the root node:
740                return step_in(root);
741            }
742        }
743    }
744
745    /// Move tab focus to the previous item:
746    pub fn previous_focus_item(&self) -> Self {
747        self.move_focus(
748            &|item_tree, index| {
749                crate::item_focus::default_previous_in_local_focus_chain(index, item_tree)
750            },
751            &|root| root.previous_sibling(),
752            &|_, end| end.wrapping_sub(1),
753            &|root| {
754                let mut current = root;
755                loop {
756                    if let Some(next) = current.last_child() {
757                        current = next;
758                    } else {
759                        return current;
760                    }
761                }
762            },
763            &|item_tree, index| item_tree.parent(index),
764        )
765    }
766
767    /// Move tab focus to the next item:
768    pub fn next_focus_item(&self) -> Self {
769        self.move_focus(
770            &|item_tree, index| {
771                crate::item_focus::default_next_in_local_focus_chain(index, item_tree)
772            },
773            &|root| root.next_sibling(),
774            &|start, _| start,
775            &core::convert::identity,
776            &|item_tree, index| crate::item_focus::step_out_of_node(index, item_tree),
777        )
778    }
779
780    pub fn window_adapter(&self) -> Option<WindowAdapterRc> {
781        let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
782        let mut result = None;
783        comp_ref_pin.as_ref().window_adapter(false, &mut result);
784        result
785    }
786
787    /// Visit the children of this element and call the visitor to each of them, until the visitor returns [`ControlFlow::Break`].
788    /// When the visitor breaks, the function returns the value. If it doesn't break, the function returns None.
789    fn visit_descendants_impl<R>(
790        &self,
791        visitor: &mut impl FnMut(&ItemRc) -> ControlFlow<R>,
792    ) -> Option<R> {
793        let mut result = None;
794
795        let mut actual_visitor = |item_tree: &ItemTreeRc,
796                                  index: u32,
797                                  _item_pin: core::pin::Pin<ItemRef>|
798         -> VisitChildrenResult {
799            let item_rc = ItemRc::new(item_tree.clone(), index);
800
801            match visitor(&item_rc) {
802                ControlFlow::Continue(_) => {
803                    if let Some(x) = item_rc.visit_descendants_impl(visitor) {
804                        result = Some(x);
805                        return VisitChildrenResult::abort(index, 0);
806                    }
807                }
808                ControlFlow::Break(x) => {
809                    result = Some(x);
810                    return VisitChildrenResult::abort(index, 0);
811                }
812            }
813
814            VisitChildrenResult::CONTINUE
815        };
816        vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);
817
818        VRc::borrow_pin(self.item_tree()).as_ref().visit_children_item(
819            self.index() as isize,
820            TraversalOrder::BackToFront,
821            actual_visitor,
822        );
823
824        result
825    }
826
827    /// Visit the children of this element and call the visitor to each of them, until the visitor returns [`ControlFlow::Break`].
828    /// When the visitor breaks, the function returns the value. If it doesn't break, the function returns None.
829    pub fn visit_descendants<R>(
830        &self,
831        mut visitor: impl FnMut(&ItemRc) -> ControlFlow<R>,
832    ) -> Option<R> {
833        self.visit_descendants_impl(&mut visitor)
834    }
835
836    /// Returns the transform to apply to children to map them into the local coordinate space of this item.
837    /// Typically this is None, but rotation for example may return Some.
838    pub fn children_transform(&self) -> Option<ItemTransform> {
839        self.downcast::<crate::items::Transform>().map(|transform_item| {
840            let item = transform_item.as_pin_ref();
841            let origin = item.transform_origin().to_euclid().to_vector().cast::<f32>();
842            ItemTransform::translation(-origin.x, -origin.y)
843                .cast()
844                .then_scale(item.transform_scale_x(), item.transform_scale_y())
845                .then_rotate(euclid::Angle { radians: item.transform_rotation().to_radians() })
846                .then_translate(origin)
847        })
848    }
849
850    /// Returns the inverse of the children transform.
851    ///
852    /// None if children_transform is None or in the case of
853    /// non-invertible transforms (which should be extremely rare).
854    pub fn inverse_children_transform(&self) -> Option<ItemTransform> {
855        self.children_transform()
856            // Should practically always be possible.
857            .and_then(|child_transform| child_transform.inverse())
858    }
859}
860
861impl PartialEq for ItemRc {
862    fn eq(&self, other: &Self) -> bool {
863        VRc::ptr_eq(&self.item_tree, &other.item_tree) && self.index == other.index
864    }
865}
866
867impl Eq for ItemRc {}
868
869/// A Weak reference to an item that can be constructed from an ItemRc.
870#[derive(Clone, Default)]
871#[repr(C)]
872pub struct ItemWeak {
873    item_tree: crate::item_tree::ItemTreeWeak,
874    index: u32,
875}
876
877impl ItemWeak {
878    pub fn upgrade(&self) -> Option<ItemRc> {
879        self.item_tree.upgrade().map(|c| ItemRc::new(c, self.index))
880    }
881}
882
883impl PartialEq for ItemWeak {
884    fn eq(&self, other: &Self) -> bool {
885        VWeak::ptr_eq(&self.item_tree, &other.item_tree) && self.index == other.index
886    }
887}
888
889impl Eq for ItemWeak {}
890
891#[repr(u8)]
892#[derive(Debug, Copy, Clone, Eq, PartialEq)]
893pub enum TraversalOrder {
894    BackToFront,
895    FrontToBack,
896}
897
898/// The return value of the ItemTree::visit_children_item function
899///
900/// Represents something like `enum { Continue, Aborted{aborted_at_item: isize} }`.
901/// But this is just wrapping a int because it is easier to use ffi with isize than
902/// complex enum.
903///
904/// -1 means the visitor will continue
905/// otherwise this is the index of the item that aborted the visit.
906#[repr(transparent)]
907#[derive(Copy, Clone, Eq, PartialEq)]
908pub struct VisitChildrenResult(u64);
909impl VisitChildrenResult {
910    /// The result used for a visitor that want to continue the visit
911    pub const CONTINUE: Self = Self(u64::MAX);
912
913    /// Returns a result that means that the visitor must stop, and convey the item that caused the abort
914    pub fn abort(item_index: u32, index_within_repeater: usize) -> Self {
915        assert!(index_within_repeater < u32::MAX as usize);
916        Self(item_index as u64 | (index_within_repeater as u64) << 32)
917    }
918    /// True if the visitor wants to abort the visit
919    pub fn has_aborted(&self) -> bool {
920        self.0 != Self::CONTINUE.0
921    }
922    pub fn aborted_index(&self) -> Option<usize> {
923        if self.0 != Self::CONTINUE.0 {
924            Some((self.0 & 0xffff_ffff) as usize)
925        } else {
926            None
927        }
928    }
929    pub fn aborted_indexes(&self) -> Option<(usize, usize)> {
930        if self.0 != Self::CONTINUE.0 {
931            Some(((self.0 & 0xffff_ffff) as usize, (self.0 >> 32) as usize))
932        } else {
933            None
934        }
935    }
936}
937impl core::fmt::Debug for VisitChildrenResult {
938    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
939        if self.0 == Self::CONTINUE.0 {
940            write!(f, "CONTINUE")
941        } else {
942            write!(f, "({},{})", (self.0 & 0xffff_ffff) as usize, (self.0 >> 32) as usize)
943        }
944    }
945}
946
947/// The item tree is an array of ItemTreeNode representing a static tree of items
948/// within a ItemTree.
949#[repr(u8)]
950#[derive(Debug)]
951pub enum ItemTreeNode {
952    /// Static item
953    Item {
954        /// True when the item has accessibility properties attached
955        is_accessible: bool,
956
957        /// number of children
958        children_count: u32,
959
960        /// index of the first children within the item tree
961        children_index: u32,
962
963        /// The index of the parent item (not valid for the root)
964        parent_index: u32,
965
966        /// The index in the extra item_array
967        item_array_index: u32,
968    },
969    /// A placeholder for many instance of item in their own ItemTree which
970    /// are instantiated according to a model.
971    DynamicTree {
972        /// the index which is passed in the visit_dynamic callback.
973        index: u32,
974
975        /// The index of the parent item (not valid for the root)
976        parent_index: u32,
977    },
978}
979
980impl ItemTreeNode {
981    pub fn parent_index(&self) -> u32 {
982        match self {
983            ItemTreeNode::Item { parent_index, .. } => *parent_index,
984            ItemTreeNode::DynamicTree { parent_index, .. } => *parent_index,
985        }
986    }
987}
988
989/// The `ItemTreeNodeArray` provides tree walking code for the physical ItemTree stored in
990/// a `ItemTree` without stitching any inter-ItemTree links together!
991pub struct ItemTreeNodeArray<'a> {
992    node_array: &'a [ItemTreeNode],
993}
994
995impl<'a> ItemTreeNodeArray<'a> {
996    /// Create a new `ItemTree` from its raw data.
997    pub fn new(comp_ref_pin: &'a Pin<VRef<'a, ItemTreeVTable>>) -> Self {
998        Self { node_array: comp_ref_pin.as_ref().get_item_tree().as_slice() }
999    }
1000
1001    /// Get a ItemTreeNode
1002    pub fn get(&self, index: u32) -> Option<&ItemTreeNode> {
1003        self.node_array.get(index as usize)
1004    }
1005
1006    /// Get the parent of a node, returns `None` if this is the root node of this item tree.
1007    pub fn parent(&self, index: u32) -> Option<u32> {
1008        let index = index as usize;
1009        (index < self.node_array.len() && index != 0).then(|| self.node_array[index].parent_index())
1010    }
1011
1012    /// Returns the next sibling or `None` if this is the last sibling.
1013    pub fn next_sibling(&self, index: u32) -> Option<u32> {
1014        if let Some(parent_index) = self.parent(index) {
1015            match self.node_array[parent_index as usize] {
1016                ItemTreeNode::Item { children_index, children_count, .. } => {
1017                    (index < (children_count + children_index - 1)).then_some(index + 1)
1018                }
1019                ItemTreeNode::DynamicTree { .. } => {
1020                    unreachable!("Parent in same item tree is a repeater.")
1021                }
1022            }
1023        } else {
1024            None // No parent, so we have no siblings either:-)
1025        }
1026    }
1027
1028    /// Returns the previous sibling or `None` if this is the first sibling.
1029    pub fn previous_sibling(&self, index: u32) -> Option<u32> {
1030        if let Some(parent_index) = self.parent(index) {
1031            match self.node_array[parent_index as usize] {
1032                ItemTreeNode::Item { children_index, .. } => {
1033                    (index > children_index).then_some(index - 1)
1034                }
1035                ItemTreeNode::DynamicTree { .. } => {
1036                    unreachable!("Parent in same item tree is a repeater.")
1037                }
1038            }
1039        } else {
1040            None // No parent, so we have no siblings either:-)
1041        }
1042    }
1043
1044    /// Returns the first child or `None` if this are no children or the `index`
1045    /// points to a `DynamicTree`.
1046    pub fn first_child(&self, index: u32) -> Option<u32> {
1047        match self.node_array.get(index as usize)? {
1048            ItemTreeNode::Item { children_index, children_count, .. } => {
1049                (*children_count != 0).then_some(*children_index as _)
1050            }
1051            ItemTreeNode::DynamicTree { .. } => None,
1052        }
1053    }
1054
1055    /// Returns the last child or `None` if this are no children or the `index`
1056    /// points to an `DynamicTree`.
1057    pub fn last_child(&self, index: u32) -> Option<u32> {
1058        match self.node_array.get(index as usize)? {
1059            ItemTreeNode::Item { children_index, children_count, .. } => {
1060                if *children_count != 0 {
1061                    Some(*children_index + *children_count - 1)
1062                } else {
1063                    None
1064                }
1065            }
1066            ItemTreeNode::DynamicTree { .. } => None,
1067        }
1068    }
1069
1070    /// Returns the number of nodes in the `ItemTreeNodeArray`
1071    pub fn node_count(&self) -> usize {
1072        self.node_array.len()
1073    }
1074}
1075
1076impl<'a> From<&'a [ItemTreeNode]> for ItemTreeNodeArray<'a> {
1077    fn from(item_tree: &'a [ItemTreeNode]) -> Self {
1078        Self { node_array: item_tree }
1079    }
1080}
1081
1082#[cfg_attr(not(feature = "ffi"), i_slint_core_macros::remove_extern)]
1083#[vtable]
1084#[repr(C)]
1085/// Object to be passed in visit_item_children method of the ItemTree.
1086pub struct ItemVisitorVTable {
1087    /// Called for each child of the visited item
1088    ///
1089    /// The `item_tree` parameter is the ItemTree in which the item live which might not be the same
1090    /// as the parent's ItemTree.
1091    /// `index` is to be used again in the visit_item_children function of the ItemTree (the one passed as parameter)
1092    /// and `item` is a reference to the item itself
1093    visit_item: extern "C" fn(
1094        VRefMut<ItemVisitorVTable>,
1095        item_tree: &VRc<ItemTreeVTable, vtable::Dyn>,
1096        index: u32,
1097        item: Pin<VRef<ItemVTable>>,
1098    ) -> VisitChildrenResult,
1099    /// Destructor
1100    drop: extern "C" fn(VRefMut<ItemVisitorVTable>),
1101}
1102
1103/// Type alias to `vtable::VRefMut<ItemVisitorVTable>`
1104pub type ItemVisitorRefMut<'a> = vtable::VRefMut<'a, ItemVisitorVTable>;
1105
1106impl<T: FnMut(&ItemTreeRc, u32, Pin<ItemRef>) -> VisitChildrenResult> ItemVisitor for T {
1107    fn visit_item(
1108        &mut self,
1109        item_tree: &ItemTreeRc,
1110        index: u32,
1111        item: Pin<ItemRef>,
1112    ) -> VisitChildrenResult {
1113        self(item_tree, index, item)
1114    }
1115}
1116pub enum ItemVisitorResult<State> {
1117    Continue(State),
1118    SkipChildren,
1119    Abort,
1120}
1121
1122/// Visit each items recursively
1123///
1124/// The state parameter returned by the visitor is passed to each child.
1125///
1126/// Returns the index of the item that cancelled, or -1 if nobody cancelled
1127pub fn visit_items<State>(
1128    item_tree: &ItemTreeRc,
1129    order: TraversalOrder,
1130    mut visitor: impl FnMut(&ItemTreeRc, Pin<ItemRef>, u32, &State) -> ItemVisitorResult<State>,
1131    state: State,
1132) -> VisitChildrenResult {
1133    visit_internal(item_tree, order, &mut visitor, -1, &state)
1134}
1135
1136fn visit_internal<State>(
1137    item_tree: &ItemTreeRc,
1138    order: TraversalOrder,
1139    visitor: &mut impl FnMut(&ItemTreeRc, Pin<ItemRef>, u32, &State) -> ItemVisitorResult<State>,
1140    index: isize,
1141    state: &State,
1142) -> VisitChildrenResult {
1143    let mut actual_visitor =
1144        |item_tree: &ItemTreeRc, index: u32, item: Pin<ItemRef>| -> VisitChildrenResult {
1145            match visitor(item_tree, item, index, state) {
1146                ItemVisitorResult::Continue(state) => {
1147                    visit_internal(item_tree, order, visitor, index as isize, &state)
1148                }
1149                ItemVisitorResult::SkipChildren => VisitChildrenResult::CONTINUE,
1150                ItemVisitorResult::Abort => VisitChildrenResult::abort(index, 0),
1151            }
1152        };
1153    vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);
1154    VRc::borrow_pin(item_tree).as_ref().visit_children_item(index, order, actual_visitor)
1155}
1156
1157/// Visit the children within an array of ItemTreeNode
1158///
1159/// The dynamic visitor is called for the dynamic nodes, its signature is
1160/// `fn(base: &Base, visitor: vtable::VRefMut<ItemVisitorVTable>, dyn_index: usize)`
1161///
1162/// FIXME: the design of this use lots of indirection and stack frame in recursive functions
1163/// Need to check if the compiler is able to optimize away some of it.
1164/// Possibly we should generate code that directly call the visitor instead
1165pub fn visit_item_tree<Base>(
1166    base: Pin<&Base>,
1167    item_tree: &ItemTreeRc,
1168    item_tree_array: &[ItemTreeNode],
1169    index: isize,
1170    order: TraversalOrder,
1171    mut visitor: vtable::VRefMut<ItemVisitorVTable>,
1172    visit_dynamic: impl Fn(
1173        Pin<&Base>,
1174        TraversalOrder,
1175        vtable::VRefMut<ItemVisitorVTable>,
1176        u32,
1177    ) -> VisitChildrenResult,
1178) -> VisitChildrenResult {
1179    let mut visit_at_index = |idx: u32| -> VisitChildrenResult {
1180        match &item_tree_array[idx as usize] {
1181            ItemTreeNode::Item { .. } => {
1182                let item = crate::items::ItemRc::new(item_tree.clone(), idx);
1183                visitor.visit_item(item_tree, idx, item.borrow())
1184            }
1185            ItemTreeNode::DynamicTree { index, .. } => {
1186                if let Some(sub_idx) =
1187                    visit_dynamic(base, order, visitor.borrow_mut(), *index).aborted_index()
1188                {
1189                    VisitChildrenResult::abort(idx, sub_idx)
1190                } else {
1191                    VisitChildrenResult::CONTINUE
1192                }
1193            }
1194        }
1195    };
1196    if index == -1 {
1197        visit_at_index(0)
1198    } else {
1199        match &item_tree_array[index as usize] {
1200            ItemTreeNode::Item { children_index, children_count, .. } => {
1201                for c in 0..*children_count {
1202                    let idx = match order {
1203                        TraversalOrder::BackToFront => *children_index + c,
1204                        TraversalOrder::FrontToBack => *children_index + *children_count - c - 1,
1205                    };
1206                    let maybe_abort_index = visit_at_index(idx);
1207                    if maybe_abort_index.has_aborted() {
1208                        return maybe_abort_index;
1209                    }
1210                }
1211            }
1212            ItemTreeNode::DynamicTree { .. } => panic!("should not be called with dynamic items"),
1213        };
1214        VisitChildrenResult::CONTINUE
1215    }
1216}
1217
1218#[cfg(feature = "ffi")]
1219pub(crate) mod ffi {
1220    #![allow(unsafe_code)]
1221
1222    use super::*;
1223    use core::ffi::c_void;
1224
1225    /// Call init() on the ItemVTable of each item in the item array.
1226    #[unsafe(no_mangle)]
1227    pub unsafe extern "C" fn slint_register_item_tree(
1228        item_tree_rc: &ItemTreeRc,
1229        window_handle: *const crate::window::ffi::WindowAdapterRcOpaque,
1230    ) {
1231        let window_adapter = (window_handle as *const WindowAdapterRc).as_ref().cloned();
1232        super::register_item_tree(item_tree_rc, window_adapter)
1233    }
1234
1235    /// Free the backend graphics resources allocated in the item array.
1236    #[unsafe(no_mangle)]
1237    pub unsafe extern "C" fn slint_unregister_item_tree(
1238        component: ItemTreeRefPin,
1239        item_array: Slice<vtable::VOffset<u8, ItemVTable, vtable::AllowPin>>,
1240        window_handle: *const crate::window::ffi::WindowAdapterRcOpaque,
1241    ) {
1242        let window_adapter = &*(window_handle as *const WindowAdapterRc);
1243        super::unregister_item_tree(
1244            core::pin::Pin::new_unchecked(&*(component.as_ptr() as *const u8)),
1245            core::pin::Pin::into_inner(component),
1246            item_array.as_slice(),
1247            window_adapter,
1248        )
1249    }
1250
1251    /// Expose `crate::item_tree::visit_item_tree` to C++
1252    ///
1253    /// Safety: Assume a correct implementation of the item_tree array
1254    #[unsafe(no_mangle)]
1255    pub unsafe extern "C" fn slint_visit_item_tree(
1256        item_tree: &ItemTreeRc,
1257        item_tree_array: Slice<ItemTreeNode>,
1258        index: isize,
1259        order: TraversalOrder,
1260        visitor: VRefMut<ItemVisitorVTable>,
1261        visit_dynamic: extern "C" fn(
1262            base: *const c_void,
1263            order: TraversalOrder,
1264            visitor: vtable::VRefMut<ItemVisitorVTable>,
1265            dyn_index: u32,
1266        ) -> VisitChildrenResult,
1267    ) -> VisitChildrenResult {
1268        crate::item_tree::visit_item_tree(
1269            VRc::as_pin_ref(item_tree),
1270            item_tree,
1271            item_tree_array.as_slice(),
1272            index,
1273            order,
1274            visitor,
1275            |a, b, c, d| visit_dynamic(a.get_ref() as *const vtable::Dyn as *const c_void, b, c, d),
1276        )
1277    }
1278}
1279
1280#[cfg(test)]
1281mod tests {
1282    use super::*;
1283    use std::vec;
1284
1285    struct TestItemTree {
1286        parent_component: Option<ItemTreeRc>,
1287        item_tree: Vec<ItemTreeNode>,
1288        subtrees: std::cell::RefCell<Vec<Vec<vtable::VRc<ItemTreeVTable, TestItemTree>>>>,
1289        subtree_index: usize,
1290    }
1291
1292    impl ItemTree for TestItemTree {
1293        fn visit_children_item(
1294            self: core::pin::Pin<&Self>,
1295            _1: isize,
1296            _2: crate::item_tree::TraversalOrder,
1297            _3: vtable::VRefMut<crate::item_tree::ItemVisitorVTable>,
1298        ) -> crate::item_tree::VisitChildrenResult {
1299            unimplemented!("Not needed for this test")
1300        }
1301
1302        fn get_item_ref(
1303            self: core::pin::Pin<&Self>,
1304            _1: u32,
1305        ) -> core::pin::Pin<vtable::VRef<'_, super::ItemVTable>> {
1306            unimplemented!("Not needed for this test")
1307        }
1308
1309        fn get_item_tree(self: core::pin::Pin<&Self>) -> Slice<'_, ItemTreeNode> {
1310            Slice::from_slice(&self.get_ref().item_tree)
1311        }
1312
1313        fn parent_node(self: core::pin::Pin<&Self>, result: &mut ItemWeak) {
1314            if let Some(parent_item) = self.parent_component.clone() {
1315                *result =
1316                    ItemRc::new(parent_item.clone(), self.item_tree[0].parent_index()).downgrade();
1317            }
1318        }
1319
1320        fn embed_component(
1321            self: core::pin::Pin<&Self>,
1322            _parent_component: &ItemTreeWeak,
1323            _item_tree_index: u32,
1324        ) -> bool {
1325            false
1326        }
1327
1328        fn layout_info(self: core::pin::Pin<&Self>, _1: Orientation) -> LayoutInfo {
1329            unimplemented!("Not needed for this test")
1330        }
1331
1332        fn subtree_index(self: core::pin::Pin<&Self>) -> usize {
1333            self.subtree_index
1334        }
1335
1336        fn get_subtree_range(self: core::pin::Pin<&Self>, subtree_index: u32) -> IndexRange {
1337            (0..self.subtrees.borrow()[subtree_index as usize].len()).into()
1338        }
1339
1340        fn get_subtree(
1341            self: core::pin::Pin<&Self>,
1342            subtree_index: u32,
1343            component_index: usize,
1344            result: &mut ItemTreeWeak,
1345        ) {
1346            if let Some(vrc) = self.subtrees.borrow()[subtree_index as usize].get(component_index) {
1347                *result = vtable::VRc::downgrade(&vtable::VRc::into_dyn(vrc.clone()))
1348            }
1349        }
1350
1351        fn accessible_role(self: Pin<&Self>, _: u32) -> AccessibleRole {
1352            unimplemented!("Not needed for this test")
1353        }
1354
1355        fn accessible_string_property(
1356            self: Pin<&Self>,
1357            _: u32,
1358            _: AccessibleStringProperty,
1359            _: &mut SharedString,
1360        ) -> bool {
1361            false
1362        }
1363
1364        fn item_element_infos(self: Pin<&Self>, _: u32, _: &mut SharedString) -> bool {
1365            false
1366        }
1367
1368        fn window_adapter(
1369            self: Pin<&Self>,
1370            _do_create: bool,
1371            _result: &mut Option<WindowAdapterRc>,
1372        ) {
1373            unimplemented!("Not needed for this test")
1374        }
1375
1376        fn item_geometry(self: Pin<&Self>, _: u32) -> LogicalRect {
1377            unimplemented!("Not needed for this test")
1378        }
1379
1380        fn accessibility_action(self: core::pin::Pin<&Self>, _: u32, _: &AccessibilityAction) {
1381            unimplemented!("Not needed for this test")
1382        }
1383
1384        fn supported_accessibility_actions(
1385            self: core::pin::Pin<&Self>,
1386            _: u32,
1387        ) -> SupportedAccessibilityAction {
1388            unimplemented!("Not needed for this test")
1389        }
1390    }
1391
1392    crate::item_tree::ItemTreeVTable_static!(static TEST_COMPONENT_VT for TestItemTree);
1393
1394    fn create_one_node_component() -> VRc<ItemTreeVTable, vtable::Dyn> {
1395        let component = VRc::new(TestItemTree {
1396            parent_component: None,
1397            item_tree: vec![ItemTreeNode::Item {
1398                is_accessible: false,
1399                children_count: 0,
1400                children_index: 1,
1401                parent_index: 0,
1402                item_array_index: 0,
1403            }],
1404            subtrees: std::cell::RefCell::new(vec![]),
1405            subtree_index: usize::MAX,
1406        });
1407        VRc::into_dyn(component)
1408    }
1409
1410    #[test]
1411    fn test_tree_traversal_one_node_structure() {
1412        let component = create_one_node_component();
1413
1414        let item = ItemRc::new(component.clone(), 0);
1415
1416        assert!(item.first_child().is_none());
1417        assert!(item.last_child().is_none());
1418        assert!(item.previous_sibling().is_none());
1419        assert!(item.next_sibling().is_none());
1420    }
1421
1422    #[test]
1423    fn test_tree_traversal_one_node_forward_focus() {
1424        let component = create_one_node_component();
1425
1426        let item = ItemRc::new(component.clone(), 0);
1427
1428        // Wrap the focus around:
1429        assert_eq!(item.next_focus_item(), item);
1430    }
1431
1432    #[test]
1433    fn test_tree_traversal_one_node_backward_focus() {
1434        let component = create_one_node_component();
1435
1436        let item = ItemRc::new(component.clone(), 0);
1437
1438        // Wrap the focus around:
1439        assert_eq!(item.previous_focus_item(), item);
1440    }
1441
1442    fn create_children_nodes() -> VRc<ItemTreeVTable, vtable::Dyn> {
1443        let component = VRc::new(TestItemTree {
1444            parent_component: None,
1445            item_tree: vec![
1446                ItemTreeNode::Item {
1447                    is_accessible: false,
1448                    children_count: 3,
1449                    children_index: 1,
1450                    parent_index: 0,
1451                    item_array_index: 0,
1452                },
1453                ItemTreeNode::Item {
1454                    is_accessible: false,
1455                    children_count: 0,
1456                    children_index: 4,
1457                    parent_index: 0,
1458                    item_array_index: 1,
1459                },
1460                ItemTreeNode::Item {
1461                    is_accessible: false,
1462                    children_count: 0,
1463                    children_index: 4,
1464                    parent_index: 0,
1465                    item_array_index: 2,
1466                },
1467                ItemTreeNode::Item {
1468                    is_accessible: false,
1469                    children_count: 0,
1470                    children_index: 4,
1471                    parent_index: 0,
1472                    item_array_index: 3,
1473                },
1474            ],
1475            subtrees: std::cell::RefCell::new(vec![]),
1476            subtree_index: usize::MAX,
1477        });
1478        VRc::into_dyn(component)
1479    }
1480
1481    #[test]
1482    fn test_tree_traversal_children_nodes_structure() {
1483        let component = create_children_nodes();
1484
1485        // Examine root node:
1486        let item = ItemRc::new(component.clone(), 0);
1487        assert!(item.previous_sibling().is_none());
1488        assert!(item.next_sibling().is_none());
1489
1490        let fc = item.first_child().unwrap();
1491        assert_eq!(fc.index(), 1);
1492        assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
1493
1494        let fcn = fc.next_sibling().unwrap();
1495        assert_eq!(fcn.index(), 2);
1496
1497        let lc = item.last_child().unwrap();
1498        assert_eq!(lc.index(), 3);
1499        assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
1500
1501        let lcp = lc.previous_sibling().unwrap();
1502        assert!(VRc::ptr_eq(lcp.item_tree(), item.item_tree()));
1503        assert_eq!(lcp.index(), 2);
1504
1505        // Examine first child:
1506        assert!(fc.first_child().is_none());
1507        assert!(fc.last_child().is_none());
1508        assert!(fc.previous_sibling().is_none());
1509        assert_eq!(fc.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);
1510
1511        // Examine item between first and last child:
1512        assert_eq!(fcn, lcp);
1513        assert_eq!(lcp.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);
1514        assert_eq!(fcn.previous_sibling().unwrap(), fc);
1515        assert_eq!(fcn.next_sibling().unwrap(), lc);
1516
1517        // Examine last child:
1518        assert!(lc.first_child().is_none());
1519        assert!(lc.last_child().is_none());
1520        assert!(lc.next_sibling().is_none());
1521        assert_eq!(lc.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);
1522    }
1523
1524    #[test]
1525    fn test_tree_traversal_children_nodes_forward_focus() {
1526        let component = create_children_nodes();
1527
1528        let item = ItemRc::new(component.clone(), 0);
1529        let fc = item.first_child().unwrap();
1530        let fcn = fc.next_sibling().unwrap();
1531        let lc = item.last_child().unwrap();
1532
1533        let mut cursor = item.clone();
1534
1535        cursor = cursor.next_focus_item();
1536        assert_eq!(cursor, fc);
1537
1538        cursor = cursor.next_focus_item();
1539        assert_eq!(cursor, fcn);
1540
1541        cursor = cursor.next_focus_item();
1542        assert_eq!(cursor, lc);
1543
1544        cursor = cursor.next_focus_item();
1545        assert_eq!(cursor, item);
1546    }
1547
1548    #[test]
1549    fn test_tree_traversal_children_nodes_backward_focus() {
1550        let component = create_children_nodes();
1551
1552        let item = ItemRc::new(component.clone(), 0);
1553        let fc = item.first_child().unwrap();
1554        let fcn = fc.next_sibling().unwrap();
1555        let lc = item.last_child().unwrap();
1556
1557        let mut cursor = item.clone();
1558
1559        cursor = cursor.previous_focus_item();
1560        assert_eq!(cursor, lc);
1561
1562        cursor = cursor.previous_focus_item();
1563        assert_eq!(cursor, fcn);
1564
1565        cursor = cursor.previous_focus_item();
1566        assert_eq!(cursor, fc);
1567
1568        cursor = cursor.previous_focus_item();
1569        assert_eq!(cursor, item);
1570    }
1571
1572    fn create_empty_subtree() -> VRc<ItemTreeVTable, vtable::Dyn> {
1573        let component = vtable::VRc::new(TestItemTree {
1574            parent_component: None,
1575            item_tree: vec![
1576                ItemTreeNode::Item {
1577                    is_accessible: false,
1578                    children_count: 1,
1579                    children_index: 1,
1580                    parent_index: 0,
1581                    item_array_index: 0,
1582                },
1583                ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1584            ],
1585            subtrees: std::cell::RefCell::new(vec![vec![]]),
1586            subtree_index: usize::MAX,
1587        });
1588        vtable::VRc::into_dyn(component)
1589    }
1590
1591    #[test]
1592    fn test_tree_traversal_empty_subtree_structure() {
1593        let component = create_empty_subtree();
1594
1595        // Examine root node:
1596        let item = ItemRc::new(component.clone(), 0);
1597        assert!(item.previous_sibling().is_none());
1598        assert!(item.next_sibling().is_none());
1599        assert!(item.first_child().is_none());
1600        assert!(item.last_child().is_none());
1601
1602        // Wrap the focus around:
1603        assert!(item.previous_focus_item() == item);
1604        assert!(item.next_focus_item() == item);
1605    }
1606
1607    #[test]
1608    fn test_tree_traversal_empty_subtree_forward_focus() {
1609        let component = create_empty_subtree();
1610
1611        // Examine root node:
1612        let item = ItemRc::new(component.clone(), 0);
1613
1614        assert!(item.next_focus_item() == item);
1615    }
1616
1617    #[test]
1618    fn test_tree_traversal_empty_subtree_backward_focus() {
1619        let component = create_empty_subtree();
1620
1621        // Examine root node:
1622        let item = ItemRc::new(component.clone(), 0);
1623
1624        assert!(item.previous_focus_item() == item);
1625    }
1626
1627    fn create_item_subtree_item() -> VRc<ItemTreeVTable, vtable::Dyn> {
1628        let component = VRc::new(TestItemTree {
1629            parent_component: None,
1630            item_tree: vec![
1631                ItemTreeNode::Item {
1632                    is_accessible: false,
1633                    children_count: 3,
1634                    children_index: 1,
1635                    parent_index: 0,
1636                    item_array_index: 0,
1637                },
1638                ItemTreeNode::Item {
1639                    is_accessible: false,
1640                    children_count: 0,
1641                    children_index: 4,
1642                    parent_index: 0,
1643                    item_array_index: 0,
1644                },
1645                ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1646                ItemTreeNode::Item {
1647                    is_accessible: false,
1648                    children_count: 0,
1649                    children_index: 4,
1650                    parent_index: 0,
1651                    item_array_index: 0,
1652                },
1653            ],
1654            subtrees: std::cell::RefCell::new(vec![]),
1655            subtree_index: usize::MAX,
1656        });
1657
1658        component.as_pin_ref().subtrees.replace(vec![vec![VRc::new(TestItemTree {
1659            parent_component: Some(VRc::into_dyn(component.clone())),
1660            item_tree: vec![ItemTreeNode::Item {
1661                is_accessible: false,
1662                children_count: 0,
1663                children_index: 1,
1664                parent_index: 2,
1665                item_array_index: 0,
1666            }],
1667            subtrees: std::cell::RefCell::new(vec![]),
1668            subtree_index: 0,
1669        })]]);
1670
1671        VRc::into_dyn(component)
1672    }
1673
1674    #[test]
1675    fn test_tree_traversal_item_subtree_item_structure() {
1676        let component = create_item_subtree_item();
1677
1678        // Examine root node:
1679        let item = ItemRc::new(component.clone(), 0);
1680        assert!(item.previous_sibling().is_none());
1681        assert!(item.next_sibling().is_none());
1682
1683        let fc = item.first_child().unwrap();
1684        assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
1685        assert_eq!(fc.index(), 1);
1686
1687        let lc = item.last_child().unwrap();
1688        assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
1689        assert_eq!(lc.index(), 3);
1690
1691        let fcn = fc.next_sibling().unwrap();
1692        let lcp = lc.previous_sibling().unwrap();
1693
1694        assert_eq!(fcn, lcp);
1695        assert!(!VRc::ptr_eq(fcn.item_tree(), item.item_tree()));
1696
1697        let last = fcn.next_sibling().unwrap();
1698        assert_eq!(last, lc);
1699
1700        let first = lcp.previous_sibling().unwrap();
1701        assert_eq!(first, fc);
1702    }
1703
1704    #[test]
1705    fn test_tree_traversal_item_subtree_item_forward_focus() {
1706        let component = create_item_subtree_item();
1707
1708        let item = ItemRc::new(component.clone(), 0);
1709        let fc = item.first_child().unwrap();
1710        let lc = item.last_child().unwrap();
1711        let fcn = fc.next_sibling().unwrap();
1712
1713        let mut cursor = item.clone();
1714
1715        cursor = cursor.next_focus_item();
1716        assert_eq!(cursor, fc);
1717
1718        cursor = cursor.next_focus_item();
1719        assert_eq!(cursor, fcn);
1720
1721        cursor = cursor.next_focus_item();
1722        assert_eq!(cursor, lc);
1723
1724        cursor = cursor.next_focus_item();
1725        assert_eq!(cursor, item);
1726    }
1727
1728    #[test]
1729    fn test_tree_traversal_item_subtree_item_backward_focus() {
1730        let component = create_item_subtree_item();
1731
1732        let item = ItemRc::new(component.clone(), 0);
1733        let fc = item.first_child().unwrap();
1734        let lc = item.last_child().unwrap();
1735        let fcn = fc.next_sibling().unwrap();
1736
1737        let mut cursor = item.clone();
1738
1739        cursor = cursor.previous_focus_item();
1740        assert_eq!(cursor, lc);
1741
1742        cursor = cursor.previous_focus_item();
1743        assert_eq!(cursor, fcn);
1744
1745        cursor = cursor.previous_focus_item();
1746        assert_eq!(cursor, fc);
1747
1748        cursor = cursor.previous_focus_item();
1749        assert_eq!(cursor, item);
1750    }
1751
1752    fn create_nested_subtrees() -> VRc<ItemTreeVTable, vtable::Dyn> {
1753        let component = VRc::new(TestItemTree {
1754            parent_component: None,
1755            item_tree: vec![
1756                ItemTreeNode::Item {
1757                    is_accessible: false,
1758                    children_count: 3,
1759                    children_index: 1,
1760                    parent_index: 0,
1761                    item_array_index: 0,
1762                },
1763                ItemTreeNode::Item {
1764                    is_accessible: false,
1765                    children_count: 0,
1766                    children_index: 4,
1767                    parent_index: 0,
1768                    item_array_index: 0,
1769                },
1770                ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1771                ItemTreeNode::Item {
1772                    is_accessible: false,
1773                    children_count: 0,
1774                    children_index: 4,
1775                    parent_index: 0,
1776                    item_array_index: 0,
1777                },
1778            ],
1779            subtrees: std::cell::RefCell::new(vec![]),
1780            subtree_index: usize::MAX,
1781        });
1782
1783        let sub_component1 = VRc::new(TestItemTree {
1784            parent_component: Some(VRc::into_dyn(component.clone())),
1785            item_tree: vec![
1786                ItemTreeNode::Item {
1787                    is_accessible: false,
1788                    children_count: 1,
1789                    children_index: 1,
1790                    parent_index: 2,
1791                    item_array_index: 0,
1792                },
1793                ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1794            ],
1795            subtrees: std::cell::RefCell::new(vec![]),
1796            subtree_index: usize::MAX,
1797        });
1798        let sub_component2 = VRc::new(TestItemTree {
1799            parent_component: Some(VRc::into_dyn(sub_component1.clone())),
1800            item_tree: vec![
1801                ItemTreeNode::Item {
1802                    is_accessible: false,
1803                    children_count: 1,
1804                    children_index: 1,
1805                    parent_index: 1,
1806                    item_array_index: 0,
1807                },
1808                ItemTreeNode::Item {
1809                    is_accessible: false,
1810                    children_count: 0,
1811                    children_index: 2,
1812                    parent_index: 0,
1813                    item_array_index: 0,
1814                },
1815            ],
1816            subtrees: std::cell::RefCell::new(vec![]),
1817            subtree_index: usize::MAX,
1818        });
1819
1820        sub_component1.as_pin_ref().subtrees.replace(vec![vec![sub_component2]]);
1821        component.as_pin_ref().subtrees.replace(vec![vec![sub_component1]]);
1822
1823        VRc::into_dyn(component)
1824    }
1825
1826    #[test]
1827    fn test_tree_traversal_nested_subtrees_structure() {
1828        let component = create_nested_subtrees();
1829
1830        // Examine root node:
1831        let item = ItemRc::new(component.clone(), 0);
1832        assert!(item.previous_sibling().is_none());
1833        assert!(item.next_sibling().is_none());
1834
1835        let fc = item.first_child().unwrap();
1836        assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
1837        assert_eq!(fc.index(), 1);
1838
1839        let lc = item.last_child().unwrap();
1840        assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
1841        assert_eq!(lc.index(), 3);
1842
1843        let fcn = fc.next_sibling().unwrap();
1844        let lcp = lc.previous_sibling().unwrap();
1845
1846        assert_eq!(fcn, lcp);
1847        assert!(!VRc::ptr_eq(fcn.item_tree(), item.item_tree()));
1848
1849        let last = fcn.next_sibling().unwrap();
1850        assert_eq!(last, lc);
1851
1852        let first = lcp.previous_sibling().unwrap();
1853        assert_eq!(first, fc);
1854
1855        // Nested component:
1856        let nested_root = fcn.first_child().unwrap();
1857        assert_eq!(nested_root, fcn.last_child().unwrap());
1858        assert!(nested_root.next_sibling().is_none());
1859        assert!(nested_root.previous_sibling().is_none());
1860        assert!(!VRc::ptr_eq(nested_root.item_tree(), item.item_tree()));
1861        assert!(!VRc::ptr_eq(nested_root.item_tree(), fcn.item_tree()));
1862
1863        let nested_child = nested_root.first_child().unwrap();
1864        assert_eq!(nested_child, nested_root.last_child().unwrap());
1865        assert!(VRc::ptr_eq(nested_root.item_tree(), nested_child.item_tree()));
1866    }
1867
1868    #[test]
1869    fn test_tree_traversal_nested_subtrees_forward_focus() {
1870        let component = create_nested_subtrees();
1871
1872        // Examine root node:
1873        let item = ItemRc::new(component.clone(), 0);
1874        let fc = item.first_child().unwrap();
1875        let fcn = fc.next_sibling().unwrap();
1876        let lc = item.last_child().unwrap();
1877        let nested_root = fcn.first_child().unwrap();
1878        let nested_child = nested_root.first_child().unwrap();
1879
1880        // Focus traversal:
1881        let mut cursor = item.clone();
1882
1883        cursor = cursor.next_focus_item();
1884        assert_eq!(cursor, fc);
1885
1886        cursor = cursor.next_focus_item();
1887        assert_eq!(cursor, fcn);
1888
1889        cursor = cursor.next_focus_item();
1890        assert_eq!(cursor, nested_root);
1891
1892        cursor = cursor.next_focus_item();
1893        assert_eq!(cursor, nested_child);
1894
1895        cursor = cursor.next_focus_item();
1896        assert_eq!(cursor, lc);
1897
1898        cursor = cursor.next_focus_item();
1899        assert_eq!(cursor, item);
1900    }
1901
1902    #[test]
1903    fn test_tree_traversal_nested_subtrees_backward_focus() {
1904        let component = create_nested_subtrees();
1905
1906        // Examine root node:
1907        let item = ItemRc::new(component.clone(), 0);
1908        let fc = item.first_child().unwrap();
1909        let fcn = fc.next_sibling().unwrap();
1910        let lc = item.last_child().unwrap();
1911        let nested_root = fcn.first_child().unwrap();
1912        let nested_child = nested_root.first_child().unwrap();
1913
1914        // Focus traversal:
1915        let mut cursor = item.clone();
1916
1917        cursor = cursor.previous_focus_item();
1918        assert_eq!(cursor, lc);
1919
1920        cursor = cursor.previous_focus_item();
1921        assert_eq!(cursor, nested_child);
1922
1923        cursor = cursor.previous_focus_item();
1924        assert_eq!(cursor, nested_root);
1925
1926        cursor = cursor.previous_focus_item();
1927        assert_eq!(cursor, fcn);
1928
1929        cursor = cursor.previous_focus_item();
1930        assert_eq!(cursor, fc);
1931
1932        cursor = cursor.previous_focus_item();
1933        assert_eq!(cursor, item);
1934    }
1935
1936    fn create_subtrees_item() -> VRc<ItemTreeVTable, vtable::Dyn> {
1937        let component = VRc::new(TestItemTree {
1938            parent_component: None,
1939            item_tree: vec![
1940                ItemTreeNode::Item {
1941                    is_accessible: false,
1942                    children_count: 2,
1943                    children_index: 1,
1944                    parent_index: 0,
1945                    item_array_index: 0,
1946                },
1947                ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1948                ItemTreeNode::Item {
1949                    is_accessible: false,
1950                    children_count: 0,
1951                    children_index: 4,
1952                    parent_index: 0,
1953                    item_array_index: 0,
1954                },
1955            ],
1956            subtrees: std::cell::RefCell::new(vec![]),
1957            subtree_index: usize::MAX,
1958        });
1959
1960        component.as_pin_ref().subtrees.replace(vec![vec![
1961            VRc::new(TestItemTree {
1962                parent_component: Some(VRc::into_dyn(component.clone())),
1963                item_tree: vec![ItemTreeNode::Item {
1964                    is_accessible: false,
1965                    children_count: 0,
1966                    children_index: 1,
1967                    parent_index: 1,
1968                    item_array_index: 0,
1969                }],
1970                subtrees: std::cell::RefCell::new(vec![]),
1971                subtree_index: 0,
1972            }),
1973            VRc::new(TestItemTree {
1974                parent_component: Some(VRc::into_dyn(component.clone())),
1975                item_tree: vec![ItemTreeNode::Item {
1976                    is_accessible: false,
1977                    children_count: 0,
1978                    children_index: 1,
1979                    parent_index: 1,
1980                    item_array_index: 0,
1981                }],
1982                subtrees: std::cell::RefCell::new(vec![]),
1983                subtree_index: 1,
1984            }),
1985            VRc::new(TestItemTree {
1986                parent_component: Some(VRc::into_dyn(component.clone())),
1987                item_tree: vec![ItemTreeNode::Item {
1988                    is_accessible: false,
1989                    children_count: 0,
1990                    children_index: 1,
1991                    parent_index: 1,
1992                    item_array_index: 0,
1993                }],
1994                subtrees: std::cell::RefCell::new(vec![]),
1995                subtree_index: 2,
1996            }),
1997        ]]);
1998
1999        VRc::into_dyn(component)
2000    }
2001
2002    #[test]
2003    fn test_tree_traversal_subtrees_item_structure() {
2004        let component = create_subtrees_item();
2005
2006        // Examine root node:
2007        let item = ItemRc::new(component.clone(), 0);
2008        assert!(item.previous_sibling().is_none());
2009        assert!(item.next_sibling().is_none());
2010
2011        let sub1 = item.first_child().unwrap();
2012        assert_eq!(sub1.index(), 0);
2013        assert!(!VRc::ptr_eq(sub1.item_tree(), item.item_tree()));
2014
2015        // assert!(sub1.previous_sibling().is_none());
2016
2017        let sub2 = sub1.next_sibling().unwrap();
2018        assert_eq!(sub2.index(), 0);
2019        assert!(!VRc::ptr_eq(sub1.item_tree(), sub2.item_tree()));
2020        assert!(!VRc::ptr_eq(item.item_tree(), sub2.item_tree()));
2021
2022        assert!(sub2.previous_sibling() == Some(sub1.clone()));
2023
2024        let sub3 = sub2.next_sibling().unwrap();
2025        assert_eq!(sub3.index(), 0);
2026        assert!(!VRc::ptr_eq(sub1.item_tree(), sub2.item_tree()));
2027        assert!(!VRc::ptr_eq(sub2.item_tree(), sub3.item_tree()));
2028        assert!(!VRc::ptr_eq(item.item_tree(), sub3.item_tree()));
2029
2030        assert_eq!(sub3.previous_sibling().unwrap(), sub2.clone());
2031    }
2032
2033    #[test]
2034    fn test_component_item_tree_root_only() {
2035        let nodes = vec![ItemTreeNode::Item {
2036            is_accessible: false,
2037            children_count: 0,
2038            children_index: 1,
2039            parent_index: 0,
2040            item_array_index: 0,
2041        }];
2042
2043        let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
2044
2045        assert_eq!(tree.first_child(0), None);
2046        assert_eq!(tree.last_child(0), None);
2047        assert_eq!(tree.previous_sibling(0), None);
2048        assert_eq!(tree.next_sibling(0), None);
2049        assert_eq!(tree.parent(0), None);
2050    }
2051
2052    #[test]
2053    fn test_component_item_tree_one_child() {
2054        let nodes = vec![
2055            ItemTreeNode::Item {
2056                is_accessible: false,
2057                children_count: 1,
2058                children_index: 1,
2059                parent_index: 0,
2060                item_array_index: 0,
2061            },
2062            ItemTreeNode::Item {
2063                is_accessible: false,
2064                children_count: 0,
2065                children_index: 2,
2066                parent_index: 0,
2067                item_array_index: 0,
2068            },
2069        ];
2070
2071        let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
2072
2073        assert_eq!(tree.first_child(0), Some(1));
2074        assert_eq!(tree.last_child(0), Some(1));
2075        assert_eq!(tree.previous_sibling(0), None);
2076        assert_eq!(tree.next_sibling(0), None);
2077        assert_eq!(tree.parent(0), None);
2078        assert_eq!(tree.previous_sibling(1), None);
2079        assert_eq!(tree.next_sibling(1), None);
2080        assert_eq!(tree.parent(1), Some(0));
2081    }
2082
2083    #[test]
2084    fn test_component_item_tree_tree_children() {
2085        let nodes = vec![
2086            ItemTreeNode::Item {
2087                is_accessible: false,
2088                children_count: 3,
2089                children_index: 1,
2090                parent_index: 0,
2091                item_array_index: 0,
2092            },
2093            ItemTreeNode::Item {
2094                is_accessible: false,
2095                children_count: 0,
2096                children_index: 4,
2097                parent_index: 0,
2098                item_array_index: 0,
2099            },
2100            ItemTreeNode::Item {
2101                is_accessible: false,
2102                children_count: 0,
2103                children_index: 4,
2104                parent_index: 0,
2105                item_array_index: 0,
2106            },
2107            ItemTreeNode::Item {
2108                is_accessible: false,
2109                children_count: 0,
2110                children_index: 4,
2111                parent_index: 0,
2112                item_array_index: 0,
2113            },
2114        ];
2115
2116        let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
2117
2118        assert_eq!(tree.first_child(0), Some(1));
2119        assert_eq!(tree.last_child(0), Some(3));
2120        assert_eq!(tree.previous_sibling(0), None);
2121        assert_eq!(tree.next_sibling(0), None);
2122        assert_eq!(tree.parent(0), None);
2123
2124        assert_eq!(tree.previous_sibling(1), None);
2125        assert_eq!(tree.next_sibling(1), Some(2));
2126        assert_eq!(tree.parent(1), Some(0));
2127
2128        assert_eq!(tree.previous_sibling(2), Some(1));
2129        assert_eq!(tree.next_sibling(2), Some(3));
2130        assert_eq!(tree.parent(2), Some(0));
2131
2132        assert_eq!(tree.previous_sibling(3), Some(2));
2133        assert_eq!(tree.next_sibling(3), None);
2134        assert_eq!(tree.parent(3), Some(0));
2135    }
2136}