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