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