1use crate::accessibility::{
9 AccessibilityAction, AccessibleStringProperty, SupportedAccessibilityAction,
10};
11use crate::items::{AccessibleRole, ItemRef, ItemVTable};
12use crate::layout::{LayoutInfo, Orientation};
13use crate::lengths::{ItemTransform, LogicalPoint, LogicalRect};
14use crate::slice::Slice;
15use crate::window::WindowAdapterRc;
16use crate::SharedString;
17use alloc::vec::Vec;
18use core::ops::ControlFlow;
19use core::pin::Pin;
20use vtable::*;
21
22#[repr(C)]
23#[derive(Debug, Clone, Copy)]
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>,
80
81 pub parent_node: extern "C" fn(core::pin::Pin<VRef<ItemTreeVTable>>, result: &mut ItemWeak),
88
89 pub embed_component: extern "C" fn(
94 core::pin::Pin<VRef<ItemTreeVTable>>,
95 parent: &VWeak<ItemTreeVTable>,
96 parent_item_tree_index: u32,
97 ) -> bool,
98
99 pub subtree_index: extern "C" fn(core::pin::Pin<VRef<ItemTreeVTable>>) -> usize,
101
102 pub layout_info: 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();
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
202fn find_sibling_outside_repeater(
203 component: &ItemTreeRc,
204 comp_ref_pin: Pin<VRef<ItemTreeVTable>>,
205 index: u32,
206 sibling_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
207 subtree_child: &dyn Fn(usize, usize) -> usize,
208) -> Option<ItemRc> {
209 assert_ne!(index, 0);
210
211 let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
212
213 let mut current_sibling = index;
214 loop {
215 current_sibling = sibling_step(&item_tree, current_sibling)?;
216
217 if let Some(node) = step_into_node(
218 component,
219 &comp_ref_pin,
220 current_sibling,
221 &item_tree,
222 subtree_child,
223 &core::convert::identity,
224 ) {
225 return Some(node);
226 }
227 }
228}
229
230fn step_into_node(
231 component: &ItemTreeRc,
232 comp_ref_pin: &Pin<VRef<ItemTreeVTable>>,
233 node_index: u32,
234 item_tree: &crate::item_tree::ItemTreeNodeArray,
235 subtree_child: &dyn Fn(usize, usize) -> usize,
236 wrap_around: &dyn Fn(ItemRc) -> ItemRc,
237) -> Option<ItemRc> {
238 match item_tree.get(node_index).expect("Invalid index passed to item tree") {
239 crate::item_tree::ItemTreeNode::Item { .. } => {
240 Some(ItemRc::new(component.clone(), node_index))
241 }
242 crate::item_tree::ItemTreeNode::DynamicTree { index, .. } => {
243 let range = comp_ref_pin.as_ref().get_subtree_range(*index);
244 let component_index = subtree_child(range.start, range.end);
245 let mut child_instance = Default::default();
246 comp_ref_pin.as_ref().get_subtree(*index, component_index, &mut child_instance);
247 child_instance
248 .upgrade()
249 .map(|child_instance| wrap_around(ItemRc::new(child_instance, 0)))
250 }
251 }
252}
253
254pub enum ParentItemTraversalMode {
255 FindAllParents,
256 StopAtPopups,
257}
258
259#[repr(C)]
261#[derive(Clone, Debug)]
262pub struct ItemRc {
263 item_tree: vtable::VRc<ItemTreeVTable>,
264 index: u32,
265}
266
267impl ItemRc {
268 pub fn new(item_tree: vtable::VRc<ItemTreeVTable>, index: u32) -> Self {
270 Self { item_tree, index }
271 }
272
273 pub fn is_root_item_of(&self, item_tree: &VRc<ItemTreeVTable>) -> bool {
274 self.index == 0 && VRc::ptr_eq(&self.item_tree, item_tree)
275 }
276
277 pub fn borrow<'a>(&'a self) -> Pin<ItemRef<'a>> {
279 #![allow(unsafe_code)]
280 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
281 let result = comp_ref_pin.as_ref().get_item_ref(self.index);
282 unsafe { core::mem::transmute::<Pin<ItemRef<'_>>, Pin<ItemRef<'a>>>(result) }
285 }
286
287 pub fn downcast<T: HasStaticVTable<ItemVTable>>(&self) -> Option<VRcMapped<ItemTreeVTable, T>> {
289 #![allow(unsafe_code)]
290 let item = self.borrow();
291 ItemRef::downcast_pin::<T>(item)?;
292
293 Some(vtable::VRc::map_dyn(self.item_tree.clone(), |comp_ref_pin| {
294 let result = comp_ref_pin.as_ref().get_item_ref(self.index);
295 let item =
298 unsafe { core::mem::transmute::<Pin<ItemRef<'_>>, Pin<ItemRef<'_>>>(result) };
299 ItemRef::downcast_pin::<T>(item).unwrap()
300 }))
301 }
302
303 pub fn downgrade(&self) -> ItemWeak {
304 ItemWeak { item_tree: VRc::downgrade(&self.item_tree), index: self.index }
305 }
306
307 pub fn parent_item(&self, find_mode: ParentItemTraversalMode) -> Option<ItemRc> {
311 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
312 let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
313
314 if let Some(parent_index) = item_tree.parent(self.index) {
315 return Some(ItemRc::new(self.item_tree.clone(), parent_index));
316 }
317
318 let mut r = ItemWeak::default();
319 comp_ref_pin.as_ref().parent_node(&mut r);
320 let parent = r.upgrade()?;
321 let comp_ref_pin = vtable::VRc::borrow_pin(&parent.item_tree);
322 let item_tree_array = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
323 if let Some(ItemTreeNode::DynamicTree { parent_index, .. }) =
324 item_tree_array.get(parent.index())
325 {
326 Some(ItemRc::new(parent.item_tree.clone(), *parent_index))
328 } else {
329 match find_mode {
332 ParentItemTraversalMode::FindAllParents => Some(parent),
333 ParentItemTraversalMode::StopAtPopups => None,
334 }
335 }
336 }
337
338 pub fn is_visible(&self) -> bool {
341 let (clip, geometry) = self.absolute_clip_rect_and_geometry();
342 let clip = clip.to_box2d();
343 let geometry = geometry.to_box2d();
344 !clip.is_empty()
345 && clip.max.x >= geometry.min.x
346 && clip.max.y >= geometry.min.y
347 && clip.min.x <= geometry.max.x
348 && clip.min.y <= geometry.max.y
349 }
350
351 fn absolute_clip_rect_and_geometry(&self) -> (LogicalRect, LogicalRect) {
354 let (mut clip, parent_geometry) =
355 self.parent_item(ParentItemTraversalMode::StopAtPopups).map_or_else(
356 || {
357 (
358 LogicalRect::from_size((crate::Coord::MAX, crate::Coord::MAX).into()),
359 Default::default(),
360 )
361 },
362 |parent| parent.absolute_clip_rect_and_geometry(),
363 );
364
365 let geometry = self.geometry().translate(parent_geometry.origin.to_vector());
366
367 let item = self.borrow();
368 if item.as_ref().clips_children() {
369 clip = geometry.intersection(&clip).unwrap_or_default();
370 }
371
372 (clip, geometry)
373 }
374
375 pub fn is_accessible(&self) -> bool {
376 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
377 let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
378
379 if let Some(n) = &item_tree.get(self.index) {
380 match n {
381 ItemTreeNode::Item { is_accessible, .. } => *is_accessible,
382 ItemTreeNode::DynamicTree { .. } => false,
383 }
384 } else {
385 false
386 }
387 }
388
389 pub fn accessible_role(&self) -> crate::items::AccessibleRole {
390 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
391 comp_ref_pin.as_ref().accessible_role(self.index)
392 }
393
394 pub fn accessible_string_property(
395 &self,
396 what: crate::accessibility::AccessibleStringProperty,
397 ) -> Option<SharedString> {
398 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
399 let mut result = Default::default();
400 let ok = comp_ref_pin.as_ref().accessible_string_property(self.index, what, &mut result);
401 ok.then_some(result)
402 }
403
404 pub fn accessible_action(&self, action: &crate::accessibility::AccessibilityAction) {
405 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
406 comp_ref_pin.as_ref().accessibility_action(self.index, action);
407 }
408
409 pub fn supported_accessibility_actions(&self) -> SupportedAccessibilityAction {
410 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
411 comp_ref_pin.as_ref().supported_accessibility_actions(self.index)
412 }
413
414 pub fn element_count(&self) -> Option<usize> {
415 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
416 let mut result = SharedString::new();
417 comp_ref_pin
418 .as_ref()
419 .item_element_infos(self.index, &mut result)
420 .then(|| result.as_str().split("/").count())
421 }
422
423 pub fn element_type_names_and_ids(
424 &self,
425 element_index: usize,
426 ) -> Option<Vec<(SharedString, SharedString)>> {
427 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
428 let mut result = SharedString::new();
429 comp_ref_pin.as_ref().item_element_infos(self.index, &mut result).then(|| {
430 result
431 .as_str()
432 .split("/")
433 .nth(element_index)
434 .unwrap()
435 .split(";")
436 .map(|encoded_elem_info| {
437 let mut decoder = encoded_elem_info.split(',');
438 let type_name = decoder.next().unwrap().into();
439 let id = decoder.next().map(Into::into).unwrap_or_default();
440 (type_name, id)
441 })
442 .collect()
443 })
444 }
445
446 pub fn geometry(&self) -> LogicalRect {
447 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
448 comp_ref_pin.as_ref().item_geometry(self.index)
449 }
450
451 pub fn bounding_rect(
452 &self,
453 geometry: &LogicalRect,
454 window_adapter: &WindowAdapterRc,
455 ) -> LogicalRect {
456 self.borrow().as_ref().bounding_rect(window_adapter, self, *geometry)
457 }
458
459 pub fn map_to_window(&self, p: LogicalPoint) -> LogicalPoint {
462 let mut current = self.clone();
463 let mut result = p;
464 while let Some(parent) = current.parent_item(ParentItemTraversalMode::StopAtPopups) {
465 let geometry = parent.geometry();
466 result += geometry.origin.to_vector();
467 current = parent.clone();
468 }
469 result
470 }
471
472 pub fn map_to_item_tree(
475 &self,
476 p: LogicalPoint,
477 item_tree: &vtable::VRc<ItemTreeVTable>,
478 ) -> LogicalPoint {
479 let mut current = self.clone();
480 let mut result = p;
481 if current.is_root_item_of(item_tree) {
482 return result;
483 }
484 while let Some(parent) = current.parent_item(ParentItemTraversalMode::StopAtPopups) {
485 if parent.is_root_item_of(item_tree) {
486 break;
487 }
488 let geometry = parent.geometry();
489 result += geometry.origin.to_vector();
490 current = parent.clone();
491 }
492 result
493 }
494
495 pub fn index(&self) -> u32 {
497 self.index
498 }
499 pub fn item_tree(&self) -> &vtable::VRc<ItemTreeVTable> {
501 &self.item_tree
502 }
503
504 fn find_child(
505 &self,
506 child_access: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
507 child_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
508 subtree_child: &dyn Fn(usize, usize) -> usize,
509 ) -> Option<Self> {
510 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
511 let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
512
513 let mut current_child_index = child_access(&item_tree, self.index())?;
514 loop {
515 if let Some(item) = step_into_node(
516 self.item_tree(),
517 &comp_ref_pin,
518 current_child_index,
519 &item_tree,
520 subtree_child,
521 &core::convert::identity,
522 ) {
523 return Some(item);
524 }
525 current_child_index = child_step(&item_tree, current_child_index)?;
526 }
527 }
528
529 pub fn first_child(&self) -> Option<Self> {
531 self.find_child(
532 &|item_tree, index| item_tree.first_child(index),
533 &|item_tree, index| item_tree.next_sibling(index),
534 &|start, _| start,
535 )
536 }
537
538 pub fn last_child(&self) -> Option<Self> {
540 self.find_child(
541 &|item_tree, index| item_tree.last_child(index),
542 &|item_tree, index| item_tree.previous_sibling(index),
543 &|_, end| end.wrapping_sub(1),
544 )
545 }
546
547 fn find_sibling(
548 &self,
549 sibling_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
550 subtree_step: &dyn Fn(usize) -> usize,
551 subtree_child: &dyn Fn(usize, usize) -> usize,
552 ) -> Option<Self> {
553 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
554 if self.index == 0 {
555 let mut parent_item = Default::default();
556 comp_ref_pin.as_ref().parent_node(&mut parent_item);
557 let current_component_subtree_index = comp_ref_pin.as_ref().subtree_index();
558 if let Some(parent_item) = parent_item.upgrade() {
559 let parent = parent_item.item_tree();
560 let parent_ref_pin = vtable::VRc::borrow_pin(parent);
561 let parent_item_index = parent_item.index();
562 let parent_item_tree = crate::item_tree::ItemTreeNodeArray::new(&parent_ref_pin);
563
564 let subtree_index = match parent_item_tree.get(parent_item_index)? {
565 crate::item_tree::ItemTreeNode::Item { .. } => {
566 return None;
568 }
569 crate::item_tree::ItemTreeNode::DynamicTree { index, .. } => *index,
570 };
571
572 let next_subtree_index = subtree_step(current_component_subtree_index);
573
574 let mut next_subtree_instance = Default::default();
576 parent_ref_pin.as_ref().get_subtree(
577 subtree_index,
578 next_subtree_index,
579 &mut next_subtree_instance,
580 );
581 if let Some(next_subtree_instance) = next_subtree_instance.upgrade() {
582 return Some(ItemRc::new(next_subtree_instance, 0));
583 }
584
585 find_sibling_outside_repeater(
587 parent,
588 parent_ref_pin,
589 parent_item_index,
590 sibling_step,
591 subtree_child,
592 )
593 } else {
594 None }
596 } else {
597 find_sibling_outside_repeater(
598 self.item_tree(),
599 comp_ref_pin,
600 self.index(),
601 sibling_step,
602 subtree_child,
603 )
604 }
605 }
606
607 pub fn previous_sibling(&self) -> Option<Self> {
609 self.find_sibling(
610 &|item_tree, index| item_tree.previous_sibling(index),
611 &|index| index.wrapping_sub(1),
612 &|_, end| end.wrapping_sub(1),
613 )
614 }
615
616 pub fn next_sibling(&self) -> Option<Self> {
618 self.find_sibling(
619 &|item_tree, index| item_tree.next_sibling(index),
620 &|index| index.saturating_add(1),
621 &|start, _| start,
622 )
623 }
624
625 fn move_focus(
626 &self,
627 focus_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
628 subtree_step: &dyn Fn(ItemRc) -> Option<ItemRc>,
629 subtree_child: &dyn Fn(usize, usize) -> usize,
630 step_in: &dyn Fn(ItemRc) -> ItemRc,
631 step_out: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
632 ) -> Self {
633 let mut component = self.item_tree().clone();
634 let mut comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
635 let mut item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
636
637 let mut to_focus = self.index();
638
639 'in_tree: loop {
640 if let Some(next) = focus_step(&item_tree, to_focus) {
641 if let Some(item) = step_into_node(
642 &component,
643 &comp_ref_pin,
644 next,
645 &item_tree,
646 subtree_child,
647 step_in,
648 ) {
649 return item;
650 }
651 to_focus = next;
652 } else {
654 let mut root = ItemRc::new(component, 0);
656 if let Some(item) = subtree_step(root.clone()) {
657 return step_in(item);
659 }
660
661 let root_component = root.item_tree();
663 let root_comp_ref = vtable::VRc::borrow_pin(root_component);
664 let mut parent_node = Default::default();
665 root_comp_ref.as_ref().parent_node(&mut parent_node);
666
667 while let Some(parent) = parent_node.upgrade() {
668 component = parent.item_tree().clone();
670 comp_ref_pin = vtable::VRc::borrow_pin(&component);
671 item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
672
673 let index = parent.index();
674
675 if !matches!(item_tree.get(index), Some(ItemTreeNode::DynamicTree { .. })) {
676 break;
678 }
679
680 if let Some(next) = step_out(&item_tree, index) {
681 if let Some(item) = step_into_node(
682 parent.item_tree(),
683 &comp_ref_pin,
684 next,
685 &item_tree,
686 subtree_child,
687 step_in,
688 ) {
689 return item;
691 } else {
692 to_focus = parent.index();
694 continue 'in_tree; }
696 }
697
698 root = ItemRc::new(component.clone(), 0);
699 if let Some(item) = subtree_step(root.clone()) {
700 return step_in(item);
701 }
702
703 let root_component = root.item_tree();
705 let root_comp_ref = vtable::VRc::borrow_pin(root_component);
706 parent_node = Default::default();
707 root_comp_ref.as_ref().parent_node(&mut parent_node);
708 }
709
710 return step_in(root);
712 }
713 }
714 }
715
716 pub fn previous_focus_item(&self) -> Self {
718 self.move_focus(
719 &|item_tree, index| {
720 crate::item_focus::default_previous_in_local_focus_chain(index, item_tree)
721 },
722 &|root| root.previous_sibling(),
723 &|_, end| end.wrapping_sub(1),
724 &|root| {
725 let mut current = root;
726 loop {
727 if let Some(next) = current.last_child() {
728 current = next;
729 } else {
730 return current;
731 }
732 }
733 },
734 &|item_tree, index| item_tree.parent(index),
735 )
736 }
737
738 pub fn next_focus_item(&self) -> Self {
740 self.move_focus(
741 &|item_tree, index| {
742 crate::item_focus::default_next_in_local_focus_chain(index, item_tree)
743 },
744 &|root| root.next_sibling(),
745 &|start, _| start,
746 &core::convert::identity,
747 &|item_tree, index| crate::item_focus::step_out_of_node(index, item_tree),
748 )
749 }
750
751 pub fn window_adapter(&self) -> Option<WindowAdapterRc> {
752 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
753 let mut result = None;
754 comp_ref_pin.as_ref().window_adapter(false, &mut result);
755 result
756 }
757
758 fn visit_descendants_impl<R>(
761 &self,
762 visitor: &mut impl FnMut(&ItemRc) -> ControlFlow<R>,
763 ) -> Option<R> {
764 let mut result = None;
765
766 let mut actual_visitor = |item_tree: &ItemTreeRc,
767 index: u32,
768 _item_pin: core::pin::Pin<ItemRef>|
769 -> VisitChildrenResult {
770 let item_rc = ItemRc::new(item_tree.clone(), index);
771
772 match visitor(&item_rc) {
773 ControlFlow::Continue(_) => {
774 if let Some(x) = item_rc.visit_descendants_impl(visitor) {
775 result = Some(x);
776 return VisitChildrenResult::abort(index, 0);
777 }
778 }
779 ControlFlow::Break(x) => {
780 result = Some(x);
781 return VisitChildrenResult::abort(index, 0);
782 }
783 }
784
785 VisitChildrenResult::CONTINUE
786 };
787 vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);
788
789 VRc::borrow_pin(self.item_tree()).as_ref().visit_children_item(
790 self.index() as isize,
791 TraversalOrder::BackToFront,
792 actual_visitor,
793 );
794
795 result
796 }
797
798 pub fn visit_descendants<R>(
801 &self,
802 mut visitor: impl FnMut(&ItemRc) -> ControlFlow<R>,
803 ) -> Option<R> {
804 self.visit_descendants_impl(&mut visitor)
805 }
806
807 pub fn children_transform(&self) -> Option<ItemTransform> {
810 self.downcast::<crate::items::Rotate>().map(|rotate_item| {
811 let origin = euclid::Vector2D::<f32, crate::lengths::LogicalPx>::from_lengths(
812 rotate_item.as_pin_ref().rotation_origin_x().cast(),
813 rotate_item.as_pin_ref().rotation_origin_y().cast(),
814 );
815 ItemTransform::translation(-origin.x, -origin.y)
816 .cast()
817 .then_rotate(euclid::Angle {
818 radians: rotate_item.as_pin_ref().rotation_angle().to_radians(),
819 })
820 .then_translate(origin)
821 })
822 }
823}
824
825impl PartialEq for ItemRc {
826 fn eq(&self, other: &Self) -> bool {
827 VRc::ptr_eq(&self.item_tree, &other.item_tree) && self.index == other.index
828 }
829}
830
831impl Eq for ItemRc {}
832
833#[derive(Clone, Default)]
835#[repr(C)]
836pub struct ItemWeak {
837 item_tree: crate::item_tree::ItemTreeWeak,
838 index: u32,
839}
840
841impl ItemWeak {
842 pub fn upgrade(&self) -> Option<ItemRc> {
843 self.item_tree.upgrade().map(|c| ItemRc::new(c, self.index))
844 }
845}
846
847impl PartialEq for ItemWeak {
848 fn eq(&self, other: &Self) -> bool {
849 VWeak::ptr_eq(&self.item_tree, &other.item_tree) && self.index == other.index
850 }
851}
852
853impl Eq for ItemWeak {}
854
855#[repr(u8)]
856#[derive(Debug, Copy, Clone, Eq, PartialEq)]
857pub enum TraversalOrder {
858 BackToFront,
859 FrontToBack,
860}
861
862#[repr(transparent)]
871#[derive(Copy, Clone, Eq, PartialEq)]
872pub struct VisitChildrenResult(u64);
873impl VisitChildrenResult {
874 pub const CONTINUE: Self = Self(u64::MAX);
876
877 pub fn abort(item_index: u32, index_within_repeater: usize) -> Self {
879 assert!(index_within_repeater < u32::MAX as usize);
880 Self(item_index as u64 | (index_within_repeater as u64) << 32)
881 }
882 pub fn has_aborted(&self) -> bool {
884 self.0 != Self::CONTINUE.0
885 }
886 pub fn aborted_index(&self) -> Option<usize> {
887 if self.0 != Self::CONTINUE.0 {
888 Some((self.0 & 0xffff_ffff) as usize)
889 } else {
890 None
891 }
892 }
893 pub fn aborted_indexes(&self) -> Option<(usize, usize)> {
894 if self.0 != Self::CONTINUE.0 {
895 Some(((self.0 & 0xffff_ffff) as usize, (self.0 >> 32) as usize))
896 } else {
897 None
898 }
899 }
900}
901impl core::fmt::Debug for VisitChildrenResult {
902 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
903 if self.0 == Self::CONTINUE.0 {
904 write!(f, "CONTINUE")
905 } else {
906 write!(f, "({},{})", (self.0 & 0xffff_ffff) as usize, (self.0 >> 32) as usize)
907 }
908 }
909}
910
911#[repr(u8)]
914#[derive(Debug)]
915pub enum ItemTreeNode {
916 Item {
918 is_accessible: bool,
920
921 children_count: u32,
923
924 children_index: u32,
926
927 parent_index: u32,
929
930 item_array_index: u32,
932 },
933 DynamicTree {
936 index: u32,
938
939 parent_index: u32,
941 },
942}
943
944impl ItemTreeNode {
945 pub fn parent_index(&self) -> u32 {
946 match self {
947 ItemTreeNode::Item { parent_index, .. } => *parent_index,
948 ItemTreeNode::DynamicTree { parent_index, .. } => *parent_index,
949 }
950 }
951}
952
953pub struct ItemTreeNodeArray<'a> {
956 node_array: &'a [ItemTreeNode],
957}
958
959impl<'a> ItemTreeNodeArray<'a> {
960 pub fn new(comp_ref_pin: &'a Pin<VRef<'a, ItemTreeVTable>>) -> Self {
962 Self { node_array: comp_ref_pin.as_ref().get_item_tree().as_slice() }
963 }
964
965 pub fn get(&self, index: u32) -> Option<&ItemTreeNode> {
967 self.node_array.get(index as usize)
968 }
969
970 pub fn parent(&self, index: u32) -> Option<u32> {
972 let index = index as usize;
973 (index < self.node_array.len() && index != 0).then(|| self.node_array[index].parent_index())
974 }
975
976 pub fn next_sibling(&self, index: u32) -> Option<u32> {
978 if let Some(parent_index) = self.parent(index) {
979 match self.node_array[parent_index as usize] {
980 ItemTreeNode::Item { children_index, children_count, .. } => {
981 (index < (children_count + children_index - 1)).then_some(index + 1)
982 }
983 ItemTreeNode::DynamicTree { .. } => {
984 unreachable!("Parent in same item tree is a repeater.")
985 }
986 }
987 } else {
988 None }
990 }
991
992 pub fn previous_sibling(&self, index: u32) -> Option<u32> {
994 if let Some(parent_index) = self.parent(index) {
995 match self.node_array[parent_index as usize] {
996 ItemTreeNode::Item { children_index, .. } => {
997 (index > children_index).then_some(index - 1)
998 }
999 ItemTreeNode::DynamicTree { .. } => {
1000 unreachable!("Parent in same item tree is a repeater.")
1001 }
1002 }
1003 } else {
1004 None }
1006 }
1007
1008 pub fn first_child(&self, index: u32) -> Option<u32> {
1011 match self.node_array.get(index as usize)? {
1012 ItemTreeNode::Item { children_index, children_count, .. } => {
1013 (*children_count != 0).then_some(*children_index as _)
1014 }
1015 ItemTreeNode::DynamicTree { .. } => None,
1016 }
1017 }
1018
1019 pub fn last_child(&self, index: u32) -> Option<u32> {
1022 match self.node_array.get(index as usize)? {
1023 ItemTreeNode::Item { children_index, children_count, .. } => {
1024 if *children_count != 0 {
1025 Some(*children_index + *children_count - 1)
1026 } else {
1027 None
1028 }
1029 }
1030 ItemTreeNode::DynamicTree { .. } => None,
1031 }
1032 }
1033
1034 pub fn node_count(&self) -> usize {
1036 self.node_array.len()
1037 }
1038}
1039
1040impl<'a> From<&'a [ItemTreeNode]> for ItemTreeNodeArray<'a> {
1041 fn from(item_tree: &'a [ItemTreeNode]) -> Self {
1042 Self { node_array: item_tree }
1043 }
1044}
1045
1046#[cfg_attr(not(feature = "ffi"), i_slint_core_macros::remove_extern)]
1047#[vtable]
1048#[repr(C)]
1049pub struct ItemVisitorVTable {
1051 visit_item: extern "C" fn(
1058 VRefMut<ItemVisitorVTable>,
1059 item_tree: &VRc<ItemTreeVTable, vtable::Dyn>,
1060 index: u32,
1061 item: Pin<VRef<ItemVTable>>,
1062 ) -> VisitChildrenResult,
1063 drop: extern "C" fn(VRefMut<ItemVisitorVTable>),
1065}
1066
1067pub type ItemVisitorRefMut<'a> = vtable::VRefMut<'a, ItemVisitorVTable>;
1069
1070impl<T: FnMut(&ItemTreeRc, u32, Pin<ItemRef>) -> VisitChildrenResult> ItemVisitor for T {
1071 fn visit_item(
1072 &mut self,
1073 item_tree: &ItemTreeRc,
1074 index: u32,
1075 item: Pin<ItemRef>,
1076 ) -> VisitChildrenResult {
1077 self(item_tree, index, item)
1078 }
1079}
1080pub enum ItemVisitorResult<State> {
1081 Continue(State),
1082 Abort,
1083}
1084
1085pub fn visit_items<State>(
1091 item_tree: &ItemTreeRc,
1092 order: TraversalOrder,
1093 mut visitor: impl FnMut(&ItemTreeRc, Pin<ItemRef>, u32, &State) -> ItemVisitorResult<State>,
1094 state: State,
1095) -> VisitChildrenResult {
1096 visit_internal(item_tree, order, &mut visitor, -1, &state)
1097}
1098
1099fn visit_internal<State>(
1100 item_tree: &ItemTreeRc,
1101 order: TraversalOrder,
1102 visitor: &mut impl FnMut(&ItemTreeRc, Pin<ItemRef>, u32, &State) -> ItemVisitorResult<State>,
1103 index: isize,
1104 state: &State,
1105) -> VisitChildrenResult {
1106 let mut actual_visitor =
1107 |item_tree: &ItemTreeRc, index: u32, item: Pin<ItemRef>| -> VisitChildrenResult {
1108 match visitor(item_tree, item, index, state) {
1109 ItemVisitorResult::Continue(state) => {
1110 visit_internal(item_tree, order, visitor, index as isize, &state)
1111 }
1112
1113 ItemVisitorResult::Abort => VisitChildrenResult::abort(index, 0),
1114 }
1115 };
1116 vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);
1117 VRc::borrow_pin(item_tree).as_ref().visit_children_item(index, order, actual_visitor)
1118}
1119
1120pub fn visit_item_tree<Base>(
1129 base: Pin<&Base>,
1130 item_tree: &ItemTreeRc,
1131 item_tree_array: &[ItemTreeNode],
1132 index: isize,
1133 order: TraversalOrder,
1134 mut visitor: vtable::VRefMut<ItemVisitorVTable>,
1135 visit_dynamic: impl Fn(
1136 Pin<&Base>,
1137 TraversalOrder,
1138 vtable::VRefMut<ItemVisitorVTable>,
1139 u32,
1140 ) -> VisitChildrenResult,
1141) -> VisitChildrenResult {
1142 let mut visit_at_index = |idx: u32| -> VisitChildrenResult {
1143 match &item_tree_array[idx as usize] {
1144 ItemTreeNode::Item { .. } => {
1145 let item = crate::items::ItemRc::new(item_tree.clone(), idx);
1146 visitor.visit_item(item_tree, idx, item.borrow())
1147 }
1148 ItemTreeNode::DynamicTree { index, .. } => {
1149 if let Some(sub_idx) =
1150 visit_dynamic(base, order, visitor.borrow_mut(), *index).aborted_index()
1151 {
1152 VisitChildrenResult::abort(idx, sub_idx)
1153 } else {
1154 VisitChildrenResult::CONTINUE
1155 }
1156 }
1157 }
1158 };
1159 if index == -1 {
1160 visit_at_index(0)
1161 } else {
1162 match &item_tree_array[index as usize] {
1163 ItemTreeNode::Item { children_index, children_count, .. } => {
1164 for c in 0..*children_count {
1165 let idx = match order {
1166 TraversalOrder::BackToFront => *children_index + c,
1167 TraversalOrder::FrontToBack => *children_index + *children_count - c - 1,
1168 };
1169 let maybe_abort_index = visit_at_index(idx);
1170 if maybe_abort_index.has_aborted() {
1171 return maybe_abort_index;
1172 }
1173 }
1174 }
1175 ItemTreeNode::DynamicTree { .. } => panic!("should not be called with dynamic items"),
1176 };
1177 VisitChildrenResult::CONTINUE
1178 }
1179}
1180
1181#[cfg(feature = "ffi")]
1182pub(crate) mod ffi {
1183 #![allow(unsafe_code)]
1184
1185 use super::*;
1186 use core::ffi::c_void;
1187
1188 #[unsafe(no_mangle)]
1190 pub unsafe extern "C" fn slint_register_item_tree(
1191 item_tree_rc: &ItemTreeRc,
1192 window_handle: *const crate::window::ffi::WindowAdapterRcOpaque,
1193 ) {
1194 let window_adapter = (window_handle as *const WindowAdapterRc).as_ref().cloned();
1195 super::register_item_tree(item_tree_rc, window_adapter)
1196 }
1197
1198 #[unsafe(no_mangle)]
1200 pub unsafe extern "C" fn slint_unregister_item_tree(
1201 component: ItemTreeRefPin,
1202 item_array: Slice<vtable::VOffset<u8, ItemVTable, vtable::AllowPin>>,
1203 window_handle: *const crate::window::ffi::WindowAdapterRcOpaque,
1204 ) {
1205 let window_adapter = &*(window_handle as *const WindowAdapterRc);
1206 super::unregister_item_tree(
1207 core::pin::Pin::new_unchecked(&*(component.as_ptr() as *const u8)),
1208 core::pin::Pin::into_inner(component),
1209 item_array.as_slice(),
1210 window_adapter,
1211 )
1212 }
1213
1214 #[unsafe(no_mangle)]
1218 pub unsafe extern "C" fn slint_visit_item_tree(
1219 item_tree: &ItemTreeRc,
1220 item_tree_array: Slice<ItemTreeNode>,
1221 index: isize,
1222 order: TraversalOrder,
1223 visitor: VRefMut<ItemVisitorVTable>,
1224 visit_dynamic: extern "C" fn(
1225 base: *const c_void,
1226 order: TraversalOrder,
1227 visitor: vtable::VRefMut<ItemVisitorVTable>,
1228 dyn_index: u32,
1229 ) -> VisitChildrenResult,
1230 ) -> VisitChildrenResult {
1231 crate::item_tree::visit_item_tree(
1232 VRc::as_pin_ref(item_tree),
1233 item_tree,
1234 item_tree_array.as_slice(),
1235 index,
1236 order,
1237 visitor,
1238 |a, b, c, d| visit_dynamic(a.get_ref() as *const vtable::Dyn as *const c_void, b, c, d),
1239 )
1240 }
1241}
1242
1243#[cfg(test)]
1244mod tests {
1245 use super::*;
1246 use std::vec;
1247
1248 struct TestItemTree {
1249 parent_component: Option<ItemTreeRc>,
1250 item_tree: Vec<ItemTreeNode>,
1251 subtrees: std::cell::RefCell<Vec<Vec<vtable::VRc<ItemTreeVTable, TestItemTree>>>>,
1252 subtree_index: usize,
1253 }
1254
1255 impl ItemTree for TestItemTree {
1256 fn visit_children_item(
1257 self: core::pin::Pin<&Self>,
1258 _1: isize,
1259 _2: crate::item_tree::TraversalOrder,
1260 _3: vtable::VRefMut<crate::item_tree::ItemVisitorVTable>,
1261 ) -> crate::item_tree::VisitChildrenResult {
1262 unimplemented!("Not needed for this test")
1263 }
1264
1265 fn get_item_ref(
1266 self: core::pin::Pin<&Self>,
1267 _1: u32,
1268 ) -> core::pin::Pin<vtable::VRef<'_, super::ItemVTable>> {
1269 unimplemented!("Not needed for this test")
1270 }
1271
1272 fn get_item_tree(self: core::pin::Pin<&Self>) -> Slice<'_, ItemTreeNode> {
1273 Slice::from_slice(&self.get_ref().item_tree)
1274 }
1275
1276 fn parent_node(self: core::pin::Pin<&Self>, result: &mut ItemWeak) {
1277 if let Some(parent_item) = self.parent_component.clone() {
1278 *result =
1279 ItemRc::new(parent_item.clone(), self.item_tree[0].parent_index()).downgrade();
1280 }
1281 }
1282
1283 fn embed_component(
1284 self: core::pin::Pin<&Self>,
1285 _parent_component: &ItemTreeWeak,
1286 _item_tree_index: u32,
1287 ) -> bool {
1288 false
1289 }
1290
1291 fn layout_info(self: core::pin::Pin<&Self>, _1: Orientation) -> LayoutInfo {
1292 unimplemented!("Not needed for this test")
1293 }
1294
1295 fn subtree_index(self: core::pin::Pin<&Self>) -> usize {
1296 self.subtree_index
1297 }
1298
1299 fn get_subtree_range(self: core::pin::Pin<&Self>, subtree_index: u32) -> IndexRange {
1300 (0..self.subtrees.borrow()[subtree_index as usize].len()).into()
1301 }
1302
1303 fn get_subtree(
1304 self: core::pin::Pin<&Self>,
1305 subtree_index: u32,
1306 component_index: usize,
1307 result: &mut ItemTreeWeak,
1308 ) {
1309 if let Some(vrc) = self.subtrees.borrow()[subtree_index as usize].get(component_index) {
1310 *result = vtable::VRc::downgrade(&vtable::VRc::into_dyn(vrc.clone()))
1311 }
1312 }
1313
1314 fn accessible_role(self: Pin<&Self>, _: u32) -> AccessibleRole {
1315 unimplemented!("Not needed for this test")
1316 }
1317
1318 fn accessible_string_property(
1319 self: Pin<&Self>,
1320 _: u32,
1321 _: AccessibleStringProperty,
1322 _: &mut SharedString,
1323 ) -> bool {
1324 false
1325 }
1326
1327 fn item_element_infos(self: Pin<&Self>, _: u32, _: &mut SharedString) -> bool {
1328 false
1329 }
1330
1331 fn window_adapter(
1332 self: Pin<&Self>,
1333 _do_create: bool,
1334 _result: &mut Option<WindowAdapterRc>,
1335 ) {
1336 unimplemented!("Not needed for this test")
1337 }
1338
1339 fn item_geometry(self: Pin<&Self>, _: u32) -> LogicalRect {
1340 unimplemented!("Not needed for this test")
1341 }
1342
1343 fn accessibility_action(self: core::pin::Pin<&Self>, _: u32, _: &AccessibilityAction) {
1344 unimplemented!("Not needed for this test")
1345 }
1346
1347 fn supported_accessibility_actions(
1348 self: core::pin::Pin<&Self>,
1349 _: u32,
1350 ) -> SupportedAccessibilityAction {
1351 unimplemented!("Not needed for this test")
1352 }
1353 }
1354
1355 crate::item_tree::ItemTreeVTable_static!(static TEST_COMPONENT_VT for TestItemTree);
1356
1357 fn create_one_node_component() -> VRc<ItemTreeVTable, vtable::Dyn> {
1358 let component = VRc::new(TestItemTree {
1359 parent_component: None,
1360 item_tree: vec![ItemTreeNode::Item {
1361 is_accessible: false,
1362 children_count: 0,
1363 children_index: 1,
1364 parent_index: 0,
1365 item_array_index: 0,
1366 }],
1367 subtrees: std::cell::RefCell::new(vec![]),
1368 subtree_index: usize::MAX,
1369 });
1370 VRc::into_dyn(component)
1371 }
1372
1373 #[test]
1374 fn test_tree_traversal_one_node_structure() {
1375 let component = create_one_node_component();
1376
1377 let item = ItemRc::new(component.clone(), 0);
1378
1379 assert!(item.first_child().is_none());
1380 assert!(item.last_child().is_none());
1381 assert!(item.previous_sibling().is_none());
1382 assert!(item.next_sibling().is_none());
1383 }
1384
1385 #[test]
1386 fn test_tree_traversal_one_node_forward_focus() {
1387 let component = create_one_node_component();
1388
1389 let item = ItemRc::new(component.clone(), 0);
1390
1391 assert_eq!(item.next_focus_item(), item);
1393 }
1394
1395 #[test]
1396 fn test_tree_traversal_one_node_backward_focus() {
1397 let component = create_one_node_component();
1398
1399 let item = ItemRc::new(component.clone(), 0);
1400
1401 assert_eq!(item.previous_focus_item(), item);
1403 }
1404
1405 fn create_children_nodes() -> VRc<ItemTreeVTable, vtable::Dyn> {
1406 let component = VRc::new(TestItemTree {
1407 parent_component: None,
1408 item_tree: vec![
1409 ItemTreeNode::Item {
1410 is_accessible: false,
1411 children_count: 3,
1412 children_index: 1,
1413 parent_index: 0,
1414 item_array_index: 0,
1415 },
1416 ItemTreeNode::Item {
1417 is_accessible: false,
1418 children_count: 0,
1419 children_index: 4,
1420 parent_index: 0,
1421 item_array_index: 1,
1422 },
1423 ItemTreeNode::Item {
1424 is_accessible: false,
1425 children_count: 0,
1426 children_index: 4,
1427 parent_index: 0,
1428 item_array_index: 2,
1429 },
1430 ItemTreeNode::Item {
1431 is_accessible: false,
1432 children_count: 0,
1433 children_index: 4,
1434 parent_index: 0,
1435 item_array_index: 3,
1436 },
1437 ],
1438 subtrees: std::cell::RefCell::new(vec![]),
1439 subtree_index: usize::MAX,
1440 });
1441 VRc::into_dyn(component)
1442 }
1443
1444 #[test]
1445 fn test_tree_traversal_children_nodes_structure() {
1446 let component = create_children_nodes();
1447
1448 let item = ItemRc::new(component.clone(), 0);
1450 assert!(item.previous_sibling().is_none());
1451 assert!(item.next_sibling().is_none());
1452
1453 let fc = item.first_child().unwrap();
1454 assert_eq!(fc.index(), 1);
1455 assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
1456
1457 let fcn = fc.next_sibling().unwrap();
1458 assert_eq!(fcn.index(), 2);
1459
1460 let lc = item.last_child().unwrap();
1461 assert_eq!(lc.index(), 3);
1462 assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
1463
1464 let lcp = lc.previous_sibling().unwrap();
1465 assert!(VRc::ptr_eq(lcp.item_tree(), item.item_tree()));
1466 assert_eq!(lcp.index(), 2);
1467
1468 assert!(fc.first_child().is_none());
1470 assert!(fc.last_child().is_none());
1471 assert!(fc.previous_sibling().is_none());
1472 assert_eq!(fc.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);
1473
1474 assert_eq!(fcn, lcp);
1476 assert_eq!(lcp.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);
1477 assert_eq!(fcn.previous_sibling().unwrap(), fc);
1478 assert_eq!(fcn.next_sibling().unwrap(), lc);
1479
1480 assert!(lc.first_child().is_none());
1482 assert!(lc.last_child().is_none());
1483 assert!(lc.next_sibling().is_none());
1484 assert_eq!(lc.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);
1485 }
1486
1487 #[test]
1488 fn test_tree_traversal_children_nodes_forward_focus() {
1489 let component = create_children_nodes();
1490
1491 let item = ItemRc::new(component.clone(), 0);
1492 let fc = item.first_child().unwrap();
1493 let fcn = fc.next_sibling().unwrap();
1494 let lc = item.last_child().unwrap();
1495
1496 let mut cursor = item.clone();
1497
1498 cursor = cursor.next_focus_item();
1499 assert_eq!(cursor, fc);
1500
1501 cursor = cursor.next_focus_item();
1502 assert_eq!(cursor, fcn);
1503
1504 cursor = cursor.next_focus_item();
1505 assert_eq!(cursor, lc);
1506
1507 cursor = cursor.next_focus_item();
1508 assert_eq!(cursor, item);
1509 }
1510
1511 #[test]
1512 fn test_tree_traversal_children_nodes_backward_focus() {
1513 let component = create_children_nodes();
1514
1515 let item = ItemRc::new(component.clone(), 0);
1516 let fc = item.first_child().unwrap();
1517 let fcn = fc.next_sibling().unwrap();
1518 let lc = item.last_child().unwrap();
1519
1520 let mut cursor = item.clone();
1521
1522 cursor = cursor.previous_focus_item();
1523 assert_eq!(cursor, lc);
1524
1525 cursor = cursor.previous_focus_item();
1526 assert_eq!(cursor, fcn);
1527
1528 cursor = cursor.previous_focus_item();
1529 assert_eq!(cursor, fc);
1530
1531 cursor = cursor.previous_focus_item();
1532 assert_eq!(cursor, item);
1533 }
1534
1535 fn create_empty_subtree() -> VRc<ItemTreeVTable, vtable::Dyn> {
1536 let component = vtable::VRc::new(TestItemTree {
1537 parent_component: None,
1538 item_tree: vec![
1539 ItemTreeNode::Item {
1540 is_accessible: false,
1541 children_count: 1,
1542 children_index: 1,
1543 parent_index: 0,
1544 item_array_index: 0,
1545 },
1546 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1547 ],
1548 subtrees: std::cell::RefCell::new(vec![vec![]]),
1549 subtree_index: usize::MAX,
1550 });
1551 vtable::VRc::into_dyn(component)
1552 }
1553
1554 #[test]
1555 fn test_tree_traversal_empty_subtree_structure() {
1556 let component = create_empty_subtree();
1557
1558 let item = ItemRc::new(component.clone(), 0);
1560 assert!(item.previous_sibling().is_none());
1561 assert!(item.next_sibling().is_none());
1562 assert!(item.first_child().is_none());
1563 assert!(item.last_child().is_none());
1564
1565 assert!(item.previous_focus_item() == item);
1567 assert!(item.next_focus_item() == item);
1568 }
1569
1570 #[test]
1571 fn test_tree_traversal_empty_subtree_forward_focus() {
1572 let component = create_empty_subtree();
1573
1574 let item = ItemRc::new(component.clone(), 0);
1576
1577 assert!(item.next_focus_item() == item);
1578 }
1579
1580 #[test]
1581 fn test_tree_traversal_empty_subtree_backward_focus() {
1582 let component = create_empty_subtree();
1583
1584 let item = ItemRc::new(component.clone(), 0);
1586
1587 assert!(item.previous_focus_item() == item);
1588 }
1589
1590 fn create_item_subtree_item() -> VRc<ItemTreeVTable, vtable::Dyn> {
1591 let component = VRc::new(TestItemTree {
1592 parent_component: None,
1593 item_tree: vec![
1594 ItemTreeNode::Item {
1595 is_accessible: false,
1596 children_count: 3,
1597 children_index: 1,
1598 parent_index: 0,
1599 item_array_index: 0,
1600 },
1601 ItemTreeNode::Item {
1602 is_accessible: false,
1603 children_count: 0,
1604 children_index: 4,
1605 parent_index: 0,
1606 item_array_index: 0,
1607 },
1608 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1609 ItemTreeNode::Item {
1610 is_accessible: false,
1611 children_count: 0,
1612 children_index: 4,
1613 parent_index: 0,
1614 item_array_index: 0,
1615 },
1616 ],
1617 subtrees: std::cell::RefCell::new(vec![]),
1618 subtree_index: usize::MAX,
1619 });
1620
1621 component.as_pin_ref().subtrees.replace(vec![vec![VRc::new(TestItemTree {
1622 parent_component: Some(VRc::into_dyn(component.clone())),
1623 item_tree: vec![ItemTreeNode::Item {
1624 is_accessible: false,
1625 children_count: 0,
1626 children_index: 1,
1627 parent_index: 2,
1628 item_array_index: 0,
1629 }],
1630 subtrees: std::cell::RefCell::new(vec![]),
1631 subtree_index: 0,
1632 })]]);
1633
1634 VRc::into_dyn(component)
1635 }
1636
1637 #[test]
1638 fn test_tree_traversal_item_subtree_item_structure() {
1639 let component = create_item_subtree_item();
1640
1641 let item = ItemRc::new(component.clone(), 0);
1643 assert!(item.previous_sibling().is_none());
1644 assert!(item.next_sibling().is_none());
1645
1646 let fc = item.first_child().unwrap();
1647 assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
1648 assert_eq!(fc.index(), 1);
1649
1650 let lc = item.last_child().unwrap();
1651 assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
1652 assert_eq!(lc.index(), 3);
1653
1654 let fcn = fc.next_sibling().unwrap();
1655 let lcp = lc.previous_sibling().unwrap();
1656
1657 assert_eq!(fcn, lcp);
1658 assert!(!VRc::ptr_eq(fcn.item_tree(), item.item_tree()));
1659
1660 let last = fcn.next_sibling().unwrap();
1661 assert_eq!(last, lc);
1662
1663 let first = lcp.previous_sibling().unwrap();
1664 assert_eq!(first, fc);
1665 }
1666
1667 #[test]
1668 fn test_tree_traversal_item_subtree_item_forward_focus() {
1669 let component = create_item_subtree_item();
1670
1671 let item = ItemRc::new(component.clone(), 0);
1672 let fc = item.first_child().unwrap();
1673 let lc = item.last_child().unwrap();
1674 let fcn = fc.next_sibling().unwrap();
1675
1676 let mut cursor = item.clone();
1677
1678 cursor = cursor.next_focus_item();
1679 assert_eq!(cursor, fc);
1680
1681 cursor = cursor.next_focus_item();
1682 assert_eq!(cursor, fcn);
1683
1684 cursor = cursor.next_focus_item();
1685 assert_eq!(cursor, lc);
1686
1687 cursor = cursor.next_focus_item();
1688 assert_eq!(cursor, item);
1689 }
1690
1691 #[test]
1692 fn test_tree_traversal_item_subtree_item_backward_focus() {
1693 let component = create_item_subtree_item();
1694
1695 let item = ItemRc::new(component.clone(), 0);
1696 let fc = item.first_child().unwrap();
1697 let lc = item.last_child().unwrap();
1698 let fcn = fc.next_sibling().unwrap();
1699
1700 let mut cursor = item.clone();
1701
1702 cursor = cursor.previous_focus_item();
1703 assert_eq!(cursor, lc);
1704
1705 cursor = cursor.previous_focus_item();
1706 assert_eq!(cursor, fcn);
1707
1708 cursor = cursor.previous_focus_item();
1709 assert_eq!(cursor, fc);
1710
1711 cursor = cursor.previous_focus_item();
1712 assert_eq!(cursor, item);
1713 }
1714
1715 fn create_nested_subtrees() -> VRc<ItemTreeVTable, vtable::Dyn> {
1716 let component = VRc::new(TestItemTree {
1717 parent_component: None,
1718 item_tree: vec![
1719 ItemTreeNode::Item {
1720 is_accessible: false,
1721 children_count: 3,
1722 children_index: 1,
1723 parent_index: 0,
1724 item_array_index: 0,
1725 },
1726 ItemTreeNode::Item {
1727 is_accessible: false,
1728 children_count: 0,
1729 children_index: 4,
1730 parent_index: 0,
1731 item_array_index: 0,
1732 },
1733 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1734 ItemTreeNode::Item {
1735 is_accessible: false,
1736 children_count: 0,
1737 children_index: 4,
1738 parent_index: 0,
1739 item_array_index: 0,
1740 },
1741 ],
1742 subtrees: std::cell::RefCell::new(vec![]),
1743 subtree_index: usize::MAX,
1744 });
1745
1746 let sub_component1 = VRc::new(TestItemTree {
1747 parent_component: Some(VRc::into_dyn(component.clone())),
1748 item_tree: vec![
1749 ItemTreeNode::Item {
1750 is_accessible: false,
1751 children_count: 1,
1752 children_index: 1,
1753 parent_index: 2,
1754 item_array_index: 0,
1755 },
1756 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1757 ],
1758 subtrees: std::cell::RefCell::new(vec![]),
1759 subtree_index: usize::MAX,
1760 });
1761 let sub_component2 = VRc::new(TestItemTree {
1762 parent_component: Some(VRc::into_dyn(sub_component1.clone())),
1763 item_tree: vec![
1764 ItemTreeNode::Item {
1765 is_accessible: false,
1766 children_count: 1,
1767 children_index: 1,
1768 parent_index: 1,
1769 item_array_index: 0,
1770 },
1771 ItemTreeNode::Item {
1772 is_accessible: false,
1773 children_count: 0,
1774 children_index: 2,
1775 parent_index: 0,
1776 item_array_index: 0,
1777 },
1778 ],
1779 subtrees: std::cell::RefCell::new(vec![]),
1780 subtree_index: usize::MAX,
1781 });
1782
1783 sub_component1.as_pin_ref().subtrees.replace(vec![vec![sub_component2]]);
1784 component.as_pin_ref().subtrees.replace(vec![vec![sub_component1]]);
1785
1786 VRc::into_dyn(component)
1787 }
1788
1789 #[test]
1790 fn test_tree_traversal_nested_subtrees_structure() {
1791 let component = create_nested_subtrees();
1792
1793 let item = ItemRc::new(component.clone(), 0);
1795 assert!(item.previous_sibling().is_none());
1796 assert!(item.next_sibling().is_none());
1797
1798 let fc = item.first_child().unwrap();
1799 assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
1800 assert_eq!(fc.index(), 1);
1801
1802 let lc = item.last_child().unwrap();
1803 assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
1804 assert_eq!(lc.index(), 3);
1805
1806 let fcn = fc.next_sibling().unwrap();
1807 let lcp = lc.previous_sibling().unwrap();
1808
1809 assert_eq!(fcn, lcp);
1810 assert!(!VRc::ptr_eq(fcn.item_tree(), item.item_tree()));
1811
1812 let last = fcn.next_sibling().unwrap();
1813 assert_eq!(last, lc);
1814
1815 let first = lcp.previous_sibling().unwrap();
1816 assert_eq!(first, fc);
1817
1818 let nested_root = fcn.first_child().unwrap();
1820 assert_eq!(nested_root, fcn.last_child().unwrap());
1821 assert!(nested_root.next_sibling().is_none());
1822 assert!(nested_root.previous_sibling().is_none());
1823 assert!(!VRc::ptr_eq(nested_root.item_tree(), item.item_tree()));
1824 assert!(!VRc::ptr_eq(nested_root.item_tree(), fcn.item_tree()));
1825
1826 let nested_child = nested_root.first_child().unwrap();
1827 assert_eq!(nested_child, nested_root.last_child().unwrap());
1828 assert!(VRc::ptr_eq(nested_root.item_tree(), nested_child.item_tree()));
1829 }
1830
1831 #[test]
1832 fn test_tree_traversal_nested_subtrees_forward_focus() {
1833 let component = create_nested_subtrees();
1834
1835 let item = ItemRc::new(component.clone(), 0);
1837 let fc = item.first_child().unwrap();
1838 let fcn = fc.next_sibling().unwrap();
1839 let lc = item.last_child().unwrap();
1840 let nested_root = fcn.first_child().unwrap();
1841 let nested_child = nested_root.first_child().unwrap();
1842
1843 let mut cursor = item.clone();
1845
1846 cursor = cursor.next_focus_item();
1847 assert_eq!(cursor, fc);
1848
1849 cursor = cursor.next_focus_item();
1850 assert_eq!(cursor, fcn);
1851
1852 cursor = cursor.next_focus_item();
1853 assert_eq!(cursor, nested_root);
1854
1855 cursor = cursor.next_focus_item();
1856 assert_eq!(cursor, nested_child);
1857
1858 cursor = cursor.next_focus_item();
1859 assert_eq!(cursor, lc);
1860
1861 cursor = cursor.next_focus_item();
1862 assert_eq!(cursor, item);
1863 }
1864
1865 #[test]
1866 fn test_tree_traversal_nested_subtrees_backward_focus() {
1867 let component = create_nested_subtrees();
1868
1869 let item = ItemRc::new(component.clone(), 0);
1871 let fc = item.first_child().unwrap();
1872 let fcn = fc.next_sibling().unwrap();
1873 let lc = item.last_child().unwrap();
1874 let nested_root = fcn.first_child().unwrap();
1875 let nested_child = nested_root.first_child().unwrap();
1876
1877 let mut cursor = item.clone();
1879
1880 cursor = cursor.previous_focus_item();
1881 assert_eq!(cursor, lc);
1882
1883 cursor = cursor.previous_focus_item();
1884 assert_eq!(cursor, nested_child);
1885
1886 cursor = cursor.previous_focus_item();
1887 assert_eq!(cursor, nested_root);
1888
1889 cursor = cursor.previous_focus_item();
1890 assert_eq!(cursor, fcn);
1891
1892 cursor = cursor.previous_focus_item();
1893 assert_eq!(cursor, fc);
1894
1895 cursor = cursor.previous_focus_item();
1896 assert_eq!(cursor, item);
1897 }
1898
1899 fn create_subtrees_item() -> VRc<ItemTreeVTable, vtable::Dyn> {
1900 let component = VRc::new(TestItemTree {
1901 parent_component: None,
1902 item_tree: vec![
1903 ItemTreeNode::Item {
1904 is_accessible: false,
1905 children_count: 2,
1906 children_index: 1,
1907 parent_index: 0,
1908 item_array_index: 0,
1909 },
1910 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1911 ItemTreeNode::Item {
1912 is_accessible: false,
1913 children_count: 0,
1914 children_index: 4,
1915 parent_index: 0,
1916 item_array_index: 0,
1917 },
1918 ],
1919 subtrees: std::cell::RefCell::new(vec![]),
1920 subtree_index: usize::MAX,
1921 });
1922
1923 component.as_pin_ref().subtrees.replace(vec![vec![
1924 VRc::new(TestItemTree {
1925 parent_component: Some(VRc::into_dyn(component.clone())),
1926 item_tree: vec![ItemTreeNode::Item {
1927 is_accessible: false,
1928 children_count: 0,
1929 children_index: 1,
1930 parent_index: 1,
1931 item_array_index: 0,
1932 }],
1933 subtrees: std::cell::RefCell::new(vec![]),
1934 subtree_index: 0,
1935 }),
1936 VRc::new(TestItemTree {
1937 parent_component: Some(VRc::into_dyn(component.clone())),
1938 item_tree: vec![ItemTreeNode::Item {
1939 is_accessible: false,
1940 children_count: 0,
1941 children_index: 1,
1942 parent_index: 1,
1943 item_array_index: 0,
1944 }],
1945 subtrees: std::cell::RefCell::new(vec![]),
1946 subtree_index: 1,
1947 }),
1948 VRc::new(TestItemTree {
1949 parent_component: Some(VRc::into_dyn(component.clone())),
1950 item_tree: vec![ItemTreeNode::Item {
1951 is_accessible: false,
1952 children_count: 0,
1953 children_index: 1,
1954 parent_index: 1,
1955 item_array_index: 0,
1956 }],
1957 subtrees: std::cell::RefCell::new(vec![]),
1958 subtree_index: 2,
1959 }),
1960 ]]);
1961
1962 VRc::into_dyn(component)
1963 }
1964
1965 #[test]
1966 fn test_tree_traversal_subtrees_item_structure() {
1967 let component = create_subtrees_item();
1968
1969 let item = ItemRc::new(component.clone(), 0);
1971 assert!(item.previous_sibling().is_none());
1972 assert!(item.next_sibling().is_none());
1973
1974 let sub1 = item.first_child().unwrap();
1975 assert_eq!(sub1.index(), 0);
1976 assert!(!VRc::ptr_eq(sub1.item_tree(), item.item_tree()));
1977
1978 let sub2 = sub1.next_sibling().unwrap();
1981 assert_eq!(sub2.index(), 0);
1982 assert!(!VRc::ptr_eq(sub1.item_tree(), sub2.item_tree()));
1983 assert!(!VRc::ptr_eq(item.item_tree(), sub2.item_tree()));
1984
1985 assert!(sub2.previous_sibling() == Some(sub1.clone()));
1986
1987 let sub3 = sub2.next_sibling().unwrap();
1988 assert_eq!(sub3.index(), 0);
1989 assert!(!VRc::ptr_eq(sub1.item_tree(), sub2.item_tree()));
1990 assert!(!VRc::ptr_eq(sub2.item_tree(), sub3.item_tree()));
1991 assert!(!VRc::ptr_eq(item.item_tree(), sub3.item_tree()));
1992
1993 assert_eq!(sub3.previous_sibling().unwrap(), sub2.clone());
1994 }
1995
1996 #[test]
1997 fn test_component_item_tree_root_only() {
1998 let nodes = vec![ItemTreeNode::Item {
1999 is_accessible: false,
2000 children_count: 0,
2001 children_index: 1,
2002 parent_index: 0,
2003 item_array_index: 0,
2004 }];
2005
2006 let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
2007
2008 assert_eq!(tree.first_child(0), None);
2009 assert_eq!(tree.last_child(0), None);
2010 assert_eq!(tree.previous_sibling(0), None);
2011 assert_eq!(tree.next_sibling(0), None);
2012 assert_eq!(tree.parent(0), None);
2013 }
2014
2015 #[test]
2016 fn test_component_item_tree_one_child() {
2017 let nodes = vec![
2018 ItemTreeNode::Item {
2019 is_accessible: false,
2020 children_count: 1,
2021 children_index: 1,
2022 parent_index: 0,
2023 item_array_index: 0,
2024 },
2025 ItemTreeNode::Item {
2026 is_accessible: false,
2027 children_count: 0,
2028 children_index: 2,
2029 parent_index: 0,
2030 item_array_index: 0,
2031 },
2032 ];
2033
2034 let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
2035
2036 assert_eq!(tree.first_child(0), Some(1));
2037 assert_eq!(tree.last_child(0), Some(1));
2038 assert_eq!(tree.previous_sibling(0), None);
2039 assert_eq!(tree.next_sibling(0), None);
2040 assert_eq!(tree.parent(0), None);
2041 assert_eq!(tree.previous_sibling(1), None);
2042 assert_eq!(tree.next_sibling(1), None);
2043 assert_eq!(tree.parent(1), Some(0));
2044 }
2045
2046 #[test]
2047 fn test_component_item_tree_tree_children() {
2048 let nodes = vec![
2049 ItemTreeNode::Item {
2050 is_accessible: false,
2051 children_count: 3,
2052 children_index: 1,
2053 parent_index: 0,
2054 item_array_index: 0,
2055 },
2056 ItemTreeNode::Item {
2057 is_accessible: false,
2058 children_count: 0,
2059 children_index: 4,
2060 parent_index: 0,
2061 item_array_index: 0,
2062 },
2063 ItemTreeNode::Item {
2064 is_accessible: false,
2065 children_count: 0,
2066 children_index: 4,
2067 parent_index: 0,
2068 item_array_index: 0,
2069 },
2070 ItemTreeNode::Item {
2071 is_accessible: false,
2072 children_count: 0,
2073 children_index: 4,
2074 parent_index: 0,
2075 item_array_index: 0,
2076 },
2077 ];
2078
2079 let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
2080
2081 assert_eq!(tree.first_child(0), Some(1));
2082 assert_eq!(tree.last_child(0), Some(3));
2083 assert_eq!(tree.previous_sibling(0), None);
2084 assert_eq!(tree.next_sibling(0), None);
2085 assert_eq!(tree.parent(0), None);
2086
2087 assert_eq!(tree.previous_sibling(1), None);
2088 assert_eq!(tree.next_sibling(1), Some(2));
2089 assert_eq!(tree.parent(1), Some(0));
2090
2091 assert_eq!(tree.previous_sibling(2), Some(1));
2092 assert_eq!(tree.next_sibling(2), Some(3));
2093 assert_eq!(tree.parent(2), Some(0));
2094
2095 assert_eq!(tree.previous_sibling(3), Some(2));
2096 assert_eq!(tree.next_sibling(3), None);
2097 assert_eq!(tree.parent(3), Some(0));
2098 }
2099}