1use crate::SharedString;
9use crate::accessibility::{
10 AccessibilityAction, AccessibleStringProperty, SupportedAccessibilityAction,
11};
12use crate::items::{AccessibleRole, ItemRef, ItemVTable};
13use crate::layout::{LayoutInfo, Orientation};
14use crate::lengths::{ItemTransform, LogicalPoint, LogicalRect};
15use crate::slice::Slice;
16use crate::window::WindowAdapterRc;
17use alloc::vec::Vec;
18use core::ops::ControlFlow;
19use core::pin::Pin;
20use vtable::*;
21
22#[repr(C)]
23#[derive(Debug, Clone, Copy)]
24pub struct IndexRange {
26 pub start: usize,
28 pub end: usize,
30}
31
32impl From<core::ops::Range<usize>> for IndexRange {
33 fn from(r: core::ops::Range<usize>) -> Self {
34 Self { start: r.start, end: r.end }
35 }
36}
37impl From<IndexRange> for core::ops::Range<usize> {
38 fn from(r: IndexRange) -> Self {
39 Self { start: r.start, end: r.end }
40 }
41}
42
43#[cfg_attr(not(feature = "ffi"), i_slint_core_macros::remove_extern)]
45#[vtable]
46#[repr(C)]
47pub struct ItemTreeVTable {
48 pub visit_children_item: extern "C" fn(
52 ::core::pin::Pin<VRef<ItemTreeVTable>>,
53 index: isize,
54 order: TraversalOrder,
55 visitor: VRefMut<ItemVisitorVTable>,
56 ) -> VisitChildrenResult,
57
58 pub get_item_ref: extern "C" fn(
60 ::core::pin::Pin<VRef<ItemTreeVTable>>,
61 index: u32,
62 ) -> ::core::pin::Pin<VRef<ItemVTable>>,
63
64 pub get_subtree_range:
66 extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, index: u32) -> IndexRange,
67
68 pub get_subtree: extern "C" fn(
70 ::core::pin::Pin<VRef<ItemTreeVTable>>,
71 index: u32,
72 subindex: usize,
73 result: &mut vtable::VWeak<ItemTreeVTable, Dyn>,
74 ),
75
76 pub get_item_tree: extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>) -> Slice<ItemTreeNode>,
78
79 pub parent_node: extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, result: &mut ItemWeak),
87
88 pub embed_component: extern "C" fn(
93 ::core::pin::Pin<VRef<ItemTreeVTable>>,
94 parent: &VWeak<ItemTreeVTable>,
95 parent_item_tree_index: u32,
96 ) -> bool,
97
98 pub subtree_index: extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>) -> usize,
100
101 pub layout_info:
103 extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, Orientation) -> LayoutInfo,
104
105 pub item_geometry:
107 extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, item_index: u32) -> LogicalRect,
108
109 pub accessible_role:
111 extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, item_index: u32) -> AccessibleRole,
112
113 pub accessible_string_property: extern "C" fn(
115 ::core::pin::Pin<VRef<ItemTreeVTable>>,
116 item_index: u32,
117 what: AccessibleStringProperty,
118 result: &mut SharedString,
119 ) -> bool,
120
121 pub accessibility_action: extern "C" fn(
123 ::core::pin::Pin<VRef<ItemTreeVTable>>,
124 item_index: u32,
125 action: &AccessibilityAction,
126 ),
127
128 pub supported_accessibility_actions: extern "C" fn(
130 ::core::pin::Pin<VRef<ItemTreeVTable>>,
131 item_index: u32,
132 ) -> SupportedAccessibilityAction,
133
134 pub item_element_infos: extern "C" fn(
136 ::core::pin::Pin<VRef<ItemTreeVTable>>,
137 item_index: u32,
138 result: &mut SharedString,
139 ) -> bool,
140
141 pub window_adapter: extern "C" fn(
143 ::core::pin::Pin<VRef<ItemTreeVTable>>,
144 do_create: bool,
145 result: &mut Option<WindowAdapterRc>,
146 ),
147
148 pub drop_in_place: unsafe extern "C" fn(VRefMut<ItemTreeVTable>) -> vtable::Layout,
150
151 pub dealloc: unsafe extern "C" fn(&ItemTreeVTable, ptr: *mut u8, layout: vtable::Layout),
153}
154
155#[cfg(test)]
156pub(crate) use ItemTreeVTable_static;
157
158pub type ItemTreeRef<'a> = vtable::VRef<'a, ItemTreeVTable>;
161
162pub type ItemTreeRefPin<'a> = core::pin::Pin<ItemTreeRef<'a>>;
164
165pub type ItemTreeRc = vtable::VRc<ItemTreeVTable, Dyn>;
167pub type ItemTreeWeak = vtable::VWeak<ItemTreeVTable, Dyn>;
169
170pub fn register_item_tree(item_tree_rc: &ItemTreeRc, window_adapter: Option<WindowAdapterRc>) {
172 let c = vtable::VRc::borrow_pin(item_tree_rc);
173 let item_tree = c.as_ref().get_item_tree();
174 item_tree.iter().enumerate().for_each(|(tree_index, node)| {
175 let tree_index = tree_index as u32;
176 if let ItemTreeNode::Item { .. } = &node {
177 let item = ItemRc::new(item_tree_rc.clone(), tree_index);
178 c.as_ref().get_item_ref(tree_index).as_ref().init(&item);
179 }
180 });
181 if let Some(adapter) = window_adapter.as_ref().and_then(|a| a.internal(crate::InternalToken)) {
182 adapter.register_item_tree(ItemTreeRc::borrow_pin(item_tree_rc));
183 }
184}
185
186pub fn unregister_item_tree<Base>(
192 base: core::pin::Pin<&Base>,
193 item_tree: ItemTreeRef,
194 item_array: &[vtable::VOffset<Base, ItemVTable, vtable::AllowPin>],
195 window_adapter: &WindowAdapterRc,
196) {
197 item_array.iter().for_each(|item| {
198 item.apply_pin(base).as_ref().deinit(window_adapter);
199 });
200 window_adapter.renderer().free_graphics_resources(item_tree, &mut item_array.iter().map(|item| item.apply_pin(base))).expect(
201 "Fatal error encountered when freeing graphics resources while destroying Slint component",
202 );
203
204 if let Some(w) = window_adapter.internal(crate::InternalToken) {
205 w.unregister_item_tree(item_tree, &mut item_array.iter().map(|item| item.apply_pin(base)));
206 }
207
208 let window_inner = crate::window::WindowInner::from_pub(window_adapter.window());
210 let to_close_popups = window_inner
211 .active_popups()
212 .iter()
213 .filter_map(|p| p.parent_item.upgrade().is_none().then_some(p.popup_id))
214 .collect::<Vec<_>>();
215 for popup_id in to_close_popups {
216 window_inner.close_popup(popup_id);
217 }
218}
219
220fn find_sibling_outside_repeater(
221 component: &ItemTreeRc,
222 comp_ref_pin: Pin<VRef<ItemTreeVTable>>,
223 index: u32,
224 sibling_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
225 subtree_child: &dyn Fn(usize, usize) -> usize,
226) -> Option<ItemRc> {
227 assert_ne!(index, 0);
228
229 let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
230
231 let mut current_sibling = index;
232 loop {
233 current_sibling = sibling_step(&item_tree, current_sibling)?;
234
235 if let Some(node) = step_into_node(
236 component,
237 &comp_ref_pin,
238 current_sibling,
239 &item_tree,
240 subtree_child,
241 &core::convert::identity,
242 ) {
243 return Some(node);
244 }
245 }
246}
247
248fn step_into_node(
249 component: &ItemTreeRc,
250 comp_ref_pin: &Pin<VRef<ItemTreeVTable>>,
251 node_index: u32,
252 item_tree: &crate::item_tree::ItemTreeNodeArray,
253 subtree_child: &dyn Fn(usize, usize) -> usize,
254 wrap_around: &dyn Fn(ItemRc) -> ItemRc,
255) -> Option<ItemRc> {
256 match item_tree.get(node_index).expect("Invalid index passed to item tree") {
257 crate::item_tree::ItemTreeNode::Item { .. } => {
258 Some(ItemRc::new(component.clone(), node_index))
259 }
260 crate::item_tree::ItemTreeNode::DynamicTree { index, .. } => {
261 let range = comp_ref_pin.as_ref().get_subtree_range(*index);
262 let component_index = subtree_child(range.start, range.end);
263 let mut child_instance = Default::default();
264 comp_ref_pin.as_ref().get_subtree(*index, component_index, &mut child_instance);
265 child_instance
266 .upgrade()
267 .map(|child_instance| wrap_around(ItemRc::new_root(child_instance)))
268 }
269 }
270}
271
272pub enum ParentItemTraversalMode {
273 FindAllParents,
274 StopAtPopups,
275}
276
277#[repr(C)]
279#[derive(Clone)]
280pub struct ItemRc {
281 item_tree: vtable::VRc<ItemTreeVTable>,
282 index: u32,
283}
284
285impl core::fmt::Debug for ItemRc {
286 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
287 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
288 let mut debug = SharedString::new();
289 comp_ref_pin.as_ref().item_element_infos(self.index, &mut debug);
290
291 write!(f, "ItemRc{{ {:p}, {:?} {debug}}}", comp_ref_pin.as_ptr(), self.index)
292 }
293}
294
295impl ItemRc {
296 pub fn new(item_tree: vtable::VRc<ItemTreeVTable>, index: u32) -> Self {
298 Self { item_tree, index }
299 }
300
301 pub fn new_root(item_tree: vtable::VRc<ItemTreeVTable>) -> Self {
302 Self { item_tree, index: Self::root_index() }
303 }
304
305 #[inline(always)]
306 pub const fn root_index() -> u32 {
307 0
308 }
309
310 #[inline(always)]
311 pub fn is_root(&self) -> bool {
312 self.index == Self::root_index()
313 }
314
315 pub fn is_root_item_of(&self, item_tree: &VRc<ItemTreeVTable>) -> bool {
317 self.is_root() && VRc::ptr_eq(&self.item_tree, item_tree)
318 }
319
320 pub fn borrow<'a>(&'a self) -> Pin<ItemRef<'a>> {
322 #![allow(unsafe_code)]
323 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
324 let result = comp_ref_pin.as_ref().get_item_ref(self.index);
325 unsafe { core::mem::transmute::<Pin<ItemRef<'_>>, Pin<ItemRef<'a>>>(result) }
328 }
329
330 pub fn downcast<T: HasStaticVTable<ItemVTable>>(&self) -> Option<VRcMapped<ItemTreeVTable, T>> {
332 #![allow(unsafe_code)]
333 let item = self.borrow();
334 ItemRef::downcast_pin::<T>(item)?;
335
336 Some(vtable::VRc::map_dyn(self.item_tree.clone(), |comp_ref_pin| {
337 let result = comp_ref_pin.as_ref().get_item_ref(self.index);
338 let item =
341 unsafe { core::mem::transmute::<Pin<ItemRef<'_>>, Pin<ItemRef<'_>>>(result) };
342 ItemRef::downcast_pin::<T>(item).unwrap()
343 }))
344 }
345
346 pub fn downgrade(&self) -> ItemWeak {
347 ItemWeak { item_tree: VRc::downgrade(&self.item_tree), index: self.index }
348 }
349
350 pub fn parent_item(&self, find_mode: ParentItemTraversalMode) -> Option<ItemRc> {
354 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
355 let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
356
357 if let Some(parent_index) = item_tree.parent(self.index) {
358 return Some(ItemRc::new(self.item_tree.clone(), parent_index));
359 }
360
361 let mut r = ItemWeak::default();
363 comp_ref_pin.as_ref().parent_node(&mut r);
364 let parent = r.upgrade()?;
365 let comp_ref_pin = vtable::VRc::borrow_pin(&parent.item_tree);
366 let item_tree_array = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
367 if let Some(ItemTreeNode::DynamicTree { parent_index, .. }) =
368 item_tree_array.get(parent.index())
369 {
370 Some(ItemRc::new(parent.item_tree.clone(), *parent_index))
372 } else {
373 match find_mode {
376 ParentItemTraversalMode::FindAllParents => Some(parent),
377 ParentItemTraversalMode::StopAtPopups => None,
378 }
379 }
380 }
381
382 pub fn is_visible(&self) -> bool {
385 let (clip, geometry) = self.absolute_clip_rect_and_geometry();
386 let clip = clip.to_box2d();
387 let geometry = geometry.to_box2d();
388 !clip.is_empty()
389 && clip.max.x >= geometry.min.x
390 && clip.max.y >= geometry.min.y
391 && clip.min.x <= geometry.max.x
392 && clip.min.y <= geometry.max.y
393 }
394
395 pub(crate) fn is_visible_or_clipped_by_flickable(&self) -> bool {
397 if self.is_visible() {
398 return true;
399 }
400
401 let (_, geometry) = self.absolute_clip_rect_and_geometry();
402 let geometry = geometry.to_box2d();
403
404 let mut clip = LogicalRect::from_size((crate::Coord::MAX, crate::Coord::MAX).into());
405 let mut ancestors = Vec::new();
406 let mut parent = self.parent_item(ParentItemTraversalMode::StopAtPopups);
407 while let Some(item_rc) = parent {
408 parent = item_rc.parent_item(ParentItemTraversalMode::StopAtPopups);
409 ancestors.push(item_rc);
410 }
411
412 for ancestor in ancestors.into_iter().rev() {
413 let clips_children = ancestor.borrow().as_ref().clips_children();
414 if !clips_children {
415 continue;
416 }
417
418 let ancestor_geometry = ancestor.absolute_clip_rect_and_geometry().1;
419 clip = ancestor_geometry.intersection(&clip).unwrap_or_default();
420 let clip = clip.to_box2d();
421
422 let is_visible = !clip.is_empty()
423 && clip.max.x >= geometry.min.x
424 && clip.max.y >= geometry.min.y
425 && clip.min.x <= geometry.max.x
426 && clip.min.y <= geometry.max.y;
427 if !is_visible {
428 return ancestor.downcast::<crate::items::Flickable>().is_some();
429 }
430 }
431
432 false
433 }
434
435 fn absolute_clip_rect_and_geometry(&self) -> (LogicalRect, LogicalRect) {
438 let (mut clip, parent_geometry) =
439 self.parent_item(ParentItemTraversalMode::StopAtPopups).map_or_else(
440 || {
441 (
442 LogicalRect::from_size((crate::Coord::MAX, crate::Coord::MAX).into()),
443 Default::default(),
444 )
445 },
446 |parent| parent.absolute_clip_rect_and_geometry(),
447 );
448
449 let geometry = self.geometry().translate(parent_geometry.origin.to_vector());
450
451 let item = self.borrow();
452 if item.as_ref().clips_children() {
453 clip = geometry.intersection(&clip).unwrap_or_default();
454 }
455
456 (clip, geometry)
457 }
458
459 pub fn is_accessible(&self) -> bool {
460 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
461 let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
462
463 if let Some(n) = &item_tree.get(self.index) {
464 match n {
465 ItemTreeNode::Item { is_accessible, .. } => *is_accessible,
466 ItemTreeNode::DynamicTree { .. } => false,
467 }
468 } else {
469 false
470 }
471 }
472
473 pub fn accessible_role(&self) -> crate::items::AccessibleRole {
474 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
475 comp_ref_pin.as_ref().accessible_role(self.index)
476 }
477
478 pub fn accessible_string_property(
479 &self,
480 what: crate::accessibility::AccessibleStringProperty,
481 ) -> Option<SharedString> {
482 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
483 let mut result = Default::default();
484 let ok = comp_ref_pin.as_ref().accessible_string_property(self.index, what, &mut result);
485 ok.then_some(result)
486 }
487
488 pub fn accessible_action(&self, action: &crate::accessibility::AccessibilityAction) {
489 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
490 comp_ref_pin.as_ref().accessibility_action(self.index, action);
491 }
492
493 pub fn supported_accessibility_actions(&self) -> SupportedAccessibilityAction {
494 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
495 comp_ref_pin.as_ref().supported_accessibility_actions(self.index)
496 }
497
498 fn raw_element_infos(&self) -> Option<SharedString> {
500 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
501 let mut result = SharedString::new();
502 comp_ref_pin.as_ref().item_element_infos(self.index, &mut result).then_some(result)
503 }
504
505 pub fn element_count(&self) -> Option<usize> {
506 self.raw_element_infos().map(|s| s.as_str().split("/").count())
507 }
508
509 pub fn element_type_names_and_ids(
510 &self,
511 element_index: usize,
512 ) -> Option<Vec<(SharedString, SharedString)>> {
513 self.raw_element_infos().map(|infos| {
514 infos
515 .as_str()
516 .split("/")
517 .nth(element_index)
518 .unwrap()
519 .split(";")
520 .map(|encoded_elem_info| {
521 let mut decoder = encoded_elem_info.split(',');
522 let type_name = decoder.next().unwrap().into();
523 let id = decoder.next().map(Into::into).unwrap_or_default();
524 (type_name, id)
525 })
526 .collect()
527 })
528 }
529
530 pub fn element_layout_kind(&self, element_index: usize) -> Option<SharedString> {
531 self.raw_element_infos().and_then(|infos| {
532 let first_debug_entry =
533 infos.as_str().split("/").nth(element_index)?.split(';').next()?;
534 let mut decoder = first_debug_entry.split(',');
535 let _type_name = decoder.next();
536 let _id = decoder.next();
537 decoder.next().filter(|s| !s.is_empty()).map(SharedString::from)
538 })
539 }
540
541 pub fn geometry(&self) -> LogicalRect {
542 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
543 comp_ref_pin.as_ref().item_geometry(self.index)
544 }
545
546 pub fn bounding_rect(
549 &self,
550 geometry: &LogicalRect,
551 window_adapter: &WindowAdapterRc,
552 ) -> LogicalRect {
553 self.borrow().as_ref().bounding_rect(window_adapter, self, *geometry)
554 }
555
556 pub fn map_to_native_window(&self, p: LogicalPoint) -> LogicalPoint {
560 let mut pos = self.map_to_item_tree_impl(p, |_| false);
561 if let Some(window_adapter) = self.window_adapter() {
563 let window_inner = crate::window::WindowInner::from_pub(window_adapter.window());
564 let active_popups = window_inner.active_popups();
565 for popup in active_popups.iter() {
566 if let crate::window::PopupWindowLocation::ChildWindow(location) = &popup.location {
567 let popup_item = ItemRc::new_root(popup.component.clone());
568
569 if popup_item.is_root_item_of(self.item_tree()) {
572 pos += location.to_vector();
573 } else {
574 let mut current = ItemRc::new_root(self.item_tree.clone());
575 while let Some(parent) =
577 current.parent_item(ParentItemTraversalMode::StopAtPopups)
578 {
579 if popup_item.is_root_item_of(parent.item_tree()) {
580 pos += location.to_vector();
581 break;
582 }
583
584 current = ItemRc::new_root(parent.item_tree);
586 }
587 }
588 }
589 }
590 }
591 pos
592 }
593
594 pub fn map_to_window(&self, p: LogicalPoint) -> LogicalPoint {
597 self.map_to_item_tree_impl(p, |_| false)
598 }
599
600 pub(crate) fn map_from_window(&self, p: LogicalPoint) -> LogicalPoint {
602 self.map_from_item_tree_impl(p, |_| false)
603 }
604
605 pub fn map_to_item_tree(
608 &self,
609 p: LogicalPoint,
610 item_tree: &vtable::VRc<ItemTreeVTable>,
611 ) -> LogicalPoint {
612 self.map_to_item_tree_impl(p, |current| current.is_root_item_of(item_tree))
613 }
614
615 fn map_to_ancestor(&self, p: LogicalPoint, ancestor: &Self) -> LogicalPoint {
619 self.map_to_item_tree_impl(p, |parent| parent == ancestor)
620 }
621
622 fn map_to_item_tree_impl(
623 &self,
624 p: LogicalPoint,
625 stop_condition: impl Fn(&Self) -> bool,
626 ) -> LogicalPoint {
627 let mut current = self.clone();
628 let mut result = p;
629 if stop_condition(¤t) {
630 return result;
631 }
632 let supports_transformations = self
633 .window_adapter()
634 .is_none_or(|adapter| adapter.renderer().supports_transformations());
635 while let Some(parent) = current.parent_item(ParentItemTraversalMode::StopAtPopups) {
636 if stop_condition(&parent) {
637 break;
638 }
639 let geometry = parent.geometry();
640 if supports_transformations && let Some(transform) = parent.children_transform() {
641 result = transform.transform_point(result.cast()).cast();
642 }
643 result += geometry.origin.to_vector();
644 current = parent;
645 }
646 result
647 }
648
649 fn map_from_item_tree_impl(
650 &self,
651 p: LogicalPoint,
652 stop_condition: impl Fn(&Self) -> bool,
653 ) -> LogicalPoint {
654 let mut current = self.clone();
655 let mut result = p;
656 if stop_condition(¤t) {
657 return result;
658 }
659 let supports_transformations = self
660 .window_adapter()
661 .is_none_or(|adapter| adapter.renderer().supports_transformations());
662
663 let mut full_transform = supports_transformations.then(ItemTransform::identity);
664 let mut offset = euclid::Vector2D::zero();
665 while let Some(parent) = current.parent_item(ParentItemTraversalMode::StopAtPopups) {
666 if stop_condition(&parent) {
667 break;
668 }
669 let geometry = parent.geometry();
670 if let (Some(transform), Some(children_transform)) =
671 (full_transform, parent.children_transform())
672 {
673 full_transform = Some(
674 transform
675 .then_translate(geometry.origin.to_vector().cast())
676 .then(&children_transform),
677 );
678 }
679 offset += geometry.origin.to_vector();
680 current = parent;
681 }
682 full_transform = full_transform.and_then(|ft| ft.inverse());
683 if let Some(transform) = full_transform {
684 result = transform.transform_point(result.cast()).cast();
685 } else {
686 result -= offset;
687 }
688 result
689 }
690
691 pub fn index(&self) -> u32 {
693 self.index
694 }
695 pub fn item_tree(&self) -> &vtable::VRc<ItemTreeVTable> {
697 &self.item_tree
698 }
699
700 fn find_child(
702 &self,
703 child_access: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
704 child_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
705 subtree_child: &dyn Fn(usize, usize) -> usize,
706 ) -> Option<Self> {
707 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
708 let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
709
710 let mut current_child_index = child_access(&item_tree, self.index())?;
711 loop {
712 if let Some(item) = step_into_node(
713 self.item_tree(),
714 &comp_ref_pin,
715 current_child_index,
716 &item_tree,
717 subtree_child,
718 &core::convert::identity,
719 ) {
720 return Some(item);
721 }
722 current_child_index = child_step(&item_tree, current_child_index)?;
723 }
724 }
725
726 pub fn first_child(&self) -> Option<Self> {
728 self.find_child(
729 &|item_tree, index| item_tree.first_child(index),
730 &|item_tree, index| item_tree.next_sibling(index),
731 &|start, _| start,
732 )
733 }
734
735 pub fn last_child(&self) -> Option<Self> {
737 self.find_child(
738 &|item_tree, index| item_tree.last_child(index),
739 &|item_tree, index| item_tree.previous_sibling(index),
740 &|_, end| end.wrapping_sub(1),
741 )
742 }
743
744 fn find_sibling(
745 &self,
746 sibling_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
747 subtree_step: &dyn Fn(usize) -> usize,
748 subtree_child: &dyn Fn(usize, usize) -> usize,
749 ) -> Option<Self> {
750 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
751 if self.is_root() {
752 let mut parent_item = Default::default();
753 comp_ref_pin.as_ref().parent_node(&mut parent_item);
754 let current_component_subtree_index = comp_ref_pin.as_ref().subtree_index();
755 if let Some(parent_item) = parent_item.upgrade() {
756 let parent = parent_item.item_tree();
757 let parent_ref_pin = vtable::VRc::borrow_pin(parent);
758 let parent_item_index = parent_item.index();
759 let parent_item_tree = crate::item_tree::ItemTreeNodeArray::new(&parent_ref_pin);
760
761 let subtree_index = match parent_item_tree.get(parent_item_index)? {
762 crate::item_tree::ItemTreeNode::Item { .. } => {
763 return None;
765 }
766 crate::item_tree::ItemTreeNode::DynamicTree { index, .. } => *index,
767 };
768
769 let next_subtree_index = subtree_step(current_component_subtree_index);
770
771 let mut next_subtree_instance = Default::default();
773 parent_ref_pin.as_ref().get_subtree(
774 subtree_index,
775 next_subtree_index,
776 &mut next_subtree_instance,
777 );
778 if let Some(next_subtree_instance) = next_subtree_instance.upgrade() {
779 return Some(ItemRc::new_root(next_subtree_instance));
780 }
781
782 find_sibling_outside_repeater(
784 parent,
785 parent_ref_pin,
786 parent_item_index,
787 sibling_step,
788 subtree_child,
789 )
790 } else {
791 None }
793 } else {
794 find_sibling_outside_repeater(
795 self.item_tree(),
796 comp_ref_pin,
797 self.index(),
798 sibling_step,
799 subtree_child,
800 )
801 }
802 }
803
804 pub fn previous_sibling(&self) -> Option<Self> {
806 self.find_sibling(
807 &|item_tree, index| item_tree.previous_sibling(index),
808 &|index| index.wrapping_sub(1),
809 &|_, end| end.wrapping_sub(1),
810 )
811 }
812
813 pub fn next_sibling(&self) -> Option<Self> {
815 self.find_sibling(
816 &|item_tree, index| item_tree.next_sibling(index),
817 &|index| index.saturating_add(1),
818 &|start, _| start,
819 )
820 }
821
822 fn move_focus(
823 &self,
824 focus_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
825 subtree_step: &dyn Fn(ItemRc) -> Option<ItemRc>,
826 subtree_child: &dyn Fn(usize, usize) -> usize,
827 step_in: &dyn Fn(ItemRc) -> ItemRc,
828 step_out: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
829 ) -> Self {
830 let mut component = self.item_tree().clone();
831 let mut comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
832 let mut item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
833
834 let mut to_focus = self.index();
835
836 'in_tree: loop {
837 if let Some(next) = focus_step(&item_tree, to_focus) {
838 if let Some(item) = step_into_node(
839 &component,
840 &comp_ref_pin,
841 next,
842 &item_tree,
843 subtree_child,
844 step_in,
845 ) {
846 return item;
847 }
848 to_focus = next;
849 } else {
851 let mut root = ItemRc::new_root(component);
853 if let Some(item) = subtree_step(root.clone()) {
854 return step_in(item);
856 }
857
858 let root_component = root.item_tree();
860 let root_comp_ref = vtable::VRc::borrow_pin(root_component);
861 let mut parent_node = Default::default();
862 root_comp_ref.as_ref().parent_node(&mut parent_node);
863
864 while let Some(parent) = parent_node.upgrade() {
865 component = parent.item_tree().clone();
867 comp_ref_pin = vtable::VRc::borrow_pin(&component);
868 item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
869
870 let index = parent.index();
871
872 if !matches!(item_tree.get(index), Some(ItemTreeNode::DynamicTree { .. })) {
873 break;
875 }
876
877 if let Some(next) = step_out(&item_tree, index) {
878 if let Some(item) = step_into_node(
879 parent.item_tree(),
880 &comp_ref_pin,
881 next,
882 &item_tree,
883 subtree_child,
884 step_in,
885 ) {
886 return item;
888 } else {
889 to_focus = parent.index();
891 continue 'in_tree; }
893 }
894
895 root = ItemRc::new_root(component.clone());
896 if let Some(item) = subtree_step(root.clone()) {
897 return step_in(item);
898 }
899
900 let root_component = root.item_tree();
902 let root_comp_ref = vtable::VRc::borrow_pin(root_component);
903 parent_node = Default::default();
904 root_comp_ref.as_ref().parent_node(&mut parent_node);
905 }
906
907 return step_in(root);
909 }
910 }
911 }
912
913 pub fn previous_focus_item(&self) -> Self {
915 self.move_focus(
916 &|item_tree, index| {
917 crate::item_focus::default_previous_in_local_focus_chain(index, item_tree)
918 },
919 &|root| root.previous_sibling(),
920 &|_, end| end.wrapping_sub(1),
921 &|root| {
922 let mut current = root;
923 loop {
924 if let Some(next) = current.last_child() {
925 current = next;
926 } else {
927 return current;
928 }
929 }
930 },
931 &|item_tree, index| item_tree.parent(index),
932 )
933 }
934
935 pub fn next_focus_item(&self) -> Self {
937 self.move_focus(
938 &|item_tree, index| {
939 crate::item_focus::default_next_in_local_focus_chain(index, item_tree)
940 },
941 &|root| root.next_sibling(),
942 &|start, _| start,
943 &core::convert::identity,
944 &|item_tree, index| crate::item_focus::step_out_of_node(index, item_tree),
945 )
946 }
947
948 pub fn window_adapter(&self) -> Option<WindowAdapterRc> {
949 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
950 let mut result = None;
951 comp_ref_pin.as_ref().window_adapter(false, &mut result);
952 result
953 }
954
955 fn visit_descendants_impl<R>(
958 &self,
959 visitor: &mut impl FnMut(&ItemRc) -> ControlFlow<R>,
960 ) -> Option<R> {
961 let mut result = None;
962
963 let mut actual_visitor = |item_tree: &ItemTreeRc,
964 index: u32,
965 _item_pin: core::pin::Pin<ItemRef>|
966 -> VisitChildrenResult {
967 let item_rc = ItemRc::new(item_tree.clone(), index);
968
969 match visitor(&item_rc) {
970 ControlFlow::Continue(_) => {
971 if let Some(x) = item_rc.visit_descendants_impl(visitor) {
972 result = Some(x);
973 return VisitChildrenResult::abort(index, 0);
974 }
975 }
976 ControlFlow::Break(x) => {
977 result = Some(x);
978 return VisitChildrenResult::abort(index, 0);
979 }
980 }
981
982 VisitChildrenResult::CONTINUE
983 };
984 vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);
985
986 VRc::borrow_pin(self.item_tree()).as_ref().visit_children_item(
987 self.index() as isize,
988 TraversalOrder::BackToFront,
989 actual_visitor,
990 );
991
992 result
993 }
994
995 pub fn visit_descendants<R>(
998 &self,
999 mut visitor: impl FnMut(&ItemRc) -> ControlFlow<R>,
1000 ) -> Option<R> {
1001 self.visit_descendants_impl(&mut visitor)
1002 }
1003
1004 pub fn children_transform(&self) -> Option<ItemTransform> {
1007 self.downcast::<crate::items::Transform>().map(|transform_item| {
1008 let item = transform_item.as_pin_ref();
1009 let origin = item.transform_origin().to_euclid().to_vector().cast::<f32>();
1010 ItemTransform::translation(-origin.x, -origin.y)
1011 .cast()
1012 .then_scale(item.transform_scale_x(), item.transform_scale_y())
1013 .then_rotate(euclid::Angle { radians: item.transform_rotation().to_radians() })
1014 .then_translate(origin)
1015 })
1016 }
1017
1018 pub fn inverse_children_transform(&self) -> Option<ItemTransform> {
1023 self.children_transform()
1024 .and_then(|child_transform| child_transform.inverse())
1026 }
1027
1028 pub(crate) fn try_scroll_into_visible(&self) {
1029 let mut parent = self.parent_item(ParentItemTraversalMode::StopAtPopups);
1030 while let Some(item_rc) = parent.as_ref() {
1031 let item_ref = item_rc.borrow();
1032 if let Some(flickable) = vtable::VRef::downcast_pin::<crate::items::Flickable>(item_ref)
1033 {
1034 let geo = self.geometry();
1035
1036 flickable.reveal_points(
1037 item_rc,
1038 &[
1039 self.map_to_ancestor(
1040 LogicalPoint::new(
1041 geo.origin.x - flickable.viewport_x().0,
1042 geo.origin.y - flickable.viewport_y().0,
1043 ),
1044 item_rc,
1045 ),
1046 self.map_to_ancestor(
1047 LogicalPoint::new(
1048 geo.max_x() - flickable.viewport_x().0,
1049 geo.max_y() - flickable.viewport_y().0,
1050 ),
1051 item_rc,
1052 ),
1053 ],
1054 );
1055 break;
1056 }
1057
1058 parent = item_rc.parent_item(ParentItemTraversalMode::StopAtPopups);
1059 }
1060 }
1061}
1062
1063impl PartialEq for ItemRc {
1064 fn eq(&self, other: &Self) -> bool {
1065 VRc::ptr_eq(&self.item_tree, &other.item_tree) && self.index == other.index
1066 }
1067}
1068
1069impl Eq for ItemRc {}
1070
1071#[derive(Clone, Default)]
1073#[repr(C)]
1074pub struct ItemWeak {
1075 item_tree: crate::item_tree::ItemTreeWeak,
1076 index: u32,
1077}
1078
1079impl ItemWeak {
1080 pub fn upgrade(&self) -> Option<ItemRc> {
1081 self.item_tree.upgrade().map(|c| ItemRc::new(c, self.index))
1082 }
1083}
1084
1085impl PartialEq for ItemWeak {
1086 fn eq(&self, other: &Self) -> bool {
1087 VWeak::ptr_eq(&self.item_tree, &other.item_tree) && self.index == other.index
1088 }
1089}
1090
1091impl Eq for ItemWeak {}
1092
1093#[repr(u8)]
1094#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1095pub enum TraversalOrder {
1096 BackToFront,
1097 FrontToBack,
1098}
1099
1100#[repr(transparent)]
1109#[derive(Copy, Clone, Eq, PartialEq)]
1110pub struct VisitChildrenResult(u64);
1111impl VisitChildrenResult {
1112 pub const CONTINUE: Self = Self(u64::MAX);
1114
1115 pub fn abort(item_index: u32, index_within_repeater: usize) -> Self {
1117 assert!(index_within_repeater < u32::MAX as usize);
1118 Self(item_index as u64 | (index_within_repeater as u64) << 32)
1119 }
1120 pub fn has_aborted(&self) -> bool {
1122 self.0 != Self::CONTINUE.0
1123 }
1124 pub fn aborted_index(&self) -> Option<usize> {
1125 if self.0 != Self::CONTINUE.0 { Some((self.0 & 0xffff_ffff) as usize) } else { None }
1126 }
1127 pub fn aborted_indexes(&self) -> Option<(usize, usize)> {
1128 if self.0 != Self::CONTINUE.0 {
1129 Some(((self.0 & 0xffff_ffff) as usize, (self.0 >> 32) as usize))
1130 } else {
1131 None
1132 }
1133 }
1134}
1135impl core::fmt::Debug for VisitChildrenResult {
1136 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1137 if self.0 == Self::CONTINUE.0 {
1138 write!(f, "CONTINUE")
1139 } else {
1140 write!(f, "({},{})", (self.0 & 0xffff_ffff) as usize, (self.0 >> 32) as usize)
1141 }
1142 }
1143}
1144
1145#[repr(u8)]
1148#[derive(Debug)]
1149pub enum ItemTreeNode {
1150 Item {
1152 is_accessible: bool,
1154
1155 children_count: u32,
1157
1158 children_index: u32,
1160
1161 parent_index: u32,
1163
1164 item_array_index: u32,
1166 },
1167 DynamicTree {
1170 index: u32,
1172
1173 parent_index: u32,
1175 },
1176}
1177
1178impl ItemTreeNode {
1179 pub fn parent_index(&self) -> u32 {
1180 match self {
1181 ItemTreeNode::Item { parent_index, .. } => *parent_index,
1182 ItemTreeNode::DynamicTree { parent_index, .. } => *parent_index,
1183 }
1184 }
1185}
1186
1187pub struct ItemTreeNodeArray<'a> {
1190 node_array: &'a [ItemTreeNode],
1191}
1192
1193impl<'a> ItemTreeNodeArray<'a> {
1194 pub fn new(comp_ref_pin: &'a Pin<VRef<'a, ItemTreeVTable>>) -> Self {
1196 Self { node_array: comp_ref_pin.as_ref().get_item_tree().as_slice() }
1197 }
1198
1199 pub fn get(&self, index: u32) -> Option<&ItemTreeNode> {
1201 self.node_array.get(index as usize)
1202 }
1203
1204 pub fn parent(&self, index: u32) -> Option<u32> {
1206 let index = index as usize;
1207 (index < self.node_array.len() && index != ItemRc::root_index() as usize)
1208 .then(|| self.node_array[index].parent_index())
1209 }
1210
1211 pub fn next_sibling(&self, index: u32) -> Option<u32> {
1213 if let Some(parent_index) = self.parent(index) {
1214 match self.node_array[parent_index as usize] {
1215 ItemTreeNode::Item { children_index, children_count, .. } => {
1216 (index < (children_count + children_index - 1)).then_some(index + 1)
1217 }
1218 ItemTreeNode::DynamicTree { .. } => {
1219 unreachable!("Parent in same item tree is a repeater.")
1220 }
1221 }
1222 } else {
1223 None }
1225 }
1226
1227 pub fn previous_sibling(&self, index: u32) -> Option<u32> {
1229 if let Some(parent_index) = self.parent(index) {
1230 match self.node_array[parent_index as usize] {
1231 ItemTreeNode::Item { children_index, .. } => {
1232 (index > children_index).then_some(index - 1)
1233 }
1234 ItemTreeNode::DynamicTree { .. } => {
1235 unreachable!("Parent in same item tree is a repeater.")
1236 }
1237 }
1238 } else {
1239 None }
1241 }
1242
1243 pub fn first_child(&self, index: u32) -> Option<u32> {
1246 match self.node_array.get(index as usize)? {
1247 ItemTreeNode::Item { children_index, children_count, .. } => {
1248 (*children_count != 0).then_some(*children_index as _)
1249 }
1250 ItemTreeNode::DynamicTree { .. } => None,
1251 }
1252 }
1253
1254 pub fn last_child(&self, index: u32) -> Option<u32> {
1257 match self.node_array.get(index as usize)? {
1258 ItemTreeNode::Item { children_index, children_count, .. } => {
1259 if *children_count != 0 {
1260 Some(*children_index + *children_count - 1)
1261 } else {
1262 None
1263 }
1264 }
1265 ItemTreeNode::DynamicTree { .. } => None,
1266 }
1267 }
1268
1269 pub fn node_count(&self) -> usize {
1271 self.node_array.len()
1272 }
1273}
1274
1275impl<'a> From<&'a [ItemTreeNode]> for ItemTreeNodeArray<'a> {
1276 fn from(item_tree: &'a [ItemTreeNode]) -> Self {
1277 Self { node_array: item_tree }
1278 }
1279}
1280
1281#[cfg_attr(not(feature = "ffi"), i_slint_core_macros::remove_extern)]
1282#[vtable]
1283#[repr(C)]
1284pub struct ItemVisitorVTable {
1286 visit_item: extern "C" fn(
1293 VRefMut<ItemVisitorVTable>,
1294 item_tree: &VRc<ItemTreeVTable, vtable::Dyn>,
1295 index: u32,
1296 item: Pin<VRef<ItemVTable>>,
1297 ) -> VisitChildrenResult,
1298 drop: extern "C" fn(VRefMut<ItemVisitorVTable>),
1300}
1301
1302pub type ItemVisitorRefMut<'a> = vtable::VRefMut<'a, ItemVisitorVTable>;
1304
1305impl<T: FnMut(&ItemTreeRc, u32, Pin<ItemRef>) -> VisitChildrenResult> ItemVisitor for T {
1306 fn visit_item(
1307 &mut self,
1308 item_tree: &ItemTreeRc,
1309 index: u32,
1310 item: Pin<ItemRef>,
1311 ) -> VisitChildrenResult {
1312 self(item_tree, index, item)
1313 }
1314}
1315pub enum ItemVisitorResult<State> {
1316 Continue(State),
1317 SkipChildren,
1318 Abort,
1319}
1320
1321pub fn visit_items<State>(
1327 item_tree: &ItemTreeRc,
1328 order: TraversalOrder,
1329 mut visitor: impl FnMut(&ItemTreeRc, Pin<ItemRef>, u32, &State) -> ItemVisitorResult<State>,
1330 state: State,
1331) -> VisitChildrenResult {
1332 visit_internal(item_tree, order, &mut visitor, -1, &state)
1333}
1334
1335fn visit_internal<State>(
1336 item_tree: &ItemTreeRc,
1337 order: TraversalOrder,
1338 visitor: &mut impl FnMut(&ItemTreeRc, Pin<ItemRef>, u32, &State) -> ItemVisitorResult<State>,
1339 index: isize,
1340 state: &State,
1341) -> VisitChildrenResult {
1342 let mut actual_visitor =
1343 |item_tree: &ItemTreeRc, index: u32, item: Pin<ItemRef>| -> VisitChildrenResult {
1344 match visitor(item_tree, item, index, state) {
1345 ItemVisitorResult::Continue(state) => {
1346 visit_internal(item_tree, order, visitor, index as isize, &state)
1347 }
1348 ItemVisitorResult::SkipChildren => VisitChildrenResult::CONTINUE,
1349 ItemVisitorResult::Abort => VisitChildrenResult::abort(index, 0),
1350 }
1351 };
1352 vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);
1353 VRc::borrow_pin(item_tree).as_ref().visit_children_item(index, order, actual_visitor)
1354}
1355
1356pub fn visit_item_tree<Base>(
1365 base: Pin<&Base>,
1366 item_tree: &ItemTreeRc,
1367 item_tree_array: &[ItemTreeNode],
1368 index: isize,
1369 order: TraversalOrder,
1370 mut visitor: vtable::VRefMut<ItemVisitorVTable>,
1371 visit_dynamic: impl Fn(
1372 Pin<&Base>,
1373 TraversalOrder,
1374 vtable::VRefMut<ItemVisitorVTable>,
1375 u32,
1376 ) -> VisitChildrenResult,
1377) -> VisitChildrenResult {
1378 let mut visit_at_index = |idx: u32| -> VisitChildrenResult {
1379 match &item_tree_array[idx as usize] {
1380 ItemTreeNode::Item { .. } => {
1381 let item = crate::items::ItemRc::new(item_tree.clone(), idx);
1382 visitor.visit_item(item_tree, idx, item.borrow())
1383 }
1384 ItemTreeNode::DynamicTree { index, .. } => {
1385 if let Some(sub_idx) =
1386 visit_dynamic(base, order, visitor.borrow_mut(), *index).aborted_index()
1387 {
1388 VisitChildrenResult::abort(idx, sub_idx)
1389 } else {
1390 VisitChildrenResult::CONTINUE
1391 }
1392 }
1393 }
1394 };
1395 if index == -1 {
1396 visit_at_index(0)
1397 } else {
1398 match &item_tree_array[index as usize] {
1399 ItemTreeNode::Item { children_index, children_count, .. } => {
1400 for c in 0..*children_count {
1401 let idx = match order {
1402 TraversalOrder::BackToFront => *children_index + c,
1403 TraversalOrder::FrontToBack => *children_index + *children_count - c - 1,
1404 };
1405 let maybe_abort_index = visit_at_index(idx);
1406 if maybe_abort_index.has_aborted() {
1407 return maybe_abort_index;
1408 }
1409 }
1410 }
1411 ItemTreeNode::DynamicTree { .. } => panic!("should not be called with dynamic items"),
1412 };
1413 VisitChildrenResult::CONTINUE
1414 }
1415}
1416
1417#[cfg(feature = "ffi")]
1418pub(crate) mod ffi {
1419 #![allow(unsafe_code)]
1420
1421 use super::*;
1422 use core::ffi::c_void;
1423
1424 #[unsafe(no_mangle)]
1426 pub unsafe extern "C" fn slint_register_item_tree(
1427 item_tree_rc: &ItemTreeRc,
1428 window_handle: *const crate::window::ffi::WindowAdapterRcOpaque,
1429 ) {
1430 unsafe {
1431 let window_adapter = (window_handle as *const WindowAdapterRc).as_ref().cloned();
1432 super::register_item_tree(item_tree_rc, window_adapter)
1433 }
1434 }
1435
1436 #[unsafe(no_mangle)]
1438 pub unsafe extern "C" fn slint_unregister_item_tree(
1439 component: ItemTreeRefPin,
1440 item_array: Slice<vtable::VOffset<u8, ItemVTable, vtable::AllowPin>>,
1441 window_handle: *const crate::window::ffi::WindowAdapterRcOpaque,
1442 ) {
1443 unsafe {
1444 let window_adapter = &*(window_handle as *const WindowAdapterRc);
1445 super::unregister_item_tree(
1446 core::pin::Pin::new_unchecked(&*(component.as_ptr() as *const u8)),
1447 core::pin::Pin::into_inner(component),
1448 item_array.as_slice(),
1449 window_adapter,
1450 )
1451 }
1452 }
1453
1454 #[unsafe(no_mangle)]
1458 pub unsafe extern "C" fn slint_visit_item_tree(
1459 item_tree: &ItemTreeRc,
1460 item_tree_array: Slice<ItemTreeNode>,
1461 index: isize,
1462 order: TraversalOrder,
1463 visitor: VRefMut<ItemVisitorVTable>,
1464 visit_dynamic: extern "C" fn(
1465 base: *const c_void,
1466 order: TraversalOrder,
1467 visitor: vtable::VRefMut<ItemVisitorVTable>,
1468 dyn_index: u32,
1469 ) -> VisitChildrenResult,
1470 ) -> VisitChildrenResult {
1471 crate::item_tree::visit_item_tree(
1472 VRc::as_pin_ref(item_tree),
1473 item_tree,
1474 item_tree_array.as_slice(),
1475 index,
1476 order,
1477 visitor,
1478 |a, b, c, d| visit_dynamic(a.get_ref() as *const vtable::Dyn as *const c_void, b, c, d),
1479 )
1480 }
1481}
1482
1483#[cfg(test)]
1484mod tests {
1485 use super::*;
1486 use crate::Property;
1487 use crate::api::LogicalPosition;
1488 use crate::api::Window;
1489 use crate::items::WindowItem;
1490 use crate::lengths::LogicalLength;
1491 use crate::lengths::LogicalSize;
1492 use euclid::Point2D;
1493 use std::{rc::Rc, vec};
1494
1495 const GEOMETRY_POSITION_X: f32 = 6.;
1496 const GEOMETRY_POSITION_Y: f32 = 27.;
1497 const GEOMETRY_WIDTH: f32 = 33.;
1498 const GEOMETRY_HEIGHT: f32 = 42.;
1499
1500 #[derive(Default)]
1501 struct Renderer {}
1502
1503 struct WindowAdapter {
1504 renderer: Renderer,
1505 window: Window,
1506 }
1507
1508 impl WindowAdapter {
1509 fn new() -> Rc<Self> {
1510 Rc::<Self>::new_cyclic(|w| Self {
1511 window: Window::new(w.clone()),
1512 renderer: Default::default(),
1513 })
1514 }
1515 }
1516
1517 impl crate::window::WindowAdapter for WindowAdapter {
1518 fn window(&self) -> &crate::api::Window {
1519 &self.window
1520 }
1521
1522 fn size(&self) -> crate::api::PhysicalSize {
1523 crate::api::PhysicalSize::new(100, 100)
1524 }
1525
1526 fn renderer(&self) -> &dyn crate::platform::Renderer {
1527 &self.renderer
1528 }
1529 }
1530
1531 struct TestItemTree {
1532 parent_component: Option<ItemTreeRc>,
1533 item_tree: Vec<ItemTreeNode>,
1535 subtrees: std::cell::RefCell<Vec<Vec<vtable::VRc<ItemTreeVTable, TestItemTree>>>>,
1537 subtree_index: usize,
1538
1539 window_adapter: WindowAdapterRc,
1540 window_item: Option<crate::items::WindowItem>,
1541 }
1542
1543 impl ItemTree for TestItemTree {
1544 fn visit_children_item(
1545 self: core::pin::Pin<&Self>,
1546 _1: isize,
1547 _2: crate::item_tree::TraversalOrder,
1548 _3: vtable::VRefMut<crate::item_tree::ItemVisitorVTable>,
1549 ) -> crate::item_tree::VisitChildrenResult {
1550 unimplemented!("Not needed for this test")
1551 }
1552
1553 fn get_item_ref(
1554 self: core::pin::Pin<&Self>,
1555 index: u32,
1556 ) -> core::pin::Pin<vtable::VRef<'_, super::ItemVTable>> {
1557 if index == 0 {
1558 return Pin::new(VRef::new(
1559 self.get_ref().window_item.as_ref().expect("Not needed for this test"),
1560 ));
1561 }
1562 unimplemented!("Not needed for this test")
1563 }
1564
1565 fn get_item_tree(self: core::pin::Pin<&Self>) -> Slice<'_, ItemTreeNode> {
1566 Slice::from_slice(&self.get_ref().item_tree)
1567 }
1568
1569 fn parent_node(self: core::pin::Pin<&Self>, result: &mut ItemWeak) {
1570 if let Some(parent_item) = self.parent_component.clone() {
1571 *result =
1572 ItemRc::new(parent_item.clone(), self.item_tree[0].parent_index()).downgrade();
1573 }
1574 }
1575
1576 fn embed_component(
1577 self: core::pin::Pin<&Self>,
1578 _parent_component: &ItemTreeWeak,
1579 _item_tree_index: u32,
1580 ) -> bool {
1581 false
1582 }
1583
1584 fn layout_info(self: core::pin::Pin<&Self>, o: Orientation) -> LayoutInfo {
1585 if let Some(wi) = &self.window_item {
1586 match o {
1587 Orientation::Horizontal => {
1588 return LayoutInfo {
1589 max: wi.width.get_internal().0,
1590 max_percent: 100.,
1591 min: wi.width.get_internal().0,
1592 min_percent: 100.,
1593 preferred: wi.width.get_internal().0,
1594 stretch: 1.,
1595 };
1596 }
1597 Orientation::Vertical => {
1598 return LayoutInfo {
1599 max: wi.height.get_internal().0,
1600 max_percent: 100.,
1601 min: wi.height.get_internal().0,
1602 min_percent: 100.,
1603 preferred: wi.height.get_internal().0,
1604 stretch: 1.,
1605 };
1606 }
1607 }
1608 }
1609 unimplemented!("Not needed for this test")
1610 }
1611
1612 fn subtree_index(self: core::pin::Pin<&Self>) -> usize {
1613 self.subtree_index
1614 }
1615
1616 fn get_subtree_range(self: core::pin::Pin<&Self>, subtree_index: u32) -> IndexRange {
1617 (0..self.subtrees.borrow()[subtree_index as usize].len()).into()
1618 }
1619
1620 fn get_subtree(
1621 self: core::pin::Pin<&Self>,
1622 subtree_index: u32,
1623 component_index: usize,
1624 result: &mut ItemTreeWeak,
1625 ) {
1626 if let Some(vrc) = self.subtrees.borrow()[subtree_index as usize].get(component_index) {
1627 *result = vtable::VRc::downgrade(&vtable::VRc::into_dyn(vrc.clone()))
1628 }
1629 }
1630
1631 fn accessible_role(self: Pin<&Self>, _: u32) -> AccessibleRole {
1632 unimplemented!("Not needed for this test")
1633 }
1634
1635 fn accessible_string_property(
1636 self: Pin<&Self>,
1637 _: u32,
1638 _: AccessibleStringProperty,
1639 _: &mut SharedString,
1640 ) -> bool {
1641 false
1642 }
1643
1644 fn item_element_infos(self: Pin<&Self>, _: u32, _: &mut SharedString) -> bool {
1645 false
1646 }
1647
1648 fn window_adapter(
1649 self: Pin<&Self>,
1650 _do_create: bool,
1651 result: &mut Option<WindowAdapterRc>,
1652 ) {
1653 *result = Some(self.window_adapter.clone())
1654 }
1655
1656 fn item_geometry(self: Pin<&Self>, _: u32) -> LogicalRect {
1657 LogicalRect::new(
1658 euclid::Point2D::new(GEOMETRY_POSITION_X, GEOMETRY_POSITION_Y),
1659 euclid::Size2D::new(GEOMETRY_WIDTH, GEOMETRY_HEIGHT),
1660 )
1661 }
1662
1663 fn accessibility_action(self: core::pin::Pin<&Self>, _: u32, _: &AccessibilityAction) {
1664 unimplemented!("Not needed for this test")
1665 }
1666
1667 fn supported_accessibility_actions(
1668 self: core::pin::Pin<&Self>,
1669 _: u32,
1670 ) -> SupportedAccessibilityAction {
1671 unimplemented!("Not needed for this test")
1672 }
1673 }
1674
1675 crate::item_tree::ItemTreeVTable_static!(static TEST_COMPONENT_VT for TestItemTree);
1676
1677 fn create_one_node_component() -> VRc<ItemTreeVTable, vtable::Dyn> {
1678 let component = VRc::new(TestItemTree {
1679 parent_component: None,
1680 item_tree: vec![ItemTreeNode::Item {
1681 is_accessible: false,
1682 children_count: 0,
1683 children_index: 1,
1684 parent_index: 0,
1685 item_array_index: 0,
1686 }],
1687 subtrees: std::cell::RefCell::new(Vec::new()),
1688 subtree_index: usize::MAX,
1689
1690 window_adapter: WindowAdapter::new(),
1691 window_item: None,
1692 });
1693 VRc::into_dyn(component)
1694 }
1695
1696 #[test]
1697 fn test_tree_traversal_one_node_structure() {
1698 let component = create_one_node_component();
1699
1700 let item = ItemRc::new_root(component.clone());
1701
1702 assert!(item.first_child().is_none());
1703 assert!(item.last_child().is_none());
1704 assert!(item.previous_sibling().is_none());
1705 assert!(item.next_sibling().is_none());
1706 }
1707
1708 #[test]
1709 fn test_tree_traversal_one_node_forward_focus() {
1710 let component = create_one_node_component();
1711
1712 let item = ItemRc::new_root(component.clone());
1713
1714 assert_eq!(item.next_focus_item(), item);
1716 }
1717
1718 #[test]
1719 fn test_tree_traversal_one_node_backward_focus() {
1720 let component = create_one_node_component();
1721
1722 let item = ItemRc::new_root(component.clone());
1723
1724 assert_eq!(item.previous_focus_item(), item);
1726 }
1727
1728 fn create_children_nodes() -> VRc<ItemTreeVTable, vtable::Dyn> {
1729 let component = VRc::new(TestItemTree {
1730 parent_component: None,
1731 item_tree: vec![
1732 ItemTreeNode::Item {
1734 is_accessible: false,
1735 children_count: 3,
1736 children_index: 1,
1737 parent_index: 0,
1738 item_array_index: 0, },
1740 ItemTreeNode::Item {
1742 is_accessible: false,
1743 children_count: 0,
1744 children_index: 4, parent_index: 0, item_array_index: 1, },
1748 ItemTreeNode::Item {
1750 is_accessible: false,
1751 children_count: 0,
1752 children_index: 4, parent_index: 0, item_array_index: 2,
1755 },
1756 ItemTreeNode::Item {
1758 is_accessible: false,
1759 children_count: 0,
1760 children_index: 4, parent_index: 0, item_array_index: 3,
1763 },
1764 ],
1765 subtrees: std::cell::RefCell::new(Vec::new()),
1766 subtree_index: usize::MAX,
1767
1768 window_adapter: WindowAdapter::new(),
1769 window_item: None,
1770 });
1771 VRc::into_dyn(component)
1772 }
1773
1774 #[test]
1775 fn test_tree_traversal_children_nodes_structure() {
1776 let component: VRc<ItemTreeVTable> = create_children_nodes();
1777
1778 let item = ItemRc::new_root(component.clone());
1780 assert!(item.previous_sibling().is_none());
1781 assert!(item.next_sibling().is_none());
1782
1783 let fc = item.first_child().unwrap();
1784 assert_eq!(fc.index(), 1);
1785 assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
1786
1787 let fcn = fc.next_sibling().unwrap();
1788 assert_eq!(fcn.index(), 2);
1789
1790 let lc = item.last_child().unwrap();
1791 assert_eq!(lc.index(), 3);
1792 assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
1793
1794 let lcp = lc.previous_sibling().unwrap();
1795 assert!(VRc::ptr_eq(lcp.item_tree(), item.item_tree()));
1796 assert_eq!(lcp.index(), 2);
1797
1798 assert!(fc.first_child().is_none());
1800 assert!(fc.last_child().is_none());
1801 assert!(fc.previous_sibling().is_none());
1802 assert_eq!(fc.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);
1803
1804 assert_eq!(fcn, lcp);
1806 assert_eq!(lcp.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);
1807 assert_eq!(fcn.previous_sibling().unwrap(), fc);
1808 assert_eq!(fcn.next_sibling().unwrap(), lc);
1809
1810 assert!(lc.first_child().is_none());
1812 assert!(lc.last_child().is_none());
1813 assert!(lc.next_sibling().is_none());
1814 assert_eq!(lc.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);
1815 }
1816
1817 #[test]
1818 fn test_tree_traversal_children_nodes_forward_focus() {
1819 let component = create_children_nodes();
1820
1821 let item = ItemRc::new_root(component.clone());
1822 let fc = item.first_child().unwrap();
1823 let fcn = fc.next_sibling().unwrap();
1824 let lc = item.last_child().unwrap();
1825
1826 let mut cursor = item.clone();
1827
1828 cursor = cursor.next_focus_item();
1829 assert_eq!(cursor, fc);
1830
1831 cursor = cursor.next_focus_item();
1832 assert_eq!(cursor, fcn);
1833
1834 cursor = cursor.next_focus_item();
1835 assert_eq!(cursor, lc);
1836
1837 cursor = cursor.next_focus_item();
1838 assert_eq!(cursor, item);
1839 }
1840
1841 #[test]
1842 fn test_tree_traversal_children_nodes_backward_focus() {
1843 let component = create_children_nodes();
1844
1845 let item = ItemRc::new_root(component.clone());
1846 let fc = item.first_child().unwrap();
1847 let fcn = fc.next_sibling().unwrap();
1848 let lc = item.last_child().unwrap();
1849
1850 let mut cursor = item.clone();
1851
1852 cursor = cursor.previous_focus_item();
1853 assert_eq!(cursor, lc);
1854
1855 cursor = cursor.previous_focus_item();
1856 assert_eq!(cursor, fcn);
1857
1858 cursor = cursor.previous_focus_item();
1859 assert_eq!(cursor, fc);
1860
1861 cursor = cursor.previous_focus_item();
1862 assert_eq!(cursor, item);
1863 }
1864
1865 fn create_empty_subtree() -> VRc<ItemTreeVTable, vtable::Dyn> {
1866 let component = vtable::VRc::new(TestItemTree {
1867 parent_component: None,
1868 item_tree: vec![
1869 ItemTreeNode::Item {
1870 is_accessible: false,
1871 children_count: 1,
1872 children_index: 1,
1873 parent_index: 0,
1874 item_array_index: 0,
1875 },
1876 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1877 ],
1878 subtrees: std::cell::RefCell::new(vec![Vec::new()]),
1879 subtree_index: usize::MAX,
1880
1881 window_adapter: WindowAdapter::new(),
1882 window_item: None,
1883 });
1884 vtable::VRc::into_dyn(component)
1885 }
1886
1887 #[test]
1888 fn test_tree_traversal_empty_subtree_structure() {
1889 let component = create_empty_subtree();
1890
1891 let item = ItemRc::new_root(component.clone());
1893 assert!(item.previous_sibling().is_none());
1894 assert!(item.next_sibling().is_none());
1895 assert!(item.first_child().is_none());
1896 assert!(item.last_child().is_none());
1897
1898 assert!(item.previous_focus_item() == item);
1900 assert!(item.next_focus_item() == item);
1901 }
1902
1903 #[test]
1904 fn test_tree_traversal_empty_subtree_forward_focus() {
1905 let component = create_empty_subtree();
1906
1907 let item = ItemRc::new_root(component.clone());
1909
1910 assert!(item.next_focus_item() == item);
1911 }
1912
1913 #[test]
1914 fn test_tree_traversal_empty_subtree_backward_focus() {
1915 let component = create_empty_subtree();
1916
1917 let item = ItemRc::new_root(component.clone());
1919
1920 assert!(item.previous_focus_item() == item);
1921 }
1922
1923 fn create_item_subtree_item() -> VRc<ItemTreeVTable, vtable::Dyn> {
1924 let window_adapter = WindowAdapter::new();
1925 let component = VRc::new(TestItemTree {
1926 parent_component: None,
1927 item_tree: vec![
1928 ItemTreeNode::Item {
1930 is_accessible: false,
1931 children_count: 3,
1932 children_index: 1,
1933 parent_index: 0,
1934 item_array_index: 0,
1935 },
1936 ItemTreeNode::Item {
1938 is_accessible: false,
1939 children_count: 0,
1940 children_index: 4, parent_index: 0, item_array_index: 0,
1943 },
1944 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1945 ItemTreeNode::Item {
1946 is_accessible: false,
1947 children_count: 0,
1948 children_index: 4,
1949 parent_index: 0, item_array_index: 0,
1951 },
1952 ],
1953 subtrees: std::cell::RefCell::new(Vec::new()),
1954 subtree_index: usize::MAX,
1955
1956 window_adapter: window_adapter.clone(),
1957 window_item: None,
1958 });
1959
1960 component.as_pin_ref().subtrees.replace(vec![vec![VRc::new(TestItemTree {
1961 parent_component: Some(VRc::into_dyn(component.clone())),
1962 item_tree: vec![ItemTreeNode::Item {
1963 is_accessible: false,
1964 children_count: 0,
1965 children_index: 1,
1966 parent_index: 2,
1967 item_array_index: 0,
1968 }],
1969 subtrees: std::cell::RefCell::new(Vec::new()),
1970 subtree_index: 0,
1971
1972 window_adapter,
1973 window_item: None,
1974 })]]);
1975
1976 VRc::into_dyn(component)
1977 }
1978
1979 #[test]
1980 fn test_tree_traversal_item_subtree_item_structure() {
1981 let component = create_item_subtree_item();
1982
1983 let item = ItemRc::new_root(component.clone());
1985 assert!(item.previous_sibling().is_none());
1986 assert!(item.next_sibling().is_none());
1987
1988 let fc = item.first_child().unwrap();
1989 assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
1990 assert_eq!(fc.index(), 1);
1991
1992 let lc = item.last_child().unwrap();
1993 assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
1994 assert_eq!(lc.index(), 3);
1995
1996 let fcn = fc.next_sibling().unwrap();
1997 let lcp = lc.previous_sibling().unwrap();
1998
1999 assert_eq!(fcn, lcp);
2000 assert!(!VRc::ptr_eq(fcn.item_tree(), item.item_tree()));
2001
2002 let last = fcn.next_sibling().unwrap();
2003 assert_eq!(last, lc);
2004
2005 let first = lcp.previous_sibling().unwrap();
2006 assert_eq!(first, fc);
2007 }
2008
2009 #[test]
2010 fn test_tree_traversal_item_subtree_item_forward_focus() {
2011 let component = create_item_subtree_item();
2012
2013 let item = ItemRc::new_root(component.clone());
2014 let fc = item.first_child().unwrap();
2015 let lc = item.last_child().unwrap();
2016 let fcn = fc.next_sibling().unwrap();
2017
2018 let mut cursor = item.clone();
2019
2020 cursor = cursor.next_focus_item();
2021 assert_eq!(cursor, fc);
2022
2023 cursor = cursor.next_focus_item();
2024 assert_eq!(cursor, fcn);
2025
2026 cursor = cursor.next_focus_item();
2027 assert_eq!(cursor, lc);
2028
2029 cursor = cursor.next_focus_item();
2030 assert_eq!(cursor, item);
2031 }
2032
2033 #[test]
2034 fn test_tree_traversal_item_subtree_item_backward_focus() {
2035 let component = create_item_subtree_item();
2036
2037 let item = ItemRc::new_root(component.clone());
2038 let fc = item.first_child().unwrap();
2039 let lc = item.last_child().unwrap();
2040 let fcn = fc.next_sibling().unwrap();
2041
2042 let mut cursor = item.clone();
2043
2044 cursor = cursor.previous_focus_item();
2045 assert_eq!(cursor, lc);
2046
2047 cursor = cursor.previous_focus_item();
2048 assert_eq!(cursor, fcn);
2049
2050 cursor = cursor.previous_focus_item();
2051 assert_eq!(cursor, fc);
2052
2053 cursor = cursor.previous_focus_item();
2054 assert_eq!(cursor, item);
2055 }
2056
2057 fn create_nested_subtrees() -> VRc<ItemTreeVTable, vtable::Dyn> {
2058 let window_adapter = WindowAdapter::new();
2063
2064 let component = VRc::new(TestItemTree {
2065 parent_component: None,
2066 item_tree: vec![
2067 ItemTreeNode::Item {
2069 is_accessible: false,
2070 children_count: 3,
2071 children_index: 1,
2072 parent_index: 0,
2073 item_array_index: 0,
2074 },
2075 ItemTreeNode::Item {
2077 is_accessible: false,
2078 children_count: 0,
2079 children_index: 4,
2080 parent_index: 0,
2081 item_array_index: 0,
2082 },
2083 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
2086 ItemTreeNode::Item {
2088 is_accessible: false,
2089 children_count: 0,
2090 children_index: 4,
2091 parent_index: 0,
2092 item_array_index: 0,
2093 },
2094 ],
2095 subtrees: std::cell::RefCell::new(Vec::new()),
2096 subtree_index: usize::MAX,
2097
2098 window_adapter: window_adapter.clone(),
2099 window_item: None,
2100 });
2101
2102 let sub_component1 = VRc::new(TestItemTree {
2103 parent_component: Some(VRc::into_dyn(component.clone())),
2104 item_tree: vec![
2105 ItemTreeNode::Item {
2107 is_accessible: false,
2108 children_count: 1,
2109 children_index: 1,
2110 parent_index: 2,
2111 item_array_index: 0,
2112 },
2113 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
2116 ],
2117 subtrees: std::cell::RefCell::new(Vec::new()),
2118 subtree_index: usize::MAX,
2119
2120 window_adapter: window_adapter.clone(),
2121 window_item: None,
2122 });
2123 let sub_component2 = VRc::new(TestItemTree {
2124 parent_component: Some(VRc::into_dyn(sub_component1.clone())),
2125 item_tree: vec![
2126 ItemTreeNode::Item {
2127 is_accessible: false,
2128 children_count: 1,
2129 children_index: 1,
2130 parent_index: 1,
2131 item_array_index: 0,
2132 },
2133 ItemTreeNode::Item {
2134 is_accessible: false,
2135 children_count: 0,
2136 children_index: 2,
2137 parent_index: 0,
2138 item_array_index: 0,
2139 },
2140 ],
2141 subtrees: std::cell::RefCell::new(Vec::new()),
2142 subtree_index: usize::MAX,
2143
2144 window_adapter,
2145 window_item: None,
2146 });
2147
2148 sub_component1.as_pin_ref().subtrees.replace(vec![vec![sub_component2]]);
2149 component.as_pin_ref().subtrees.replace(vec![vec![sub_component1]]);
2150
2151 VRc::into_dyn(component)
2152 }
2153
2154 #[test]
2155 fn test_tree_traversal_nested_subtrees_structure() {
2156 let component = create_nested_subtrees();
2157
2158 let item = ItemRc::new_root(component.clone());
2160 assert!(item.previous_sibling().is_none());
2161 assert!(item.next_sibling().is_none());
2162
2163 let fc = item.first_child().unwrap();
2164 assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
2165 assert_eq!(fc.index(), 1);
2166
2167 let lc = item.last_child().unwrap();
2168 assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
2169 assert_eq!(lc.index(), 3);
2170
2171 let fcn = fc.next_sibling().unwrap();
2172 let lcp = lc.previous_sibling().unwrap();
2173
2174 assert_eq!(fcn, lcp);
2175 assert!(!VRc::ptr_eq(fcn.item_tree(), item.item_tree()));
2176
2177 let last = fcn.next_sibling().unwrap();
2178 assert_eq!(last, lc);
2179
2180 let first = lcp.previous_sibling().unwrap();
2181 assert_eq!(first, fc);
2182
2183 let nested_root = fcn.first_child().unwrap();
2185 assert_eq!(nested_root, fcn.last_child().unwrap());
2186 assert!(nested_root.next_sibling().is_none());
2187 assert!(nested_root.previous_sibling().is_none());
2188 assert!(!VRc::ptr_eq(nested_root.item_tree(), item.item_tree()));
2189 assert!(!VRc::ptr_eq(nested_root.item_tree(), fcn.item_tree()));
2190
2191 let nested_child = nested_root.first_child().unwrap();
2192 assert_eq!(nested_child, nested_root.last_child().unwrap());
2193 assert!(VRc::ptr_eq(nested_root.item_tree(), nested_child.item_tree()));
2194 }
2195
2196 #[test]
2197 fn test_tree_traversal_nested_subtrees_forward_focus() {
2198 let component = create_nested_subtrees();
2199
2200 let item = ItemRc::new_root(component.clone());
2202 let fc = item.first_child().unwrap();
2203 let fcn = fc.next_sibling().unwrap();
2204 let lc = item.last_child().unwrap();
2205 let nested_root = fcn.first_child().unwrap();
2206 let nested_child = nested_root.first_child().unwrap();
2207
2208 let mut cursor = item.clone();
2210
2211 cursor = cursor.next_focus_item();
2212 assert_eq!(cursor, fc);
2213
2214 cursor = cursor.next_focus_item();
2215 assert_eq!(cursor, fcn);
2216
2217 cursor = cursor.next_focus_item();
2218 assert_eq!(cursor, nested_root);
2219
2220 cursor = cursor.next_focus_item();
2221 assert_eq!(cursor, nested_child);
2222
2223 cursor = cursor.next_focus_item();
2224 assert_eq!(cursor, lc);
2225
2226 cursor = cursor.next_focus_item();
2227 assert_eq!(cursor, item);
2228 }
2229
2230 #[test]
2231 fn test_tree_traversal_nested_subtrees_backward_focus() {
2232 let component = create_nested_subtrees();
2233
2234 let item = ItemRc::new_root(component.clone());
2236 let fc = item.first_child().unwrap();
2237 let fcn = fc.next_sibling().unwrap();
2238 let lc = item.last_child().unwrap();
2239 let nested_root = fcn.first_child().unwrap();
2240 let nested_child = nested_root.first_child().unwrap();
2241
2242 let mut cursor = item.clone();
2244
2245 cursor = cursor.previous_focus_item();
2246 assert_eq!(cursor, lc);
2247
2248 cursor = cursor.previous_focus_item();
2249 assert_eq!(cursor, nested_child);
2250
2251 cursor = cursor.previous_focus_item();
2252 assert_eq!(cursor, nested_root);
2253
2254 cursor = cursor.previous_focus_item();
2255 assert_eq!(cursor, fcn);
2256
2257 cursor = cursor.previous_focus_item();
2258 assert_eq!(cursor, fc);
2259
2260 cursor = cursor.previous_focus_item();
2261 assert_eq!(cursor, item);
2262 }
2263
2264 fn create_subtrees_item() -> VRc<ItemTreeVTable, vtable::Dyn> {
2265 let window_adapter = WindowAdapter::new();
2266
2267 let component = VRc::new(TestItemTree {
2268 parent_component: None,
2269 item_tree: vec![
2270 ItemTreeNode::Item {
2271 is_accessible: false,
2272 children_count: 2,
2273 children_index: 1,
2274 parent_index: 0,
2275 item_array_index: 0,
2276 },
2277 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
2278 ItemTreeNode::Item {
2279 is_accessible: false,
2280 children_count: 0,
2281 children_index: 4,
2282 parent_index: 0,
2283 item_array_index: 0,
2284 },
2285 ],
2286 subtrees: std::cell::RefCell::new(Vec::new()),
2287 subtree_index: usize::MAX,
2288
2289 window_adapter: window_adapter.clone(),
2290 window_item: None,
2291 });
2292
2293 component.as_pin_ref().subtrees.replace(vec![vec![
2294 VRc::new(TestItemTree {
2295 parent_component: Some(VRc::into_dyn(component.clone())),
2296 item_tree: vec![ItemTreeNode::Item {
2297 is_accessible: false,
2298 children_count: 0,
2299 children_index: 1,
2300 parent_index: 1,
2301 item_array_index: 0,
2302 }],
2303 subtrees: std::cell::RefCell::new(Vec::new()),
2304 subtree_index: 0,
2305
2306 window_adapter: window_adapter.clone(),
2307 window_item: None,
2308 }),
2309 VRc::new(TestItemTree {
2310 parent_component: Some(VRc::into_dyn(component.clone())),
2311 item_tree: vec![ItemTreeNode::Item {
2312 is_accessible: false,
2313 children_count: 0,
2314 children_index: 1,
2315 parent_index: 1,
2316 item_array_index: 0,
2317 }],
2318 subtrees: std::cell::RefCell::new(Vec::new()),
2319 subtree_index: 1,
2320
2321 window_adapter: window_adapter.clone(),
2322 window_item: None,
2323 }),
2324 VRc::new(TestItemTree {
2325 parent_component: Some(VRc::into_dyn(component.clone())),
2326 item_tree: vec![ItemTreeNode::Item {
2327 is_accessible: false,
2328 children_count: 0,
2329 children_index: 1,
2330 parent_index: 1,
2331 item_array_index: 0,
2332 }],
2333 subtrees: std::cell::RefCell::new(Vec::new()),
2334 subtree_index: 2,
2335
2336 window_adapter,
2337 window_item: None,
2338 }),
2339 ]]);
2340
2341 VRc::into_dyn(component)
2342 }
2343
2344 #[test]
2345 fn test_tree_traversal_subtrees_item_structure() {
2346 let component = create_subtrees_item();
2347
2348 let item = ItemRc::new_root(component.clone());
2350 assert!(item.previous_sibling().is_none());
2351 assert!(item.next_sibling().is_none());
2352
2353 let sub1 = item.first_child().unwrap();
2354 assert_eq!(sub1.index(), 0);
2355 assert!(!VRc::ptr_eq(sub1.item_tree(), item.item_tree()));
2356
2357 let sub2 = sub1.next_sibling().unwrap();
2360 assert_eq!(sub2.index(), 0);
2361 assert!(!VRc::ptr_eq(sub1.item_tree(), sub2.item_tree()));
2362 assert!(!VRc::ptr_eq(item.item_tree(), sub2.item_tree()));
2363
2364 assert!(sub2.previous_sibling() == Some(sub1.clone()));
2365
2366 let sub3 = sub2.next_sibling().unwrap();
2367 assert_eq!(sub3.index(), 0);
2368 assert!(!VRc::ptr_eq(sub1.item_tree(), sub2.item_tree()));
2369 assert!(!VRc::ptr_eq(sub2.item_tree(), sub3.item_tree()));
2370 assert!(!VRc::ptr_eq(item.item_tree(), sub3.item_tree()));
2371
2372 assert_eq!(sub3.previous_sibling().unwrap(), sub2.clone());
2373 }
2374
2375 #[test]
2376 fn test_component_item_tree_root_only() {
2377 let nodes = vec![ItemTreeNode::Item {
2378 is_accessible: false,
2379 children_count: 0,
2380 children_index: 1,
2381 parent_index: 0,
2382 item_array_index: 0,
2383 }];
2384
2385 let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
2386
2387 assert_eq!(tree.first_child(0), None);
2388 assert_eq!(tree.last_child(0), None);
2389 assert_eq!(tree.previous_sibling(0), None);
2390 assert_eq!(tree.next_sibling(0), None);
2391 assert_eq!(tree.parent(0), None);
2392 }
2393
2394 #[test]
2395 fn test_component_item_tree_one_child() {
2396 let nodes = vec![
2397 ItemTreeNode::Item {
2398 is_accessible: false,
2399 children_count: 1,
2400 children_index: 1,
2401 parent_index: 0,
2402 item_array_index: 0,
2403 },
2404 ItemTreeNode::Item {
2405 is_accessible: false,
2406 children_count: 0,
2407 children_index: 2,
2408 parent_index: 0,
2409 item_array_index: 0,
2410 },
2411 ];
2412
2413 let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
2414
2415 assert_eq!(tree.first_child(0), Some(1));
2416 assert_eq!(tree.last_child(0), Some(1));
2417 assert_eq!(tree.previous_sibling(0), None);
2418 assert_eq!(tree.next_sibling(0), None);
2419 assert_eq!(tree.parent(0), None);
2420 assert_eq!(tree.previous_sibling(1), None);
2421 assert_eq!(tree.next_sibling(1), None);
2422 assert_eq!(tree.parent(1), Some(0));
2423 }
2424
2425 #[test]
2426 fn test_component_item_tree_tree_children() {
2427 let nodes = vec![
2428 ItemTreeNode::Item {
2429 is_accessible: false,
2430 children_count: 3,
2431 children_index: 1,
2432 parent_index: 0,
2433 item_array_index: 0,
2434 },
2435 ItemTreeNode::Item {
2436 is_accessible: false,
2437 children_count: 0,
2438 children_index: 4,
2439 parent_index: 0,
2440 item_array_index: 0,
2441 },
2442 ItemTreeNode::Item {
2443 is_accessible: false,
2444 children_count: 0,
2445 children_index: 4,
2446 parent_index: 0,
2447 item_array_index: 0,
2448 },
2449 ItemTreeNode::Item {
2450 is_accessible: false,
2451 children_count: 0,
2452 children_index: 4,
2453 parent_index: 0,
2454 item_array_index: 0,
2455 },
2456 ];
2457
2458 let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
2459
2460 assert_eq!(tree.first_child(0), Some(1));
2461 assert_eq!(tree.last_child(0), Some(3));
2462 assert_eq!(tree.previous_sibling(0), None);
2463 assert_eq!(tree.next_sibling(0), None);
2464 assert_eq!(tree.parent(0), None);
2465
2466 assert_eq!(tree.previous_sibling(1), None);
2467 assert_eq!(tree.next_sibling(1), Some(2));
2468 assert_eq!(tree.parent(1), Some(0));
2469
2470 assert_eq!(tree.previous_sibling(2), Some(1));
2471 assert_eq!(tree.next_sibling(2), Some(3));
2472 assert_eq!(tree.parent(2), Some(0));
2473
2474 assert_eq!(tree.previous_sibling(3), Some(2));
2475 assert_eq!(tree.next_sibling(3), None);
2476 assert_eq!(tree.parent(3), Some(0));
2477 }
2478
2479 fn create_subsubtree_items() -> (std::rc::Weak<WindowAdapter>, VRc<ItemTreeVTable>) {
2481 let window_adapter = WindowAdapter::new();
2482 let weak = Rc::downgrade(&window_adapter);
2483 let mut window_item = WindowItem::default();
2484 window_item.width = Property::new(LogicalLength::new(30.));
2485 window_item.height = Property::new(LogicalLength::new(30.));
2486 (
2487 weak,
2488 VRc::into_dyn(VRc::new(TestItemTree {
2489 parent_component: None,
2490 item_tree: vec![
2491 ItemTreeNode::Item {
2493 is_accessible: false,
2494 children_count: 1,
2495 children_index: 1,
2496 parent_index: 0,
2497 item_array_index: 0,
2498 },
2499 ItemTreeNode::Item {
2501 is_accessible: false,
2502 children_count: 1,
2503 children_index: 2, parent_index: 0,
2505 item_array_index: 1,
2506 },
2507 ItemTreeNode::Item {
2509 is_accessible: false,
2510 children_count: 0,
2511 children_index: 3, parent_index: 1,
2513 item_array_index: 2,
2514 },
2515 ],
2516 subtrees: std::cell::RefCell::new(Vec::new()),
2517 subtree_index: usize::MAX,
2518 window_adapter,
2519 window_item: Some(window_item),
2520 })),
2521 )
2522 }
2523
2524 #[test]
2525 fn test_map_to_anchestor() {
2526 let item_tree = create_subsubtree_items().1;
2527 let root = ItemRc::new_root(item_tree);
2528 let first_child = root.first_child().unwrap();
2529 let first_child_of_first_child = first_child.first_child().unwrap();
2530
2531 {
2532 let point = first_child.map_to_ancestor(Point2D::new(6., 19.), &root);
2533 assert_eq!(point.x, 6.);
2534 assert_eq!(point.y, 19.);
2535 }
2536
2537 {
2538 let point =
2539 first_child_of_first_child.map_to_ancestor(Point2D::new(27., -10.), &first_child);
2540 assert_eq!(point.x, 27.);
2541 assert_eq!(point.y, -10.);
2542 }
2543
2544 {
2545 let point = first_child_of_first_child.map_to_ancestor(Point2D::new(27., -10.), &root);
2547 assert_eq!(point.x, GEOMETRY_POSITION_X + 27.);
2549 assert_eq!(point.y, GEOMETRY_POSITION_Y - 10.);
2550 }
2551 }
2552
2553 #[test]
2554 fn test_map_to_window() {
2555 let item_tree = create_subsubtree_items().1;
2556 let root = ItemRc::new_root(item_tree);
2557 let first_child = root.first_child().unwrap();
2558 let first_child_of_first_child = first_child.first_child().unwrap();
2559
2560 let point = first_child_of_first_child.map_to_window(Point2D::new(-5., 7.));
2561 assert_eq!(point.x, GEOMETRY_POSITION_X + GEOMETRY_POSITION_X - 5.);
2563 assert_eq!(point.y, GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y + 7.);
2564 }
2565
2566 #[test]
2567 fn test_map_to_native_window_popup() {
2568 const POPUP_LOCATION: LogicalPosition = LogicalPosition::new(20., 33.);
2569 let (window_adapter_weak, item_tree) = create_subsubtree_items();
2570 window_adapter_weak.upgrade().unwrap().window.0.show_popup(
2571 &item_tree,
2572 POPUP_LOCATION,
2573 crate::items::PopupClosePolicy::NoAutoClose,
2574 &ItemRc::new_root(item_tree.clone()),
2575 false,
2576 );
2577
2578 let root = ItemRc::new_root(item_tree);
2579 let first_child = root.first_child().unwrap();
2580 let first_child_of_first_child = first_child.first_child().unwrap();
2581
2582 let window_adapter = window_adapter_weak.upgrade().unwrap();
2584 let active_popups = window_adapter.window.0.active_popups();
2585 assert_eq!(active_popups.len(), 1);
2586 let popup = active_popups.first().unwrap();
2587 assert!(matches!(popup.location, crate::window::PopupWindowLocation::ChildWindow { .. }));
2588
2589 let point = first_child_of_first_child.map_to_native_window(Point2D::new(3., -82.));
2592 assert_eq!(
2593 point.x,
2594 POPUP_LOCATION.x + GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + 3.
2596 );
2597 assert_eq!(
2598 point.y,
2599 POPUP_LOCATION.y + GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y
2600 - 82.
2601 );
2602 }
2603
2604 #[test]
2605 fn test_map_to_window_popup() {
2606 const POPUP_LOCATION: LogicalPosition = LogicalPosition::new(20., 33.);
2607 let (window_adapter_weak, item_tree) = create_subsubtree_items();
2608 window_adapter_weak.upgrade().unwrap().window.0.show_popup(
2609 &item_tree,
2610 POPUP_LOCATION,
2611 crate::items::PopupClosePolicy::NoAutoClose,
2612 &ItemRc::new_root(item_tree.clone()),
2613 false,
2614 );
2615
2616 let root = ItemRc::new_root(item_tree);
2617 let first_child = root.first_child().unwrap();
2618 let first_child_of_first_child = first_child.first_child().unwrap();
2619
2620 let window_adapter = window_adapter_weak.upgrade().unwrap();
2622 let active_popups = window_adapter.window.0.active_popups();
2623 assert_eq!(active_popups.len(), 1);
2624 let popup = active_popups.first().unwrap();
2625 assert!(matches!(popup.location, crate::window::PopupWindowLocation::ChildWindow { .. }));
2626
2627 let point = first_child_of_first_child.map_to_window(Point2D::new(3., -82.));
2630 assert_eq!(point.x, GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + 3.);
2633 assert_eq!(point.y, GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y - 82.);
2634 }
2635
2636 fn create_subsubtree_items_dynamic_elements()
2638 -> (std::rc::Weak<WindowAdapter>, VRc<ItemTreeVTable>) {
2639 let window_adapter = WindowAdapter::new();
2640 let weak = Rc::downgrade(&window_adapter);
2641 let mut window_item = WindowItem::default();
2642 window_item.width = Property::new(LogicalLength::new(30.));
2643 window_item.height = Property::new(LogicalLength::new(30.));
2644
2645 let item_tree = VRc::new(TestItemTree {
2646 parent_component: None,
2647 item_tree: vec![
2648 ItemTreeNode::Item {
2650 is_accessible: false,
2651 children_count: 1,
2652 children_index: 1,
2653 parent_index: 0,
2654 item_array_index: 0,
2655 },
2656 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
2658 ],
2659 subtrees: std::cell::RefCell::new(Vec::new()),
2660 subtree_index: usize::MAX,
2661 window_adapter: window_adapter.clone(),
2662 window_item: Some(window_item),
2663 });
2664
2665 item_tree.as_pin_ref().subtrees.replace(vec![vec![VRc::new(TestItemTree {
2666 parent_component: Some(VRc::into_dyn(item_tree.clone())),
2667 item_tree: vec![
2668 ItemTreeNode::Item {
2670 is_accessible: false,
2671 children_count: 1,
2672 children_index: 1,
2673 parent_index: 1, item_array_index: 0,
2675 },
2676 ItemTreeNode::Item {
2678 is_accessible: false,
2679 children_count: 0,
2680 children_index: 0,
2681 parent_index: 0,
2682 item_array_index: 1,
2683 },
2684 ],
2685 subtrees: std::cell::RefCell::new(Vec::new()),
2686 subtree_index: 0,
2687
2688 window_adapter,
2689 window_item: None,
2690 })]]);
2691
2692 (weak, VRc::into_dyn(item_tree))
2693 }
2694
2695 #[test]
2698 fn test_map_to_native_window_popup_dynamic_element() {
2699 const POPUP_LOCATION: LogicalPosition = LogicalPosition::new(20., 33.);
2700 let (window_adapter_weak, item_tree) = create_subsubtree_items_dynamic_elements();
2701 window_adapter_weak.upgrade().unwrap().window.0.show_popup(
2702 &item_tree,
2703 POPUP_LOCATION,
2704 crate::items::PopupClosePolicy::NoAutoClose,
2705 &ItemRc::new_root(item_tree.clone()),
2706 false,
2707 );
2708
2709 let window_adapter = window_adapter_weak.upgrade().unwrap();
2711 let active_popups = window_adapter.window.0.active_popups();
2712 assert_eq!(active_popups.len(), 1);
2713 let popup = active_popups.first().unwrap();
2714 assert!(matches!(popup.location, crate::window::PopupWindowLocation::ChildWindow { .. }));
2715
2716 let root = ItemRc::new_root(item_tree);
2717 let first_child = root.first_child().unwrap();
2718 let comp_ref_pin = vtable::VRc::borrow_pin(&root.item_tree);
2720 let item_tree_array = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
2721 assert!(matches!(
2722 item_tree_array.get(1).expect("Must be one element"),
2723 ItemTreeNode::DynamicTree { .. }
2724 ));
2725 let first_child_of_first_child = first_child.first_child().expect("We have one child");
2727
2728 let point = first_child_of_first_child.map_to_native_window(Point2D::new(3., -82.));
2731 assert_eq!(
2732 point.x,
2733 POPUP_LOCATION.x + GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + 3.
2735 );
2736 assert_eq!(
2737 point.y,
2738 POPUP_LOCATION.y + GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y
2739 - 82.
2740 );
2741 }
2742
2743 impl crate::renderer::RendererSealed for Renderer {
2744 fn char_size(
2745 &self,
2746 _text_item: Pin<&dyn crate::item_rendering::HasFont>,
2747 _item_rc: &crate::item_tree::ItemRc,
2748 _ch: char,
2749 ) -> LogicalSize {
2750 LogicalSize::new(5., 10.)
2751 }
2752
2753 fn default_font_size(&self) -> LogicalLength {
2754 LogicalLength::new(10.)
2755 }
2756
2757 fn font_metrics(
2758 &self,
2759 _font_request: crate::graphics::FontRequest,
2760 ) -> crate::items::FontMetrics {
2761 crate::items::FontMetrics { ..Default::default() }
2762 }
2763
2764 fn free_graphics_resources(
2765 &self,
2766 _component: ItemTreeRef,
2767 _items: &mut dyn Iterator<Item = Pin<crate::items::ItemRef<'_>>>,
2768 ) -> Result<(), crate::platform::PlatformError> {
2769 Ok(())
2770 }
2771
2772 fn mark_dirty_region(&self, _region: crate::partial_renderer::DirtyRegion) {
2773 unimplemented!("Not required in this test");
2774 }
2775
2776 fn register_bitmap_font(&self, _font_data: &'static crate::graphics::BitmapFont) {
2777 unimplemented!("Not required in this test");
2778 }
2779
2780 fn register_font_from_memory(
2781 &self,
2782 _data: &'static [u8],
2783 ) -> Result<(), std::prelude::v1::Box<dyn std::error::Error>> {
2784 unimplemented!("Not required in this test");
2785 }
2786
2787 fn register_font_from_path(
2788 &self,
2789 _path: &std::path::Path,
2790 ) -> Result<(), std::prelude::v1::Box<dyn std::error::Error>> {
2791 unimplemented!("Not required in this test");
2792 }
2793
2794 fn resize(&self, _size: crate::api::PhysicalSize) -> Result<(), crate::api::PlatformError> {
2795 Ok(())
2796 }
2797
2798 fn scale_factor(&self) -> Option<crate::lengths::ScaleFactor> {
2799 None
2800 }
2801
2802 fn set_rendering_notifier(
2803 &self,
2804 _callback: std::prelude::v1::Box<dyn crate::api::RenderingNotifier>,
2805 ) -> Result<(), crate::api::SetRenderingNotifierError> {
2806 Ok(())
2807 }
2808
2809 fn set_window_adapter(
2810 &self,
2811 _window_adapter: &std::rc::Rc<dyn crate::window::WindowAdapter>,
2812 ) {
2813 unimplemented!("Not required in this test");
2814 }
2815
2816 fn slint_context(&self) -> Option<crate::SlintContext> {
2817 None
2818 }
2819
2820 fn supports_transformations(&self) -> bool {
2821 false
2822 }
2823
2824 fn take_snapshot(
2825 &self,
2826 ) -> Result<crate::api::SharedPixelBuffer<crate::api::Rgba8Pixel>, crate::api::PlatformError>
2827 {
2828 unimplemented!("Not required in this test");
2829 }
2830
2831 fn text_input_byte_offset_for_position(
2832 &self,
2833 _text_input: Pin<&crate::items::TextInput>,
2834 _item_rc: &ItemRc,
2835 _pos: LogicalPoint,
2836 ) -> usize {
2837 unimplemented!("Not required in this test");
2838 }
2839
2840 fn text_input_cursor_rect_for_byte_offset(
2841 &self,
2842 _text_input: Pin<&crate::items::TextInput>,
2843 _item_rc: &ItemRc,
2844 _byte_offset: usize,
2845 ) -> LogicalRect {
2846 unimplemented!("Not required in this test");
2847 }
2848
2849 fn text_size(
2850 &self,
2851 _text_item: Pin<&dyn crate::item_rendering::RenderString>,
2852 _item_rc: &crate::item_tree::ItemRc,
2853 _max_width: Option<crate::lengths::LogicalLength>,
2854 _text_wrap: crate::items::TextWrap,
2855 ) -> crate::lengths::LogicalSize {
2856 unimplemented!("Not required in this test");
2857 }
2858
2859 fn window_adapter(&self) -> Option<std::rc::Rc<dyn crate::window::WindowAdapter>> {
2860 unimplemented!("Not required in this test");
2861 }
2862 }
2863}