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