Skip to main content

i_slint_core/
item_tree.rs

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