1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4// cSpell: ignore xffff
5
6//! This module contains the ItemTree and code that helps navigating it
7
8use 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)]
24/// A range of indices
25pub struct IndexRange {
26 /// Start index
27 pub start: usize,
28 /// Index one past the last index
29 pub end: usize,
30}
31
32impl From<core::ops::Range<usize>> for IndexRange {
33 fn from(r: core::ops::Range<usize>) -> Self {
34 Self { start: r.start, end: r.end }
35 }
36}
37impl From<IndexRange> for core::ops::Range<usize> {
38 fn from(r: IndexRange) -> Self {
39 Self { start: r.start, end: r.end }
40 }
41}
42
43/// A ItemTree is representing an unit that is allocated together
44#[vtable]
45#[repr(C)]
46pub struct ItemTreeVTable {
47 /// Visit the children of the item at index `index`.
48 /// Note that the root item is at index 0, so passing 0 would visit the item under root (the children of root).
49 /// If you want to visit the root item, you need to pass -1 as an index.
50 pub visit_children_item: extern "C" fn(
51 core::pin::Pin<VRef<ItemTreeVTable>>,
52 index: isize,
53 order: TraversalOrder,
54 visitor: VRefMut<ItemVisitorVTable>,
55 ) -> VisitChildrenResult,
56
57 /// Return a reference to an item using the given index
58 pub get_item_ref: extern "C" fn(
59 core::pin::Pin<VRef<ItemTreeVTable>>,
60 index: u32,
61 ) -> core::pin::Pin<VRef<ItemVTable>>,
62
63 /// Return the range of indices below the dynamic `ItemTreeNode` at `index`
64 pub get_subtree_range:
65 extern "C" fn(core::pin::Pin<VRef<ItemTreeVTable>>, index: u32) -> IndexRange,
66
67 /// Return the `ItemTreeRc` at `subindex` below the dynamic `ItemTreeNode` at `index`
68 pub get_subtree: extern "C" fn(
69 core::pin::Pin<VRef<ItemTreeVTable>>,
70 index: u32,
71 subindex: usize,
72 result: &mut vtable::VWeak<ItemTreeVTable, Dyn>,
73 ),
74
75 /// Return the item tree that is defined by this `ItemTree`.
76 /// The return value is an item weak because it can be null if there is no parent.
77 /// And the return value is passed by &mut because ItemWeak has a destructor
78 pub get_item_tree: extern "C" fn(core::pin::Pin<VRef<ItemTreeVTable>>) -> Slice<ItemTreeNode>,
79
80 /// Return the node this ItemTree is a part of in the parent ItemTree.
81 ///
82 /// The return value is an item weak because it can be null if there is no parent.
83 /// And the return value is passed by &mut because ItemWeak has a destructor
84 /// Note that the returned value will typically point to a repeater node, which is
85 /// strictly speaking not an Item at all!
86 pub parent_node: extern "C" fn(core::pin::Pin<VRef<ItemTreeVTable>>, result: &mut ItemWeak),
87
88 /// This embeds this ItemTree into the item tree of another ItemTree
89 ///
90 /// Returns `true` if this ItemTree was embedded into the `parent`
91 /// at `parent_item_tree_index`.
92 pub embed_component: extern "C" fn(
93 core::pin::Pin<VRef<ItemTreeVTable>>,
94 parent: &VWeak<ItemTreeVTable>,
95 parent_item_tree_index: u32,
96 ) -> bool,
97
98 /// Return the index of the current subtree or usize::MAX if this is not a subtree
99 pub subtree_index: extern "C" fn(core::pin::Pin<VRef<ItemTreeVTable>>) -> usize,
100
101 /// Returns the layout info for the root of the ItemTree
102 pub layout_info: extern "C" fn(core::pin::Pin<VRef<ItemTreeVTable>>, Orientation) -> LayoutInfo,
103
104 /// Returns the item's geometry (relative to its parent item)
105 pub item_geometry:
106 extern "C" fn(core::pin::Pin<VRef<ItemTreeVTable>>, item_index: u32) -> LogicalRect,
107
108 /// Returns the accessible role for a given item
109 pub accessible_role:
110 extern "C" fn(core::pin::Pin<VRef<ItemTreeVTable>>, item_index: u32) -> AccessibleRole,
111
112 /// Returns the accessible property via the `result`. Returns true if such a property exists.
113 pub accessible_string_property: extern "C" fn(
114 core::pin::Pin<VRef<ItemTreeVTable>>,
115 item_index: u32,
116 what: AccessibleStringProperty,
117 result: &mut SharedString,
118 ) -> bool,
119
120 /// Executes an accessibility action.
121 pub accessibility_action: extern "C" fn(
122 core::pin::Pin<VRef<ItemTreeVTable>>,
123 item_index: u32,
124 action: &AccessibilityAction,
125 ),
126
127 /// Returns the supported accessibility actions.
128 pub supported_accessibility_actions: extern "C" fn(
129 core::pin::Pin<VRef<ItemTreeVTable>>,
130 item_index: u32,
131 ) -> SupportedAccessibilityAction,
132
133 /// Add the `ElementName::id` entries of the given item
134 pub item_element_infos: extern "C" fn(
135 core::pin::Pin<VRef<ItemTreeVTable>>,
136 item_index: u32,
137 result: &mut SharedString,
138 ) -> bool,
139
140 /// Returns a Window, creating a fresh one if `do_create` is true.
141 pub window_adapter: extern "C" fn(
142 core::pin::Pin<VRef<ItemTreeVTable>>,
143 do_create: bool,
144 result: &mut Option<WindowAdapterRc>,
145 ),
146
147 /// in-place destructor (for VRc)
148 pub drop_in_place: unsafe fn(VRefMut<ItemTreeVTable>) -> vtable::Layout,
149
150 /// dealloc function (for VRc)
151 pub dealloc: unsafe fn(&ItemTreeVTable, ptr: *mut u8, layout: vtable::Layout),
152}
153
154#[cfg(test)]
155pub(crate) use ItemTreeVTable_static;
156
157/// Alias for `vtable::VRef<ItemTreeVTable>` which represent a pointer to a `dyn ItemTree` with
158/// the associated vtable
159pub type ItemTreeRef<'a> = vtable::VRef<'a, ItemTreeVTable>;
160
161/// Type alias to the commonly used `Pin<VRef<ItemTreeVTable>>>`
162pub type ItemTreeRefPin<'a> = core::pin::Pin<ItemTreeRef<'a>>;
163
164/// Type alias to the commonly used VRc<ItemTreeVTable, Dyn>>
165pub type ItemTreeRc = vtable::VRc<ItemTreeVTable, Dyn>;
166/// Type alias to the commonly used VWeak<ItemTreeVTable, Dyn>>
167pub type ItemTreeWeak = vtable::VWeak<ItemTreeVTable, Dyn>;
168
169/// Call init() on the ItemVTable for each item of the ItemTree.
170pub fn register_item_tree(item_tree_rc: &ItemTreeRc, window_adapter: Option<WindowAdapterRc>) {
171 let c: Pin> = vtable::VRc::borrow_pin(this:item_tree_rc);
172 let item_tree = c.as_ref().get_item_tree();
173 item_tree.iter().enumerate().for_each(|(tree_index: usize, node: ItemTreeNode)| {
174 let tree_index: u32 = tree_index as u32;
175 if let ItemTreeNode::Item { .. } = &node {
176 let item: ItemRc = ItemRc::new(item_tree_rc.clone(), tree_index);
177 c.as_ref().get_item_ref(tree_index).as_ref().init(&item);
178 }
179 });
180 if let Some(adapter: &dyn WindowAdapterInternal) = window_adapter.as_ref().and_then(|a: &Rc| a.internal(crate::InternalToken)) {
181 adapter.register_item_tree();
182 }
183}
184
185/// Free the backend graphics resources allocated by the ItemTree's items.
186pub fn unregister_item_tree<Base>(
187 base: core::pin::Pin<&Base>,
188 item_tree: ItemTreeRef,
189 item_array: &[vtable::VOffset<Base, ItemVTable, vtable::AllowPin>],
190 window_adapter: &WindowAdapterRc,
191) {
192 window_adapter.renderer().free_graphics_resources(
193 item_tree,
194 &mut item_array.iter().map(|item| item.apply_pin(base)),
195 ).expect(msg:"Fatal error encountered when freeing graphics resources while destroying Slint component");
196 if let Some(w: &dyn WindowAdapterInternal) = window_adapter.internal(crate::InternalToken) {
197 w.unregister_item_tree(_component:item_tree, &mut item_array.iter().map(|item: &VOffset| item.apply_pin(base)));
198 }
199}
200
201fn find_sibling_outside_repeater(
202 component: &ItemTreeRc,
203 comp_ref_pin: Pin<VRef<ItemTreeVTable>>,
204 index: u32,
205 sibling_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
206 subtree_child: &dyn Fn(usize, usize) -> usize,
207) -> Option<ItemRc> {
208 assert_ne!(index, 0);
209
210 let item_tree: ItemTreeNodeArray<'_> = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
211
212 let mut current_sibling: u32 = index;
213 loop {
214 current_sibling = sibling_step(&item_tree, current_sibling)?;
215
216 if let Some(node: ItemRc) = step_into_node(
217 component,
218 &comp_ref_pin,
219 node_index:current_sibling,
220 &item_tree,
221 subtree_child,
222 &core::convert::identity,
223 ) {
224 return Some(node);
225 }
226 }
227}
228
229fn step_into_node(
230 component: &ItemTreeRc,
231 comp_ref_pin: &Pin<VRef<ItemTreeVTable>>,
232 node_index: u32,
233 item_tree: &crate::item_tree::ItemTreeNodeArray,
234 subtree_child: &dyn Fn(usize, usize) -> usize,
235 wrap_around: &dyn Fn(ItemRc) -> ItemRc,
236) -> Option<ItemRc> {
237 match item_tree.get(node_index).expect(msg:"Invalid index passed to item tree") {
238 crate::item_tree::ItemTreeNode::Item { .. } => {
239 Some(ItemRc::new(item_tree:component.clone(), node_index))
240 }
241 crate::item_tree::ItemTreeNode::DynamicTree { index: &u32, .. } => {
242 let range = comp_ref_pin.as_ref().get_subtree_range(*index);
243 let component_index: usize = subtree_child(range.start, range.end);
244 let mut child_instance = Default::default();
245 comp_ref_pin.as_ref().get_subtree(*index, component_index, &mut child_instance);
246 child_instance
247 .upgrade()
248 .map(|child_instance: VRc| wrap_around(ItemRc::new(item_tree:child_instance, index:0)))
249 }
250 }
251}
252
253/// A ItemRc is holding a reference to a ItemTree containing the item, and the index of this item
254#[repr(C)]
255#[derive(Clone, Debug)]
256pub struct ItemRc {
257 item_tree: vtable::VRc<ItemTreeVTable>,
258 index: u32,
259}
260
261impl ItemRc {
262 /// Create an ItemRc from a ItemTree and an index
263 pub fn new(item_tree: vtable::VRc<ItemTreeVTable>, index: u32) -> Self {
264 Self { item_tree, index }
265 }
266
267 pub fn is_root_item_of(&self, item_tree: &VRc<ItemTreeVTable>) -> bool {
268 self.index == 0 && VRc::ptr_eq(&self.item_tree, item_tree)
269 }
270
271 /// Return a `Pin<ItemRef<'a>>`
272 pub fn borrow<'a>(&'a self) -> Pin<ItemRef<'a>> {
273 #![allow(unsafe_code)]
274 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
275 let result = comp_ref_pin.as_ref().get_item_ref(self.index);
276 // Safety: we can expand the lifetime of the ItemRef because we know it lives for at least the
277 // lifetime of the ItemTree, which is 'a. Pin::as_ref removes the lifetime, but we can just put it back.
278 unsafe { core::mem::transmute::<Pin<ItemRef<'_>>, Pin<ItemRef<'a>>>(result) }
279 }
280
281 /// Returns a `VRcMapped` of this item, to conveniently access specialized item API.
282 pub fn downcast<T: HasStaticVTable<ItemVTable>>(&self) -> Option<VRcMapped<ItemTreeVTable, T>> {
283 #![allow(unsafe_code)]
284 let item = self.borrow();
285 ItemRef::downcast_pin::<T>(item)?;
286
287 Some(vtable::VRc::map_dyn(self.item_tree.clone(), |comp_ref_pin| {
288 let result = comp_ref_pin.as_ref().get_item_ref(self.index);
289 // Safety: we can expand the lifetime of the ItemRef because we know it lives for at least the
290 // lifetime of the ItemTree, which is 'a. Pin::as_ref removes the lifetime, but we can just put it back.
291 let item =
292 unsafe { core::mem::transmute::<Pin<ItemRef<'_>>, Pin<ItemRef<'_>>>(result) };
293 ItemRef::downcast_pin::<T>(item).unwrap()
294 }))
295 }
296
297 pub fn downgrade(&self) -> ItemWeak {
298 ItemWeak { item_tree: VRc::downgrade(&self.item_tree), index: self.index }
299 }
300
301 /// Return the parent Item in the item tree.
302 ///
303 /// If the item is a the root on its Window or PopupWindow, then the parent is None.
304 pub fn parent_item(&self) -> Option<ItemRc> {
305 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
306 let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
307
308 if let Some(parent_index) = item_tree.parent(self.index) {
309 return Some(ItemRc::new(self.item_tree.clone(), parent_index));
310 }
311
312 let mut r = ItemWeak::default();
313 comp_ref_pin.as_ref().parent_node(&mut r);
314 let parent = r.upgrade()?;
315 let comp_ref_pin = vtable::VRc::borrow_pin(&parent.item_tree);
316 let item_tree_array = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
317 if let Some(ItemTreeNode::DynamicTree { parent_index, .. }) =
318 item_tree_array.get(parent.index())
319 {
320 // parent_node returns the repeater node, go up one more level!
321 Some(ItemRc::new(parent.item_tree.clone(), *parent_index))
322 } else {
323 // the Item was most likely a PopupWindow and we don't want to return the item for the purpose of this call
324 // (eg, focus/geometry/...)
325 None
326 }
327 }
328
329 /// Returns true if this item is visible from the root of the item tree. Note that this will return
330 /// false for `Clip` elements with the `clip` property evaluating to true.
331 pub fn is_visible(&self) -> bool {
332 let (clip, geometry) = self.absolute_clip_rect_and_geometry();
333 let clip = clip.to_box2d();
334 let geometry = geometry.to_box2d();
335 !clip.is_empty()
336 && clip.max.x >= geometry.min.x
337 && clip.max.y >= geometry.min.y
338 && clip.min.x <= geometry.max.x
339 && clip.min.y <= geometry.max.y
340 }
341
342 /// Returns the clip rect that applies to this item (in window coordinates) as well as the
343 /// item's (unclipped) geometry (also in window coordinates).
344 fn absolute_clip_rect_and_geometry(&self) -> (LogicalRect, LogicalRect) {
345 let (mut clip, parent_geometry) = self.parent_item().map_or_else(
346 || {
347 (
348 LogicalRect::from_size((crate::Coord::MAX, crate::Coord::MAX).into()),
349 Default::default(),
350 )
351 },
352 |parent| parent.absolute_clip_rect_and_geometry(),
353 );
354
355 let geometry = self.geometry().translate(parent_geometry.origin.to_vector());
356
357 let item = self.borrow();
358 if item.as_ref().clips_children() {
359 clip = geometry.intersection(&clip).unwrap_or_default();
360 }
361
362 (clip, geometry)
363 }
364
365 pub fn is_accessible(&self) -> bool {
366 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
367 let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
368
369 if let Some(n) = &item_tree.get(self.index) {
370 match n {
371 ItemTreeNode::Item { is_accessible, .. } => *is_accessible,
372 ItemTreeNode::DynamicTree { .. } => false,
373 }
374 } else {
375 false
376 }
377 }
378
379 pub fn accessible_role(&self) -> crate::items::AccessibleRole {
380 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
381 comp_ref_pin.as_ref().accessible_role(self.index)
382 }
383
384 pub fn accessible_string_property(
385 &self,
386 what: crate::accessibility::AccessibleStringProperty,
387 ) -> Option<SharedString> {
388 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
389 let mut result = Default::default();
390 let ok = comp_ref_pin.as_ref().accessible_string_property(self.index, what, &mut result);
391 ok.then_some(result)
392 }
393
394 pub fn accessible_action(&self, action: &crate::accessibility::AccessibilityAction) {
395 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
396 comp_ref_pin.as_ref().accessibility_action(self.index, action);
397 }
398
399 pub fn supported_accessibility_actions(&self) -> SupportedAccessibilityAction {
400 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
401 comp_ref_pin.as_ref().supported_accessibility_actions(self.index)
402 }
403
404 pub fn element_count(&self) -> Option<usize> {
405 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
406 let mut result = SharedString::new();
407 comp_ref_pin
408 .as_ref()
409 .item_element_infos(self.index, &mut result)
410 .then(|| result.as_str().split("/").count())
411 }
412
413 pub fn element_type_names_and_ids(
414 &self,
415 element_index: usize,
416 ) -> Option<Vec<(SharedString, SharedString)>> {
417 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
418 let mut result = SharedString::new();
419 comp_ref_pin.as_ref().item_element_infos(self.index, &mut result).then(|| {
420 result
421 .as_str()
422 .split("/")
423 .nth(element_index)
424 .unwrap()
425 .split(";")
426 .map(|encoded_elem_info| {
427 let mut decoder = encoded_elem_info.split(',');
428 let type_name = decoder.next().unwrap().into();
429 let id = decoder.next().map(Into::into).unwrap_or_default();
430 (type_name, id)
431 })
432 .collect()
433 })
434 }
435
436 pub fn geometry(&self) -> LogicalRect {
437 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
438 comp_ref_pin.as_ref().item_geometry(self.index)
439 }
440
441 pub fn bounding_rect(
442 &self,
443 geometry: &LogicalRect,
444 window_adapter: &WindowAdapterRc,
445 ) -> LogicalRect {
446 self.borrow().as_ref().bounding_rect(window_adapter, self, *geometry)
447 }
448
449 /// Returns an absolute position of `p` in the parent item coordinate system
450 /// (does not add this item's x and y)
451 pub fn map_to_window(&self, p: LogicalPoint) -> LogicalPoint {
452 let mut current = self.clone();
453 let mut result = p;
454 while let Some(parent) = current.parent_item() {
455 let geometry = parent.geometry();
456 result += geometry.origin.to_vector();
457 current = parent.clone();
458 }
459 result
460 }
461
462 /// Returns an absolute position of `p` in the `ItemTree`'s coordinate system
463 /// (does not add this item's x and y)
464 pub fn map_to_item_tree(
465 &self,
466 p: LogicalPoint,
467 item_tree: &vtable::VRc<ItemTreeVTable>,
468 ) -> LogicalPoint {
469 let mut current = self.clone();
470 let mut result = p;
471 if current.is_root_item_of(item_tree) {
472 return result;
473 }
474 while let Some(parent) = current.parent_item() {
475 if parent.is_root_item_of(item_tree) {
476 break;
477 }
478 let geometry = parent.geometry();
479 result += geometry.origin.to_vector();
480 current = parent.clone();
481 }
482 result
483 }
484
485 /// Return the index of the item within the ItemTree
486 pub fn index(&self) -> u32 {
487 self.index
488 }
489 /// Returns a reference to the ItemTree holding this item
490 pub fn item_tree(&self) -> &vtable::VRc<ItemTreeVTable> {
491 &self.item_tree
492 }
493
494 fn find_child(
495 &self,
496 child_access: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
497 child_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
498 subtree_child: &dyn Fn(usize, usize) -> usize,
499 ) -> Option<Self> {
500 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
501 let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
502
503 let mut current_child_index = child_access(&item_tree, self.index())?;
504 loop {
505 if let Some(item) = step_into_node(
506 self.item_tree(),
507 &comp_ref_pin,
508 current_child_index,
509 &item_tree,
510 subtree_child,
511 &core::convert::identity,
512 ) {
513 return Some(item);
514 }
515 current_child_index = child_step(&item_tree, current_child_index)?;
516 }
517 }
518
519 /// The first child Item of this Item
520 pub fn first_child(&self) -> Option<Self> {
521 self.find_child(
522 &|item_tree, index| item_tree.first_child(index),
523 &|item_tree, index| item_tree.next_sibling(index),
524 &|start, _| start,
525 )
526 }
527
528 /// The last child Item of this Item
529 pub fn last_child(&self) -> Option<Self> {
530 self.find_child(
531 &|item_tree, index| item_tree.last_child(index),
532 &|item_tree, index| item_tree.previous_sibling(index),
533 &|_, end| end.wrapping_sub(1),
534 )
535 }
536
537 fn find_sibling(
538 &self,
539 sibling_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
540 subtree_step: &dyn Fn(usize) -> usize,
541 subtree_child: &dyn Fn(usize, usize) -> usize,
542 ) -> Option<Self> {
543 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
544 if self.index == 0 {
545 let mut parent_item = Default::default();
546 comp_ref_pin.as_ref().parent_node(&mut parent_item);
547 let current_component_subtree_index = comp_ref_pin.as_ref().subtree_index();
548 if let Some(parent_item) = parent_item.upgrade() {
549 let parent = parent_item.item_tree();
550 let parent_ref_pin = vtable::VRc::borrow_pin(parent);
551 let parent_item_index = parent_item.index();
552 let parent_item_tree = crate::item_tree::ItemTreeNodeArray::new(&parent_ref_pin);
553
554 let subtree_index = match parent_item_tree.get(parent_item_index)? {
555 crate::item_tree::ItemTreeNode::Item { .. } => {
556 // Popups can trigger this case!
557 return None;
558 }
559 crate::item_tree::ItemTreeNode::DynamicTree { index, .. } => *index,
560 };
561
562 let next_subtree_index = subtree_step(current_component_subtree_index);
563
564 // Get next subtree from repeater!
565 let mut next_subtree_instance = Default::default();
566 parent_ref_pin.as_ref().get_subtree(
567 subtree_index,
568 next_subtree_index,
569 &mut next_subtree_instance,
570 );
571 if let Some(next_subtree_instance) = next_subtree_instance.upgrade() {
572 return Some(ItemRc::new(next_subtree_instance, 0));
573 }
574
575 // We need to leave the repeater:
576 find_sibling_outside_repeater(
577 parent,
578 parent_ref_pin,
579 parent_item_index,
580 sibling_step,
581 subtree_child,
582 )
583 } else {
584 None // At root if the item tree
585 }
586 } else {
587 find_sibling_outside_repeater(
588 self.item_tree(),
589 comp_ref_pin,
590 self.index(),
591 sibling_step,
592 subtree_child,
593 )
594 }
595 }
596
597 /// The previous sibling of this Item
598 pub fn previous_sibling(&self) -> Option<Self> {
599 self.find_sibling(
600 &|item_tree, index| item_tree.previous_sibling(index),
601 &|index| index.wrapping_sub(1),
602 &|_, end| end.wrapping_sub(1),
603 )
604 }
605
606 /// The next sibling of this Item
607 pub fn next_sibling(&self) -> Option<Self> {
608 self.find_sibling(
609 &|item_tree, index| item_tree.next_sibling(index),
610 &|index| index.saturating_add(1),
611 &|start, _| start,
612 )
613 }
614
615 fn move_focus(
616 &self,
617 focus_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
618 subtree_step: &dyn Fn(ItemRc) -> Option<ItemRc>,
619 subtree_child: &dyn Fn(usize, usize) -> usize,
620 step_in: &dyn Fn(ItemRc) -> ItemRc,
621 step_out: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
622 ) -> Self {
623 let mut component = self.item_tree().clone();
624 let mut comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
625 let mut item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
626
627 let mut to_focus = self.index();
628
629 'in_tree: loop {
630 if let Some(next) = focus_step(&item_tree, to_focus) {
631 if let Some(item) = step_into_node(
632 &component,
633 &comp_ref_pin,
634 next,
635 &item_tree,
636 subtree_child,
637 step_in,
638 ) {
639 return item;
640 }
641 to_focus = next;
642 // Loop: We stepped into an empty repeater!
643 } else {
644 // Step out of this component:
645 let mut root = ItemRc::new(component, 0);
646 if let Some(item) = subtree_step(root.clone()) {
647 // Next component inside same repeater
648 return step_in(item);
649 }
650
651 // Step out of the repeater
652 let root_component = root.item_tree();
653 let root_comp_ref = vtable::VRc::borrow_pin(root_component);
654 let mut parent_node = Default::default();
655 root_comp_ref.as_ref().parent_node(&mut parent_node);
656
657 while let Some(parent) = parent_node.upgrade() {
658 // .. not at the root of the item tree:
659 component = parent.item_tree().clone();
660 comp_ref_pin = vtable::VRc::borrow_pin(&component);
661 item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
662
663 let index = parent.index();
664
665 if !matches!(item_tree.get(index), Some(ItemTreeNode::DynamicTree { .. })) {
666 // That was not a repeater (eg, a popup window)
667 break;
668 }
669
670 if let Some(next) = step_out(&item_tree, index) {
671 if let Some(item) = step_into_node(
672 parent.item_tree(),
673 &comp_ref_pin,
674 next,
675 &item_tree,
676 subtree_child,
677 step_in,
678 ) {
679 // Step into a dynamic node
680 return item;
681 } else {
682 // The dynamic node was empty, proceed in normal tree
683 to_focus = parent.index();
684 continue 'in_tree; // Find a node in the current (parent!) tree
685 }
686 }
687
688 root = ItemRc::new(component.clone(), 0);
689 if let Some(item) = subtree_step(root.clone()) {
690 return step_in(item);
691 }
692
693 // Go up one more level:
694 let root_component = root.item_tree();
695 let root_comp_ref = vtable::VRc::borrow_pin(root_component);
696 parent_node = Default::default();
697 root_comp_ref.as_ref().parent_node(&mut parent_node);
698 }
699
700 // Loop around after hitting the root node:
701 return step_in(root);
702 }
703 }
704 }
705
706 /// Move tab focus to the previous item:
707 pub fn previous_focus_item(&self) -> Self {
708 self.move_focus(
709 &|item_tree, index| {
710 crate::item_focus::default_previous_in_local_focus_chain(index, item_tree)
711 },
712 &|root| root.previous_sibling(),
713 &|_, end| end.wrapping_sub(1),
714 &|root| {
715 let mut current = root;
716 loop {
717 if let Some(next) = current.last_child() {
718 current = next;
719 } else {
720 return current;
721 }
722 }
723 },
724 &|item_tree, index| item_tree.parent(index),
725 )
726 }
727
728 /// Move tab focus to the next item:
729 pub fn next_focus_item(&self) -> Self {
730 self.move_focus(
731 &|item_tree, index| {
732 crate::item_focus::default_next_in_local_focus_chain(index, item_tree)
733 },
734 &|root| root.next_sibling(),
735 &|start, _| start,
736 &core::convert::identity,
737 &|item_tree, index| crate::item_focus::step_out_of_node(index, item_tree),
738 )
739 }
740
741 pub fn window_adapter(&self) -> Option<WindowAdapterRc> {
742 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
743 let mut result = None;
744 comp_ref_pin.as_ref().window_adapter(false, &mut result);
745 result
746 }
747
748 /// Visit the children of this element and call the visitor to each of them, until the visitor returns [`ControlFlow::Break`].
749 /// When the visitor breaks, the function returns the value. If it doesn't break, the function returns None.
750 fn visit_descendants_impl<R>(
751 &self,
752 visitor: &mut impl FnMut(&ItemRc) -> ControlFlow<R>,
753 ) -> Option<R> {
754 let mut result = None;
755
756 let mut actual_visitor = |item_tree: &ItemTreeRc,
757 index: u32,
758 _item_pin: core::pin::Pin<ItemRef>|
759 -> VisitChildrenResult {
760 let item_rc = ItemRc::new(item_tree.clone(), index);
761
762 match visitor(&item_rc) {
763 ControlFlow::Continue(_) => {
764 if let Some(x) = item_rc.visit_descendants_impl(visitor) {
765 result = Some(x);
766 return VisitChildrenResult::abort(index, 0);
767 }
768 }
769 ControlFlow::Break(x) => {
770 result = Some(x);
771 return VisitChildrenResult::abort(index, 0);
772 }
773 }
774
775 VisitChildrenResult::CONTINUE
776 };
777 vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);
778
779 VRc::borrow_pin(self.item_tree()).as_ref().visit_children_item(
780 self.index() as isize,
781 TraversalOrder::BackToFront,
782 actual_visitor,
783 );
784
785 result
786 }
787
788 /// Visit the children of this element and call the visitor to each of them, until the visitor returns [`ControlFlow::Break`].
789 /// When the visitor breaks, the function returns the value. If it doesn't break, the function returns None.
790 pub fn visit_descendants<R>(
791 &self,
792 mut visitor: impl FnMut(&ItemRc) -> ControlFlow<R>,
793 ) -> Option<R> {
794 self.visit_descendants_impl(&mut visitor)
795 }
796
797 /// Returns the transform to apply to children to map them into the local coordinate space of this item.
798 /// Typically this is None, but rotation for example may return Some.
799 pub fn children_transform(&self) -> Option<ItemTransform> {
800 self.downcast::<crate::items::Rotate>().map(|rotate_item| {
801 let origin = euclid::Vector2D::<f32, crate::lengths::LogicalPx>::from_lengths(
802 rotate_item.as_pin_ref().rotation_origin_x().cast(),
803 rotate_item.as_pin_ref().rotation_origin_y().cast(),
804 );
805 ItemTransform::translation(-origin.x, -origin.y)
806 .cast()
807 .then_rotate(euclid::Angle {
808 radians: rotate_item.as_pin_ref().rotation_angle().to_radians(),
809 })
810 .then_translate(origin)
811 })
812 }
813}
814
815impl PartialEq for ItemRc {
816 fn eq(&self, other: &Self) -> bool {
817 VRc::ptr_eq(&self.item_tree, &other.item_tree) && self.index == other.index
818 }
819}
820
821impl Eq for ItemRc {}
822
823/// A Weak reference to an item that can be constructed from an ItemRc.
824#[derive(Clone, Default)]
825#[repr(C)]
826pub struct ItemWeak {
827 item_tree: crate::item_tree::ItemTreeWeak,
828 index: u32,
829}
830
831impl ItemWeak {
832 pub fn upgrade(&self) -> Option<ItemRc> {
833 self.item_tree.upgrade().map(|c: VRc| ItemRc::new(item_tree:c, self.index))
834 }
835}
836
837impl PartialEq for ItemWeak {
838 fn eq(&self, other: &Self) -> bool {
839 VWeak::ptr_eq(&self.item_tree, &other.item_tree) && self.index == other.index
840 }
841}
842
843impl Eq for ItemWeak {}
844
845#[repr(u8)]
846#[derive(Debug, Copy, Clone, Eq, PartialEq)]
847pub enum TraversalOrder {
848 BackToFront,
849 FrontToBack,
850}
851
852/// The return value of the ItemTree::visit_children_item function
853///
854/// Represents something like `enum { Continue, Aborted{aborted_at_item: isize} }`.
855/// But this is just wrapping a int because it is easier to use ffi with isize than
856/// complex enum.
857///
858/// -1 means the visitor will continue
859/// otherwise this is the index of the item that aborted the visit.
860#[repr(transparent)]
861#[derive(Copy, Clone, Eq, PartialEq)]
862pub struct VisitChildrenResult(u64);
863impl VisitChildrenResult {
864 /// The result used for a visitor that want to continue the visit
865 pub const CONTINUE: Self = Self(u64::MAX);
866
867 /// Returns a result that means that the visitor must stop, and convey the item that caused the abort
868 pub fn abort(item_index: u32, index_within_repeater: usize) -> Self {
869 assert!(index_within_repeater < u32::MAX as usize);
870 Self(item_index as u64 | (index_within_repeater as u64) << 32)
871 }
872 /// True if the visitor wants to abort the visit
873 pub fn has_aborted(&self) -> bool {
874 self.0 != Self::CONTINUE.0
875 }
876 pub fn aborted_index(&self) -> Option<usize> {
877 if self.0 != Self::CONTINUE.0 {
878 Some((self.0 & 0xffff_ffff) as usize)
879 } else {
880 None
881 }
882 }
883 pub fn aborted_indexes(&self) -> Option<(usize, usize)> {
884 if self.0 != Self::CONTINUE.0 {
885 Some(((self.0 & 0xffff_ffff) as usize, (self.0 >> 32) as usize))
886 } else {
887 None
888 }
889 }
890}
891impl core::fmt::Debug for VisitChildrenResult {
892 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
893 if self.0 == Self::CONTINUE.0 {
894 write!(f, "CONTINUE")
895 } else {
896 write!(f, "({},{})", (self.0 & 0xffff_ffff) as usize, (self.0 >> 32) as usize)
897 }
898 }
899}
900
901/// The item tree is an array of ItemTreeNode representing a static tree of items
902/// within a ItemTree.
903#[repr(u8)]
904#[derive(Debug)]
905pub enum ItemTreeNode {
906 /// Static item
907 Item {
908 /// True when the item has accessibility properties attached
909 is_accessible: bool,
910
911 /// number of children
912 children_count: u32,
913
914 /// index of the first children within the item tree
915 children_index: u32,
916
917 /// The index of the parent item (not valid for the root)
918 parent_index: u32,
919
920 /// The index in the extra item_array
921 item_array_index: u32,
922 },
923 /// A placeholder for many instance of item in their own ItemTree which
924 /// are instantiated according to a model.
925 DynamicTree {
926 /// the index which is passed in the visit_dynamic callback.
927 index: u32,
928
929 /// The index of the parent item (not valid for the root)
930 parent_index: u32,
931 },
932}
933
934impl ItemTreeNode {
935 pub fn parent_index(&self) -> u32 {
936 match self {
937 ItemTreeNode::Item { parent_index: &u32, .. } => *parent_index,
938 ItemTreeNode::DynamicTree { parent_index: &u32, .. } => *parent_index,
939 }
940 }
941}
942
943/// The `ItemTreeNodeArray` provides tree walking code for the physical ItemTree stored in
944/// a `ItemTree` without stitching any inter-ItemTree links together!
945pub struct ItemTreeNodeArray<'a> {
946 node_array: &'a [ItemTreeNode],
947}
948
949impl<'a> ItemTreeNodeArray<'a> {
950 /// Create a new `ItemTree` from its raw data.
951 pub fn new(comp_ref_pin: &'a Pin<VRef<'a, ItemTreeVTable>>) -> Self {
952 Self { node_array: comp_ref_pin.as_ref().get_item_tree().as_slice() }
953 }
954
955 /// Get a ItemTreeNode
956 pub fn get(&self, index: u32) -> Option<&ItemTreeNode> {
957 self.node_array.get(index as usize)
958 }
959
960 /// Get the parent of a node, returns `None` if this is the root node of this item tree.
961 pub fn parent(&self, index: u32) -> Option<u32> {
962 let index = index as usize;
963 (index < self.node_array.len() && index != 0).then(|| self.node_array[index].parent_index())
964 }
965
966 /// Returns the next sibling or `None` if this is the last sibling.
967 pub fn next_sibling(&self, index: u32) -> Option<u32> {
968 if let Some(parent_index) = self.parent(index) {
969 match self.node_array[parent_index as usize] {
970 ItemTreeNode::Item { children_index, children_count, .. } => {
971 (index < (children_count + children_index - 1)).then_some(index + 1)
972 }
973 ItemTreeNode::DynamicTree { .. } => {
974 unreachable!("Parent in same item tree is a repeater.")
975 }
976 }
977 } else {
978 None // No parent, so we have no siblings either:-)
979 }
980 }
981
982 /// Returns the previous sibling or `None` if this is the first sibling.
983 pub fn previous_sibling(&self, index: u32) -> Option<u32> {
984 if let Some(parent_index) = self.parent(index) {
985 match self.node_array[parent_index as usize] {
986 ItemTreeNode::Item { children_index, .. } => {
987 (index > children_index).then_some(index - 1)
988 }
989 ItemTreeNode::DynamicTree { .. } => {
990 unreachable!("Parent in same item tree is a repeater.")
991 }
992 }
993 } else {
994 None // No parent, so we have no siblings either:-)
995 }
996 }
997
998 /// Returns the first child or `None` if this are no children or the `index`
999 /// points to a `DynamicTree`.
1000 pub fn first_child(&self, index: u32) -> Option<u32> {
1001 match self.node_array.get(index as usize)? {
1002 ItemTreeNode::Item { children_index, children_count, .. } => {
1003 (*children_count != 0).then_some(*children_index as _)
1004 }
1005 ItemTreeNode::DynamicTree { .. } => None,
1006 }
1007 }
1008
1009 /// Returns the last child or `None` if this are no children or the `index`
1010 /// points to an `DynamicTree`.
1011 pub fn last_child(&self, index: u32) -> Option<u32> {
1012 match self.node_array.get(index as usize)? {
1013 ItemTreeNode::Item { children_index, children_count, .. } => {
1014 if *children_count != 0 {
1015 Some(*children_index + *children_count - 1)
1016 } else {
1017 None
1018 }
1019 }
1020 ItemTreeNode::DynamicTree { .. } => None,
1021 }
1022 }
1023
1024 /// Returns the number of nodes in the `ItemTreeNodeArray`
1025 pub fn node_count(&self) -> usize {
1026 self.node_array.len()
1027 }
1028}
1029
1030impl<'a> From<&'a [ItemTreeNode]> for ItemTreeNodeArray<'a> {
1031 fn from(item_tree: &'a [ItemTreeNode]) -> Self {
1032 Self { node_array: item_tree }
1033 }
1034}
1035
1036#[repr(C)]
1037#[vtable]
1038/// Object to be passed in visit_item_children method of the ItemTree.
1039pub struct ItemVisitorVTable {
1040 /// Called for each child of the visited item
1041 ///
1042 /// The `item_tree` parameter is the ItemTree in which the item live which might not be the same
1043 /// as the parent's ItemTree.
1044 /// `index` is to be used again in the visit_item_children function of the ItemTree (the one passed as parameter)
1045 /// and `item` is a reference to the item itself
1046 visit_item: fn(
1047 VRefMut<ItemVisitorVTable>,
1048 item_tree: &VRc<ItemTreeVTable, vtable::Dyn>,
1049 index: u32,
1050 item: Pin<VRef<ItemVTable>>,
1051 ) -> VisitChildrenResult,
1052 /// Destructor
1053 drop: fn(VRefMut<ItemVisitorVTable>),
1054}
1055
1056/// Type alias to `vtable::VRefMut<ItemVisitorVTable>`
1057pub type ItemVisitorRefMut<'a> = vtable::VRefMut<'a, ItemVisitorVTable>;
1058
1059impl<T: FnMut(&ItemTreeRc, u32, Pin<ItemRef>) -> VisitChildrenResult> ItemVisitor for T {
1060 fn visit_item(
1061 &mut self,
1062 item_tree: &ItemTreeRc,
1063 index: u32,
1064 item: Pin<ItemRef>,
1065 ) -> VisitChildrenResult {
1066 self(item_tree, index, item)
1067 }
1068}
1069pub enum ItemVisitorResult<State> {
1070 Continue(State),
1071 Abort,
1072}
1073
1074/// Visit each items recursively
1075///
1076/// The state parameter returned by the visitor is passed to each child.
1077///
1078/// Returns the index of the item that cancelled, or -1 if nobody cancelled
1079pub fn visit_items<State>(
1080 item_tree: &ItemTreeRc,
1081 order: TraversalOrder,
1082 mut visitor: impl FnMut(&ItemTreeRc, Pin<ItemRef>, u32, &State) -> ItemVisitorResult<State>,
1083 state: State,
1084) -> VisitChildrenResult {
1085 visit_internal(item_tree, order, &mut visitor, index:-1, &state)
1086}
1087
1088fn visit_internal<State>(
1089 item_tree: &ItemTreeRc,
1090 order: TraversalOrder,
1091 visitor: &mut impl FnMut(&ItemTreeRc, Pin<ItemRef>, u32, &State) -> ItemVisitorResult<State>,
1092 index: isize,
1093 state: &State,
1094) -> VisitChildrenResult {
1095 let mut actual_visitor: impl FnMut(&VRc, …) -> … =
1096 |item_tree: &ItemTreeRc, index: u32, item: Pin<ItemRef>| -> VisitChildrenResult {
1097 match visitor(item_tree, item, index, state) {
1098 ItemVisitorResult::Continue(state: State) => {
1099 visit_internal(item_tree, order, visitor, index as isize, &state)
1100 }
1101
1102 ItemVisitorResult::Abort => VisitChildrenResult::abort(index, index_within_repeater:0),
1103 }
1104 };
1105 vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);
1106 VRc::borrow_pin(this:item_tree).as_ref().visit_children_item(index, order, actual_visitor)
1107}
1108
1109/// Visit the children within an array of ItemTreeNode
1110///
1111/// The dynamic visitor is called for the dynamic nodes, its signature is
1112/// `fn(base: &Base, visitor: vtable::VRefMut<ItemVisitorVTable>, dyn_index: usize)`
1113///
1114/// FIXME: the design of this use lots of indirection and stack frame in recursive functions
1115/// Need to check if the compiler is able to optimize away some of it.
1116/// Possibly we should generate code that directly call the visitor instead
1117pub fn visit_item_tree<Base>(
1118 base: Pin<&Base>,
1119 item_tree: &ItemTreeRc,
1120 item_tree_array: &[ItemTreeNode],
1121 index: isize,
1122 order: TraversalOrder,
1123 mut visitor: vtable::VRefMut<ItemVisitorVTable>,
1124 visit_dynamic: impl Fn(
1125 Pin<&Base>,
1126 TraversalOrder,
1127 vtable::VRefMut<ItemVisitorVTable>,
1128 u32,
1129 ) -> VisitChildrenResult,
1130) -> VisitChildrenResult {
1131 let mut visit_at_index = |idx: u32| -> VisitChildrenResult {
1132 match &item_tree_array[idx as usize] {
1133 ItemTreeNode::Item { .. } => {
1134 let item = crate::items::ItemRc::new(item_tree.clone(), idx);
1135 visitor.visit_item(item_tree, idx, item.borrow())
1136 }
1137 ItemTreeNode::DynamicTree { index, .. } => {
1138 if let Some(sub_idx) =
1139 visit_dynamic(base, order, visitor.borrow_mut(), *index).aborted_index()
1140 {
1141 VisitChildrenResult::abort(idx, sub_idx)
1142 } else {
1143 VisitChildrenResult::CONTINUE
1144 }
1145 }
1146 }
1147 };
1148 if index == -1 {
1149 visit_at_index(0)
1150 } else {
1151 match &item_tree_array[index as usize] {
1152 ItemTreeNode::Item { children_index, children_count, .. } => {
1153 for c in 0..*children_count {
1154 let idx = match order {
1155 TraversalOrder::BackToFront => *children_index + c,
1156 TraversalOrder::FrontToBack => *children_index + *children_count - c - 1,
1157 };
1158 let maybe_abort_index = visit_at_index(idx);
1159 if maybe_abort_index.has_aborted() {
1160 return maybe_abort_index;
1161 }
1162 }
1163 }
1164 ItemTreeNode::DynamicTree { .. } => panic!("should not be called with dynamic items"),
1165 };
1166 VisitChildrenResult::CONTINUE
1167 }
1168}
1169
1170#[cfg(feature = "ffi")]
1171pub(crate) mod ffi {
1172 #![allow(unsafe_code)]
1173
1174 use super::*;
1175 use core::ffi::c_void;
1176
1177 /// Call init() on the ItemVTable of each item in the item array.
1178 #[no_mangle]
1179 pub unsafe extern "C" fn slint_register_item_tree(
1180 item_tree_rc: &ItemTreeRc,
1181 window_handle: *const crate::window::ffi::WindowAdapterRcOpaque,
1182 ) {
1183 let window_adapter = (window_handle as *const WindowAdapterRc).as_ref().cloned();
1184 super::register_item_tree(item_tree_rc, window_adapter)
1185 }
1186
1187 /// Free the backend graphics resources allocated in the item array.
1188 #[no_mangle]
1189 pub unsafe extern "C" fn slint_unregister_item_tree(
1190 component: ItemTreeRefPin,
1191 item_array: Slice<vtable::VOffset<u8, ItemVTable, vtable::AllowPin>>,
1192 window_handle: *const crate::window::ffi::WindowAdapterRcOpaque,
1193 ) {
1194 let window_adapter = &*(window_handle as *const WindowAdapterRc);
1195 super::unregister_item_tree(
1196 core::pin::Pin::new_unchecked(&*(component.as_ptr() as *const u8)),
1197 core::pin::Pin::into_inner(component),
1198 item_array.as_slice(),
1199 window_adapter,
1200 )
1201 }
1202
1203 /// Expose `crate::item_tree::visit_item_tree` to C++
1204 ///
1205 /// Safety: Assume a correct implementation of the item_tree array
1206 #[no_mangle]
1207 pub unsafe extern "C" fn slint_visit_item_tree(
1208 item_tree: &ItemTreeRc,
1209 item_tree_array: Slice<ItemTreeNode>,
1210 index: isize,
1211 order: TraversalOrder,
1212 visitor: VRefMut<ItemVisitorVTable>,
1213 visit_dynamic: extern "C" fn(
1214 base: *const c_void,
1215 order: TraversalOrder,
1216 visitor: vtable::VRefMut<ItemVisitorVTable>,
1217 dyn_index: u32,
1218 ) -> VisitChildrenResult,
1219 ) -> VisitChildrenResult {
1220 crate::item_tree::visit_item_tree(
1221 VRc::as_pin_ref(item_tree),
1222 item_tree,
1223 item_tree_array.as_slice(),
1224 index,
1225 order,
1226 visitor,
1227 |a, b, c, d| visit_dynamic(a.get_ref() as *const vtable::Dyn as *const c_void, b, c, d),
1228 )
1229 }
1230}
1231
1232#[cfg(test)]
1233mod tests {
1234 use super::*;
1235 use std::vec;
1236
1237 struct TestItemTree {
1238 parent_component: Option<ItemTreeRc>,
1239 item_tree: Vec<ItemTreeNode>,
1240 subtrees: std::cell::RefCell<Vec<Vec<vtable::VRc<ItemTreeVTable, TestItemTree>>>>,
1241 subtree_index: usize,
1242 }
1243
1244 impl ItemTree for TestItemTree {
1245 fn visit_children_item(
1246 self: core::pin::Pin<&Self>,
1247 _1: isize,
1248 _2: crate::item_tree::TraversalOrder,
1249 _3: vtable::VRefMut<crate::item_tree::ItemVisitorVTable>,
1250 ) -> crate::item_tree::VisitChildrenResult {
1251 unimplemented!("Not needed for this test")
1252 }
1253
1254 fn get_item_ref(
1255 self: core::pin::Pin<&Self>,
1256 _1: u32,
1257 ) -> core::pin::Pin<vtable::VRef<super::ItemVTable>> {
1258 unimplemented!("Not needed for this test")
1259 }
1260
1261 fn get_item_tree(self: core::pin::Pin<&Self>) -> Slice<ItemTreeNode> {
1262 Slice::from_slice(&self.get_ref().item_tree)
1263 }
1264
1265 fn parent_node(self: core::pin::Pin<&Self>, result: &mut ItemWeak) {
1266 if let Some(parent_item) = self.parent_component.clone() {
1267 *result =
1268 ItemRc::new(parent_item.clone(), self.item_tree[0].parent_index()).downgrade();
1269 }
1270 }
1271
1272 fn embed_component(
1273 self: core::pin::Pin<&Self>,
1274 _parent_component: &ItemTreeWeak,
1275 _item_tree_index: u32,
1276 ) -> bool {
1277 false
1278 }
1279
1280 fn layout_info(self: core::pin::Pin<&Self>, _1: Orientation) -> LayoutInfo {
1281 unimplemented!("Not needed for this test")
1282 }
1283
1284 fn subtree_index(self: core::pin::Pin<&Self>) -> usize {
1285 self.subtree_index
1286 }
1287
1288 fn get_subtree_range(self: core::pin::Pin<&Self>, subtree_index: u32) -> IndexRange {
1289 (0..self.subtrees.borrow()[subtree_index as usize].len()).into()
1290 }
1291
1292 fn get_subtree(
1293 self: core::pin::Pin<&Self>,
1294 subtree_index: u32,
1295 component_index: usize,
1296 result: &mut ItemTreeWeak,
1297 ) {
1298 if let Some(vrc) = self.subtrees.borrow()[subtree_index as usize].get(component_index) {
1299 *result = vtable::VRc::downgrade(&vtable::VRc::into_dyn(vrc.clone()))
1300 }
1301 }
1302
1303 fn accessible_role(self: Pin<&Self>, _: u32) -> AccessibleRole {
1304 unimplemented!("Not needed for this test")
1305 }
1306
1307 fn accessible_string_property(
1308 self: Pin<&Self>,
1309 _: u32,
1310 _: AccessibleStringProperty,
1311 _: &mut SharedString,
1312 ) -> bool {
1313 false
1314 }
1315
1316 fn item_element_infos(self: Pin<&Self>, _: u32, _: &mut SharedString) -> bool {
1317 false
1318 }
1319
1320 fn window_adapter(
1321 self: Pin<&Self>,
1322 _do_create: bool,
1323 _result: &mut Option<WindowAdapterRc>,
1324 ) {
1325 unimplemented!("Not needed for this test")
1326 }
1327
1328 fn item_geometry(self: Pin<&Self>, _: u32) -> LogicalRect {
1329 unimplemented!("Not needed for this test")
1330 }
1331
1332 fn accessibility_action(self: core::pin::Pin<&Self>, _: u32, _: &AccessibilityAction) {
1333 unimplemented!("Not needed for this test")
1334 }
1335
1336 fn supported_accessibility_actions(
1337 self: core::pin::Pin<&Self>,
1338 _: u32,
1339 ) -> SupportedAccessibilityAction {
1340 unimplemented!("Not needed for this test")
1341 }
1342 }
1343
1344 crate::item_tree::ItemTreeVTable_static!(static TEST_COMPONENT_VT for TestItemTree);
1345
1346 fn create_one_node_component() -> VRc<ItemTreeVTable, vtable::Dyn> {
1347 let component = VRc::new(TestItemTree {
1348 parent_component: None,
1349 item_tree: vec![ItemTreeNode::Item {
1350 is_accessible: false,
1351 children_count: 0,
1352 children_index: 1,
1353 parent_index: 0,
1354 item_array_index: 0,
1355 }],
1356 subtrees: std::cell::RefCell::new(vec![]),
1357 subtree_index: usize::MAX,
1358 });
1359 VRc::into_dyn(component)
1360 }
1361
1362 #[test]
1363 fn test_tree_traversal_one_node_structure() {
1364 let component = create_one_node_component();
1365
1366 let item = ItemRc::new(component.clone(), 0);
1367
1368 assert!(item.first_child().is_none());
1369 assert!(item.last_child().is_none());
1370 assert!(item.previous_sibling().is_none());
1371 assert!(item.next_sibling().is_none());
1372 }
1373
1374 #[test]
1375 fn test_tree_traversal_one_node_forward_focus() {
1376 let component = create_one_node_component();
1377
1378 let item = ItemRc::new(component.clone(), 0);
1379
1380 // Wrap the focus around:
1381 assert_eq!(item.next_focus_item(), item);
1382 }
1383
1384 #[test]
1385 fn test_tree_traversal_one_node_backward_focus() {
1386 let component = create_one_node_component();
1387
1388 let item = ItemRc::new(component.clone(), 0);
1389
1390 // Wrap the focus around:
1391 assert_eq!(item.previous_focus_item(), item);
1392 }
1393
1394 fn create_children_nodes() -> VRc<ItemTreeVTable, vtable::Dyn> {
1395 let component = VRc::new(TestItemTree {
1396 parent_component: None,
1397 item_tree: vec![
1398 ItemTreeNode::Item {
1399 is_accessible: false,
1400 children_count: 3,
1401 children_index: 1,
1402 parent_index: 0,
1403 item_array_index: 0,
1404 },
1405 ItemTreeNode::Item {
1406 is_accessible: false,
1407 children_count: 0,
1408 children_index: 4,
1409 parent_index: 0,
1410 item_array_index: 1,
1411 },
1412 ItemTreeNode::Item {
1413 is_accessible: false,
1414 children_count: 0,
1415 children_index: 4,
1416 parent_index: 0,
1417 item_array_index: 2,
1418 },
1419 ItemTreeNode::Item {
1420 is_accessible: false,
1421 children_count: 0,
1422 children_index: 4,
1423 parent_index: 0,
1424 item_array_index: 3,
1425 },
1426 ],
1427 subtrees: std::cell::RefCell::new(vec![]),
1428 subtree_index: usize::MAX,
1429 });
1430 VRc::into_dyn(component)
1431 }
1432
1433 #[test]
1434 fn test_tree_traversal_children_nodes_structure() {
1435 let component = create_children_nodes();
1436
1437 // Examine root node:
1438 let item = ItemRc::new(component.clone(), 0);
1439 assert!(item.previous_sibling().is_none());
1440 assert!(item.next_sibling().is_none());
1441
1442 let fc = item.first_child().unwrap();
1443 assert_eq!(fc.index(), 1);
1444 assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
1445
1446 let fcn = fc.next_sibling().unwrap();
1447 assert_eq!(fcn.index(), 2);
1448
1449 let lc = item.last_child().unwrap();
1450 assert_eq!(lc.index(), 3);
1451 assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
1452
1453 let lcp = lc.previous_sibling().unwrap();
1454 assert!(VRc::ptr_eq(lcp.item_tree(), item.item_tree()));
1455 assert_eq!(lcp.index(), 2);
1456
1457 // Examine first child:
1458 assert!(fc.first_child().is_none());
1459 assert!(fc.last_child().is_none());
1460 assert!(fc.previous_sibling().is_none());
1461 assert_eq!(fc.parent_item().unwrap(), item);
1462
1463 // Examine item between first and last child:
1464 assert_eq!(fcn, lcp);
1465 assert_eq!(lcp.parent_item().unwrap(), item);
1466 assert_eq!(fcn.previous_sibling().unwrap(), fc);
1467 assert_eq!(fcn.next_sibling().unwrap(), lc);
1468
1469 // Examine last child:
1470 assert!(lc.first_child().is_none());
1471 assert!(lc.last_child().is_none());
1472 assert!(lc.next_sibling().is_none());
1473 assert_eq!(lc.parent_item().unwrap(), item);
1474 }
1475
1476 #[test]
1477 fn test_tree_traversal_children_nodes_forward_focus() {
1478 let component = create_children_nodes();
1479
1480 let item = ItemRc::new(component.clone(), 0);
1481 let fc = item.first_child().unwrap();
1482 let fcn = fc.next_sibling().unwrap();
1483 let lc = item.last_child().unwrap();
1484
1485 let mut cursor = item.clone();
1486
1487 cursor = cursor.next_focus_item();
1488 assert_eq!(cursor, fc);
1489
1490 cursor = cursor.next_focus_item();
1491 assert_eq!(cursor, fcn);
1492
1493 cursor = cursor.next_focus_item();
1494 assert_eq!(cursor, lc);
1495
1496 cursor = cursor.next_focus_item();
1497 assert_eq!(cursor, item);
1498 }
1499
1500 #[test]
1501 fn test_tree_traversal_children_nodes_backward_focus() {
1502 let component = create_children_nodes();
1503
1504 let item = ItemRc::new(component.clone(), 0);
1505 let fc = item.first_child().unwrap();
1506 let fcn = fc.next_sibling().unwrap();
1507 let lc = item.last_child().unwrap();
1508
1509 let mut cursor = item.clone();
1510
1511 cursor = cursor.previous_focus_item();
1512 assert_eq!(cursor, lc);
1513
1514 cursor = cursor.previous_focus_item();
1515 assert_eq!(cursor, fcn);
1516
1517 cursor = cursor.previous_focus_item();
1518 assert_eq!(cursor, fc);
1519
1520 cursor = cursor.previous_focus_item();
1521 assert_eq!(cursor, item);
1522 }
1523
1524 fn create_empty_subtree() -> VRc<ItemTreeVTable, vtable::Dyn> {
1525 let component = vtable::VRc::new(TestItemTree {
1526 parent_component: None,
1527 item_tree: vec![
1528 ItemTreeNode::Item {
1529 is_accessible: false,
1530 children_count: 1,
1531 children_index: 1,
1532 parent_index: 0,
1533 item_array_index: 0,
1534 },
1535 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1536 ],
1537 subtrees: std::cell::RefCell::new(vec![vec![]]),
1538 subtree_index: usize::MAX,
1539 });
1540 vtable::VRc::into_dyn(component)
1541 }
1542
1543 #[test]
1544 fn test_tree_traversal_empty_subtree_structure() {
1545 let component = create_empty_subtree();
1546
1547 // Examine root node:
1548 let item = ItemRc::new(component.clone(), 0);
1549 assert!(item.previous_sibling().is_none());
1550 assert!(item.next_sibling().is_none());
1551 assert!(item.first_child().is_none());
1552 assert!(item.last_child().is_none());
1553
1554 // Wrap the focus around:
1555 assert!(item.previous_focus_item() == item);
1556 assert!(item.next_focus_item() == item);
1557 }
1558
1559 #[test]
1560 fn test_tree_traversal_empty_subtree_forward_focus() {
1561 let component = create_empty_subtree();
1562
1563 // Examine root node:
1564 let item = ItemRc::new(component.clone(), 0);
1565
1566 assert!(item.next_focus_item() == item);
1567 }
1568
1569 #[test]
1570 fn test_tree_traversal_empty_subtree_backward_focus() {
1571 let component = create_empty_subtree();
1572
1573 // Examine root node:
1574 let item = ItemRc::new(component.clone(), 0);
1575
1576 assert!(item.previous_focus_item() == item);
1577 }
1578
1579 fn create_item_subtree_item() -> VRc<ItemTreeVTable, vtable::Dyn> {
1580 let component = VRc::new(TestItemTree {
1581 parent_component: None,
1582 item_tree: vec![
1583 ItemTreeNode::Item {
1584 is_accessible: false,
1585 children_count: 3,
1586 children_index: 1,
1587 parent_index: 0,
1588 item_array_index: 0,
1589 },
1590 ItemTreeNode::Item {
1591 is_accessible: false,
1592 children_count: 0,
1593 children_index: 4,
1594 parent_index: 0,
1595 item_array_index: 0,
1596 },
1597 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1598 ItemTreeNode::Item {
1599 is_accessible: false,
1600 children_count: 0,
1601 children_index: 4,
1602 parent_index: 0,
1603 item_array_index: 0,
1604 },
1605 ],
1606 subtrees: std::cell::RefCell::new(vec![]),
1607 subtree_index: usize::MAX,
1608 });
1609
1610 component.as_pin_ref().subtrees.replace(vec![vec![VRc::new(TestItemTree {
1611 parent_component: Some(VRc::into_dyn(component.clone())),
1612 item_tree: vec![ItemTreeNode::Item {
1613 is_accessible: false,
1614 children_count: 0,
1615 children_index: 1,
1616 parent_index: 2,
1617 item_array_index: 0,
1618 }],
1619 subtrees: std::cell::RefCell::new(vec![]),
1620 subtree_index: 0,
1621 })]]);
1622
1623 VRc::into_dyn(component)
1624 }
1625
1626 #[test]
1627 fn test_tree_traversal_item_subtree_item_structure() {
1628 let component = create_item_subtree_item();
1629
1630 // Examine root node:
1631 let item = ItemRc::new(component.clone(), 0);
1632 assert!(item.previous_sibling().is_none());
1633 assert!(item.next_sibling().is_none());
1634
1635 let fc = item.first_child().unwrap();
1636 assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
1637 assert_eq!(fc.index(), 1);
1638
1639 let lc = item.last_child().unwrap();
1640 assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
1641 assert_eq!(lc.index(), 3);
1642
1643 let fcn = fc.next_sibling().unwrap();
1644 let lcp = lc.previous_sibling().unwrap();
1645
1646 assert_eq!(fcn, lcp);
1647 assert!(!VRc::ptr_eq(fcn.item_tree(), item.item_tree()));
1648
1649 let last = fcn.next_sibling().unwrap();
1650 assert_eq!(last, lc);
1651
1652 let first = lcp.previous_sibling().unwrap();
1653 assert_eq!(first, fc);
1654 }
1655
1656 #[test]
1657 fn test_tree_traversal_item_subtree_item_forward_focus() {
1658 let component = create_item_subtree_item();
1659
1660 let item = ItemRc::new(component.clone(), 0);
1661 let fc = item.first_child().unwrap();
1662 let lc = item.last_child().unwrap();
1663 let fcn = fc.next_sibling().unwrap();
1664
1665 let mut cursor = item.clone();
1666
1667 cursor = cursor.next_focus_item();
1668 assert_eq!(cursor, fc);
1669
1670 cursor = cursor.next_focus_item();
1671 assert_eq!(cursor, fcn);
1672
1673 cursor = cursor.next_focus_item();
1674 assert_eq!(cursor, lc);
1675
1676 cursor = cursor.next_focus_item();
1677 assert_eq!(cursor, item);
1678 }
1679
1680 #[test]
1681 fn test_tree_traversal_item_subtree_item_backward_focus() {
1682 let component = create_item_subtree_item();
1683
1684 let item = ItemRc::new(component.clone(), 0);
1685 let fc = item.first_child().unwrap();
1686 let lc = item.last_child().unwrap();
1687 let fcn = fc.next_sibling().unwrap();
1688
1689 let mut cursor = item.clone();
1690
1691 cursor = cursor.previous_focus_item();
1692 assert_eq!(cursor, lc);
1693
1694 cursor = cursor.previous_focus_item();
1695 assert_eq!(cursor, fcn);
1696
1697 cursor = cursor.previous_focus_item();
1698 assert_eq!(cursor, fc);
1699
1700 cursor = cursor.previous_focus_item();
1701 assert_eq!(cursor, item);
1702 }
1703
1704 fn create_nested_subtrees() -> VRc<ItemTreeVTable, vtable::Dyn> {
1705 let component = VRc::new(TestItemTree {
1706 parent_component: None,
1707 item_tree: vec![
1708 ItemTreeNode::Item {
1709 is_accessible: false,
1710 children_count: 3,
1711 children_index: 1,
1712 parent_index: 0,
1713 item_array_index: 0,
1714 },
1715 ItemTreeNode::Item {
1716 is_accessible: false,
1717 children_count: 0,
1718 children_index: 4,
1719 parent_index: 0,
1720 item_array_index: 0,
1721 },
1722 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1723 ItemTreeNode::Item {
1724 is_accessible: false,
1725 children_count: 0,
1726 children_index: 4,
1727 parent_index: 0,
1728 item_array_index: 0,
1729 },
1730 ],
1731 subtrees: std::cell::RefCell::new(vec![]),
1732 subtree_index: usize::MAX,
1733 });
1734
1735 let sub_component1 = VRc::new(TestItemTree {
1736 parent_component: Some(VRc::into_dyn(component.clone())),
1737 item_tree: vec![
1738 ItemTreeNode::Item {
1739 is_accessible: false,
1740 children_count: 1,
1741 children_index: 1,
1742 parent_index: 2,
1743 item_array_index: 0,
1744 },
1745 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1746 ],
1747 subtrees: std::cell::RefCell::new(vec![]),
1748 subtree_index: usize::MAX,
1749 });
1750 let sub_component2 = VRc::new(TestItemTree {
1751 parent_component: Some(VRc::into_dyn(sub_component1.clone())),
1752 item_tree: vec![
1753 ItemTreeNode::Item {
1754 is_accessible: false,
1755 children_count: 1,
1756 children_index: 1,
1757 parent_index: 1,
1758 item_array_index: 0,
1759 },
1760 ItemTreeNode::Item {
1761 is_accessible: false,
1762 children_count: 0,
1763 children_index: 2,
1764 parent_index: 0,
1765 item_array_index: 0,
1766 },
1767 ],
1768 subtrees: std::cell::RefCell::new(vec![]),
1769 subtree_index: usize::MAX,
1770 });
1771
1772 sub_component1.as_pin_ref().subtrees.replace(vec![vec![sub_component2]]);
1773 component.as_pin_ref().subtrees.replace(vec![vec![sub_component1]]);
1774
1775 VRc::into_dyn(component)
1776 }
1777
1778 #[test]
1779 fn test_tree_traversal_nested_subtrees_structure() {
1780 let component = create_nested_subtrees();
1781
1782 // Examine root node:
1783 let item = ItemRc::new(component.clone(), 0);
1784 assert!(item.previous_sibling().is_none());
1785 assert!(item.next_sibling().is_none());
1786
1787 let fc = item.first_child().unwrap();
1788 assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
1789 assert_eq!(fc.index(), 1);
1790
1791 let lc = item.last_child().unwrap();
1792 assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
1793 assert_eq!(lc.index(), 3);
1794
1795 let fcn = fc.next_sibling().unwrap();
1796 let lcp = lc.previous_sibling().unwrap();
1797
1798 assert_eq!(fcn, lcp);
1799 assert!(!VRc::ptr_eq(fcn.item_tree(), item.item_tree()));
1800
1801 let last = fcn.next_sibling().unwrap();
1802 assert_eq!(last, lc);
1803
1804 let first = lcp.previous_sibling().unwrap();
1805 assert_eq!(first, fc);
1806
1807 // Nested component:
1808 let nested_root = fcn.first_child().unwrap();
1809 assert_eq!(nested_root, fcn.last_child().unwrap());
1810 assert!(nested_root.next_sibling().is_none());
1811 assert!(nested_root.previous_sibling().is_none());
1812 assert!(!VRc::ptr_eq(nested_root.item_tree(), item.item_tree()));
1813 assert!(!VRc::ptr_eq(nested_root.item_tree(), fcn.item_tree()));
1814
1815 let nested_child = nested_root.first_child().unwrap();
1816 assert_eq!(nested_child, nested_root.last_child().unwrap());
1817 assert!(VRc::ptr_eq(nested_root.item_tree(), nested_child.item_tree()));
1818 }
1819
1820 #[test]
1821 fn test_tree_traversal_nested_subtrees_forward_focus() {
1822 let component = create_nested_subtrees();
1823
1824 // Examine root node:
1825 let item = ItemRc::new(component.clone(), 0);
1826 let fc = item.first_child().unwrap();
1827 let fcn = fc.next_sibling().unwrap();
1828 let lc = item.last_child().unwrap();
1829 let nested_root = fcn.first_child().unwrap();
1830 let nested_child = nested_root.first_child().unwrap();
1831
1832 // Focus traversal:
1833 let mut cursor = item.clone();
1834
1835 cursor = cursor.next_focus_item();
1836 assert_eq!(cursor, fc);
1837
1838 cursor = cursor.next_focus_item();
1839 assert_eq!(cursor, fcn);
1840
1841 cursor = cursor.next_focus_item();
1842 assert_eq!(cursor, nested_root);
1843
1844 cursor = cursor.next_focus_item();
1845 assert_eq!(cursor, nested_child);
1846
1847 cursor = cursor.next_focus_item();
1848 assert_eq!(cursor, lc);
1849
1850 cursor = cursor.next_focus_item();
1851 assert_eq!(cursor, item);
1852 }
1853
1854 #[test]
1855 fn test_tree_traversal_nested_subtrees_backward_focus() {
1856 let component = create_nested_subtrees();
1857
1858 // Examine root node:
1859 let item = ItemRc::new(component.clone(), 0);
1860 let fc = item.first_child().unwrap();
1861 let fcn = fc.next_sibling().unwrap();
1862 let lc = item.last_child().unwrap();
1863 let nested_root = fcn.first_child().unwrap();
1864 let nested_child = nested_root.first_child().unwrap();
1865
1866 // Focus traversal:
1867 let mut cursor = item.clone();
1868
1869 cursor = cursor.previous_focus_item();
1870 assert_eq!(cursor, lc);
1871
1872 cursor = cursor.previous_focus_item();
1873 assert_eq!(cursor, nested_child);
1874
1875 cursor = cursor.previous_focus_item();
1876 assert_eq!(cursor, nested_root);
1877
1878 cursor = cursor.previous_focus_item();
1879 assert_eq!(cursor, fcn);
1880
1881 cursor = cursor.previous_focus_item();
1882 assert_eq!(cursor, fc);
1883
1884 cursor = cursor.previous_focus_item();
1885 assert_eq!(cursor, item);
1886 }
1887
1888 fn create_subtrees_item() -> VRc<ItemTreeVTable, vtable::Dyn> {
1889 let component = VRc::new(TestItemTree {
1890 parent_component: None,
1891 item_tree: vec![
1892 ItemTreeNode::Item {
1893 is_accessible: false,
1894 children_count: 2,
1895 children_index: 1,
1896 parent_index: 0,
1897 item_array_index: 0,
1898 },
1899 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1900 ItemTreeNode::Item {
1901 is_accessible: false,
1902 children_count: 0,
1903 children_index: 4,
1904 parent_index: 0,
1905 item_array_index: 0,
1906 },
1907 ],
1908 subtrees: std::cell::RefCell::new(vec![]),
1909 subtree_index: usize::MAX,
1910 });
1911
1912 component.as_pin_ref().subtrees.replace(vec![vec![
1913 VRc::new(TestItemTree {
1914 parent_component: Some(VRc::into_dyn(component.clone())),
1915 item_tree: vec![ItemTreeNode::Item {
1916 is_accessible: false,
1917 children_count: 0,
1918 children_index: 1,
1919 parent_index: 1,
1920 item_array_index: 0,
1921 }],
1922 subtrees: std::cell::RefCell::new(vec![]),
1923 subtree_index: 0,
1924 }),
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: 1,
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: 2,
1948 }),
1949 ]]);
1950
1951 VRc::into_dyn(component)
1952 }
1953
1954 #[test]
1955 fn test_tree_traversal_subtrees_item_structure() {
1956 let component = create_subtrees_item();
1957
1958 // Examine root node:
1959 let item = ItemRc::new(component.clone(), 0);
1960 assert!(item.previous_sibling().is_none());
1961 assert!(item.next_sibling().is_none());
1962
1963 let sub1 = item.first_child().unwrap();
1964 assert_eq!(sub1.index(), 0);
1965 assert!(!VRc::ptr_eq(sub1.item_tree(), item.item_tree()));
1966
1967 // assert!(sub1.previous_sibling().is_none());
1968
1969 let sub2 = sub1.next_sibling().unwrap();
1970 assert_eq!(sub2.index(), 0);
1971 assert!(!VRc::ptr_eq(sub1.item_tree(), sub2.item_tree()));
1972 assert!(!VRc::ptr_eq(item.item_tree(), sub2.item_tree()));
1973
1974 assert!(sub2.previous_sibling() == Some(sub1.clone()));
1975
1976 let sub3 = sub2.next_sibling().unwrap();
1977 assert_eq!(sub3.index(), 0);
1978 assert!(!VRc::ptr_eq(sub1.item_tree(), sub2.item_tree()));
1979 assert!(!VRc::ptr_eq(sub2.item_tree(), sub3.item_tree()));
1980 assert!(!VRc::ptr_eq(item.item_tree(), sub3.item_tree()));
1981
1982 assert_eq!(sub3.previous_sibling().unwrap(), sub2.clone());
1983 }
1984
1985 #[test]
1986 fn test_component_item_tree_root_only() {
1987 let nodes = vec![ItemTreeNode::Item {
1988 is_accessible: false,
1989 children_count: 0,
1990 children_index: 1,
1991 parent_index: 0,
1992 item_array_index: 0,
1993 }];
1994
1995 let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
1996
1997 assert_eq!(tree.first_child(0), None);
1998 assert_eq!(tree.last_child(0), None);
1999 assert_eq!(tree.previous_sibling(0), None);
2000 assert_eq!(tree.next_sibling(0), None);
2001 assert_eq!(tree.parent(0), None);
2002 }
2003
2004 #[test]
2005 fn test_component_item_tree_one_child() {
2006 let nodes = vec![
2007 ItemTreeNode::Item {
2008 is_accessible: false,
2009 children_count: 1,
2010 children_index: 1,
2011 parent_index: 0,
2012 item_array_index: 0,
2013 },
2014 ItemTreeNode::Item {
2015 is_accessible: false,
2016 children_count: 0,
2017 children_index: 2,
2018 parent_index: 0,
2019 item_array_index: 0,
2020 },
2021 ];
2022
2023 let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
2024
2025 assert_eq!(tree.first_child(0), Some(1));
2026 assert_eq!(tree.last_child(0), Some(1));
2027 assert_eq!(tree.previous_sibling(0), None);
2028 assert_eq!(tree.next_sibling(0), None);
2029 assert_eq!(tree.parent(0), None);
2030 assert_eq!(tree.previous_sibling(1), None);
2031 assert_eq!(tree.next_sibling(1), None);
2032 assert_eq!(tree.parent(1), Some(0));
2033 }
2034
2035 #[test]
2036 fn test_component_item_tree_tree_children() {
2037 let nodes = vec![
2038 ItemTreeNode::Item {
2039 is_accessible: false,
2040 children_count: 3,
2041 children_index: 1,
2042 parent_index: 0,
2043 item_array_index: 0,
2044 },
2045 ItemTreeNode::Item {
2046 is_accessible: false,
2047 children_count: 0,
2048 children_index: 4,
2049 parent_index: 0,
2050 item_array_index: 0,
2051 },
2052 ItemTreeNode::Item {
2053 is_accessible: false,
2054 children_count: 0,
2055 children_index: 4,
2056 parent_index: 0,
2057 item_array_index: 0,
2058 },
2059 ItemTreeNode::Item {
2060 is_accessible: false,
2061 children_count: 0,
2062 children_index: 4,
2063 parent_index: 0,
2064 item_array_index: 0,
2065 },
2066 ];
2067
2068 let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
2069
2070 assert_eq!(tree.first_child(0), Some(1));
2071 assert_eq!(tree.last_child(0), Some(3));
2072 assert_eq!(tree.previous_sibling(0), None);
2073 assert_eq!(tree.next_sibling(0), None);
2074 assert_eq!(tree.parent(0), None);
2075
2076 assert_eq!(tree.previous_sibling(1), None);
2077 assert_eq!(tree.next_sibling(1), Some(2));
2078 assert_eq!(tree.parent(1), Some(0));
2079
2080 assert_eq!(tree.previous_sibling(2), Some(1));
2081 assert_eq!(tree.next_sibling(2), Some(3));
2082 assert_eq!(tree.parent(2), Some(0));
2083
2084 assert_eq!(tree.previous_sibling(3), Some(2));
2085 assert_eq!(tree.next_sibling(3), None);
2086 assert_eq!(tree.parent(3), Some(0));
2087 }
2088}
2089