1use 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)]
24pub struct IndexRange {
26 pub start: usize,
28 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#[cfg_attr(not(feature = "ffi"), i_slint_core_macros::remove_extern)]
45#[vtable]
46#[repr(C)]
47pub struct ItemTreeVTable {
48 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 pub get_item_ref: extern "C" fn(
60 ::core::pin::Pin<VRef<ItemTreeVTable>>,
61 index: u32,
62 ) -> ::core::pin::Pin<VRef<ItemVTable>>,
63
64 pub get_subtree_range:
66 extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, index: u32) -> IndexRange,
67
68 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 pub get_item_tree: extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>) -> Slice<ItemTreeNode>,
78
79 pub parent_node: extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, result: &mut ItemWeak),
87
88 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 pub subtree_index: extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>) -> usize,
100
101 pub layout_info:
103 extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, Orientation) -> LayoutInfo,
104
105 pub item_geometry:
107 extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, item_index: u32) -> LogicalRect,
108
109 pub accessible_role:
111 extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, item_index: u32) -> AccessibleRole,
112
113 pub accessible_string_property: extern "C" fn(
115 ::core::pin::Pin<VRef<ItemTreeVTable>>,
116 item_index: u32,
117 what: AccessibleStringProperty,
118 result: &mut SharedString,
119 ) -> bool,
120
121 pub accessibility_action: extern "C" fn(
123 ::core::pin::Pin<VRef<ItemTreeVTable>>,
124 item_index: u32,
125 action: &AccessibilityAction,
126 ),
127
128 pub supported_accessibility_actions: extern "C" fn(
130 ::core::pin::Pin<VRef<ItemTreeVTable>>,
131 item_index: u32,
132 ) -> SupportedAccessibilityAction,
133
134 pub item_element_infos: extern "C" fn(
136 ::core::pin::Pin<VRef<ItemTreeVTable>>,
137 item_index: u32,
138 result: &mut SharedString,
139 ) -> bool,
140
141 pub window_adapter: extern "C" fn(
143 ::core::pin::Pin<VRef<ItemTreeVTable>>,
144 do_create: bool,
145 result: &mut Option<WindowAdapterRc>,
146 ),
147
148 pub drop_in_place: unsafe extern "C" fn(VRefMut<ItemTreeVTable>) -> vtable::Layout,
150
151 pub dealloc: unsafe extern "C" fn(&ItemTreeVTable, ptr: *mut u8, layout: vtable::Layout),
153}
154
155#[cfg(test)]
156pub(crate) use ItemTreeVTable_static;
157
158pub type ItemTreeRef<'a> = vtable::VRef<'a, ItemTreeVTable>;
161
162pub type ItemTreeRefPin<'a> = core::pin::Pin<ItemTreeRef<'a>>;
164
165pub type ItemTreeRc = vtable::VRc<ItemTreeVTable, Dyn>;
167pub type ItemTreeWeak = vtable::VWeak<ItemTreeVTable, Dyn>;
169
170pub fn register_item_tree(item_tree_rc: &ItemTreeRc, window_adapter: Option<WindowAdapterRc>) {
172 let c = vtable::VRc::borrow_pin(item_tree_rc);
173 let item_tree = c.as_ref().get_item_tree();
174 item_tree.iter().enumerate().for_each(|(tree_index, node)| {
175 let tree_index = tree_index as u32;
176 if let ItemTreeNode::Item { .. } = &node {
177 let item = ItemRc::new(item_tree_rc.clone(), tree_index);
178 c.as_ref().get_item_ref(tree_index).as_ref().init(&item);
179 }
180 });
181 if let Some(adapter) = window_adapter.as_ref().and_then(|a| a.internal(crate::InternalToken)) {
182 adapter.register_item_tree(ItemTreeRc::borrow_pin(item_tree_rc));
183 }
184}
185
186pub fn unregister_item_tree<Base>(
188 base: core::pin::Pin<&Base>,
189 item_tree: ItemTreeRef,
190 item_array: &[vtable::VOffset<Base, ItemVTable, vtable::AllowPin>],
191 window_adapter: &WindowAdapterRc,
192) {
193 window_adapter.renderer().free_graphics_resources(
194 item_tree,
195 &mut item_array.iter().map(|item| item.apply_pin(base)),
196 ).expect("Fatal error encountered when freeing graphics resources while destroying Slint component");
197 if let Some(w) = window_adapter.internal(crate::InternalToken) {
198 w.unregister_item_tree(item_tree, &mut item_array.iter().map(|item| item.apply_pin(base)));
199 }
200
201 let window_inner = crate::window::WindowInner::from_pub(window_adapter.window());
203 let to_close_popups = window_inner
204 .active_popups()
205 .iter()
206 .filter_map(|p| p.parent_item.upgrade().is_none().then_some(p.popup_id))
207 .collect::<Vec<_>>();
208 for popup_id in to_close_popups {
209 window_inner.close_popup(popup_id);
210 }
211}
212
213fn find_sibling_outside_repeater(
214 component: &ItemTreeRc,
215 comp_ref_pin: Pin<VRef<ItemTreeVTable>>,
216 index: u32,
217 sibling_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
218 subtree_child: &dyn Fn(usize, usize) -> usize,
219) -> Option<ItemRc> {
220 assert_ne!(index, 0);
221
222 let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
223
224 let mut current_sibling = index;
225 loop {
226 current_sibling = sibling_step(&item_tree, current_sibling)?;
227
228 if let Some(node) = step_into_node(
229 component,
230 &comp_ref_pin,
231 current_sibling,
232 &item_tree,
233 subtree_child,
234 &core::convert::identity,
235 ) {
236 return Some(node);
237 }
238 }
239}
240
241fn step_into_node(
242 component: &ItemTreeRc,
243 comp_ref_pin: &Pin<VRef<ItemTreeVTable>>,
244 node_index: u32,
245 item_tree: &crate::item_tree::ItemTreeNodeArray,
246 subtree_child: &dyn Fn(usize, usize) -> usize,
247 wrap_around: &dyn Fn(ItemRc) -> ItemRc,
248) -> Option<ItemRc> {
249 match item_tree.get(node_index).expect("Invalid index passed to item tree") {
250 crate::item_tree::ItemTreeNode::Item { .. } => {
251 Some(ItemRc::new(component.clone(), node_index))
252 }
253 crate::item_tree::ItemTreeNode::DynamicTree { index, .. } => {
254 let range = comp_ref_pin.as_ref().get_subtree_range(*index);
255 let component_index = subtree_child(range.start, range.end);
256 let mut child_instance = Default::default();
257 comp_ref_pin.as_ref().get_subtree(*index, component_index, &mut child_instance);
258 child_instance
259 .upgrade()
260 .map(|child_instance| wrap_around(ItemRc::new(child_instance, 0)))
261 }
262 }
263}
264
265pub enum ParentItemTraversalMode {
266 FindAllParents,
267 StopAtPopups,
268}
269
270#[repr(C)]
272#[derive(Clone)]
273pub struct ItemRc {
274 item_tree: vtable::VRc<ItemTreeVTable>,
275 index: u32,
276}
277
278impl core::fmt::Debug for ItemRc {
279 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
280 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
281 let mut debug = SharedString::new();
282 comp_ref_pin.as_ref().item_element_infos(self.index, &mut debug);
283
284 write!(f, "ItemRc{{ {:p}, {:?} {debug}}}", comp_ref_pin.as_ptr(), self.index)
285 }
286}
287
288impl ItemRc {
289 pub fn new(item_tree: vtable::VRc<ItemTreeVTable>, index: u32) -> Self {
291 Self { item_tree, index }
292 }
293
294 pub fn is_root_item_of(&self, item_tree: &VRc<ItemTreeVTable>) -> bool {
295 self.index == 0 && VRc::ptr_eq(&self.item_tree, item_tree)
296 }
297
298 pub fn borrow<'a>(&'a self) -> Pin<ItemRef<'a>> {
300 #![allow(unsafe_code)]
301 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
302 let result = comp_ref_pin.as_ref().get_item_ref(self.index);
303 unsafe { core::mem::transmute::<Pin<ItemRef<'_>>, Pin<ItemRef<'a>>>(result) }
306 }
307
308 pub fn downcast<T: HasStaticVTable<ItemVTable>>(&self) -> Option<VRcMapped<ItemTreeVTable, T>> {
310 #![allow(unsafe_code)]
311 let item = self.borrow();
312 ItemRef::downcast_pin::<T>(item)?;
313
314 Some(vtable::VRc::map_dyn(self.item_tree.clone(), |comp_ref_pin| {
315 let result = comp_ref_pin.as_ref().get_item_ref(self.index);
316 let item =
319 unsafe { core::mem::transmute::<Pin<ItemRef<'_>>, Pin<ItemRef<'_>>>(result) };
320 ItemRef::downcast_pin::<T>(item).unwrap()
321 }))
322 }
323
324 pub fn downgrade(&self) -> ItemWeak {
325 ItemWeak { item_tree: VRc::downgrade(&self.item_tree), index: self.index }
326 }
327
328 pub fn parent_item(&self, find_mode: ParentItemTraversalMode) -> Option<ItemRc> {
332 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
333 let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
334
335 if let Some(parent_index) = item_tree.parent(self.index) {
336 return Some(ItemRc::new(self.item_tree.clone(), parent_index));
337 }
338
339 let mut r = ItemWeak::default();
340 comp_ref_pin.as_ref().parent_node(&mut r);
341 let parent = r.upgrade()?;
342 let comp_ref_pin = vtable::VRc::borrow_pin(&parent.item_tree);
343 let item_tree_array = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
344 if let Some(ItemTreeNode::DynamicTree { parent_index, .. }) =
345 item_tree_array.get(parent.index())
346 {
347 Some(ItemRc::new(parent.item_tree.clone(), *parent_index))
349 } else {
350 match find_mode {
353 ParentItemTraversalMode::FindAllParents => Some(parent),
354 ParentItemTraversalMode::StopAtPopups => None,
355 }
356 }
357 }
358
359 pub fn is_visible(&self) -> bool {
362 let (clip, geometry) = self.absolute_clip_rect_and_geometry();
363 let clip = clip.to_box2d();
364 let geometry = geometry.to_box2d();
365 !clip.is_empty()
366 && clip.max.x >= geometry.min.x
367 && clip.max.y >= geometry.min.y
368 && clip.min.x <= geometry.max.x
369 && clip.min.y <= geometry.max.y
370 }
371
372 fn absolute_clip_rect_and_geometry(&self) -> (LogicalRect, LogicalRect) {
375 let (mut clip, parent_geometry) =
376 self.parent_item(ParentItemTraversalMode::StopAtPopups).map_or_else(
377 || {
378 (
379 LogicalRect::from_size((crate::Coord::MAX, crate::Coord::MAX).into()),
380 Default::default(),
381 )
382 },
383 |parent| parent.absolute_clip_rect_and_geometry(),
384 );
385
386 let geometry = self.geometry().translate(parent_geometry.origin.to_vector());
387
388 let item = self.borrow();
389 if item.as_ref().clips_children() {
390 clip = geometry.intersection(&clip).unwrap_or_default();
391 }
392
393 (clip, geometry)
394 }
395
396 pub fn is_accessible(&self) -> bool {
397 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
398 let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
399
400 if let Some(n) = &item_tree.get(self.index) {
401 match n {
402 ItemTreeNode::Item { is_accessible, .. } => *is_accessible,
403 ItemTreeNode::DynamicTree { .. } => false,
404 }
405 } else {
406 false
407 }
408 }
409
410 pub fn accessible_role(&self) -> crate::items::AccessibleRole {
411 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
412 comp_ref_pin.as_ref().accessible_role(self.index)
413 }
414
415 pub fn accessible_string_property(
416 &self,
417 what: crate::accessibility::AccessibleStringProperty,
418 ) -> Option<SharedString> {
419 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
420 let mut result = Default::default();
421 let ok = comp_ref_pin.as_ref().accessible_string_property(self.index, what, &mut result);
422 ok.then_some(result)
423 }
424
425 pub fn accessible_action(&self, action: &crate::accessibility::AccessibilityAction) {
426 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
427 comp_ref_pin.as_ref().accessibility_action(self.index, action);
428 }
429
430 pub fn supported_accessibility_actions(&self) -> SupportedAccessibilityAction {
431 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
432 comp_ref_pin.as_ref().supported_accessibility_actions(self.index)
433 }
434
435 pub fn element_count(&self) -> Option<usize> {
436 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
437 let mut result = SharedString::new();
438 comp_ref_pin
439 .as_ref()
440 .item_element_infos(self.index, &mut result)
441 .then(|| result.as_str().split("/").count())
442 }
443
444 pub fn element_type_names_and_ids(
445 &self,
446 element_index: usize,
447 ) -> Option<Vec<(SharedString, SharedString)>> {
448 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
449 let mut result = SharedString::new();
450 comp_ref_pin.as_ref().item_element_infos(self.index, &mut result).then(|| {
451 result
452 .as_str()
453 .split("/")
454 .nth(element_index)
455 .unwrap()
456 .split(";")
457 .map(|encoded_elem_info| {
458 let mut decoder = encoded_elem_info.split(',');
459 let type_name = decoder.next().unwrap().into();
460 let id = decoder.next().map(Into::into).unwrap_or_default();
461 (type_name, id)
462 })
463 .collect()
464 })
465 }
466
467 pub fn geometry(&self) -> LogicalRect {
468 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
469 comp_ref_pin.as_ref().item_geometry(self.index)
470 }
471
472 pub fn bounding_rect(
475 &self,
476 geometry: &LogicalRect,
477 window_adapter: &WindowAdapterRc,
478 ) -> LogicalRect {
479 self.borrow().as_ref().bounding_rect(window_adapter, self, *geometry)
480 }
481
482 pub fn map_to_window(&self, p: LogicalPoint) -> LogicalPoint {
485 self.map_to_item_tree_impl(p, |_| false)
486 }
487
488 pub(crate) fn map_from_window(&self, p: LogicalPoint) -> LogicalPoint {
489 self.map_from_item_tree_impl(p, |_| false)
490 }
491
492 pub fn map_to_item_tree(
495 &self,
496 p: LogicalPoint,
497 item_tree: &vtable::VRc<ItemTreeVTable>,
498 ) -> LogicalPoint {
499 self.map_to_item_tree_impl(p, |current| current.is_root_item_of(item_tree))
500 }
501
502 fn map_to_ancestor(&self, p: LogicalPoint, ancestor: &Self) -> LogicalPoint {
506 self.map_to_item_tree_impl(p, |parent| parent == ancestor)
507 }
508
509 fn map_to_item_tree_impl(
510 &self,
511 p: LogicalPoint,
512 stop_condition: impl Fn(&Self) -> bool,
513 ) -> LogicalPoint {
514 let mut current = self.clone();
515 let mut result = p;
516 if stop_condition(¤t) {
517 return result;
518 }
519 let supports_transformations = self
520 .window_adapter()
521 .is_none_or(|adapter| adapter.renderer().supports_transformations());
522 while let Some(parent) = current.parent_item(ParentItemTraversalMode::StopAtPopups) {
523 if stop_condition(&parent) {
524 break;
525 }
526 let geometry = parent.geometry();
527 if supports_transformations {
528 if let Some(transform) = parent.children_transform() {
529 result = transform.transform_point(result.cast()).cast();
530 }
531 }
532 result += geometry.origin.to_vector();
533 current = parent;
534 }
535 result
536 }
537
538 fn map_from_item_tree_impl(
539 &self,
540 p: LogicalPoint,
541 stop_condition: impl Fn(&Self) -> bool,
542 ) -> LogicalPoint {
543 let mut current = self.clone();
544 let mut result = p;
545 if stop_condition(¤t) {
546 return result;
547 }
548 let supports_transformations = self
549 .window_adapter()
550 .is_none_or(|adapter| adapter.renderer().supports_transformations());
551
552 let mut full_transform = supports_transformations.then(ItemTransform::identity);
553 let mut offset = euclid::Vector2D::zero();
554 while let Some(parent) = current.parent_item(ParentItemTraversalMode::StopAtPopups) {
555 if stop_condition(&parent) {
556 break;
557 }
558 let geometry = parent.geometry();
559 if let (Some(transform), Some(children_transform)) =
560 (full_transform, parent.children_transform())
561 {
562 full_transform = Some(
563 transform
564 .then_translate(geometry.origin.to_vector().cast())
565 .then(&children_transform),
566 );
567 }
568 offset += geometry.origin.to_vector();
569 current = parent;
570 }
571 full_transform = full_transform.and_then(|ft| ft.inverse());
572 if let Some(transform) = full_transform {
573 result = transform.transform_point(result.cast()).cast();
574 } else {
575 result -= offset;
576 }
577 result
578 }
579
580 pub fn index(&self) -> u32 {
582 self.index
583 }
584 pub fn item_tree(&self) -> &vtable::VRc<ItemTreeVTable> {
586 &self.item_tree
587 }
588
589 fn find_child(
590 &self,
591 child_access: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
592 child_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
593 subtree_child: &dyn Fn(usize, usize) -> usize,
594 ) -> Option<Self> {
595 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
596 let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
597
598 let mut current_child_index = child_access(&item_tree, self.index())?;
599 loop {
600 if let Some(item) = step_into_node(
601 self.item_tree(),
602 &comp_ref_pin,
603 current_child_index,
604 &item_tree,
605 subtree_child,
606 &core::convert::identity,
607 ) {
608 return Some(item);
609 }
610 current_child_index = child_step(&item_tree, current_child_index)?;
611 }
612 }
613
614 pub fn first_child(&self) -> Option<Self> {
616 self.find_child(
617 &|item_tree, index| item_tree.first_child(index),
618 &|item_tree, index| item_tree.next_sibling(index),
619 &|start, _| start,
620 )
621 }
622
623 pub fn last_child(&self) -> Option<Self> {
625 self.find_child(
626 &|item_tree, index| item_tree.last_child(index),
627 &|item_tree, index| item_tree.previous_sibling(index),
628 &|_, end| end.wrapping_sub(1),
629 )
630 }
631
632 fn find_sibling(
633 &self,
634 sibling_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
635 subtree_step: &dyn Fn(usize) -> usize,
636 subtree_child: &dyn Fn(usize, usize) -> usize,
637 ) -> Option<Self> {
638 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
639 if self.index == 0 {
640 let mut parent_item = Default::default();
641 comp_ref_pin.as_ref().parent_node(&mut parent_item);
642 let current_component_subtree_index = comp_ref_pin.as_ref().subtree_index();
643 if let Some(parent_item) = parent_item.upgrade() {
644 let parent = parent_item.item_tree();
645 let parent_ref_pin = vtable::VRc::borrow_pin(parent);
646 let parent_item_index = parent_item.index();
647 let parent_item_tree = crate::item_tree::ItemTreeNodeArray::new(&parent_ref_pin);
648
649 let subtree_index = match parent_item_tree.get(parent_item_index)? {
650 crate::item_tree::ItemTreeNode::Item { .. } => {
651 return None;
653 }
654 crate::item_tree::ItemTreeNode::DynamicTree { index, .. } => *index,
655 };
656
657 let next_subtree_index = subtree_step(current_component_subtree_index);
658
659 let mut next_subtree_instance = Default::default();
661 parent_ref_pin.as_ref().get_subtree(
662 subtree_index,
663 next_subtree_index,
664 &mut next_subtree_instance,
665 );
666 if let Some(next_subtree_instance) = next_subtree_instance.upgrade() {
667 return Some(ItemRc::new(next_subtree_instance, 0));
668 }
669
670 find_sibling_outside_repeater(
672 parent,
673 parent_ref_pin,
674 parent_item_index,
675 sibling_step,
676 subtree_child,
677 )
678 } else {
679 None }
681 } else {
682 find_sibling_outside_repeater(
683 self.item_tree(),
684 comp_ref_pin,
685 self.index(),
686 sibling_step,
687 subtree_child,
688 )
689 }
690 }
691
692 pub fn previous_sibling(&self) -> Option<Self> {
694 self.find_sibling(
695 &|item_tree, index| item_tree.previous_sibling(index),
696 &|index| index.wrapping_sub(1),
697 &|_, end| end.wrapping_sub(1),
698 )
699 }
700
701 pub fn next_sibling(&self) -> Option<Self> {
703 self.find_sibling(
704 &|item_tree, index| item_tree.next_sibling(index),
705 &|index| index.saturating_add(1),
706 &|start, _| start,
707 )
708 }
709
710 fn move_focus(
711 &self,
712 focus_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
713 subtree_step: &dyn Fn(ItemRc) -> Option<ItemRc>,
714 subtree_child: &dyn Fn(usize, usize) -> usize,
715 step_in: &dyn Fn(ItemRc) -> ItemRc,
716 step_out: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
717 ) -> Self {
718 let mut component = self.item_tree().clone();
719 let mut comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
720 let mut item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
721
722 let mut to_focus = self.index();
723
724 'in_tree: loop {
725 if let Some(next) = focus_step(&item_tree, to_focus) {
726 if let Some(item) = step_into_node(
727 &component,
728 &comp_ref_pin,
729 next,
730 &item_tree,
731 subtree_child,
732 step_in,
733 ) {
734 return item;
735 }
736 to_focus = next;
737 } else {
739 let mut root = ItemRc::new(component, 0);
741 if let Some(item) = subtree_step(root.clone()) {
742 return step_in(item);
744 }
745
746 let root_component = root.item_tree();
748 let root_comp_ref = vtable::VRc::borrow_pin(root_component);
749 let mut parent_node = Default::default();
750 root_comp_ref.as_ref().parent_node(&mut parent_node);
751
752 while let Some(parent) = parent_node.upgrade() {
753 component = parent.item_tree().clone();
755 comp_ref_pin = vtable::VRc::borrow_pin(&component);
756 item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
757
758 let index = parent.index();
759
760 if !matches!(item_tree.get(index), Some(ItemTreeNode::DynamicTree { .. })) {
761 break;
763 }
764
765 if let Some(next) = step_out(&item_tree, index) {
766 if let Some(item) = step_into_node(
767 parent.item_tree(),
768 &comp_ref_pin,
769 next,
770 &item_tree,
771 subtree_child,
772 step_in,
773 ) {
774 return item;
776 } else {
777 to_focus = parent.index();
779 continue 'in_tree; }
781 }
782
783 root = ItemRc::new(component.clone(), 0);
784 if let Some(item) = subtree_step(root.clone()) {
785 return step_in(item);
786 }
787
788 let root_component = root.item_tree();
790 let root_comp_ref = vtable::VRc::borrow_pin(root_component);
791 parent_node = Default::default();
792 root_comp_ref.as_ref().parent_node(&mut parent_node);
793 }
794
795 return step_in(root);
797 }
798 }
799 }
800
801 pub fn previous_focus_item(&self) -> Self {
803 self.move_focus(
804 &|item_tree, index| {
805 crate::item_focus::default_previous_in_local_focus_chain(index, item_tree)
806 },
807 &|root| root.previous_sibling(),
808 &|_, end| end.wrapping_sub(1),
809 &|root| {
810 let mut current = root;
811 loop {
812 if let Some(next) = current.last_child() {
813 current = next;
814 } else {
815 return current;
816 }
817 }
818 },
819 &|item_tree, index| item_tree.parent(index),
820 )
821 }
822
823 pub fn next_focus_item(&self) -> Self {
825 self.move_focus(
826 &|item_tree, index| {
827 crate::item_focus::default_next_in_local_focus_chain(index, item_tree)
828 },
829 &|root| root.next_sibling(),
830 &|start, _| start,
831 &core::convert::identity,
832 &|item_tree, index| crate::item_focus::step_out_of_node(index, item_tree),
833 )
834 }
835
836 pub fn window_adapter(&self) -> Option<WindowAdapterRc> {
837 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
838 let mut result = None;
839 comp_ref_pin.as_ref().window_adapter(false, &mut result);
840 result
841 }
842
843 fn visit_descendants_impl<R>(
846 &self,
847 visitor: &mut impl FnMut(&ItemRc) -> ControlFlow<R>,
848 ) -> Option<R> {
849 let mut result = None;
850
851 let mut actual_visitor = |item_tree: &ItemTreeRc,
852 index: u32,
853 _item_pin: core::pin::Pin<ItemRef>|
854 -> VisitChildrenResult {
855 let item_rc = ItemRc::new(item_tree.clone(), index);
856
857 match visitor(&item_rc) {
858 ControlFlow::Continue(_) => {
859 if let Some(x) = item_rc.visit_descendants_impl(visitor) {
860 result = Some(x);
861 return VisitChildrenResult::abort(index, 0);
862 }
863 }
864 ControlFlow::Break(x) => {
865 result = Some(x);
866 return VisitChildrenResult::abort(index, 0);
867 }
868 }
869
870 VisitChildrenResult::CONTINUE
871 };
872 vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);
873
874 VRc::borrow_pin(self.item_tree()).as_ref().visit_children_item(
875 self.index() as isize,
876 TraversalOrder::BackToFront,
877 actual_visitor,
878 );
879
880 result
881 }
882
883 pub fn visit_descendants<R>(
886 &self,
887 mut visitor: impl FnMut(&ItemRc) -> ControlFlow<R>,
888 ) -> Option<R> {
889 self.visit_descendants_impl(&mut visitor)
890 }
891
892 pub fn children_transform(&self) -> Option<ItemTransform> {
895 self.downcast::<crate::items::Transform>().map(|transform_item| {
896 let item = transform_item.as_pin_ref();
897 let origin = item.transform_origin().to_euclid().to_vector().cast::<f32>();
898 ItemTransform::translation(-origin.x, -origin.y)
899 .cast()
900 .then_scale(item.transform_scale_x(), item.transform_scale_y())
901 .then_rotate(euclid::Angle { radians: item.transform_rotation().to_radians() })
902 .then_translate(origin)
903 })
904 }
905
906 pub fn inverse_children_transform(&self) -> Option<ItemTransform> {
911 self.children_transform()
912 .and_then(|child_transform| child_transform.inverse())
914 }
915
916 pub(crate) fn try_scroll_into_visible(&self) {
917 let mut parent = self.parent_item(ParentItemTraversalMode::StopAtPopups);
918 while let Some(item_rc) = parent.as_ref() {
919 let item_ref = item_rc.borrow();
920 if let Some(flickable) = vtable::VRef::downcast_pin::<crate::items::Flickable>(item_ref)
921 {
922 let geo = self.geometry();
923
924 flickable.reveal_points(
925 item_rc,
926 &[
927 self.map_to_ancestor(
928 LogicalPoint::new(
929 geo.origin.x - flickable.viewport_x().0,
930 geo.origin.y - flickable.viewport_y().0,
931 ),
932 item_rc,
933 ),
934 self.map_to_ancestor(
935 LogicalPoint::new(
936 geo.max_x() - flickable.viewport_x().0,
937 geo.max_y() - flickable.viewport_y().0,
938 ),
939 item_rc,
940 ),
941 ],
942 );
943 break;
944 }
945
946 parent = item_rc.parent_item(ParentItemTraversalMode::StopAtPopups);
947 }
948 }
949}
950
951impl PartialEq for ItemRc {
952 fn eq(&self, other: &Self) -> bool {
953 VRc::ptr_eq(&self.item_tree, &other.item_tree) && self.index == other.index
954 }
955}
956
957impl Eq for ItemRc {}
958
959#[derive(Clone, Default)]
961#[repr(C)]
962pub struct ItemWeak {
963 item_tree: crate::item_tree::ItemTreeWeak,
964 index: u32,
965}
966
967impl ItemWeak {
968 pub fn upgrade(&self) -> Option<ItemRc> {
969 self.item_tree.upgrade().map(|c| ItemRc::new(c, self.index))
970 }
971}
972
973impl PartialEq for ItemWeak {
974 fn eq(&self, other: &Self) -> bool {
975 VWeak::ptr_eq(&self.item_tree, &other.item_tree) && self.index == other.index
976 }
977}
978
979impl Eq for ItemWeak {}
980
981#[repr(u8)]
982#[derive(Debug, Copy, Clone, Eq, PartialEq)]
983pub enum TraversalOrder {
984 BackToFront,
985 FrontToBack,
986}
987
988#[repr(transparent)]
997#[derive(Copy, Clone, Eq, PartialEq)]
998pub struct VisitChildrenResult(u64);
999impl VisitChildrenResult {
1000 pub const CONTINUE: Self = Self(u64::MAX);
1002
1003 pub fn abort(item_index: u32, index_within_repeater: usize) -> Self {
1005 assert!(index_within_repeater < u32::MAX as usize);
1006 Self(item_index as u64 | (index_within_repeater as u64) << 32)
1007 }
1008 pub fn has_aborted(&self) -> bool {
1010 self.0 != Self::CONTINUE.0
1011 }
1012 pub fn aborted_index(&self) -> Option<usize> {
1013 if self.0 != Self::CONTINUE.0 { Some((self.0 & 0xffff_ffff) as usize) } else { None }
1014 }
1015 pub fn aborted_indexes(&self) -> Option<(usize, usize)> {
1016 if self.0 != Self::CONTINUE.0 {
1017 Some(((self.0 & 0xffff_ffff) as usize, (self.0 >> 32) as usize))
1018 } else {
1019 None
1020 }
1021 }
1022}
1023impl core::fmt::Debug for VisitChildrenResult {
1024 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1025 if self.0 == Self::CONTINUE.0 {
1026 write!(f, "CONTINUE")
1027 } else {
1028 write!(f, "({},{})", (self.0 & 0xffff_ffff) as usize, (self.0 >> 32) as usize)
1029 }
1030 }
1031}
1032
1033#[repr(u8)]
1036#[derive(Debug)]
1037pub enum ItemTreeNode {
1038 Item {
1040 is_accessible: bool,
1042
1043 children_count: u32,
1045
1046 children_index: u32,
1048
1049 parent_index: u32,
1051
1052 item_array_index: u32,
1054 },
1055 DynamicTree {
1058 index: u32,
1060
1061 parent_index: u32,
1063 },
1064}
1065
1066impl ItemTreeNode {
1067 pub fn parent_index(&self) -> u32 {
1068 match self {
1069 ItemTreeNode::Item { parent_index, .. } => *parent_index,
1070 ItemTreeNode::DynamicTree { parent_index, .. } => *parent_index,
1071 }
1072 }
1073}
1074
1075pub struct ItemTreeNodeArray<'a> {
1078 node_array: &'a [ItemTreeNode],
1079}
1080
1081impl<'a> ItemTreeNodeArray<'a> {
1082 pub fn new(comp_ref_pin: &'a Pin<VRef<'a, ItemTreeVTable>>) -> Self {
1084 Self { node_array: comp_ref_pin.as_ref().get_item_tree().as_slice() }
1085 }
1086
1087 pub fn get(&self, index: u32) -> Option<&ItemTreeNode> {
1089 self.node_array.get(index as usize)
1090 }
1091
1092 pub fn parent(&self, index: u32) -> Option<u32> {
1094 let index = index as usize;
1095 (index < self.node_array.len() && index != 0).then(|| self.node_array[index].parent_index())
1096 }
1097
1098 pub fn next_sibling(&self, index: u32) -> Option<u32> {
1100 if let Some(parent_index) = self.parent(index) {
1101 match self.node_array[parent_index as usize] {
1102 ItemTreeNode::Item { children_index, children_count, .. } => {
1103 (index < (children_count + children_index - 1)).then_some(index + 1)
1104 }
1105 ItemTreeNode::DynamicTree { .. } => {
1106 unreachable!("Parent in same item tree is a repeater.")
1107 }
1108 }
1109 } else {
1110 None }
1112 }
1113
1114 pub fn previous_sibling(&self, index: u32) -> Option<u32> {
1116 if let Some(parent_index) = self.parent(index) {
1117 match self.node_array[parent_index as usize] {
1118 ItemTreeNode::Item { children_index, .. } => {
1119 (index > children_index).then_some(index - 1)
1120 }
1121 ItemTreeNode::DynamicTree { .. } => {
1122 unreachable!("Parent in same item tree is a repeater.")
1123 }
1124 }
1125 } else {
1126 None }
1128 }
1129
1130 pub fn first_child(&self, index: u32) -> Option<u32> {
1133 match self.node_array.get(index as usize)? {
1134 ItemTreeNode::Item { children_index, children_count, .. } => {
1135 (*children_count != 0).then_some(*children_index as _)
1136 }
1137 ItemTreeNode::DynamicTree { .. } => None,
1138 }
1139 }
1140
1141 pub fn last_child(&self, index: u32) -> Option<u32> {
1144 match self.node_array.get(index as usize)? {
1145 ItemTreeNode::Item { children_index, children_count, .. } => {
1146 if *children_count != 0 {
1147 Some(*children_index + *children_count - 1)
1148 } else {
1149 None
1150 }
1151 }
1152 ItemTreeNode::DynamicTree { .. } => None,
1153 }
1154 }
1155
1156 pub fn node_count(&self) -> usize {
1158 self.node_array.len()
1159 }
1160}
1161
1162impl<'a> From<&'a [ItemTreeNode]> for ItemTreeNodeArray<'a> {
1163 fn from(item_tree: &'a [ItemTreeNode]) -> Self {
1164 Self { node_array: item_tree }
1165 }
1166}
1167
1168#[cfg_attr(not(feature = "ffi"), i_slint_core_macros::remove_extern)]
1169#[vtable]
1170#[repr(C)]
1171pub struct ItemVisitorVTable {
1173 visit_item: extern "C" fn(
1180 VRefMut<ItemVisitorVTable>,
1181 item_tree: &VRc<ItemTreeVTable, vtable::Dyn>,
1182 index: u32,
1183 item: Pin<VRef<ItemVTable>>,
1184 ) -> VisitChildrenResult,
1185 drop: extern "C" fn(VRefMut<ItemVisitorVTable>),
1187}
1188
1189pub type ItemVisitorRefMut<'a> = vtable::VRefMut<'a, ItemVisitorVTable>;
1191
1192impl<T: FnMut(&ItemTreeRc, u32, Pin<ItemRef>) -> VisitChildrenResult> ItemVisitor for T {
1193 fn visit_item(
1194 &mut self,
1195 item_tree: &ItemTreeRc,
1196 index: u32,
1197 item: Pin<ItemRef>,
1198 ) -> VisitChildrenResult {
1199 self(item_tree, index, item)
1200 }
1201}
1202pub enum ItemVisitorResult<State> {
1203 Continue(State),
1204 SkipChildren,
1205 Abort,
1206}
1207
1208pub fn visit_items<State>(
1214 item_tree: &ItemTreeRc,
1215 order: TraversalOrder,
1216 mut visitor: impl FnMut(&ItemTreeRc, Pin<ItemRef>, u32, &State) -> ItemVisitorResult<State>,
1217 state: State,
1218) -> VisitChildrenResult {
1219 visit_internal(item_tree, order, &mut visitor, -1, &state)
1220}
1221
1222fn visit_internal<State>(
1223 item_tree: &ItemTreeRc,
1224 order: TraversalOrder,
1225 visitor: &mut impl FnMut(&ItemTreeRc, Pin<ItemRef>, u32, &State) -> ItemVisitorResult<State>,
1226 index: isize,
1227 state: &State,
1228) -> VisitChildrenResult {
1229 let mut actual_visitor =
1230 |item_tree: &ItemTreeRc, index: u32, item: Pin<ItemRef>| -> VisitChildrenResult {
1231 match visitor(item_tree, item, index, state) {
1232 ItemVisitorResult::Continue(state) => {
1233 visit_internal(item_tree, order, visitor, index as isize, &state)
1234 }
1235 ItemVisitorResult::SkipChildren => VisitChildrenResult::CONTINUE,
1236 ItemVisitorResult::Abort => VisitChildrenResult::abort(index, 0),
1237 }
1238 };
1239 vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);
1240 VRc::borrow_pin(item_tree).as_ref().visit_children_item(index, order, actual_visitor)
1241}
1242
1243pub fn visit_item_tree<Base>(
1252 base: Pin<&Base>,
1253 item_tree: &ItemTreeRc,
1254 item_tree_array: &[ItemTreeNode],
1255 index: isize,
1256 order: TraversalOrder,
1257 mut visitor: vtable::VRefMut<ItemVisitorVTable>,
1258 visit_dynamic: impl Fn(
1259 Pin<&Base>,
1260 TraversalOrder,
1261 vtable::VRefMut<ItemVisitorVTable>,
1262 u32,
1263 ) -> VisitChildrenResult,
1264) -> VisitChildrenResult {
1265 let mut visit_at_index = |idx: u32| -> VisitChildrenResult {
1266 match &item_tree_array[idx as usize] {
1267 ItemTreeNode::Item { .. } => {
1268 let item = crate::items::ItemRc::new(item_tree.clone(), idx);
1269 visitor.visit_item(item_tree, idx, item.borrow())
1270 }
1271 ItemTreeNode::DynamicTree { index, .. } => {
1272 if let Some(sub_idx) =
1273 visit_dynamic(base, order, visitor.borrow_mut(), *index).aborted_index()
1274 {
1275 VisitChildrenResult::abort(idx, sub_idx)
1276 } else {
1277 VisitChildrenResult::CONTINUE
1278 }
1279 }
1280 }
1281 };
1282 if index == -1 {
1283 visit_at_index(0)
1284 } else {
1285 match &item_tree_array[index as usize] {
1286 ItemTreeNode::Item { children_index, children_count, .. } => {
1287 for c in 0..*children_count {
1288 let idx = match order {
1289 TraversalOrder::BackToFront => *children_index + c,
1290 TraversalOrder::FrontToBack => *children_index + *children_count - c - 1,
1291 };
1292 let maybe_abort_index = visit_at_index(idx);
1293 if maybe_abort_index.has_aborted() {
1294 return maybe_abort_index;
1295 }
1296 }
1297 }
1298 ItemTreeNode::DynamicTree { .. } => panic!("should not be called with dynamic items"),
1299 };
1300 VisitChildrenResult::CONTINUE
1301 }
1302}
1303
1304#[cfg(feature = "ffi")]
1305pub(crate) mod ffi {
1306 #![allow(unsafe_code)]
1307
1308 use super::*;
1309 use core::ffi::c_void;
1310
1311 #[unsafe(no_mangle)]
1313 pub unsafe extern "C" fn slint_register_item_tree(
1314 item_tree_rc: &ItemTreeRc,
1315 window_handle: *const crate::window::ffi::WindowAdapterRcOpaque,
1316 ) {
1317 unsafe {
1318 let window_adapter = (window_handle as *const WindowAdapterRc).as_ref().cloned();
1319 super::register_item_tree(item_tree_rc, window_adapter)
1320 }
1321 }
1322
1323 #[unsafe(no_mangle)]
1325 pub unsafe extern "C" fn slint_unregister_item_tree(
1326 component: ItemTreeRefPin,
1327 item_array: Slice<vtable::VOffset<u8, ItemVTable, vtable::AllowPin>>,
1328 window_handle: *const crate::window::ffi::WindowAdapterRcOpaque,
1329 ) {
1330 unsafe {
1331 let window_adapter = &*(window_handle as *const WindowAdapterRc);
1332 super::unregister_item_tree(
1333 core::pin::Pin::new_unchecked(&*(component.as_ptr() as *const u8)),
1334 core::pin::Pin::into_inner(component),
1335 item_array.as_slice(),
1336 window_adapter,
1337 )
1338 }
1339 }
1340
1341 #[unsafe(no_mangle)]
1345 pub unsafe extern "C" fn slint_visit_item_tree(
1346 item_tree: &ItemTreeRc,
1347 item_tree_array: Slice<ItemTreeNode>,
1348 index: isize,
1349 order: TraversalOrder,
1350 visitor: VRefMut<ItemVisitorVTable>,
1351 visit_dynamic: extern "C" fn(
1352 base: *const c_void,
1353 order: TraversalOrder,
1354 visitor: vtable::VRefMut<ItemVisitorVTable>,
1355 dyn_index: u32,
1356 ) -> VisitChildrenResult,
1357 ) -> VisitChildrenResult {
1358 crate::item_tree::visit_item_tree(
1359 VRc::as_pin_ref(item_tree),
1360 item_tree,
1361 item_tree_array.as_slice(),
1362 index,
1363 order,
1364 visitor,
1365 |a, b, c, d| visit_dynamic(a.get_ref() as *const vtable::Dyn as *const c_void, b, c, d),
1366 )
1367 }
1368}
1369
1370#[cfg(test)]
1371mod tests {
1372 use super::*;
1373 use std::vec;
1374
1375 struct TestItemTree {
1376 parent_component: Option<ItemTreeRc>,
1377 item_tree: Vec<ItemTreeNode>,
1378 subtrees: std::cell::RefCell<Vec<Vec<vtable::VRc<ItemTreeVTable, TestItemTree>>>>,
1379 subtree_index: usize,
1380 }
1381
1382 impl ItemTree for TestItemTree {
1383 fn visit_children_item(
1384 self: core::pin::Pin<&Self>,
1385 _1: isize,
1386 _2: crate::item_tree::TraversalOrder,
1387 _3: vtable::VRefMut<crate::item_tree::ItemVisitorVTable>,
1388 ) -> crate::item_tree::VisitChildrenResult {
1389 unimplemented!("Not needed for this test")
1390 }
1391
1392 fn get_item_ref(
1393 self: core::pin::Pin<&Self>,
1394 _1: u32,
1395 ) -> core::pin::Pin<vtable::VRef<'_, super::ItemVTable>> {
1396 unimplemented!("Not needed for this test")
1397 }
1398
1399 fn get_item_tree(self: core::pin::Pin<&Self>) -> Slice<'_, ItemTreeNode> {
1400 Slice::from_slice(&self.get_ref().item_tree)
1401 }
1402
1403 fn parent_node(self: core::pin::Pin<&Self>, result: &mut ItemWeak) {
1404 if let Some(parent_item) = self.parent_component.clone() {
1405 *result =
1406 ItemRc::new(parent_item.clone(), self.item_tree[0].parent_index()).downgrade();
1407 }
1408 }
1409
1410 fn embed_component(
1411 self: core::pin::Pin<&Self>,
1412 _parent_component: &ItemTreeWeak,
1413 _item_tree_index: u32,
1414 ) -> bool {
1415 false
1416 }
1417
1418 fn layout_info(self: core::pin::Pin<&Self>, _1: Orientation) -> LayoutInfo {
1419 unimplemented!("Not needed for this test")
1420 }
1421
1422 fn subtree_index(self: core::pin::Pin<&Self>) -> usize {
1423 self.subtree_index
1424 }
1425
1426 fn get_subtree_range(self: core::pin::Pin<&Self>, subtree_index: u32) -> IndexRange {
1427 (0..self.subtrees.borrow()[subtree_index as usize].len()).into()
1428 }
1429
1430 fn get_subtree(
1431 self: core::pin::Pin<&Self>,
1432 subtree_index: u32,
1433 component_index: usize,
1434 result: &mut ItemTreeWeak,
1435 ) {
1436 if let Some(vrc) = self.subtrees.borrow()[subtree_index as usize].get(component_index) {
1437 *result = vtable::VRc::downgrade(&vtable::VRc::into_dyn(vrc.clone()))
1438 }
1439 }
1440
1441 fn accessible_role(self: Pin<&Self>, _: u32) -> AccessibleRole {
1442 unimplemented!("Not needed for this test")
1443 }
1444
1445 fn accessible_string_property(
1446 self: Pin<&Self>,
1447 _: u32,
1448 _: AccessibleStringProperty,
1449 _: &mut SharedString,
1450 ) -> bool {
1451 false
1452 }
1453
1454 fn item_element_infos(self: Pin<&Self>, _: u32, _: &mut SharedString) -> bool {
1455 false
1456 }
1457
1458 fn window_adapter(
1459 self: Pin<&Self>,
1460 _do_create: bool,
1461 _result: &mut Option<WindowAdapterRc>,
1462 ) {
1463 unimplemented!("Not needed for this test")
1464 }
1465
1466 fn item_geometry(self: Pin<&Self>, _: u32) -> LogicalRect {
1467 unimplemented!("Not needed for this test")
1468 }
1469
1470 fn accessibility_action(self: core::pin::Pin<&Self>, _: u32, _: &AccessibilityAction) {
1471 unimplemented!("Not needed for this test")
1472 }
1473
1474 fn supported_accessibility_actions(
1475 self: core::pin::Pin<&Self>,
1476 _: u32,
1477 ) -> SupportedAccessibilityAction {
1478 unimplemented!("Not needed for this test")
1479 }
1480 }
1481
1482 crate::item_tree::ItemTreeVTable_static!(static TEST_COMPONENT_VT for TestItemTree);
1483
1484 fn create_one_node_component() -> VRc<ItemTreeVTable, vtable::Dyn> {
1485 let component = VRc::new(TestItemTree {
1486 parent_component: None,
1487 item_tree: vec![ItemTreeNode::Item {
1488 is_accessible: false,
1489 children_count: 0,
1490 children_index: 1,
1491 parent_index: 0,
1492 item_array_index: 0,
1493 }],
1494 subtrees: std::cell::RefCell::new(Vec::new()),
1495 subtree_index: usize::MAX,
1496 });
1497 VRc::into_dyn(component)
1498 }
1499
1500 #[test]
1501 fn test_tree_traversal_one_node_structure() {
1502 let component = create_one_node_component();
1503
1504 let item = ItemRc::new(component.clone(), 0);
1505
1506 assert!(item.first_child().is_none());
1507 assert!(item.last_child().is_none());
1508 assert!(item.previous_sibling().is_none());
1509 assert!(item.next_sibling().is_none());
1510 }
1511
1512 #[test]
1513 fn test_tree_traversal_one_node_forward_focus() {
1514 let component = create_one_node_component();
1515
1516 let item = ItemRc::new(component.clone(), 0);
1517
1518 assert_eq!(item.next_focus_item(), item);
1520 }
1521
1522 #[test]
1523 fn test_tree_traversal_one_node_backward_focus() {
1524 let component = create_one_node_component();
1525
1526 let item = ItemRc::new(component.clone(), 0);
1527
1528 assert_eq!(item.previous_focus_item(), item);
1530 }
1531
1532 fn create_children_nodes() -> VRc<ItemTreeVTable, vtable::Dyn> {
1533 let component = VRc::new(TestItemTree {
1534 parent_component: None,
1535 item_tree: vec![
1536 ItemTreeNode::Item {
1537 is_accessible: false,
1538 children_count: 3,
1539 children_index: 1,
1540 parent_index: 0,
1541 item_array_index: 0,
1542 },
1543 ItemTreeNode::Item {
1544 is_accessible: false,
1545 children_count: 0,
1546 children_index: 4,
1547 parent_index: 0,
1548 item_array_index: 1,
1549 },
1550 ItemTreeNode::Item {
1551 is_accessible: false,
1552 children_count: 0,
1553 children_index: 4,
1554 parent_index: 0,
1555 item_array_index: 2,
1556 },
1557 ItemTreeNode::Item {
1558 is_accessible: false,
1559 children_count: 0,
1560 children_index: 4,
1561 parent_index: 0,
1562 item_array_index: 3,
1563 },
1564 ],
1565 subtrees: std::cell::RefCell::new(Vec::new()),
1566 subtree_index: usize::MAX,
1567 });
1568 VRc::into_dyn(component)
1569 }
1570
1571 #[test]
1572 fn test_tree_traversal_children_nodes_structure() {
1573 let component = create_children_nodes();
1574
1575 let item = ItemRc::new(component.clone(), 0);
1577 assert!(item.previous_sibling().is_none());
1578 assert!(item.next_sibling().is_none());
1579
1580 let fc = item.first_child().unwrap();
1581 assert_eq!(fc.index(), 1);
1582 assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
1583
1584 let fcn = fc.next_sibling().unwrap();
1585 assert_eq!(fcn.index(), 2);
1586
1587 let lc = item.last_child().unwrap();
1588 assert_eq!(lc.index(), 3);
1589 assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
1590
1591 let lcp = lc.previous_sibling().unwrap();
1592 assert!(VRc::ptr_eq(lcp.item_tree(), item.item_tree()));
1593 assert_eq!(lcp.index(), 2);
1594
1595 assert!(fc.first_child().is_none());
1597 assert!(fc.last_child().is_none());
1598 assert!(fc.previous_sibling().is_none());
1599 assert_eq!(fc.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);
1600
1601 assert_eq!(fcn, lcp);
1603 assert_eq!(lcp.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);
1604 assert_eq!(fcn.previous_sibling().unwrap(), fc);
1605 assert_eq!(fcn.next_sibling().unwrap(), lc);
1606
1607 assert!(lc.first_child().is_none());
1609 assert!(lc.last_child().is_none());
1610 assert!(lc.next_sibling().is_none());
1611 assert_eq!(lc.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);
1612 }
1613
1614 #[test]
1615 fn test_tree_traversal_children_nodes_forward_focus() {
1616 let component = create_children_nodes();
1617
1618 let item = ItemRc::new(component.clone(), 0);
1619 let fc = item.first_child().unwrap();
1620 let fcn = fc.next_sibling().unwrap();
1621 let lc = item.last_child().unwrap();
1622
1623 let mut cursor = item.clone();
1624
1625 cursor = cursor.next_focus_item();
1626 assert_eq!(cursor, fc);
1627
1628 cursor = cursor.next_focus_item();
1629 assert_eq!(cursor, fcn);
1630
1631 cursor = cursor.next_focus_item();
1632 assert_eq!(cursor, lc);
1633
1634 cursor = cursor.next_focus_item();
1635 assert_eq!(cursor, item);
1636 }
1637
1638 #[test]
1639 fn test_tree_traversal_children_nodes_backward_focus() {
1640 let component = create_children_nodes();
1641
1642 let item = ItemRc::new(component.clone(), 0);
1643 let fc = item.first_child().unwrap();
1644 let fcn = fc.next_sibling().unwrap();
1645 let lc = item.last_child().unwrap();
1646
1647 let mut cursor = item.clone();
1648
1649 cursor = cursor.previous_focus_item();
1650 assert_eq!(cursor, lc);
1651
1652 cursor = cursor.previous_focus_item();
1653 assert_eq!(cursor, fcn);
1654
1655 cursor = cursor.previous_focus_item();
1656 assert_eq!(cursor, fc);
1657
1658 cursor = cursor.previous_focus_item();
1659 assert_eq!(cursor, item);
1660 }
1661
1662 fn create_empty_subtree() -> VRc<ItemTreeVTable, vtable::Dyn> {
1663 let component = vtable::VRc::new(TestItemTree {
1664 parent_component: None,
1665 item_tree: vec![
1666 ItemTreeNode::Item {
1667 is_accessible: false,
1668 children_count: 1,
1669 children_index: 1,
1670 parent_index: 0,
1671 item_array_index: 0,
1672 },
1673 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1674 ],
1675 subtrees: std::cell::RefCell::new(vec![Vec::new()]),
1676 subtree_index: usize::MAX,
1677 });
1678 vtable::VRc::into_dyn(component)
1679 }
1680
1681 #[test]
1682 fn test_tree_traversal_empty_subtree_structure() {
1683 let component = create_empty_subtree();
1684
1685 let item = ItemRc::new(component.clone(), 0);
1687 assert!(item.previous_sibling().is_none());
1688 assert!(item.next_sibling().is_none());
1689 assert!(item.first_child().is_none());
1690 assert!(item.last_child().is_none());
1691
1692 assert!(item.previous_focus_item() == item);
1694 assert!(item.next_focus_item() == item);
1695 }
1696
1697 #[test]
1698 fn test_tree_traversal_empty_subtree_forward_focus() {
1699 let component = create_empty_subtree();
1700
1701 let item = ItemRc::new(component.clone(), 0);
1703
1704 assert!(item.next_focus_item() == item);
1705 }
1706
1707 #[test]
1708 fn test_tree_traversal_empty_subtree_backward_focus() {
1709 let component = create_empty_subtree();
1710
1711 let item = ItemRc::new(component.clone(), 0);
1713
1714 assert!(item.previous_focus_item() == item);
1715 }
1716
1717 fn create_item_subtree_item() -> VRc<ItemTreeVTable, vtable::Dyn> {
1718 let component = VRc::new(TestItemTree {
1719 parent_component: None,
1720 item_tree: vec![
1721 ItemTreeNode::Item {
1722 is_accessible: false,
1723 children_count: 3,
1724 children_index: 1,
1725 parent_index: 0,
1726 item_array_index: 0,
1727 },
1728 ItemTreeNode::Item {
1729 is_accessible: false,
1730 children_count: 0,
1731 children_index: 4,
1732 parent_index: 0,
1733 item_array_index: 0,
1734 },
1735 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1736 ItemTreeNode::Item {
1737 is_accessible: false,
1738 children_count: 0,
1739 children_index: 4,
1740 parent_index: 0,
1741 item_array_index: 0,
1742 },
1743 ],
1744 subtrees: std::cell::RefCell::new(Vec::new()),
1745 subtree_index: usize::MAX,
1746 });
1747
1748 component.as_pin_ref().subtrees.replace(vec![vec![VRc::new(TestItemTree {
1749 parent_component: Some(VRc::into_dyn(component.clone())),
1750 item_tree: vec![ItemTreeNode::Item {
1751 is_accessible: false,
1752 children_count: 0,
1753 children_index: 1,
1754 parent_index: 2,
1755 item_array_index: 0,
1756 }],
1757 subtrees: std::cell::RefCell::new(Vec::new()),
1758 subtree_index: 0,
1759 })]]);
1760
1761 VRc::into_dyn(component)
1762 }
1763
1764 #[test]
1765 fn test_tree_traversal_item_subtree_item_structure() {
1766 let component = create_item_subtree_item();
1767
1768 let item = ItemRc::new(component.clone(), 0);
1770 assert!(item.previous_sibling().is_none());
1771 assert!(item.next_sibling().is_none());
1772
1773 let fc = item.first_child().unwrap();
1774 assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
1775 assert_eq!(fc.index(), 1);
1776
1777 let lc = item.last_child().unwrap();
1778 assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
1779 assert_eq!(lc.index(), 3);
1780
1781 let fcn = fc.next_sibling().unwrap();
1782 let lcp = lc.previous_sibling().unwrap();
1783
1784 assert_eq!(fcn, lcp);
1785 assert!(!VRc::ptr_eq(fcn.item_tree(), item.item_tree()));
1786
1787 let last = fcn.next_sibling().unwrap();
1788 assert_eq!(last, lc);
1789
1790 let first = lcp.previous_sibling().unwrap();
1791 assert_eq!(first, fc);
1792 }
1793
1794 #[test]
1795 fn test_tree_traversal_item_subtree_item_forward_focus() {
1796 let component = create_item_subtree_item();
1797
1798 let item = ItemRc::new(component.clone(), 0);
1799 let fc = item.first_child().unwrap();
1800 let lc = item.last_child().unwrap();
1801 let fcn = fc.next_sibling().unwrap();
1802
1803 let mut cursor = item.clone();
1804
1805 cursor = cursor.next_focus_item();
1806 assert_eq!(cursor, fc);
1807
1808 cursor = cursor.next_focus_item();
1809 assert_eq!(cursor, fcn);
1810
1811 cursor = cursor.next_focus_item();
1812 assert_eq!(cursor, lc);
1813
1814 cursor = cursor.next_focus_item();
1815 assert_eq!(cursor, item);
1816 }
1817
1818 #[test]
1819 fn test_tree_traversal_item_subtree_item_backward_focus() {
1820 let component = create_item_subtree_item();
1821
1822 let item = ItemRc::new(component.clone(), 0);
1823 let fc = item.first_child().unwrap();
1824 let lc = item.last_child().unwrap();
1825 let fcn = fc.next_sibling().unwrap();
1826
1827 let mut cursor = item.clone();
1828
1829 cursor = cursor.previous_focus_item();
1830 assert_eq!(cursor, lc);
1831
1832 cursor = cursor.previous_focus_item();
1833 assert_eq!(cursor, fcn);
1834
1835 cursor = cursor.previous_focus_item();
1836 assert_eq!(cursor, fc);
1837
1838 cursor = cursor.previous_focus_item();
1839 assert_eq!(cursor, item);
1840 }
1841
1842 fn create_nested_subtrees() -> VRc<ItemTreeVTable, vtable::Dyn> {
1843 let component = VRc::new(TestItemTree {
1844 parent_component: None,
1845 item_tree: vec![
1846 ItemTreeNode::Item {
1847 is_accessible: false,
1848 children_count: 3,
1849 children_index: 1,
1850 parent_index: 0,
1851 item_array_index: 0,
1852 },
1853 ItemTreeNode::Item {
1854 is_accessible: false,
1855 children_count: 0,
1856 children_index: 4,
1857 parent_index: 0,
1858 item_array_index: 0,
1859 },
1860 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1861 ItemTreeNode::Item {
1862 is_accessible: false,
1863 children_count: 0,
1864 children_index: 4,
1865 parent_index: 0,
1866 item_array_index: 0,
1867 },
1868 ],
1869 subtrees: std::cell::RefCell::new(Vec::new()),
1870 subtree_index: usize::MAX,
1871 });
1872
1873 let sub_component1 = VRc::new(TestItemTree {
1874 parent_component: Some(VRc::into_dyn(component.clone())),
1875 item_tree: vec![
1876 ItemTreeNode::Item {
1877 is_accessible: false,
1878 children_count: 1,
1879 children_index: 1,
1880 parent_index: 2,
1881 item_array_index: 0,
1882 },
1883 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1884 ],
1885 subtrees: std::cell::RefCell::new(Vec::new()),
1886 subtree_index: usize::MAX,
1887 });
1888 let sub_component2 = VRc::new(TestItemTree {
1889 parent_component: Some(VRc::into_dyn(sub_component1.clone())),
1890 item_tree: vec![
1891 ItemTreeNode::Item {
1892 is_accessible: false,
1893 children_count: 1,
1894 children_index: 1,
1895 parent_index: 1,
1896 item_array_index: 0,
1897 },
1898 ItemTreeNode::Item {
1899 is_accessible: false,
1900 children_count: 0,
1901 children_index: 2,
1902 parent_index: 0,
1903 item_array_index: 0,
1904 },
1905 ],
1906 subtrees: std::cell::RefCell::new(Vec::new()),
1907 subtree_index: usize::MAX,
1908 });
1909
1910 sub_component1.as_pin_ref().subtrees.replace(vec![vec![sub_component2]]);
1911 component.as_pin_ref().subtrees.replace(vec![vec![sub_component1]]);
1912
1913 VRc::into_dyn(component)
1914 }
1915
1916 #[test]
1917 fn test_tree_traversal_nested_subtrees_structure() {
1918 let component = create_nested_subtrees();
1919
1920 let item = ItemRc::new(component.clone(), 0);
1922 assert!(item.previous_sibling().is_none());
1923 assert!(item.next_sibling().is_none());
1924
1925 let fc = item.first_child().unwrap();
1926 assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
1927 assert_eq!(fc.index(), 1);
1928
1929 let lc = item.last_child().unwrap();
1930 assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
1931 assert_eq!(lc.index(), 3);
1932
1933 let fcn = fc.next_sibling().unwrap();
1934 let lcp = lc.previous_sibling().unwrap();
1935
1936 assert_eq!(fcn, lcp);
1937 assert!(!VRc::ptr_eq(fcn.item_tree(), item.item_tree()));
1938
1939 let last = fcn.next_sibling().unwrap();
1940 assert_eq!(last, lc);
1941
1942 let first = lcp.previous_sibling().unwrap();
1943 assert_eq!(first, fc);
1944
1945 let nested_root = fcn.first_child().unwrap();
1947 assert_eq!(nested_root, fcn.last_child().unwrap());
1948 assert!(nested_root.next_sibling().is_none());
1949 assert!(nested_root.previous_sibling().is_none());
1950 assert!(!VRc::ptr_eq(nested_root.item_tree(), item.item_tree()));
1951 assert!(!VRc::ptr_eq(nested_root.item_tree(), fcn.item_tree()));
1952
1953 let nested_child = nested_root.first_child().unwrap();
1954 assert_eq!(nested_child, nested_root.last_child().unwrap());
1955 assert!(VRc::ptr_eq(nested_root.item_tree(), nested_child.item_tree()));
1956 }
1957
1958 #[test]
1959 fn test_tree_traversal_nested_subtrees_forward_focus() {
1960 let component = create_nested_subtrees();
1961
1962 let item = ItemRc::new(component.clone(), 0);
1964 let fc = item.first_child().unwrap();
1965 let fcn = fc.next_sibling().unwrap();
1966 let lc = item.last_child().unwrap();
1967 let nested_root = fcn.first_child().unwrap();
1968 let nested_child = nested_root.first_child().unwrap();
1969
1970 let mut cursor = item.clone();
1972
1973 cursor = cursor.next_focus_item();
1974 assert_eq!(cursor, fc);
1975
1976 cursor = cursor.next_focus_item();
1977 assert_eq!(cursor, fcn);
1978
1979 cursor = cursor.next_focus_item();
1980 assert_eq!(cursor, nested_root);
1981
1982 cursor = cursor.next_focus_item();
1983 assert_eq!(cursor, nested_child);
1984
1985 cursor = cursor.next_focus_item();
1986 assert_eq!(cursor, lc);
1987
1988 cursor = cursor.next_focus_item();
1989 assert_eq!(cursor, item);
1990 }
1991
1992 #[test]
1993 fn test_tree_traversal_nested_subtrees_backward_focus() {
1994 let component = create_nested_subtrees();
1995
1996 let item = ItemRc::new(component.clone(), 0);
1998 let fc = item.first_child().unwrap();
1999 let fcn = fc.next_sibling().unwrap();
2000 let lc = item.last_child().unwrap();
2001 let nested_root = fcn.first_child().unwrap();
2002 let nested_child = nested_root.first_child().unwrap();
2003
2004 let mut cursor = item.clone();
2006
2007 cursor = cursor.previous_focus_item();
2008 assert_eq!(cursor, lc);
2009
2010 cursor = cursor.previous_focus_item();
2011 assert_eq!(cursor, nested_child);
2012
2013 cursor = cursor.previous_focus_item();
2014 assert_eq!(cursor, nested_root);
2015
2016 cursor = cursor.previous_focus_item();
2017 assert_eq!(cursor, fcn);
2018
2019 cursor = cursor.previous_focus_item();
2020 assert_eq!(cursor, fc);
2021
2022 cursor = cursor.previous_focus_item();
2023 assert_eq!(cursor, item);
2024 }
2025
2026 fn create_subtrees_item() -> VRc<ItemTreeVTable, vtable::Dyn> {
2027 let component = VRc::new(TestItemTree {
2028 parent_component: None,
2029 item_tree: vec![
2030 ItemTreeNode::Item {
2031 is_accessible: false,
2032 children_count: 2,
2033 children_index: 1,
2034 parent_index: 0,
2035 item_array_index: 0,
2036 },
2037 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
2038 ItemTreeNode::Item {
2039 is_accessible: false,
2040 children_count: 0,
2041 children_index: 4,
2042 parent_index: 0,
2043 item_array_index: 0,
2044 },
2045 ],
2046 subtrees: std::cell::RefCell::new(Vec::new()),
2047 subtree_index: usize::MAX,
2048 });
2049
2050 component.as_pin_ref().subtrees.replace(vec![vec![
2051 VRc::new(TestItemTree {
2052 parent_component: Some(VRc::into_dyn(component.clone())),
2053 item_tree: vec![ItemTreeNode::Item {
2054 is_accessible: false,
2055 children_count: 0,
2056 children_index: 1,
2057 parent_index: 1,
2058 item_array_index: 0,
2059 }],
2060 subtrees: std::cell::RefCell::new(Vec::new()),
2061 subtree_index: 0,
2062 }),
2063 VRc::new(TestItemTree {
2064 parent_component: Some(VRc::into_dyn(component.clone())),
2065 item_tree: vec![ItemTreeNode::Item {
2066 is_accessible: false,
2067 children_count: 0,
2068 children_index: 1,
2069 parent_index: 1,
2070 item_array_index: 0,
2071 }],
2072 subtrees: std::cell::RefCell::new(Vec::new()),
2073 subtree_index: 1,
2074 }),
2075 VRc::new(TestItemTree {
2076 parent_component: Some(VRc::into_dyn(component.clone())),
2077 item_tree: vec![ItemTreeNode::Item {
2078 is_accessible: false,
2079 children_count: 0,
2080 children_index: 1,
2081 parent_index: 1,
2082 item_array_index: 0,
2083 }],
2084 subtrees: std::cell::RefCell::new(Vec::new()),
2085 subtree_index: 2,
2086 }),
2087 ]]);
2088
2089 VRc::into_dyn(component)
2090 }
2091
2092 #[test]
2093 fn test_tree_traversal_subtrees_item_structure() {
2094 let component = create_subtrees_item();
2095
2096 let item = ItemRc::new(component.clone(), 0);
2098 assert!(item.previous_sibling().is_none());
2099 assert!(item.next_sibling().is_none());
2100
2101 let sub1 = item.first_child().unwrap();
2102 assert_eq!(sub1.index(), 0);
2103 assert!(!VRc::ptr_eq(sub1.item_tree(), item.item_tree()));
2104
2105 let sub2 = sub1.next_sibling().unwrap();
2108 assert_eq!(sub2.index(), 0);
2109 assert!(!VRc::ptr_eq(sub1.item_tree(), sub2.item_tree()));
2110 assert!(!VRc::ptr_eq(item.item_tree(), sub2.item_tree()));
2111
2112 assert!(sub2.previous_sibling() == Some(sub1.clone()));
2113
2114 let sub3 = sub2.next_sibling().unwrap();
2115 assert_eq!(sub3.index(), 0);
2116 assert!(!VRc::ptr_eq(sub1.item_tree(), sub2.item_tree()));
2117 assert!(!VRc::ptr_eq(sub2.item_tree(), sub3.item_tree()));
2118 assert!(!VRc::ptr_eq(item.item_tree(), sub3.item_tree()));
2119
2120 assert_eq!(sub3.previous_sibling().unwrap(), sub2.clone());
2121 }
2122
2123 #[test]
2124 fn test_component_item_tree_root_only() {
2125 let nodes = vec![ItemTreeNode::Item {
2126 is_accessible: false,
2127 children_count: 0,
2128 children_index: 1,
2129 parent_index: 0,
2130 item_array_index: 0,
2131 }];
2132
2133 let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
2134
2135 assert_eq!(tree.first_child(0), None);
2136 assert_eq!(tree.last_child(0), None);
2137 assert_eq!(tree.previous_sibling(0), None);
2138 assert_eq!(tree.next_sibling(0), None);
2139 assert_eq!(tree.parent(0), None);
2140 }
2141
2142 #[test]
2143 fn test_component_item_tree_one_child() {
2144 let nodes = vec![
2145 ItemTreeNode::Item {
2146 is_accessible: false,
2147 children_count: 1,
2148 children_index: 1,
2149 parent_index: 0,
2150 item_array_index: 0,
2151 },
2152 ItemTreeNode::Item {
2153 is_accessible: false,
2154 children_count: 0,
2155 children_index: 2,
2156 parent_index: 0,
2157 item_array_index: 0,
2158 },
2159 ];
2160
2161 let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
2162
2163 assert_eq!(tree.first_child(0), Some(1));
2164 assert_eq!(tree.last_child(0), Some(1));
2165 assert_eq!(tree.previous_sibling(0), None);
2166 assert_eq!(tree.next_sibling(0), None);
2167 assert_eq!(tree.parent(0), None);
2168 assert_eq!(tree.previous_sibling(1), None);
2169 assert_eq!(tree.next_sibling(1), None);
2170 assert_eq!(tree.parent(1), Some(0));
2171 }
2172
2173 #[test]
2174 fn test_component_item_tree_tree_children() {
2175 let nodes = vec![
2176 ItemTreeNode::Item {
2177 is_accessible: false,
2178 children_count: 3,
2179 children_index: 1,
2180 parent_index: 0,
2181 item_array_index: 0,
2182 },
2183 ItemTreeNode::Item {
2184 is_accessible: false,
2185 children_count: 0,
2186 children_index: 4,
2187 parent_index: 0,
2188 item_array_index: 0,
2189 },
2190 ItemTreeNode::Item {
2191 is_accessible: false,
2192 children_count: 0,
2193 children_index: 4,
2194 parent_index: 0,
2195 item_array_index: 0,
2196 },
2197 ItemTreeNode::Item {
2198 is_accessible: false,
2199 children_count: 0,
2200 children_index: 4,
2201 parent_index: 0,
2202 item_array_index: 0,
2203 },
2204 ];
2205
2206 let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
2207
2208 assert_eq!(tree.first_child(0), Some(1));
2209 assert_eq!(tree.last_child(0), Some(3));
2210 assert_eq!(tree.previous_sibling(0), None);
2211 assert_eq!(tree.next_sibling(0), None);
2212 assert_eq!(tree.parent(0), None);
2213
2214 assert_eq!(tree.previous_sibling(1), None);
2215 assert_eq!(tree.next_sibling(1), Some(2));
2216 assert_eq!(tree.parent(1), Some(0));
2217
2218 assert_eq!(tree.previous_sibling(2), Some(1));
2219 assert_eq!(tree.next_sibling(2), Some(3));
2220 assert_eq!(tree.parent(2), Some(0));
2221
2222 assert_eq!(tree.previous_sibling(3), Some(2));
2223 assert_eq!(tree.next_sibling(3), None);
2224 assert_eq!(tree.parent(3), Some(0));
2225 }
2226}