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