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