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 ensure_instantiated: extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>) -> bool,
111
112 pub item_geometry:
114 extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, item_index: u32) -> LogicalRect,
115
116 pub accessible_role:
118 extern "C" fn(::core::pin::Pin<VRef<ItemTreeVTable>>, item_index: u32) -> AccessibleRole,
119
120 pub accessible_string_property: extern "C" fn(
122 ::core::pin::Pin<VRef<ItemTreeVTable>>,
123 item_index: u32,
124 what: AccessibleStringProperty,
125 result: &mut SharedString,
126 ) -> bool,
127
128 pub accessibility_action: extern "C" fn(
130 ::core::pin::Pin<VRef<ItemTreeVTable>>,
131 item_index: u32,
132 action: &AccessibilityAction,
133 ),
134
135 pub supported_accessibility_actions: extern "C" fn(
137 ::core::pin::Pin<VRef<ItemTreeVTable>>,
138 item_index: u32,
139 ) -> SupportedAccessibilityAction,
140
141 pub item_element_infos: extern "C" fn(
143 ::core::pin::Pin<VRef<ItemTreeVTable>>,
144 item_index: u32,
145 result: &mut SharedString,
146 ) -> bool,
147
148 pub window_adapter: extern "C" fn(
150 ::core::pin::Pin<VRef<ItemTreeVTable>>,
151 do_create: bool,
152 result: &mut Option<WindowAdapterRc>,
153 ),
154
155 pub drop_in_place: unsafe extern "C" fn(VRefMut<ItemTreeVTable>) -> vtable::Layout,
157
158 pub dealloc: unsafe extern "C" fn(&ItemTreeVTable, ptr: *mut u8, layout: vtable::Layout),
160}
161
162#[cfg(test)]
163pub(crate) use ItemTreeVTable_static;
164
165pub type ItemTreeRef<'a> = vtable::VRef<'a, ItemTreeVTable>;
168
169pub type ItemTreeRefPin<'a> = core::pin::Pin<ItemTreeRef<'a>>;
171
172pub type ItemTreeRc = vtable::VRc<ItemTreeVTable, Dyn>;
174pub type ItemTreeWeak = vtable::VWeak<ItemTreeVTable, Dyn>;
176
177pub fn ensure_item_tree_instantiated(item_tree: &vtable::VRc<ItemTreeVTable>) -> bool {
182 vtable::VRc::borrow_pin(item_tree).as_ref().ensure_instantiated()
183}
184
185pub fn register_item_tree(item_tree_rc: &ItemTreeRc, window_adapter: Option<WindowAdapterRc>) {
187 let c = vtable::VRc::borrow_pin(item_tree_rc);
188 let item_tree = c.as_ref().get_item_tree();
189 item_tree.iter().enumerate().for_each(|(tree_index, node)| {
190 let tree_index = tree_index as u32;
191 if let ItemTreeNode::Item { .. } = &node {
192 let item = ItemRc::new(item_tree_rc.clone(), tree_index);
193 c.as_ref().get_item_ref(tree_index).as_ref().init(&item);
194 }
195 });
196 if let Some(adapter) = window_adapter.as_ref().and_then(|a| a.internal(crate::InternalToken)) {
197 adapter.register_item_tree(ItemTreeRc::borrow_pin(item_tree_rc));
198 }
199}
200
201pub fn unregister_item_tree<Base>(
207 base: core::pin::Pin<&Base>,
208 item_tree: ItemTreeRef,
209 item_array: &[vtable::VOffset<Base, ItemVTable, vtable::AllowPin>],
210 window_adapter: &WindowAdapterRc,
211) {
212 fn unregister_item_tree_impl(
215 item_tree: ItemTreeRef,
216 items_to_deinit: &mut dyn Iterator<Item = Pin<ItemRef<'_>>>,
217 items_to_free: &mut dyn Iterator<Item = Pin<ItemRef<'_>>>,
218 items_to_unregister: &mut dyn Iterator<Item = Pin<ItemRef<'_>>>,
219 window_adapter: &WindowAdapterRc,
220 ) {
221 items_to_deinit.for_each(|item| item.as_ref().deinit(window_adapter));
222 window_adapter.renderer().free_graphics_resources(item_tree, items_to_free).expect(
223 "Fatal error encountered when freeing graphics resources while destroying Slint component",
224 );
225
226 if let Some(w) = window_adapter.internal(crate::InternalToken) {
227 w.unregister_item_tree(item_tree, items_to_unregister);
228 }
229
230 let window_inner = crate::window::WindowInner::from_pub(window_adapter.window());
232 let to_close_popups = window_inner
233 .active_popups()
234 .iter()
235 .filter_map(|p| p.parent_item.upgrade().is_none().then_some(p.popup_id))
236 .collect::<Vec<_>>();
237 for popup_id in to_close_popups {
238 window_inner.close_popup(popup_id);
239 }
240 }
241
242 let items = || item_array.iter().map(|item| item.apply_pin(base));
243 unregister_item_tree_impl(item_tree, &mut items(), &mut items(), &mut items(), window_adapter)
244}
245
246fn find_sibling_outside_repeater(
247 component: &ItemTreeRc,
248 comp_ref_pin: Pin<VRef<ItemTreeVTable>>,
249 index: u32,
250 sibling_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
251 subtree_child: &dyn Fn(usize, usize) -> usize,
252) -> Option<ItemRc> {
253 assert_ne!(index, 0);
254
255 let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
256
257 let mut current_sibling = index;
258 loop {
259 current_sibling = sibling_step(&item_tree, current_sibling)?;
260
261 if let Some(node) = step_into_node(
262 component,
263 &comp_ref_pin,
264 current_sibling,
265 &item_tree,
266 subtree_child,
267 &core::convert::identity,
268 ) {
269 return Some(node);
270 }
271 }
272}
273
274fn step_into_node(
275 component: &ItemTreeRc,
276 comp_ref_pin: &Pin<VRef<ItemTreeVTable>>,
277 node_index: u32,
278 item_tree: &crate::item_tree::ItemTreeNodeArray,
279 subtree_child: &dyn Fn(usize, usize) -> usize,
280 wrap_around: &dyn Fn(ItemRc) -> ItemRc,
281) -> Option<ItemRc> {
282 match item_tree.get(node_index).expect("Invalid index passed to item tree") {
283 crate::item_tree::ItemTreeNode::Item { .. } => {
284 Some(ItemRc::new(component.clone(), node_index))
285 }
286 crate::item_tree::ItemTreeNode::DynamicTree { index, .. } => {
287 let range = comp_ref_pin.as_ref().get_subtree_range(*index);
288 let component_index = subtree_child(range.start, range.end);
289 let mut child_instance = Default::default();
290 comp_ref_pin.as_ref().get_subtree(*index, component_index, &mut child_instance);
291 child_instance
292 .upgrade()
293 .map(|child_instance| wrap_around(ItemRc::new_root(child_instance)))
294 }
295 }
296}
297
298pub enum ParentItemTraversalMode {
299 FindAllParents,
300 StopAtPopups,
301}
302
303#[repr(C)]
305#[derive(Clone)]
306pub struct ItemRc {
307 item_tree: vtable::VRc<ItemTreeVTable>,
308 index: u32,
309}
310
311impl core::fmt::Debug for ItemRc {
312 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
313 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
314 let mut debug = SharedString::new();
315 comp_ref_pin.as_ref().item_element_infos(self.index, &mut debug);
316
317 write!(f, "ItemRc{{ {:p}, {:?} {debug}}}", comp_ref_pin.as_ptr(), self.index)
318 }
319}
320
321impl ItemRc {
322 pub fn new(item_tree: vtable::VRc<ItemTreeVTable>, index: u32) -> Self {
324 Self { item_tree, index }
325 }
326
327 pub fn new_root(item_tree: vtable::VRc<ItemTreeVTable>) -> Self {
328 Self { item_tree, index: Self::root_index() }
329 }
330
331 #[inline(always)]
332 pub const fn root_index() -> u32 {
333 0
334 }
335
336 #[inline(always)]
337 pub fn is_root(&self) -> bool {
338 self.index == Self::root_index()
339 }
340
341 pub fn is_root_item_of(&self, item_tree: &VRc<ItemTreeVTable>) -> bool {
343 self.is_root() && VRc::ptr_eq(&self.item_tree, item_tree)
344 }
345
346 pub fn borrow<'a>(&'a self) -> Pin<ItemRef<'a>> {
348 #![allow(unsafe_code)]
349 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
350 let result = comp_ref_pin.as_ref().get_item_ref(self.index);
351 unsafe { core::mem::transmute::<Pin<ItemRef<'_>>, Pin<ItemRef<'a>>>(result) }
354 }
355
356 pub fn downcast<T: HasStaticVTable<ItemVTable>>(&self) -> Option<VRcMapped<ItemTreeVTable, T>> {
358 #![allow(unsafe_code)]
359 let item = self.borrow();
360 ItemRef::downcast_pin::<T>(item)?;
361
362 Some(vtable::VRc::map_dyn(self.item_tree.clone(), |comp_ref_pin| {
363 let result = comp_ref_pin.as_ref().get_item_ref(self.index);
364 let item =
367 unsafe { core::mem::transmute::<Pin<ItemRef<'_>>, Pin<ItemRef<'_>>>(result) };
368 ItemRef::downcast_pin::<T>(item).unwrap()
369 }))
370 }
371
372 pub fn downgrade(&self) -> ItemWeak {
373 ItemWeak { item_tree: VRc::downgrade(&self.item_tree), index: self.index }
374 }
375
376 pub fn parent_item(&self, find_mode: ParentItemTraversalMode) -> Option<ItemRc> {
380 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
381 let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
382
383 if let Some(parent_index) = item_tree.parent(self.index) {
384 return Some(ItemRc::new(self.item_tree.clone(), parent_index));
385 }
386
387 let mut r = ItemWeak::default();
389 comp_ref_pin.as_ref().parent_node(&mut r);
390 let parent = r.upgrade()?;
391 let comp_ref_pin = vtable::VRc::borrow_pin(&parent.item_tree);
392 let item_tree_array = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
393 if let Some(ItemTreeNode::DynamicTree { parent_index, .. }) =
394 item_tree_array.get(parent.index())
395 {
396 Some(ItemRc::new(parent.item_tree.clone(), *parent_index))
398 } else {
399 match find_mode {
402 ParentItemTraversalMode::FindAllParents => Some(parent),
403 ParentItemTraversalMode::StopAtPopups => None,
404 }
405 }
406 }
407
408 pub fn is_visible(&self) -> bool {
411 let (clip, geometry) = self.absolute_clip_rect_and_geometry();
412 let clip = clip.to_box2d();
413 let geometry = geometry.to_box2d();
414 !clip.is_empty()
415 && clip.max.x >= geometry.min.x
416 && clip.max.y >= geometry.min.y
417 && clip.min.x <= geometry.max.x
418 && clip.min.y <= geometry.max.y
419 }
420
421 pub(crate) fn visibility_clips(&self) -> Vec<VWeakMapped<ItemTreeVTable, crate::items::Clip>> {
422 let mut visibility_clips = Vec::new();
423 let mut current = Some(self.clone());
424 while let Some(item) = current {
425 if let Some(clip) = item.downcast::<crate::items::Clip>()
426 && clip.as_pin_ref().is_visibility_clip()
427 {
428 visibility_clips.push(VRcMapped::downgrade(&clip));
429 }
430 current = item.parent_item(ParentItemTraversalMode::StopAtPopups);
431 }
432 visibility_clips
433 }
434
435 pub(crate) fn is_visible_or_clipped_by_flickable(&self) -> bool {
437 if self.is_visible() {
438 return true;
439 }
440
441 let geometry = self.absolute_clip_rect_and_geometry().1.to_box2d();
445 let mut parent = self.parent_item(ParentItemTraversalMode::StopAtPopups);
446 while let Some(ancestor) = parent {
447 if ancestor.borrow().as_ref().clips_children() {
448 let (clip, ancestor_geo) = ancestor.absolute_clip_rect_and_geometry();
449 let clip = ancestor_geo.intersection(&clip).unwrap_or_default().to_box2d();
450 let item_in_clip = !clip.is_empty()
451 && clip.max.x >= geometry.min.x
452 && clip.max.y >= geometry.min.y
453 && clip.min.x <= geometry.max.x
454 && clip.min.y <= geometry.max.y;
455 if !item_in_clip {
456 return ancestor.downcast::<crate::items::Flickable>().is_some()
457 && ancestor.is_visible_or_clipped_by_flickable();
458 }
459 }
460 parent = ancestor.parent_item(ParentItemTraversalMode::StopAtPopups);
461 }
462
463 false
464 }
465
466 fn local_to_window_transform(&self, stop_condition: impl Fn(&Self) -> bool) -> ItemTransform {
474 let supports_transformations = self
475 .window_adapter()
476 .is_none_or(|adapter| adapter.renderer().supports_transformations());
477 let mut transform = ItemTransform::identity();
478 let mut current = self.clone();
479 while let Some(parent) = current.parent_item(ParentItemTraversalMode::StopAtPopups) {
480 if stop_condition(&parent) {
481 break;
482 }
483 transform = transform.then(&parent.step_transform(supports_transformations));
484 current = parent;
485 }
486 transform
487 }
488
489 fn step_transform(&self, supports_transformations: bool) -> ItemTransform {
492 let origin = self.geometry().origin.to_vector().cast();
493 let mut step = ItemTransform::translation(origin.x, origin.y);
494 if supports_transformations && let Some(children_transform) = self.children_transform() {
495 step = children_transform.then(&step);
496 }
497 step
498 }
499
500 fn absolute_clip_rect_and_geometry(&self) -> (LogicalRect, LogicalRect) {
503 let supports_transformations = self
504 .window_adapter()
505 .is_none_or(|adapter| adapter.renderer().supports_transformations());
506
507 let mut ancestors = Vec::new();
508 let mut cur = self.parent_item(ParentItemTraversalMode::StopAtPopups);
509 while let Some(ancestor) = cur {
510 cur = ancestor.parent_item(ParentItemTraversalMode::StopAtPopups);
511 ancestors.push(ancestor);
512 }
513
514 let mut clip = LogicalRect::from_size((crate::Coord::MAX, crate::Coord::MAX).into());
517 let mut transform = ItemTransform::identity();
518 for ancestor in ancestors.iter().rev() {
519 if ancestor.borrow().as_ref().clips_children() {
520 let ancestor_geom =
521 transform.outer_transformed_rect(&ancestor.geometry().cast()).cast();
522 clip = ancestor_geom.intersection(&clip).unwrap_or_default();
523 }
524 transform = ancestor.step_transform(supports_transformations).then(&transform);
525 }
526
527 let geometry = transform.outer_transformed_rect(&self.geometry().cast()).cast();
528
529 (clip, geometry)
530 }
531
532 pub fn is_accessible(&self) -> bool {
533 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
534 let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
535
536 if let Some(n) = &item_tree.get(self.index) {
537 match n {
538 ItemTreeNode::Item { is_accessible, .. } => *is_accessible,
539 ItemTreeNode::DynamicTree { .. } => false,
540 }
541 } else {
542 false
543 }
544 }
545
546 pub fn accessible_role(&self) -> crate::items::AccessibleRole {
547 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
548 comp_ref_pin.as_ref().accessible_role(self.index)
549 }
550
551 pub fn accessible_string_property(
552 &self,
553 what: crate::accessibility::AccessibleStringProperty,
554 ) -> Option<SharedString> {
555 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
556 let mut result = Default::default();
557 let ok = comp_ref_pin.as_ref().accessible_string_property(self.index, what, &mut result);
558 ok.then_some(result)
559 }
560
561 pub fn accessible_action(&self, action: &crate::accessibility::AccessibilityAction) {
562 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
563 comp_ref_pin.as_ref().accessibility_action(self.index, action);
564 }
565
566 pub fn supported_accessibility_actions(&self) -> SupportedAccessibilityAction {
567 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
568 comp_ref_pin.as_ref().supported_accessibility_actions(self.index)
569 }
570
571 fn raw_element_infos(&self) -> Option<SharedString> {
573 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
574 let mut result = SharedString::new();
575 comp_ref_pin.as_ref().item_element_infos(self.index, &mut result).then_some(result)
576 }
577
578 pub fn element_count(&self) -> Option<usize> {
579 self.raw_element_infos().map(|s| s.as_str().split("/").count())
580 }
581
582 pub fn element_type_names_and_ids(
583 &self,
584 element_index: usize,
585 ) -> Option<Vec<(SharedString, SharedString)>> {
586 self.raw_element_infos().map(|infos| {
587 infos
588 .as_str()
589 .split("/")
590 .nth(element_index)
591 .unwrap()
592 .split(";")
593 .map(|encoded_elem_info| {
594 let mut decoder = encoded_elem_info.split(',');
595 let type_name = decoder.next().unwrap().into();
596 let id = decoder.next().map(Into::into).unwrap_or_default();
597 (type_name, id)
598 })
599 .collect()
600 })
601 }
602
603 pub fn element_layout_kind(&self, element_index: usize) -> Option<SharedString> {
604 self.raw_element_infos().and_then(|infos| {
605 let first_debug_entry =
606 infos.as_str().split("/").nth(element_index)?.split(';').next()?;
607 let mut decoder = first_debug_entry.split(',');
608 let _type_name = decoder.next();
609 let _id = decoder.next();
610 decoder.next().filter(|s| !s.is_empty()).map(SharedString::from)
611 })
612 }
613
614 pub fn geometry(&self) -> LogicalRect {
615 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
616 comp_ref_pin.as_ref().item_geometry(self.index)
617 }
618
619 pub fn bounding_rect(
622 &self,
623 geometry: &LogicalRect,
624 window_adapter: &WindowAdapterRc,
625 ) -> LogicalRect {
626 self.borrow().as_ref().bounding_rect(window_adapter, self, *geometry)
627 }
628
629 pub fn map_to_native_window(&self, p: LogicalPoint) -> LogicalPoint {
633 let mut pos = self.map_to_item_tree_impl(p, |_| false);
634 if let Some(window_adapter) = self.window_adapter() {
636 let window_inner = crate::window::WindowInner::from_pub(window_adapter.window());
637 let active_popups = window_inner.active_popups();
638 for popup in active_popups.iter() {
639 if let crate::window::PopupWindowLocation::ChildWindow(location) = &popup.location {
640 let popup_item = ItemRc::new_root(popup.component.clone());
641
642 if popup_item.is_root_item_of(self.item_tree()) {
645 pos += location.to_vector();
646 } else {
647 let mut current = ItemRc::new_root(self.item_tree.clone());
648 while let Some(parent) =
650 current.parent_item(ParentItemTraversalMode::StopAtPopups)
651 {
652 if popup_item.is_root_item_of(parent.item_tree()) {
653 pos += location.to_vector();
654 break;
655 }
656
657 current = ItemRc::new_root(parent.item_tree);
659 }
660 }
661 }
662 }
663 }
664 pos
665 }
666
667 pub fn map_to_window(&self, p: LogicalPoint) -> LogicalPoint {
670 self.map_to_item_tree_impl(p, |_| false)
671 }
672
673 pub fn map_to_item_tree(
676 &self,
677 p: LogicalPoint,
678 item_tree: &vtable::VRc<ItemTreeVTable>,
679 ) -> LogicalPoint {
680 self.transform_to_item_tree(item_tree).transform_point(p.cast()).cast()
681 }
682
683 pub fn transform_to_item_tree(&self, item_tree: &vtable::VRc<ItemTreeVTable>) -> ItemTransform {
689 self.transform_to_ancestor_impl(|current| current.is_root_item_of(item_tree))
690 }
691
692 fn map_to_ancestor(&self, p: LogicalPoint, ancestor: &Self) -> LogicalPoint {
696 self.map_to_item_tree_impl(p, |parent| parent == ancestor)
697 }
698
699 fn map_to_item_tree_impl(
700 &self,
701 p: LogicalPoint,
702 stop_condition: impl Fn(&Self) -> bool,
703 ) -> LogicalPoint {
704 self.transform_to_ancestor_impl(stop_condition).transform_point(p.cast()).cast()
705 }
706
707 fn transform_to_ancestor_impl(&self, stop_condition: impl Fn(&Self) -> bool) -> ItemTransform {
708 if stop_condition(self) {
709 return ItemTransform::identity();
710 }
711 self.local_to_window_transform(stop_condition)
712 }
713
714 pub fn index(&self) -> u32 {
716 self.index
717 }
718 pub fn item_tree(&self) -> &vtable::VRc<ItemTreeVTable> {
720 &self.item_tree
721 }
722
723 fn find_child(
725 &self,
726 child_access: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
727 child_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
728 subtree_child: &dyn Fn(usize, usize) -> usize,
729 ) -> Option<Self> {
730 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
731 let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
732
733 let mut current_child_index = child_access(&item_tree, self.index())?;
734 loop {
735 if let Some(item) = step_into_node(
736 self.item_tree(),
737 &comp_ref_pin,
738 current_child_index,
739 &item_tree,
740 subtree_child,
741 &core::convert::identity,
742 ) {
743 return Some(item);
744 }
745 current_child_index = child_step(&item_tree, current_child_index)?;
746 }
747 }
748
749 pub fn first_child(&self) -> Option<Self> {
751 self.find_child(
752 &|item_tree, index| item_tree.first_child(index),
753 &|item_tree, index| item_tree.next_sibling(index),
754 &|start, _| start,
755 )
756 }
757
758 pub fn last_child(&self) -> Option<Self> {
760 self.find_child(
761 &|item_tree, index| item_tree.last_child(index),
762 &|item_tree, index| item_tree.previous_sibling(index),
763 &|_, end| end.wrapping_sub(1),
764 )
765 }
766
767 fn find_sibling(
768 &self,
769 sibling_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
770 subtree_step: &dyn Fn(usize) -> usize,
771 subtree_child: &dyn Fn(usize, usize) -> usize,
772 ) -> Option<Self> {
773 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
774 if self.is_root() {
775 let mut parent_item = Default::default();
776 comp_ref_pin.as_ref().parent_node(&mut parent_item);
777 let current_component_subtree_index = comp_ref_pin.as_ref().subtree_index();
778 if let Some(parent_item) = parent_item.upgrade() {
779 let parent = parent_item.item_tree();
780 let parent_ref_pin = vtable::VRc::borrow_pin(parent);
781 let parent_item_index = parent_item.index();
782 let parent_item_tree = crate::item_tree::ItemTreeNodeArray::new(&parent_ref_pin);
783
784 let subtree_index = match parent_item_tree.get(parent_item_index)? {
785 crate::item_tree::ItemTreeNode::Item { .. } => {
786 return None;
788 }
789 crate::item_tree::ItemTreeNode::DynamicTree { index, .. } => *index,
790 };
791
792 let next_subtree_index = subtree_step(current_component_subtree_index);
793
794 let mut next_subtree_instance = Default::default();
796 parent_ref_pin.as_ref().get_subtree(
797 subtree_index,
798 next_subtree_index,
799 &mut next_subtree_instance,
800 );
801 if let Some(next_subtree_instance) = next_subtree_instance.upgrade() {
802 return Some(ItemRc::new_root(next_subtree_instance));
803 }
804
805 find_sibling_outside_repeater(
807 parent,
808 parent_ref_pin,
809 parent_item_index,
810 sibling_step,
811 subtree_child,
812 )
813 } else {
814 None }
816 } else {
817 find_sibling_outside_repeater(
818 self.item_tree(),
819 comp_ref_pin,
820 self.index(),
821 sibling_step,
822 subtree_child,
823 )
824 }
825 }
826
827 pub fn previous_sibling(&self) -> Option<Self> {
829 self.find_sibling(
830 &|item_tree, index| item_tree.previous_sibling(index),
831 &|index| index.wrapping_sub(1),
832 &|_, end| end.wrapping_sub(1),
833 )
834 }
835
836 pub fn next_sibling(&self) -> Option<Self> {
838 self.find_sibling(
839 &|item_tree, index| item_tree.next_sibling(index),
840 &|index| index.saturating_add(1),
841 &|start, _| start,
842 )
843 }
844
845 fn move_focus(
846 &self,
847 focus_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
848 subtree_step: &dyn Fn(ItemRc) -> Option<ItemRc>,
849 subtree_child: &dyn Fn(usize, usize) -> usize,
850 step_in: &dyn Fn(ItemRc) -> ItemRc,
851 step_out: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
852 ) -> Self {
853 let mut component = self.item_tree().clone();
854 let mut comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
855 let mut item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
856
857 let mut to_focus = self.index();
858
859 'in_tree: loop {
860 if let Some(next) = focus_step(&item_tree, to_focus) {
861 if let Some(item) = step_into_node(
862 &component,
863 &comp_ref_pin,
864 next,
865 &item_tree,
866 subtree_child,
867 step_in,
868 ) {
869 return item;
870 }
871 to_focus = next;
872 } else {
874 let mut root = ItemRc::new_root(component);
876 if let Some(item) = subtree_step(root.clone()) {
877 return step_in(item);
879 }
880
881 let root_component = root.item_tree();
883 let root_comp_ref = vtable::VRc::borrow_pin(root_component);
884 let mut parent_node = Default::default();
885 root_comp_ref.as_ref().parent_node(&mut parent_node);
886
887 while let Some(parent) = parent_node.upgrade() {
888 component = parent.item_tree().clone();
890 comp_ref_pin = vtable::VRc::borrow_pin(&component);
891 item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
892
893 let index = parent.index();
894
895 if !matches!(item_tree.get(index), Some(ItemTreeNode::DynamicTree { .. })) {
896 break;
898 }
899
900 if let Some(next) = step_out(&item_tree, index) {
901 if let Some(item) = step_into_node(
902 parent.item_tree(),
903 &comp_ref_pin,
904 next,
905 &item_tree,
906 subtree_child,
907 step_in,
908 ) {
909 return item;
911 } else {
912 to_focus = parent.index();
914 continue 'in_tree; }
916 }
917
918 root = ItemRc::new_root(component.clone());
919 if let Some(item) = subtree_step(root.clone()) {
920 return step_in(item);
921 }
922
923 let root_component = root.item_tree();
925 let root_comp_ref = vtable::VRc::borrow_pin(root_component);
926 parent_node = Default::default();
927 root_comp_ref.as_ref().parent_node(&mut parent_node);
928 }
929
930 return step_in(root);
932 }
933 }
934 }
935
936 pub fn previous_focus_item(&self) -> Self {
938 self.move_focus(
939 &|item_tree, index| {
940 crate::item_focus::default_previous_in_local_focus_chain(index, item_tree)
941 },
942 &|root| root.previous_sibling(),
943 &|_, end| end.wrapping_sub(1),
944 &|root| {
945 let mut current = root;
946 loop {
947 if let Some(next) = current.last_child() {
948 current = next;
949 } else {
950 return current;
951 }
952 }
953 },
954 &|item_tree, index| item_tree.parent(index),
955 )
956 }
957
958 pub fn next_focus_item(&self) -> Self {
960 self.move_focus(
961 &|item_tree, index| {
962 crate::item_focus::default_next_in_local_focus_chain(index, item_tree)
963 },
964 &|root| root.next_sibling(),
965 &|start, _| start,
966 &core::convert::identity,
967 &|item_tree, index| crate::item_focus::step_out_of_node(index, item_tree),
968 )
969 }
970
971 pub fn window_adapter(&self) -> Option<WindowAdapterRc> {
972 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
973 let mut result = None;
974 comp_ref_pin.as_ref().window_adapter(false, &mut result);
975 result
976 }
977
978 fn visit_descendants_impl<R>(
981 &self,
982 visitor: &mut impl FnMut(&ItemRc) -> ControlFlow<R>,
983 ) -> Option<R> {
984 let mut result = None;
985
986 let mut actual_visitor = |item_tree: &ItemTreeRc,
987 index: u32,
988 _item_pin: core::pin::Pin<ItemRef>|
989 -> VisitChildrenResult {
990 let item_rc = ItemRc::new(item_tree.clone(), index);
991
992 match visitor(&item_rc) {
993 ControlFlow::Continue(_) => {
994 if let Some(x) = item_rc.visit_descendants_impl(visitor) {
995 result = Some(x);
996 return VisitChildrenResult::abort(index, 0);
997 }
998 }
999 ControlFlow::Break(x) => {
1000 result = Some(x);
1001 return VisitChildrenResult::abort(index, 0);
1002 }
1003 }
1004
1005 VisitChildrenResult::CONTINUE
1006 };
1007 vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);
1008
1009 VRc::borrow_pin(self.item_tree()).as_ref().visit_children_item(
1010 self.index() as isize,
1011 TraversalOrder::BackToFront,
1012 actual_visitor,
1013 );
1014
1015 result
1016 }
1017
1018 pub fn visit_descendants<R>(
1028 &self,
1029 mut visitor: impl FnMut(&ItemRc) -> ControlFlow<R>,
1030 ) -> Option<R> {
1031 ensure_item_tree_instantiated(self.item_tree());
1032 self.visit_descendants_impl(&mut visitor)
1033 }
1034
1035 pub fn children_transform(&self) -> Option<ItemTransform> {
1038 self.downcast::<crate::items::Transform>().map(|transform_item| {
1039 let item = transform_item.as_pin_ref();
1040 let origin = item.transform_origin().to_euclid().to_vector().cast::<f32>();
1041 ItemTransform::translation(-origin.x, -origin.y)
1042 .cast()
1043 .then_scale(item.transform_scale_x(), item.transform_scale_y())
1044 .then_rotate(euclid::Angle { radians: item.transform_rotation().to_radians() })
1045 .then_translate(origin)
1046 })
1047 }
1048
1049 pub fn inverse_children_transform(&self) -> Option<ItemTransform> {
1054 self.children_transform()
1055 .and_then(|child_transform| child_transform.inverse())
1057 }
1058
1059 pub(crate) fn try_scroll_into_visible(&self) {
1060 let mut parent = self.parent_item(ParentItemTraversalMode::StopAtPopups);
1061 while let Some(item_rc) = parent.as_ref() {
1062 let item_ref = item_rc.borrow();
1063 if let Some(flickable) = vtable::VRef::downcast_pin::<crate::items::Flickable>(item_ref)
1064 {
1065 let geo = self.geometry();
1066
1067 flickable.reveal_points(
1068 item_rc,
1069 &[
1070 self.map_to_ancestor(
1071 LogicalPoint::new(
1072 geo.origin.x - flickable.content_x().0,
1073 geo.origin.y - flickable.content_y().0,
1074 ),
1075 item_rc,
1076 ),
1077 self.map_to_ancestor(
1078 LogicalPoint::new(
1079 geo.max_x() - flickable.content_x().0,
1080 geo.max_y() - flickable.content_y().0,
1081 ),
1082 item_rc,
1083 ),
1084 ],
1085 );
1086 }
1087
1088 parent = item_rc.parent_item(ParentItemTraversalMode::StopAtPopups);
1089 }
1090 }
1091}
1092
1093impl PartialEq for ItemRc {
1094 fn eq(&self, other: &Self) -> bool {
1095 VRc::ptr_eq(&self.item_tree, &other.item_tree) && self.index == other.index
1096 }
1097}
1098
1099impl Eq for ItemRc {}
1100
1101#[derive(Clone, Default)]
1103#[repr(C)]
1104pub struct ItemWeak {
1105 item_tree: crate::item_tree::ItemTreeWeak,
1106 index: u32,
1107}
1108
1109impl ItemWeak {
1110 pub fn upgrade(&self) -> Option<ItemRc> {
1111 self.item_tree.upgrade().map(|c| ItemRc::new(c, self.index))
1112 }
1113}
1114
1115impl PartialEq for ItemWeak {
1116 fn eq(&self, other: &Self) -> bool {
1117 VWeak::ptr_eq(&self.item_tree, &other.item_tree) && self.index == other.index
1118 }
1119}
1120
1121impl Eq for ItemWeak {}
1122
1123#[repr(u8)]
1124#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1125pub enum TraversalOrder {
1126 BackToFront,
1127 FrontToBack,
1128}
1129
1130#[repr(transparent)]
1139#[derive(Copy, Clone, Eq, PartialEq)]
1140pub struct VisitChildrenResult(u64);
1141impl VisitChildrenResult {
1142 pub const CONTINUE: Self = Self(u64::MAX);
1144
1145 pub fn abort(item_index: u32, index_within_repeater: usize) -> Self {
1147 assert!(index_within_repeater < u32::MAX as usize);
1148 Self(item_index as u64 | (index_within_repeater as u64) << 32)
1149 }
1150 pub fn has_aborted(&self) -> bool {
1152 self.0 != Self::CONTINUE.0
1153 }
1154 pub fn aborted_index(&self) -> Option<usize> {
1155 if self.0 != Self::CONTINUE.0 { Some((self.0 & 0xffff_ffff) as usize) } else { None }
1156 }
1157 pub fn aborted_indexes(&self) -> Option<(usize, usize)> {
1158 if self.0 != Self::CONTINUE.0 {
1159 Some(((self.0 & 0xffff_ffff) as usize, (self.0 >> 32) as usize))
1160 } else {
1161 None
1162 }
1163 }
1164}
1165impl core::fmt::Debug for VisitChildrenResult {
1166 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1167 if self.0 == Self::CONTINUE.0 {
1168 write!(f, "CONTINUE")
1169 } else {
1170 write!(f, "({},{})", (self.0 & 0xffff_ffff) as usize, (self.0 >> 32) as usize)
1171 }
1172 }
1173}
1174
1175#[repr(u8)]
1178#[derive(Debug)]
1179pub enum ItemTreeNode {
1180 Item {
1182 is_accessible: bool,
1184
1185 children_count: u32,
1187
1188 children_index: u32,
1190
1191 parent_index: u32,
1193
1194 item_array_index: u32,
1196 },
1197 DynamicTree {
1200 index: u32,
1202
1203 parent_index: u32,
1205 },
1206}
1207
1208impl ItemTreeNode {
1209 pub fn parent_index(&self) -> u32 {
1210 match self {
1211 ItemTreeNode::Item { parent_index, .. } => *parent_index,
1212 ItemTreeNode::DynamicTree { parent_index, .. } => *parent_index,
1213 }
1214 }
1215}
1216
1217pub struct ItemTreeNodeArray<'a> {
1220 node_array: &'a [ItemTreeNode],
1221}
1222
1223impl<'a> ItemTreeNodeArray<'a> {
1224 pub fn new(comp_ref_pin: &'a Pin<VRef<'a, ItemTreeVTable>>) -> Self {
1226 Self { node_array: comp_ref_pin.as_ref().get_item_tree().as_slice() }
1227 }
1228
1229 pub fn get(&self, index: u32) -> Option<&ItemTreeNode> {
1231 self.node_array.get(index as usize)
1232 }
1233
1234 pub fn parent(&self, index: u32) -> Option<u32> {
1236 let index = index as usize;
1237 (index < self.node_array.len() && index != ItemRc::root_index() as usize)
1238 .then(|| self.node_array[index].parent_index())
1239 }
1240
1241 pub fn next_sibling(&self, index: u32) -> Option<u32> {
1243 if let Some(parent_index) = self.parent(index) {
1244 match self.node_array[parent_index as usize] {
1245 ItemTreeNode::Item { children_index, children_count, .. } => {
1246 (index < (children_count + children_index - 1)).then_some(index + 1)
1247 }
1248 ItemTreeNode::DynamicTree { .. } => {
1249 unreachable!("Parent in same item tree is a repeater.")
1250 }
1251 }
1252 } else {
1253 None }
1255 }
1256
1257 pub fn previous_sibling(&self, index: u32) -> Option<u32> {
1259 if let Some(parent_index) = self.parent(index) {
1260 match self.node_array[parent_index as usize] {
1261 ItemTreeNode::Item { children_index, .. } => {
1262 (index > children_index).then_some(index - 1)
1263 }
1264 ItemTreeNode::DynamicTree { .. } => {
1265 unreachable!("Parent in same item tree is a repeater.")
1266 }
1267 }
1268 } else {
1269 None }
1271 }
1272
1273 pub fn first_child(&self, index: u32) -> Option<u32> {
1276 match self.node_array.get(index as usize)? {
1277 ItemTreeNode::Item { children_index, children_count, .. } => {
1278 (*children_count != 0).then_some(*children_index as _)
1279 }
1280 ItemTreeNode::DynamicTree { .. } => None,
1281 }
1282 }
1283
1284 pub fn last_child(&self, index: u32) -> Option<u32> {
1287 match self.node_array.get(index as usize)? {
1288 ItemTreeNode::Item { children_index, children_count, .. } => {
1289 if *children_count != 0 {
1290 Some(*children_index + *children_count - 1)
1291 } else {
1292 None
1293 }
1294 }
1295 ItemTreeNode::DynamicTree { .. } => None,
1296 }
1297 }
1298
1299 pub fn node_count(&self) -> usize {
1301 self.node_array.len()
1302 }
1303}
1304
1305impl<'a> From<&'a [ItemTreeNode]> for ItemTreeNodeArray<'a> {
1306 fn from(item_tree: &'a [ItemTreeNode]) -> Self {
1307 Self { node_array: item_tree }
1308 }
1309}
1310
1311#[cfg_attr(not(feature = "ffi"), i_slint_core_macros::remove_extern)]
1312#[vtable]
1313#[repr(C)]
1314pub struct ItemVisitorVTable {
1316 visit_item: extern "C" fn(
1323 VRefMut<ItemVisitorVTable>,
1324 item_tree: &VRc<ItemTreeVTable, vtable::Dyn>,
1325 index: u32,
1326 item: Pin<VRef<ItemVTable>>,
1327 ) -> VisitChildrenResult,
1328 drop: extern "C" fn(VRefMut<ItemVisitorVTable>),
1330}
1331
1332pub type ItemVisitorRefMut<'a> = vtable::VRefMut<'a, ItemVisitorVTable>;
1334
1335impl<T: FnMut(&ItemTreeRc, u32, Pin<ItemRef>) -> VisitChildrenResult> ItemVisitor for T {
1336 fn visit_item(
1337 &mut self,
1338 item_tree: &ItemTreeRc,
1339 index: u32,
1340 item: Pin<ItemRef>,
1341 ) -> VisitChildrenResult {
1342 self(item_tree, index, item)
1343 }
1344}
1345pub enum ItemVisitorResult<State> {
1346 Continue(State),
1347 SkipChildren,
1348 Abort,
1349}
1350
1351pub fn visit_items<State>(
1357 item_tree: &ItemTreeRc,
1358 order: TraversalOrder,
1359 mut visitor: impl FnMut(&ItemTreeRc, Pin<ItemRef>, u32, &State) -> ItemVisitorResult<State>,
1360 state: State,
1361) -> VisitChildrenResult {
1362 visit_internal(item_tree, order, &mut visitor, -1, &state)
1363}
1364
1365fn visit_internal<State>(
1366 item_tree: &ItemTreeRc,
1367 order: TraversalOrder,
1368 visitor: &mut impl FnMut(&ItemTreeRc, Pin<ItemRef>, u32, &State) -> ItemVisitorResult<State>,
1369 index: isize,
1370 state: &State,
1371) -> VisitChildrenResult {
1372 let mut actual_visitor =
1373 |item_tree: &ItemTreeRc, index: u32, item: Pin<ItemRef>| -> VisitChildrenResult {
1374 match visitor(item_tree, item, index, state) {
1375 ItemVisitorResult::Continue(state) => {
1376 visit_internal(item_tree, order, visitor, index as isize, &state)
1377 }
1378 ItemVisitorResult::SkipChildren => VisitChildrenResult::CONTINUE,
1379 ItemVisitorResult::Abort => VisitChildrenResult::abort(index, 0),
1380 }
1381 };
1382 vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);
1383 VRc::borrow_pin(item_tree).as_ref().visit_children_item(index, order, actual_visitor)
1384}
1385
1386#[derive(Clone, Copy, Debug)]
1389struct ZSortedChild {
1390 z: f32,
1392 child_offset: u32,
1394 instance: Option<u32>,
1398}
1399
1400fn visit_child_at_index(
1403 item_tree: &ItemTreeRc,
1404 item_tree_array: &[ItemTreeNode],
1405 idx: u32,
1406 order: TraversalOrder,
1407 visitor: &mut vtable::VRefMut<ItemVisitorVTable>,
1408 visit_dynamic: &mut dyn FnMut(
1409 TraversalOrder,
1410 vtable::VRefMut<ItemVisitorVTable>,
1411 u32,
1412 ) -> VisitChildrenResult,
1413) -> VisitChildrenResult {
1414 match &item_tree_array[idx as usize] {
1415 ItemTreeNode::Item { .. } => {
1416 let item = crate::items::ItemRc::new(item_tree.clone(), idx);
1417 visitor.visit_item(item_tree, idx, item.borrow())
1418 }
1419 ItemTreeNode::DynamicTree { index, .. } => {
1420 if let Some(sub_idx) =
1421 visit_dynamic(order, visitor.borrow_mut(), *index).aborted_index()
1422 {
1423 VisitChildrenResult::abort(idx, sub_idx)
1424 } else {
1425 VisitChildrenResult::CONTINUE
1426 }
1427 }
1428 }
1429}
1430
1431pub fn visit_item_tree(
1442 item_tree: &ItemTreeRc,
1443 item_tree_array: &[ItemTreeNode],
1444 index: isize,
1445 order: TraversalOrder,
1446 mut visitor: vtable::VRefMut<ItemVisitorVTable>,
1447 visit_dynamic: &mut dyn FnMut(
1448 TraversalOrder,
1449 vtable::VRefMut<ItemVisitorVTable>,
1450 u32,
1451 ) -> VisitChildrenResult,
1452) -> VisitChildrenResult {
1453 if index == -1 {
1454 visit_child_at_index(item_tree, item_tree_array, 0, order, &mut visitor, visit_dynamic)
1455 } else {
1456 match &item_tree_array[index as usize] {
1457 ItemTreeNode::Item { children_index, children_count, .. } => {
1458 for c in 0..*children_count {
1459 let idx = match order {
1460 TraversalOrder::BackToFront => *children_index + c,
1461 TraversalOrder::FrontToBack => *children_index + *children_count - c - 1,
1462 };
1463 let maybe_abort_index = visit_child_at_index(
1464 item_tree,
1465 item_tree_array,
1466 idx,
1467 order,
1468 &mut visitor,
1469 visit_dynamic,
1470 );
1471 if maybe_abort_index.has_aborted() {
1472 return maybe_abort_index;
1473 }
1474 }
1475 }
1476 ItemTreeNode::DynamicTree { .. } => panic!("should not be called with dynamic items"),
1477 };
1478 VisitChildrenResult::CONTINUE
1479 }
1480}
1481
1482pub fn visit_item_tree_z_sorted(
1499 item_tree: &ItemTreeRc,
1500 item_tree_array: &[ItemTreeNode],
1501 index: isize,
1502 order: TraversalOrder,
1503 mut visitor: vtable::VRefMut<ItemVisitorVTable>,
1504 visit_dynamic: &mut dyn FnMut(
1505 TraversalOrder,
1506 vtable::VRefMut<ItemVisitorVTable>,
1507 u32,
1508 ) -> VisitChildrenResult,
1509 collect_z: &mut dyn FnMut(&mut dyn FnMut(u32, Option<u32>, f32)),
1510) -> VisitChildrenResult {
1511 let ItemTreeNode::Item { children_index, children_count, .. } =
1512 &item_tree_array[index as usize]
1513 else {
1514 panic!("should not be called with dynamic items")
1515 };
1516 let mut entries = alloc::vec::Vec::with_capacity(*children_count as usize);
1517 collect_z(&mut |child_offset, instance, z| {
1518 entries.push(ZSortedChild { z, child_offset, instance })
1519 });
1520 entries.sort_unstable_by(|a: &ZSortedChild, b: &ZSortedChild| {
1521 a.z.total_cmp(&b.z)
1522 .then(a.child_offset.cmp(&b.child_offset))
1523 .then(a.instance.cmp(&b.instance))
1524 });
1525 for i in 0..entries.len() {
1526 let entry = &entries[match order {
1527 TraversalOrder::BackToFront => i,
1528 TraversalOrder::FrontToBack => entries.len() - 1 - i,
1529 }];
1530 let idx = *children_index + entry.child_offset;
1531 let maybe_abort_index = match (&item_tree_array[idx as usize], entry.instance) {
1532 (ItemTreeNode::DynamicTree { index: dyn_index, .. }, Some(instance)) => {
1533 let mut instance_tree: vtable::VWeak<ItemTreeVTable, Dyn> = Default::default();
1537 VRc::borrow_pin(item_tree).as_ref().get_subtree(
1538 *dyn_index,
1539 instance as usize,
1540 &mut instance_tree,
1541 );
1542 match instance_tree.upgrade() {
1543 Some(t)
1544 if VRc::borrow_pin(&t)
1545 .as_ref()
1546 .visit_children_item(-1, order, visitor.borrow_mut())
1547 .has_aborted() =>
1548 {
1549 VisitChildrenResult::abort(idx, instance as usize)
1550 }
1551 _ => VisitChildrenResult::CONTINUE,
1552 }
1553 }
1554 _ => visit_child_at_index(
1555 item_tree,
1556 item_tree_array,
1557 idx,
1558 order,
1559 &mut visitor,
1560 visit_dynamic,
1561 ),
1562 };
1563 if maybe_abort_index.has_aborted() {
1564 return maybe_abort_index;
1565 }
1566 }
1567 VisitChildrenResult::CONTINUE
1568}
1569
1570#[cfg(feature = "ffi")]
1571pub(crate) mod ffi {
1572 #![allow(unsafe_code)]
1573
1574 use super::*;
1575 use core::ffi::c_void;
1576
1577 #[unsafe(no_mangle)]
1579 pub unsafe extern "C" fn slint_register_item_tree(
1580 item_tree_rc: &ItemTreeRc,
1581 window_handle: *const crate::window::ffi::WindowAdapterRcOpaque,
1582 ) {
1583 unsafe {
1584 let window_adapter = (window_handle as *const WindowAdapterRc).as_ref().cloned();
1585 super::register_item_tree(item_tree_rc, window_adapter)
1586 }
1587 }
1588
1589 #[unsafe(no_mangle)]
1591 pub unsafe extern "C" fn slint_unregister_item_tree(
1592 component: ItemTreeRefPin,
1593 item_array: Slice<vtable::VOffset<u8, ItemVTable, vtable::AllowPin>>,
1594 window_handle: *const crate::window::ffi::WindowAdapterRcOpaque,
1595 ) {
1596 unsafe {
1597 let window_adapter = &*(window_handle as *const WindowAdapterRc);
1598 super::unregister_item_tree(
1599 core::pin::Pin::new_unchecked(&*(component.as_ptr() as *const u8)),
1600 core::pin::Pin::into_inner(component),
1601 item_array.as_slice(),
1602 window_adapter,
1603 )
1604 }
1605 }
1606
1607 #[unsafe(no_mangle)]
1611 pub unsafe extern "C" fn slint_visit_item_tree(
1612 item_tree: &ItemTreeRc,
1613 item_tree_array: Slice<ItemTreeNode>,
1614 index: isize,
1615 order: TraversalOrder,
1616 visitor: VRefMut<ItemVisitorVTable>,
1617 visit_dynamic: extern "C" fn(
1618 base: *const c_void,
1619 order: TraversalOrder,
1620 visitor: vtable::VRefMut<ItemVisitorVTable>,
1621 dyn_index: u32,
1622 ) -> VisitChildrenResult,
1623 ) -> VisitChildrenResult {
1624 let base = VRc::as_pin_ref(item_tree).get_ref() as *const vtable::Dyn as *const c_void;
1625 crate::item_tree::visit_item_tree(
1626 item_tree,
1627 item_tree_array.as_slice(),
1628 index,
1629 order,
1630 visitor,
1631 &mut |order, visitor, dyn_index| visit_dynamic(base, order, visitor, dyn_index),
1632 )
1633 }
1634
1635 #[unsafe(no_mangle)]
1648 pub unsafe extern "C" fn slint_visit_item_tree_z_sorted(
1649 item_tree: &ItemTreeRc,
1650 item_tree_array: Slice<ItemTreeNode>,
1651 index: isize,
1652 order: TraversalOrder,
1653 visitor: VRefMut<ItemVisitorVTable>,
1654 visit_dynamic: extern "C" fn(
1655 base: *const c_void,
1656 order: TraversalOrder,
1657 visitor: vtable::VRefMut<ItemVisitorVTable>,
1658 dyn_index: u32,
1659 ) -> VisitChildrenResult,
1660 collect_z: extern "C" fn(
1661 base: *const c_void,
1662 push_ctx: *mut c_void,
1663 push: extern "C" fn(push_ctx: *mut c_void, child_offset: u32, instance: u32, z: f32),
1664 ),
1665 ) -> VisitChildrenResult {
1666 let base = VRc::as_pin_ref(item_tree).get_ref() as *const vtable::Dyn as *const c_void;
1667 crate::item_tree::visit_item_tree_z_sorted(
1668 item_tree,
1669 item_tree_array.as_slice(),
1670 index,
1671 order,
1672 visitor,
1673 &mut |order, visitor, dyn_index| visit_dynamic(base, order, visitor, dyn_index),
1674 &mut |push| {
1675 extern "C" fn push_trampoline(
1676 push_ctx: *mut c_void,
1677 child_offset: u32,
1678 instance: u32,
1679 z: f32,
1680 ) {
1681 let push =
1682 unsafe { &mut **(push_ctx as *mut &mut dyn FnMut(u32, Option<u32>, f32)) };
1683 push(child_offset, (instance != u32::MAX).then_some(instance), z);
1684 }
1685 let mut push_ctx: &mut dyn FnMut(u32, Option<u32>, f32) = push;
1686 collect_z(base, core::ptr::addr_of_mut!(push_ctx) as *mut c_void, push_trampoline);
1687 },
1688 )
1689 }
1690}
1691
1692#[cfg(test)]
1693mod tests {
1694 use super::*;
1695 use crate::Property;
1696 use crate::api::LogicalPosition;
1697 use crate::api::Window;
1698 use crate::items::{Clip, Transform, WindowItem};
1699 use crate::lengths::LogicalLength;
1700 use crate::lengths::LogicalSize;
1701 use euclid::Point2D;
1702 use std::{rc::Rc, vec};
1703
1704 const GEOMETRY_POSITION_X: f32 = 6.;
1705 const GEOMETRY_POSITION_Y: f32 = 27.;
1706 const GEOMETRY_WIDTH: f32 = 33.;
1707 const GEOMETRY_HEIGHT: f32 = 42.;
1708
1709 #[derive(Default)]
1710 struct Renderer {
1711 supports_transformations: bool,
1712 }
1713
1714 struct WindowAdapter {
1715 renderer: Renderer,
1716 window: Window,
1717 }
1718
1719 impl WindowAdapter {
1720 fn new() -> Rc<Self> {
1721 Self::new_with_transformations(false)
1722 }
1723
1724 fn new_with_transformations(supports_transformations: bool) -> Rc<Self> {
1725 Rc::<Self>::new_cyclic(|w| Self {
1726 window: Window::new(w.clone()),
1727 renderer: Renderer { supports_transformations },
1728 })
1729 }
1730 }
1731
1732 impl crate::window::WindowAdapter for WindowAdapter {
1733 fn window(&self) -> &crate::api::Window {
1734 &self.window
1735 }
1736
1737 fn size(&self) -> crate::api::PhysicalSize {
1738 crate::api::PhysicalSize::new(100, 100)
1739 }
1740
1741 fn renderer(&self) -> &dyn crate::platform::Renderer {
1742 &self.renderer
1743 }
1744 }
1745
1746 struct TestItemTree {
1747 parent_component: Option<ItemTreeWeak>,
1748 item_tree: Vec<ItemTreeNode>,
1750 subtrees: std::cell::RefCell<Vec<Vec<vtable::VRc<ItemTreeVTable, TestItemTree>>>>,
1752 subtree_index: usize,
1753
1754 window_adapter: std::rc::Weak<dyn crate::window::WindowAdapter>,
1755 window_item: Option<crate::items::WindowItem>,
1756 }
1757
1758 impl ItemTree for TestItemTree {
1759 fn visit_children_item(
1760 self: core::pin::Pin<&Self>,
1761 _1: isize,
1762 _2: crate::item_tree::TraversalOrder,
1763 _3: vtable::VRefMut<crate::item_tree::ItemVisitorVTable>,
1764 ) -> crate::item_tree::VisitChildrenResult {
1765 unimplemented!("Not needed for this test")
1766 }
1767
1768 fn get_item_ref(
1769 self: core::pin::Pin<&Self>,
1770 index: u32,
1771 ) -> core::pin::Pin<vtable::VRef<'_, super::ItemVTable>> {
1772 if index == 0 {
1773 return Pin::new(VRef::new(
1774 self.get_ref().window_item.as_ref().expect("Not needed for this test"),
1775 ));
1776 }
1777 unimplemented!("Not needed for this test")
1778 }
1779
1780 fn get_item_tree(self: core::pin::Pin<&Self>) -> Slice<'_, ItemTreeNode> {
1781 Slice::from_slice(&self.get_ref().item_tree)
1782 }
1783
1784 fn parent_node(self: core::pin::Pin<&Self>, result: &mut ItemWeak) {
1785 if let Some(parent_item) = self.parent_component.as_ref().and_then(|w| w.upgrade()) {
1786 *result = ItemRc::new(parent_item, self.item_tree[0].parent_index()).downgrade();
1787 }
1788 }
1789
1790 fn embed_component(
1791 self: core::pin::Pin<&Self>,
1792 _parent_component: &ItemTreeWeak,
1793 _item_tree_index: u32,
1794 ) -> bool {
1795 false
1796 }
1797
1798 fn ensure_instantiated(self: core::pin::Pin<&Self>) -> bool {
1799 false
1800 }
1801
1802 fn layout_info(self: core::pin::Pin<&Self>, o: Orientation) -> LayoutInfo {
1803 if let Some(wi) = &self.window_item {
1804 match o {
1805 Orientation::Horizontal => {
1806 return LayoutInfo {
1807 max: wi.width.get_internal().0,
1808 max_percent: 100.,
1809 min: wi.width.get_internal().0,
1810 min_percent: 100.,
1811 preferred: wi.width.get_internal().0,
1812 stretch: 1.,
1813 };
1814 }
1815 Orientation::Vertical => {
1816 return LayoutInfo {
1817 max: wi.height.get_internal().0,
1818 max_percent: 100.,
1819 min: wi.height.get_internal().0,
1820 min_percent: 100.,
1821 preferred: wi.height.get_internal().0,
1822 stretch: 1.,
1823 };
1824 }
1825 }
1826 }
1827 unimplemented!("Not needed for this test")
1828 }
1829
1830 fn subtree_index(self: core::pin::Pin<&Self>) -> usize {
1831 self.subtree_index
1832 }
1833
1834 fn get_subtree_range(self: core::pin::Pin<&Self>, subtree_index: u32) -> IndexRange {
1835 (0..self.subtrees.borrow()[subtree_index as usize].len()).into()
1836 }
1837
1838 fn get_subtree(
1839 self: core::pin::Pin<&Self>,
1840 subtree_index: u32,
1841 component_index: usize,
1842 result: &mut ItemTreeWeak,
1843 ) {
1844 if let Some(vrc) = self.subtrees.borrow()[subtree_index as usize].get(component_index) {
1845 *result = vtable::VRc::downgrade(&vtable::VRc::into_dyn(vrc.clone()))
1846 }
1847 }
1848
1849 fn accessible_role(self: Pin<&Self>, _: u32) -> AccessibleRole {
1850 unimplemented!("Not needed for this test")
1851 }
1852
1853 fn accessible_string_property(
1854 self: Pin<&Self>,
1855 _: u32,
1856 _: AccessibleStringProperty,
1857 _: &mut SharedString,
1858 ) -> bool {
1859 false
1860 }
1861
1862 fn item_element_infos(self: Pin<&Self>, _: u32, _: &mut SharedString) -> bool {
1863 false
1864 }
1865
1866 fn window_adapter(
1867 self: Pin<&Self>,
1868 _do_create: bool,
1869 result: &mut Option<WindowAdapterRc>,
1870 ) {
1871 *result = self.window_adapter.upgrade()
1872 }
1873
1874 fn item_geometry(self: Pin<&Self>, _: u32) -> LogicalRect {
1875 LogicalRect::new(
1876 euclid::Point2D::new(GEOMETRY_POSITION_X, GEOMETRY_POSITION_Y),
1877 euclid::Size2D::new(GEOMETRY_WIDTH, GEOMETRY_HEIGHT),
1878 )
1879 }
1880
1881 fn accessibility_action(self: core::pin::Pin<&Self>, _: u32, _: &AccessibilityAction) {
1882 unimplemented!("Not needed for this test")
1883 }
1884
1885 fn supported_accessibility_actions(
1886 self: core::pin::Pin<&Self>,
1887 _: u32,
1888 ) -> SupportedAccessibilityAction {
1889 unimplemented!("Not needed for this test")
1890 }
1891 }
1892
1893 crate::item_tree::ItemTreeVTable_static!(static TEST_COMPONENT_VT for TestItemTree);
1894
1895 fn create_one_node_component(
1896 window_item: Option<WindowItem>,
1897 ) -> (std::rc::Rc<WindowAdapter>, VRc<ItemTreeVTable, vtable::Dyn>) {
1898 let window_adapter = WindowAdapter::new();
1899 let component = VRc::new(TestItemTree {
1900 parent_component: None,
1901 item_tree: vec![ItemTreeNode::Item {
1902 is_accessible: false,
1903 children_count: 0,
1904 children_index: 1,
1905 parent_index: 0,
1906 item_array_index: 0,
1907 }],
1908 subtrees: std::cell::RefCell::new(Vec::new()),
1909 subtree_index: usize::MAX,
1910
1911 window_adapter: Rc::downgrade(&window_adapter) as _,
1912 window_item,
1913 });
1914 (window_adapter, VRc::into_dyn(component))
1915 }
1916
1917 #[test]
1918 fn test_tree_traversal_one_node_structure() {
1919 let component = create_one_node_component(None).1;
1920
1921 let item = ItemRc::new_root(component.clone());
1922
1923 assert!(item.first_child().is_none());
1924 assert!(item.last_child().is_none());
1925 assert!(item.previous_sibling().is_none());
1926 assert!(item.next_sibling().is_none());
1927 }
1928
1929 #[test]
1930 fn test_tree_traversal_one_node_forward_focus() {
1931 let component = create_one_node_component(None).1;
1932
1933 let item = ItemRc::new_root(component.clone());
1934
1935 assert_eq!(item.next_focus_item(), item);
1937 }
1938
1939 #[test]
1940 fn test_tree_traversal_one_node_backward_focus() {
1941 let component = create_one_node_component(None).1;
1942
1943 let item = ItemRc::new_root(component.clone());
1944
1945 assert_eq!(item.previous_focus_item(), item);
1947 }
1948
1949 fn create_children_nodes() -> VRc<ItemTreeVTable, vtable::Dyn> {
1950 let component = VRc::new(TestItemTree {
1951 parent_component: None,
1952 item_tree: vec![
1953 ItemTreeNode::Item {
1955 is_accessible: false,
1956 children_count: 3,
1957 children_index: 1,
1958 parent_index: 0,
1959 item_array_index: 0, },
1961 ItemTreeNode::Item {
1963 is_accessible: false,
1964 children_count: 0,
1965 children_index: 4, parent_index: 0, item_array_index: 1, },
1969 ItemTreeNode::Item {
1971 is_accessible: false,
1972 children_count: 0,
1973 children_index: 4, parent_index: 0, item_array_index: 2,
1976 },
1977 ItemTreeNode::Item {
1979 is_accessible: false,
1980 children_count: 0,
1981 children_index: 4, parent_index: 0, item_array_index: 3,
1984 },
1985 ],
1986 subtrees: std::cell::RefCell::new(Vec::new()),
1987 subtree_index: usize::MAX,
1988
1989 window_adapter: Rc::downgrade(&WindowAdapter::new()) as _,
1990 window_item: None,
1991 });
1992 VRc::into_dyn(component)
1993 }
1994
1995 #[test]
1996 fn test_tree_traversal_children_nodes_structure() {
1997 let component: VRc<ItemTreeVTable> = create_children_nodes();
1998
1999 let item = ItemRc::new_root(component.clone());
2001 assert!(item.previous_sibling().is_none());
2002 assert!(item.next_sibling().is_none());
2003
2004 let fc = item.first_child().unwrap();
2005 assert_eq!(fc.index(), 1);
2006 assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
2007
2008 let fcn = fc.next_sibling().unwrap();
2009 assert_eq!(fcn.index(), 2);
2010
2011 let lc = item.last_child().unwrap();
2012 assert_eq!(lc.index(), 3);
2013 assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
2014
2015 let lcp = lc.previous_sibling().unwrap();
2016 assert!(VRc::ptr_eq(lcp.item_tree(), item.item_tree()));
2017 assert_eq!(lcp.index(), 2);
2018
2019 assert!(fc.first_child().is_none());
2021 assert!(fc.last_child().is_none());
2022 assert!(fc.previous_sibling().is_none());
2023 assert_eq!(fc.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);
2024
2025 assert_eq!(fcn, lcp);
2027 assert_eq!(lcp.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);
2028 assert_eq!(fcn.previous_sibling().unwrap(), fc);
2029 assert_eq!(fcn.next_sibling().unwrap(), lc);
2030
2031 assert!(lc.first_child().is_none());
2033 assert!(lc.last_child().is_none());
2034 assert!(lc.next_sibling().is_none());
2035 assert_eq!(lc.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);
2036 }
2037
2038 #[test]
2039 fn test_tree_traversal_children_nodes_forward_focus() {
2040 let component = create_children_nodes();
2041
2042 let item = ItemRc::new_root(component.clone());
2043 let fc = item.first_child().unwrap();
2044 let fcn = fc.next_sibling().unwrap();
2045 let lc = item.last_child().unwrap();
2046
2047 let mut cursor = item.clone();
2048
2049 cursor = cursor.next_focus_item();
2050 assert_eq!(cursor, fc);
2051
2052 cursor = cursor.next_focus_item();
2053 assert_eq!(cursor, fcn);
2054
2055 cursor = cursor.next_focus_item();
2056 assert_eq!(cursor, lc);
2057
2058 cursor = cursor.next_focus_item();
2059 assert_eq!(cursor, item);
2060 }
2061
2062 #[test]
2063 fn test_tree_traversal_children_nodes_backward_focus() {
2064 let component = create_children_nodes();
2065
2066 let item = ItemRc::new_root(component.clone());
2067 let fc = item.first_child().unwrap();
2068 let fcn = fc.next_sibling().unwrap();
2069 let lc = item.last_child().unwrap();
2070
2071 let mut cursor = item.clone();
2072
2073 cursor = cursor.previous_focus_item();
2074 assert_eq!(cursor, lc);
2075
2076 cursor = cursor.previous_focus_item();
2077 assert_eq!(cursor, fcn);
2078
2079 cursor = cursor.previous_focus_item();
2080 assert_eq!(cursor, fc);
2081
2082 cursor = cursor.previous_focus_item();
2083 assert_eq!(cursor, item);
2084 }
2085
2086 fn create_empty_subtree() -> VRc<ItemTreeVTable, vtable::Dyn> {
2087 let component = vtable::VRc::new(TestItemTree {
2088 parent_component: None,
2089 item_tree: vec![
2090 ItemTreeNode::Item {
2091 is_accessible: false,
2092 children_count: 1,
2093 children_index: 1,
2094 parent_index: 0,
2095 item_array_index: 0,
2096 },
2097 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
2098 ],
2099 subtrees: std::cell::RefCell::new(vec![Vec::new()]),
2100 subtree_index: usize::MAX,
2101
2102 window_adapter: Rc::downgrade(&WindowAdapter::new()) as _,
2103 window_item: None,
2104 });
2105 vtable::VRc::into_dyn(component)
2106 }
2107
2108 #[test]
2109 fn test_tree_traversal_empty_subtree_structure() {
2110 let component = create_empty_subtree();
2111
2112 let item = ItemRc::new_root(component.clone());
2114 assert!(item.previous_sibling().is_none());
2115 assert!(item.next_sibling().is_none());
2116 assert!(item.first_child().is_none());
2117 assert!(item.last_child().is_none());
2118
2119 assert!(item.previous_focus_item() == item);
2121 assert!(item.next_focus_item() == item);
2122 }
2123
2124 #[test]
2125 fn test_tree_traversal_empty_subtree_forward_focus() {
2126 let component = create_empty_subtree();
2127
2128 let item = ItemRc::new_root(component.clone());
2130
2131 assert!(item.next_focus_item() == item);
2132 }
2133
2134 #[test]
2135 fn test_tree_traversal_empty_subtree_backward_focus() {
2136 let component = create_empty_subtree();
2137
2138 let item = ItemRc::new_root(component.clone());
2140
2141 assert!(item.previous_focus_item() == item);
2142 }
2143
2144 fn create_item_subtree_item() -> VRc<ItemTreeVTable, vtable::Dyn> {
2145 let window_adapter = WindowAdapter::new();
2146 let weak_adapter =
2147 Rc::downgrade(&window_adapter) as std::rc::Weak<dyn crate::window::WindowAdapter>;
2148 let component = VRc::new(TestItemTree {
2149 parent_component: None,
2150 item_tree: vec![
2151 ItemTreeNode::Item {
2153 is_accessible: false,
2154 children_count: 3,
2155 children_index: 1,
2156 parent_index: 0,
2157 item_array_index: 0,
2158 },
2159 ItemTreeNode::Item {
2161 is_accessible: false,
2162 children_count: 0,
2163 children_index: 4, parent_index: 0, item_array_index: 0,
2166 },
2167 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
2168 ItemTreeNode::Item {
2169 is_accessible: false,
2170 children_count: 0,
2171 children_index: 4,
2172 parent_index: 0, item_array_index: 0,
2174 },
2175 ],
2176 subtrees: std::cell::RefCell::new(Vec::new()),
2177 subtree_index: usize::MAX,
2178
2179 window_adapter: weak_adapter.clone(),
2180 window_item: None,
2181 });
2182
2183 component.as_pin_ref().subtrees.replace(vec![vec![VRc::new(TestItemTree {
2184 parent_component: Some(VRc::downgrade(&VRc::into_dyn(component.clone()))),
2185 item_tree: vec![ItemTreeNode::Item {
2186 is_accessible: false,
2187 children_count: 0,
2188 children_index: 1,
2189 parent_index: 2,
2190 item_array_index: 0,
2191 }],
2192 subtrees: std::cell::RefCell::new(Vec::new()),
2193 subtree_index: 0,
2194
2195 window_adapter: weak_adapter,
2196 window_item: None,
2197 })]]);
2198
2199 VRc::into_dyn(component)
2200 }
2201
2202 #[test]
2203 fn test_tree_traversal_item_subtree_item_structure() {
2204 let component = create_item_subtree_item();
2205
2206 let item = ItemRc::new_root(component.clone());
2208 assert!(item.previous_sibling().is_none());
2209 assert!(item.next_sibling().is_none());
2210
2211 let fc = item.first_child().unwrap();
2212 assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
2213 assert_eq!(fc.index(), 1);
2214
2215 let lc = item.last_child().unwrap();
2216 assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
2217 assert_eq!(lc.index(), 3);
2218
2219 let fcn = fc.next_sibling().unwrap();
2220 let lcp = lc.previous_sibling().unwrap();
2221
2222 assert_eq!(fcn, lcp);
2223 assert!(!VRc::ptr_eq(fcn.item_tree(), item.item_tree()));
2224
2225 let last = fcn.next_sibling().unwrap();
2226 assert_eq!(last, lc);
2227
2228 let first = lcp.previous_sibling().unwrap();
2229 assert_eq!(first, fc);
2230 }
2231
2232 #[test]
2233 fn test_tree_traversal_item_subtree_item_forward_focus() {
2234 let component = create_item_subtree_item();
2235
2236 let item = ItemRc::new_root(component.clone());
2237 let fc = item.first_child().unwrap();
2238 let lc = item.last_child().unwrap();
2239 let fcn = fc.next_sibling().unwrap();
2240
2241 let mut cursor = item.clone();
2242
2243 cursor = cursor.next_focus_item();
2244 assert_eq!(cursor, fc);
2245
2246 cursor = cursor.next_focus_item();
2247 assert_eq!(cursor, fcn);
2248
2249 cursor = cursor.next_focus_item();
2250 assert_eq!(cursor, lc);
2251
2252 cursor = cursor.next_focus_item();
2253 assert_eq!(cursor, item);
2254 }
2255
2256 #[test]
2257 fn test_tree_traversal_item_subtree_item_backward_focus() {
2258 let component = create_item_subtree_item();
2259
2260 let item = ItemRc::new_root(component.clone());
2261 let fc = item.first_child().unwrap();
2262 let lc = item.last_child().unwrap();
2263 let fcn = fc.next_sibling().unwrap();
2264
2265 let mut cursor = item.clone();
2266
2267 cursor = cursor.previous_focus_item();
2268 assert_eq!(cursor, lc);
2269
2270 cursor = cursor.previous_focus_item();
2271 assert_eq!(cursor, fcn);
2272
2273 cursor = cursor.previous_focus_item();
2274 assert_eq!(cursor, fc);
2275
2276 cursor = cursor.previous_focus_item();
2277 assert_eq!(cursor, item);
2278 }
2279
2280 fn create_nested_subtrees() -> VRc<ItemTreeVTable, vtable::Dyn> {
2281 let window_adapter = WindowAdapter::new();
2286 let weak_adapter =
2287 Rc::downgrade(&window_adapter) as std::rc::Weak<dyn crate::window::WindowAdapter>;
2288
2289 let component = VRc::new(TestItemTree {
2290 parent_component: None,
2291 item_tree: vec![
2292 ItemTreeNode::Item {
2294 is_accessible: false,
2295 children_count: 3,
2296 children_index: 1,
2297 parent_index: 0,
2298 item_array_index: 0,
2299 },
2300 ItemTreeNode::Item {
2302 is_accessible: false,
2303 children_count: 0,
2304 children_index: 4,
2305 parent_index: 0,
2306 item_array_index: 0,
2307 },
2308 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
2311 ItemTreeNode::Item {
2313 is_accessible: false,
2314 children_count: 0,
2315 children_index: 4,
2316 parent_index: 0,
2317 item_array_index: 0,
2318 },
2319 ],
2320 subtrees: std::cell::RefCell::new(Vec::new()),
2321 subtree_index: usize::MAX,
2322
2323 window_adapter: weak_adapter.clone(),
2324 window_item: None,
2325 });
2326
2327 let sub_component1 = VRc::new(TestItemTree {
2328 parent_component: Some(VRc::downgrade(&VRc::into_dyn(component.clone()))),
2329 item_tree: vec![
2330 ItemTreeNode::Item {
2332 is_accessible: false,
2333 children_count: 1,
2334 children_index: 1,
2335 parent_index: 2,
2336 item_array_index: 0,
2337 },
2338 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
2341 ],
2342 subtrees: std::cell::RefCell::new(Vec::new()),
2343 subtree_index: usize::MAX,
2344
2345 window_adapter: weak_adapter.clone(),
2346 window_item: None,
2347 });
2348 let sub_component2 = VRc::new(TestItemTree {
2349 parent_component: Some(VRc::downgrade(&VRc::into_dyn(sub_component1.clone()))),
2350 item_tree: vec![
2351 ItemTreeNode::Item {
2352 is_accessible: false,
2353 children_count: 1,
2354 children_index: 1,
2355 parent_index: 1,
2356 item_array_index: 0,
2357 },
2358 ItemTreeNode::Item {
2359 is_accessible: false,
2360 children_count: 0,
2361 children_index: 2,
2362 parent_index: 0,
2363 item_array_index: 0,
2364 },
2365 ],
2366 subtrees: std::cell::RefCell::new(Vec::new()),
2367 subtree_index: usize::MAX,
2368
2369 window_adapter: weak_adapter,
2370 window_item: None,
2371 });
2372
2373 sub_component1.as_pin_ref().subtrees.replace(vec![vec![sub_component2]]);
2374 component.as_pin_ref().subtrees.replace(vec![vec![sub_component1]]);
2375
2376 VRc::into_dyn(component)
2377 }
2378
2379 #[test]
2380 fn test_tree_traversal_nested_subtrees_structure() {
2381 let component = create_nested_subtrees();
2382
2383 let item = ItemRc::new_root(component.clone());
2385 assert!(item.previous_sibling().is_none());
2386 assert!(item.next_sibling().is_none());
2387
2388 let fc = item.first_child().unwrap();
2389 assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
2390 assert_eq!(fc.index(), 1);
2391
2392 let lc = item.last_child().unwrap();
2393 assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
2394 assert_eq!(lc.index(), 3);
2395
2396 let fcn = fc.next_sibling().unwrap();
2397 let lcp = lc.previous_sibling().unwrap();
2398
2399 assert_eq!(fcn, lcp);
2400 assert!(!VRc::ptr_eq(fcn.item_tree(), item.item_tree()));
2401
2402 let last = fcn.next_sibling().unwrap();
2403 assert_eq!(last, lc);
2404
2405 let first = lcp.previous_sibling().unwrap();
2406 assert_eq!(first, fc);
2407
2408 let nested_root = fcn.first_child().unwrap();
2410 assert_eq!(nested_root, fcn.last_child().unwrap());
2411 assert!(nested_root.next_sibling().is_none());
2412 assert!(nested_root.previous_sibling().is_none());
2413 assert!(!VRc::ptr_eq(nested_root.item_tree(), item.item_tree()));
2414 assert!(!VRc::ptr_eq(nested_root.item_tree(), fcn.item_tree()));
2415
2416 let nested_child = nested_root.first_child().unwrap();
2417 assert_eq!(nested_child, nested_root.last_child().unwrap());
2418 assert!(VRc::ptr_eq(nested_root.item_tree(), nested_child.item_tree()));
2419 }
2420
2421 #[test]
2422 fn test_tree_traversal_nested_subtrees_forward_focus() {
2423 let component = create_nested_subtrees();
2424
2425 let item = ItemRc::new_root(component.clone());
2427 let fc = item.first_child().unwrap();
2428 let fcn = fc.next_sibling().unwrap();
2429 let lc = item.last_child().unwrap();
2430 let nested_root = fcn.first_child().unwrap();
2431 let nested_child = nested_root.first_child().unwrap();
2432
2433 let mut cursor = item.clone();
2435
2436 cursor = cursor.next_focus_item();
2437 assert_eq!(cursor, fc);
2438
2439 cursor = cursor.next_focus_item();
2440 assert_eq!(cursor, fcn);
2441
2442 cursor = cursor.next_focus_item();
2443 assert_eq!(cursor, nested_root);
2444
2445 cursor = cursor.next_focus_item();
2446 assert_eq!(cursor, nested_child);
2447
2448 cursor = cursor.next_focus_item();
2449 assert_eq!(cursor, lc);
2450
2451 cursor = cursor.next_focus_item();
2452 assert_eq!(cursor, item);
2453 }
2454
2455 #[test]
2456 fn test_tree_traversal_nested_subtrees_backward_focus() {
2457 let component = create_nested_subtrees();
2458
2459 let item = ItemRc::new_root(component.clone());
2461 let fc = item.first_child().unwrap();
2462 let fcn = fc.next_sibling().unwrap();
2463 let lc = item.last_child().unwrap();
2464 let nested_root = fcn.first_child().unwrap();
2465 let nested_child = nested_root.first_child().unwrap();
2466
2467 let mut cursor = item.clone();
2469
2470 cursor = cursor.previous_focus_item();
2471 assert_eq!(cursor, lc);
2472
2473 cursor = cursor.previous_focus_item();
2474 assert_eq!(cursor, nested_child);
2475
2476 cursor = cursor.previous_focus_item();
2477 assert_eq!(cursor, nested_root);
2478
2479 cursor = cursor.previous_focus_item();
2480 assert_eq!(cursor, fcn);
2481
2482 cursor = cursor.previous_focus_item();
2483 assert_eq!(cursor, fc);
2484
2485 cursor = cursor.previous_focus_item();
2486 assert_eq!(cursor, item);
2487 }
2488
2489 fn create_subtrees_item() -> VRc<ItemTreeVTable, vtable::Dyn> {
2490 let window_adapter = WindowAdapter::new();
2491 let weak_adapter =
2492 Rc::downgrade(&window_adapter) as std::rc::Weak<dyn crate::window::WindowAdapter>;
2493
2494 let component = VRc::new(TestItemTree {
2495 parent_component: None,
2496 item_tree: vec![
2497 ItemTreeNode::Item {
2498 is_accessible: false,
2499 children_count: 2,
2500 children_index: 1,
2501 parent_index: 0,
2502 item_array_index: 0,
2503 },
2504 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
2505 ItemTreeNode::Item {
2506 is_accessible: false,
2507 children_count: 0,
2508 children_index: 4,
2509 parent_index: 0,
2510 item_array_index: 0,
2511 },
2512 ],
2513 subtrees: std::cell::RefCell::new(Vec::new()),
2514 subtree_index: usize::MAX,
2515
2516 window_adapter: weak_adapter.clone(),
2517 window_item: None,
2518 });
2519
2520 component.as_pin_ref().subtrees.replace(vec![vec![
2521 VRc::new(TestItemTree {
2522 parent_component: Some(VRc::downgrade(&VRc::into_dyn(component.clone()))),
2523 item_tree: vec![ItemTreeNode::Item {
2524 is_accessible: false,
2525 children_count: 0,
2526 children_index: 1,
2527 parent_index: 1,
2528 item_array_index: 0,
2529 }],
2530 subtrees: std::cell::RefCell::new(Vec::new()),
2531 subtree_index: 0,
2532
2533 window_adapter: weak_adapter.clone(),
2534 window_item: None,
2535 }),
2536 VRc::new(TestItemTree {
2537 parent_component: Some(VRc::downgrade(&VRc::into_dyn(component.clone()))),
2538 item_tree: vec![ItemTreeNode::Item {
2539 is_accessible: false,
2540 children_count: 0,
2541 children_index: 1,
2542 parent_index: 1,
2543 item_array_index: 0,
2544 }],
2545 subtrees: std::cell::RefCell::new(Vec::new()),
2546 subtree_index: 1,
2547
2548 window_adapter: weak_adapter.clone(),
2549 window_item: None,
2550 }),
2551 VRc::new(TestItemTree {
2552 parent_component: Some(VRc::downgrade(&VRc::into_dyn(component.clone()))),
2553 item_tree: vec![ItemTreeNode::Item {
2554 is_accessible: false,
2555 children_count: 0,
2556 children_index: 1,
2557 parent_index: 1,
2558 item_array_index: 0,
2559 }],
2560 subtrees: std::cell::RefCell::new(Vec::new()),
2561 subtree_index: 2,
2562
2563 window_adapter: weak_adapter,
2564 window_item: None,
2565 }),
2566 ]]);
2567
2568 VRc::into_dyn(component)
2569 }
2570
2571 #[test]
2572 fn test_tree_traversal_subtrees_item_structure() {
2573 let component = create_subtrees_item();
2574
2575 let item = ItemRc::new_root(component.clone());
2577 assert!(item.previous_sibling().is_none());
2578 assert!(item.next_sibling().is_none());
2579
2580 let sub1 = item.first_child().unwrap();
2581 assert_eq!(sub1.index(), 0);
2582 assert!(!VRc::ptr_eq(sub1.item_tree(), item.item_tree()));
2583
2584 let sub2 = sub1.next_sibling().unwrap();
2587 assert_eq!(sub2.index(), 0);
2588 assert!(!VRc::ptr_eq(sub1.item_tree(), sub2.item_tree()));
2589 assert!(!VRc::ptr_eq(item.item_tree(), sub2.item_tree()));
2590
2591 assert!(sub2.previous_sibling() == Some(sub1.clone()));
2592
2593 let sub3 = sub2.next_sibling().unwrap();
2594 assert_eq!(sub3.index(), 0);
2595 assert!(!VRc::ptr_eq(sub1.item_tree(), sub2.item_tree()));
2596 assert!(!VRc::ptr_eq(sub2.item_tree(), sub3.item_tree()));
2597 assert!(!VRc::ptr_eq(item.item_tree(), sub3.item_tree()));
2598
2599 assert_eq!(sub3.previous_sibling().unwrap(), sub2.clone());
2600 }
2601
2602 #[test]
2603 fn test_component_item_tree_root_only() {
2604 let nodes = vec![ItemTreeNode::Item {
2605 is_accessible: false,
2606 children_count: 0,
2607 children_index: 1,
2608 parent_index: 0,
2609 item_array_index: 0,
2610 }];
2611
2612 let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
2613
2614 assert_eq!(tree.first_child(0), None);
2615 assert_eq!(tree.last_child(0), None);
2616 assert_eq!(tree.previous_sibling(0), None);
2617 assert_eq!(tree.next_sibling(0), None);
2618 assert_eq!(tree.parent(0), None);
2619 }
2620
2621 #[test]
2622 fn test_component_item_tree_one_child() {
2623 let nodes = vec![
2624 ItemTreeNode::Item {
2625 is_accessible: false,
2626 children_count: 1,
2627 children_index: 1,
2628 parent_index: 0,
2629 item_array_index: 0,
2630 },
2631 ItemTreeNode::Item {
2632 is_accessible: false,
2633 children_count: 0,
2634 children_index: 2,
2635 parent_index: 0,
2636 item_array_index: 0,
2637 },
2638 ];
2639
2640 let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
2641
2642 assert_eq!(tree.first_child(0), Some(1));
2643 assert_eq!(tree.last_child(0), Some(1));
2644 assert_eq!(tree.previous_sibling(0), None);
2645 assert_eq!(tree.next_sibling(0), None);
2646 assert_eq!(tree.parent(0), None);
2647 assert_eq!(tree.previous_sibling(1), None);
2648 assert_eq!(tree.next_sibling(1), None);
2649 assert_eq!(tree.parent(1), Some(0));
2650 }
2651
2652 #[test]
2653 fn test_component_item_tree_tree_children() {
2654 let nodes = vec![
2655 ItemTreeNode::Item {
2656 is_accessible: false,
2657 children_count: 3,
2658 children_index: 1,
2659 parent_index: 0,
2660 item_array_index: 0,
2661 },
2662 ItemTreeNode::Item {
2663 is_accessible: false,
2664 children_count: 0,
2665 children_index: 4,
2666 parent_index: 0,
2667 item_array_index: 0,
2668 },
2669 ItemTreeNode::Item {
2670 is_accessible: false,
2671 children_count: 0,
2672 children_index: 4,
2673 parent_index: 0,
2674 item_array_index: 0,
2675 },
2676 ItemTreeNode::Item {
2677 is_accessible: false,
2678 children_count: 0,
2679 children_index: 4,
2680 parent_index: 0,
2681 item_array_index: 0,
2682 },
2683 ];
2684
2685 let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
2686
2687 assert_eq!(tree.first_child(0), Some(1));
2688 assert_eq!(tree.last_child(0), Some(3));
2689 assert_eq!(tree.previous_sibling(0), None);
2690 assert_eq!(tree.next_sibling(0), None);
2691 assert_eq!(tree.parent(0), None);
2692
2693 assert_eq!(tree.previous_sibling(1), None);
2694 assert_eq!(tree.next_sibling(1), Some(2));
2695 assert_eq!(tree.parent(1), Some(0));
2696
2697 assert_eq!(tree.previous_sibling(2), Some(1));
2698 assert_eq!(tree.next_sibling(2), Some(3));
2699 assert_eq!(tree.parent(2), Some(0));
2700
2701 assert_eq!(tree.previous_sibling(3), Some(2));
2702 assert_eq!(tree.next_sibling(3), None);
2703 assert_eq!(tree.parent(3), Some(0));
2704 }
2705
2706 fn create_subsubtree_items(
2708 window_adapter: Option<std::rc::Rc<WindowAdapter>>,
2709 ) -> (std::rc::Rc<WindowAdapter>, VRc<ItemTreeVTable>) {
2710 let window_adapter = window_adapter.unwrap_or(WindowAdapter::new());
2711 let mut window_item = WindowItem::default();
2712 window_item.width = Property::new(LogicalLength::new(30.));
2713 window_item.height = Property::new(LogicalLength::new(30.));
2714 (
2715 window_adapter.clone(),
2716 VRc::into_dyn(VRc::new(TestItemTree {
2717 parent_component: None,
2718 item_tree: vec![
2719 ItemTreeNode::Item {
2721 is_accessible: false,
2722 children_count: 1,
2723 children_index: 1,
2724 parent_index: 0,
2725 item_array_index: 0,
2726 },
2727 ItemTreeNode::Item {
2729 is_accessible: false,
2730 children_count: 1,
2731 children_index: 2, parent_index: 0,
2733 item_array_index: 1,
2734 },
2735 ItemTreeNode::Item {
2737 is_accessible: false,
2738 children_count: 0,
2739 children_index: 3, parent_index: 1,
2741 item_array_index: 2,
2742 },
2743 ],
2744 subtrees: std::cell::RefCell::new(Vec::new()),
2745 subtree_index: usize::MAX,
2746 window_adapter: Rc::downgrade(&window_adapter) as _,
2747 window_item: Some(window_item),
2748 })),
2749 )
2750 }
2751
2752 struct TransformTestItemTree {
2753 item_tree: Vec<ItemTreeNode>,
2754 geometries: Vec<LogicalRect>,
2755 window_adapter: std::rc::Weak<dyn crate::window::WindowAdapter>,
2756 root: WindowItem,
2757 transform: Transform,
2758 clip: Clip,
2759 leaf: WindowItem,
2760 }
2761
2762 impl ItemTree for TransformTestItemTree {
2763 fn visit_children_item(
2764 self: Pin<&Self>,
2765 _index: isize,
2766 _order: TraversalOrder,
2767 _visitor: vtable::VRefMut<ItemVisitorVTable>,
2768 ) -> VisitChildrenResult {
2769 unimplemented!("Not needed for this test")
2770 }
2771
2772 fn get_item_ref(self: Pin<&Self>, index: u32) -> Pin<VRef<'_, ItemVTable>> {
2773 let this = self.get_ref();
2774 match index {
2775 0 => Pin::new(VRef::new(&this.root)),
2776 1 => Pin::new(VRef::new(&this.transform)),
2777 2 => Pin::new(VRef::new(&this.clip)),
2778 3 => Pin::new(VRef::new(&this.leaf)),
2779 _ => unimplemented!("Not needed for this test"),
2780 }
2781 }
2782
2783 fn get_item_tree(self: Pin<&Self>) -> Slice<'_, ItemTreeNode> {
2784 Slice::from_slice(&self.get_ref().item_tree)
2785 }
2786
2787 fn parent_node(self: Pin<&Self>, _result: &mut ItemWeak) {}
2788
2789 fn embed_component(
2790 self: Pin<&Self>,
2791 _parent_component: &ItemTreeWeak,
2792 _item_tree_index: u32,
2793 ) -> bool {
2794 false
2795 }
2796
2797 fn layout_info(self: Pin<&Self>, _orientation: Orientation) -> LayoutInfo {
2798 unimplemented!("Not needed for this test")
2799 }
2800
2801 fn subtree_index(self: Pin<&Self>) -> usize {
2802 usize::MAX
2803 }
2804
2805 fn get_subtree_range(self: Pin<&Self>, _subtree_index: u32) -> IndexRange {
2806 (0..0).into()
2807 }
2808
2809 fn get_subtree(
2810 self: Pin<&Self>,
2811 _subtree_index: u32,
2812 _component_index: usize,
2813 _result: &mut ItemTreeWeak,
2814 ) {
2815 unimplemented!("Not needed for this test")
2816 }
2817
2818 fn accessible_role(self: Pin<&Self>, _index: u32) -> AccessibleRole {
2819 unimplemented!("Not needed for this test")
2820 }
2821
2822 fn accessible_string_property(
2823 self: Pin<&Self>,
2824 _index: u32,
2825 _what: AccessibleStringProperty,
2826 _result: &mut SharedString,
2827 ) -> bool {
2828 false
2829 }
2830
2831 fn item_element_infos(self: Pin<&Self>, _index: u32, _result: &mut SharedString) -> bool {
2832 false
2833 }
2834
2835 fn ensure_instantiated(self: Pin<&Self>) -> bool {
2836 false
2837 }
2838
2839 fn window_adapter(
2840 self: Pin<&Self>,
2841 _do_create: bool,
2842 result: &mut Option<WindowAdapterRc>,
2843 ) {
2844 *result = self.window_adapter.upgrade()
2845 }
2846
2847 fn item_geometry(self: Pin<&Self>, index: u32) -> LogicalRect {
2848 self.geometries[index as usize]
2849 }
2850
2851 fn accessibility_action(self: Pin<&Self>, _index: u32, _action: &AccessibilityAction) {
2852 unimplemented!("Not needed for this test")
2853 }
2854
2855 fn supported_accessibility_actions(
2856 self: Pin<&Self>,
2857 _index: u32,
2858 ) -> SupportedAccessibilityAction {
2859 unimplemented!("Not needed for this test")
2860 }
2861 }
2862
2863 crate::item_tree::ItemTreeVTable_static!(static TRANSFORM_TEST_COMPONENT_VT for TransformTestItemTree);
2864
2865 fn create_transform_test_items() -> (std::rc::Rc<WindowAdapter>, VRc<ItemTreeVTable>) {
2866 let window_adapter = WindowAdapter::new_with_transformations(true);
2867
2868 let mut transform = Transform::default();
2869 transform.transform_scale_x = Property::new(2.);
2870 transform.transform_scale_y = Property::new(3.);
2871 transform.transform_rotation = Property::new(0.);
2872 transform.transform_origin = Property::new(LogicalPosition::new(0., 0.));
2873
2874 let mut clip = Clip::default();
2875 clip.clip = Property::new(true);
2876
2877 (
2878 window_adapter.clone(),
2879 VRc::into_dyn(VRc::new(TransformTestItemTree {
2880 item_tree: vec![
2881 ItemTreeNode::Item {
2882 is_accessible: false,
2883 children_count: 1,
2884 children_index: 1,
2885 parent_index: 0,
2886 item_array_index: 0,
2887 },
2888 ItemTreeNode::Item {
2889 is_accessible: false,
2890 children_count: 1,
2891 children_index: 2,
2892 parent_index: 0,
2893 item_array_index: 1,
2894 },
2895 ItemTreeNode::Item {
2896 is_accessible: false,
2897 children_count: 1,
2898 children_index: 3,
2899 parent_index: 1,
2900 item_array_index: 2,
2901 },
2902 ItemTreeNode::Item {
2903 is_accessible: false,
2904 children_count: 0,
2905 children_index: 4,
2906 parent_index: 2,
2907 item_array_index: 3,
2908 },
2909 ],
2910 geometries: vec![
2911 LogicalRect::new(Point2D::new(0., 0.), LogicalSize::new(100., 100.)),
2912 LogicalRect::new(Point2D::new(10., 20.), LogicalSize::new(40., 40.)),
2913 LogicalRect::new(Point2D::new(5., 6.), LogicalSize::new(20., 20.)),
2914 LogicalRect::new(Point2D::new(8., 4.), LogicalSize::new(10., 10.)),
2915 ],
2916 window_adapter: Rc::downgrade(&window_adapter) as _,
2917 root: WindowItem::default(),
2918 transform,
2919 clip,
2920 leaf: WindowItem::default(),
2921 })),
2922 )
2923 }
2924
2925 fn assert_point_approx_eq(actual: LogicalPoint, expected: LogicalPoint) {
2926 const EPSILON: f32 = 0.0001;
2927 assert!(
2928 (actual.x - expected.x).abs() < EPSILON,
2929 "actual x {}, expected x {}",
2930 actual.x,
2931 expected.x
2932 );
2933 assert!(
2934 (actual.y - expected.y).abs() < EPSILON,
2935 "actual y {}, expected y {}",
2936 actual.y,
2937 expected.y
2938 );
2939 }
2940
2941 #[test]
2942 fn test_map_to_ancestor() {
2943 let (_window_adapter, item_tree) = create_subsubtree_items(None);
2944 let root = ItemRc::new_root(item_tree);
2945 let first_child = root.first_child().unwrap();
2946 let first_child_of_first_child = first_child.first_child().unwrap();
2947
2948 {
2949 let point = first_child.map_to_ancestor(Point2D::new(6., 19.), &root);
2950 assert_eq!(point.x, 6.);
2951 assert_eq!(point.y, 19.);
2952 }
2953
2954 {
2955 let point =
2956 first_child_of_first_child.map_to_ancestor(Point2D::new(27., -10.), &first_child);
2957 assert_eq!(point.x, 27.);
2958 assert_eq!(point.y, -10.);
2959 }
2960
2961 {
2962 let point = first_child_of_first_child.map_to_ancestor(Point2D::new(27., -10.), &root);
2964 assert_eq!(point.x, GEOMETRY_POSITION_X + 27.);
2966 assert_eq!(point.y, GEOMETRY_POSITION_Y - 10.);
2967 }
2968 }
2969
2970 #[test]
2971 fn test_map_to_window() {
2972 let (_window_adapter, item_tree) = create_subsubtree_items(None);
2973 let root = ItemRc::new_root(item_tree);
2974 let first_child = root.first_child().unwrap();
2975 let first_child_of_first_child = first_child.first_child().unwrap();
2976
2977 let point = first_child_of_first_child.map_to_window(Point2D::new(-5., 7.));
2978 assert_eq!(point.x, GEOMETRY_POSITION_X + GEOMETRY_POSITION_X - 5.);
2980 assert_eq!(point.y, GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y + 7.);
2981 }
2982
2983 #[test]
2984 fn test_map_to_window_through_transform_roundtrip() {
2985 let (_window_adapter, item_tree) = create_transform_test_items();
2986 let root = ItemRc::new_root(item_tree);
2987 let transform = root.first_child().unwrap();
2988 let clip = transform.first_child().unwrap();
2989 let leaf = clip.first_child().unwrap();
2990
2991 let local_point = Point2D::new(4., 5.);
2992 let window_point = leaf.map_to_window(local_point);
2993 assert_point_approx_eq(window_point, Point2D::new(28., 53.));
2994 }
2995
2996 #[test]
2997 fn test_visibility_with_clip_under_transform() {
2998 let (_window_adapter, item_tree) = create_transform_test_items();
2999 let root = ItemRc::new_root(item_tree);
3000 let transform = root.first_child().unwrap();
3001 let clip = transform.first_child().unwrap();
3002 let leaf = clip.first_child().unwrap();
3003
3004 assert!(leaf.is_visible());
3005
3006 let hidden_point = leaf.map_to_window(Point2D::new(25., 25.));
3007 let (clip_rect, leaf_geometry) = leaf.absolute_clip_rect_and_geometry();
3008 assert!(clip_rect.intersection(&leaf_geometry).is_some());
3009 assert!(!clip_rect.contains(hidden_point));
3010 }
3011
3012 #[test]
3013 fn test_absolute_clip_rect_and_geometry_under_transform() {
3014 let (_window_adapter, item_tree) = create_transform_test_items();
3015 let root = ItemRc::new_root(item_tree);
3016 let transform = root.first_child().unwrap();
3017 let clip = transform.first_child().unwrap();
3018 let leaf = clip.first_child().unwrap();
3019
3020 let (clip_rect, leaf_geometry) = leaf.absolute_clip_rect_and_geometry();
3021 assert_point_approx_eq(clip_rect.origin, Point2D::new(20., 38.));
3024 assert_point_approx_eq(
3025 Point2D::new(clip_rect.width(), clip_rect.height()),
3026 Point2D::new(40., 60.),
3027 );
3028 assert_point_approx_eq(leaf_geometry.origin, Point2D::new(36., 50.));
3032 assert_point_approx_eq(
3033 Point2D::new(leaf_geometry.width(), leaf_geometry.height()),
3034 Point2D::new(20., 30.),
3035 );
3036 }
3037
3038 #[test]
3039 fn test_map_to_native_window_popup() {
3040 const POPUP_LOCATION: LogicalPosition = LogicalPosition::new(20., 33.);
3041 let mut window_item = WindowItem::default();
3042 window_item.width = Property::new(LogicalLength::new(30.));
3043 window_item.height = Property::new(LogicalLength::new(30.));
3044 let (window_adapter, parent) = create_one_node_component(Some(window_item));
3046 let popup_component = create_subsubtree_items(Some(window_adapter.clone())).1;
3047 window_adapter.window.0.show_popup(
3048 &popup_component,
3049 alloc::boxed::Box::new(move || POPUP_LOCATION),
3050 crate::items::PopupClosePolicy::NoAutoClose,
3051 &ItemRc::new_root(parent.clone()),
3052 crate::window::WindowKind::Popup,
3053 alloc::boxed::Box::new(|_| {}),
3054 );
3055
3056 let root = ItemRc::new_root(popup_component);
3057 let first_child = root.first_child().unwrap();
3058 let first_child_of_first_child = first_child.first_child().unwrap();
3059
3060 let active_popups = window_adapter.window.0.active_popups();
3062 assert_eq!(active_popups.len(), 1);
3063 let popup = active_popups.first().unwrap();
3064 assert!(matches!(popup.location, crate::window::PopupWindowLocation::ChildWindow { .. }));
3065
3066 let point = first_child_of_first_child.map_to_native_window(Point2D::new(3., -82.));
3069 assert_eq!(
3070 point.x,
3071 POPUP_LOCATION.x + GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + 3.
3073 );
3074 assert_eq!(
3075 point.y,
3076 POPUP_LOCATION.y + GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y
3077 - 82.
3078 );
3079 }
3080
3081 #[test]
3082 fn test_map_to_window_popup() {
3083 const POPUP_LOCATION: LogicalPosition = LogicalPosition::new(20., 33.);
3084 let (window_adapter, item_tree) = create_subsubtree_items(None);
3085 window_adapter.window.0.show_popup(
3086 &item_tree,
3087 alloc::boxed::Box::new(move || POPUP_LOCATION),
3088 crate::items::PopupClosePolicy::NoAutoClose,
3089 &ItemRc::new_root(item_tree.clone()),
3090 crate::window::WindowKind::Popup,
3091 alloc::boxed::Box::new(|_| {}),
3092 );
3093
3094 let root = ItemRc::new_root(item_tree);
3095 let first_child = root.first_child().unwrap();
3096 let first_child_of_first_child = first_child.first_child().unwrap();
3097
3098 let active_popups = window_adapter.window.0.active_popups();
3100 assert_eq!(active_popups.len(), 1);
3101 let popup = active_popups.first().unwrap();
3102 assert!(matches!(popup.location, crate::window::PopupWindowLocation::ChildWindow { .. }));
3103
3104 let point = first_child_of_first_child.map_to_window(Point2D::new(3., -82.));
3107 assert_eq!(point.x, GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + 3.);
3110 assert_eq!(point.y, GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y - 82.);
3111 }
3112
3113 fn create_subsubtree_items_dynamic_elements(
3115 window_adapter: Rc<WindowAdapter>,
3116 ) -> VRc<ItemTreeVTable> {
3117 let weak_adapter =
3118 Rc::downgrade(&window_adapter) as std::rc::Weak<dyn crate::window::WindowAdapter>;
3119 let mut window_item = WindowItem::default();
3120 window_item.width = Property::new(LogicalLength::new(30.));
3121 window_item.height = Property::new(LogicalLength::new(30.));
3122
3123 let item_tree = VRc::new(TestItemTree {
3124 parent_component: None,
3125 item_tree: vec![
3126 ItemTreeNode::Item {
3128 is_accessible: false,
3129 children_count: 1,
3130 children_index: 1,
3131 parent_index: 0,
3132 item_array_index: 0,
3133 },
3134 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
3136 ],
3137 subtrees: std::cell::RefCell::new(Vec::new()),
3138 subtree_index: usize::MAX,
3139 window_adapter: weak_adapter.clone(),
3140 window_item: Some(window_item),
3141 });
3142
3143 item_tree.as_pin_ref().subtrees.replace(vec![vec![VRc::new(TestItemTree {
3144 parent_component: Some(VRc::downgrade(&VRc::into_dyn(item_tree.clone()))),
3145 item_tree: vec![
3146 ItemTreeNode::Item {
3148 is_accessible: false,
3149 children_count: 1,
3150 children_index: 1,
3151 parent_index: 1, item_array_index: 0,
3153 },
3154 ItemTreeNode::Item {
3156 is_accessible: false,
3157 children_count: 0,
3158 children_index: 0,
3159 parent_index: 0,
3160 item_array_index: 1,
3161 },
3162 ],
3163 subtrees: std::cell::RefCell::new(Vec::new()),
3164 subtree_index: 0,
3165
3166 window_adapter: weak_adapter,
3167 window_item: None,
3168 })]]);
3169
3170 VRc::into_dyn(item_tree)
3171 }
3172
3173 #[test]
3176 fn test_map_to_native_window_popup_dynamic_element() {
3177 const POPUP_LOCATION: LogicalPosition = LogicalPosition::new(20., 33.);
3178
3179 let mut window_item = WindowItem::default();
3180 window_item.width = Property::new(LogicalLength::new(30.));
3181 window_item.height = Property::new(LogicalLength::new(30.));
3182
3183 let (window_adapter, parent) = create_one_node_component(Some(window_item));
3185 let popup_component = create_subsubtree_items_dynamic_elements(window_adapter.clone());
3186 window_adapter.window.0.show_popup(
3187 &popup_component,
3188 alloc::boxed::Box::new(move || POPUP_LOCATION),
3189 crate::items::PopupClosePolicy::NoAutoClose,
3190 &ItemRc::new_root(parent.clone()),
3191 crate::window::WindowKind::Popup,
3192 alloc::boxed::Box::new(|_| {}),
3193 );
3194
3195 let active_popups = window_adapter.window.0.active_popups();
3197 assert_eq!(active_popups.len(), 1);
3198 let popup = active_popups.first().unwrap();
3199 assert!(matches!(popup.location, crate::window::PopupWindowLocation::ChildWindow { .. }));
3200
3201 let root = ItemRc::new_root(popup_component);
3202 let first_child = root.first_child().unwrap();
3203 let comp_ref_pin = vtable::VRc::borrow_pin(&root.item_tree);
3205 let item_tree_array = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
3206 assert!(matches!(
3207 item_tree_array.get(1).expect("Must be one element"),
3208 ItemTreeNode::DynamicTree { .. }
3209 ));
3210 let first_child_of_first_child = first_child.first_child().expect("We have one child");
3212
3213 let point = first_child_of_first_child.map_to_native_window(Point2D::new(3., -82.));
3216 assert_eq!(
3217 point.x,
3218 POPUP_LOCATION.x + GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + 3.
3220 );
3221 assert_eq!(
3222 point.y,
3223 POPUP_LOCATION.y + GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y
3224 - 82.
3225 );
3226 }
3227
3228 impl crate::renderer::RendererSealed for Renderer {
3229 fn char_size(
3230 &self,
3231 _text_item: Pin<&dyn crate::item_rendering::HasFont>,
3232 _item_rc: &crate::item_tree::ItemRc,
3233 _ch: char,
3234 ) -> LogicalSize {
3235 LogicalSize::new(5., 10.)
3236 }
3237
3238 fn font_metrics(
3239 &self,
3240 _font_request: crate::graphics::FontRequest,
3241 ) -> crate::items::FontMetrics {
3242 crate::items::FontMetrics { ..Default::default() }
3243 }
3244
3245 fn free_graphics_resources(
3246 &self,
3247 _component: ItemTreeRef,
3248 _items: &mut dyn Iterator<Item = Pin<crate::items::ItemRef<'_>>>,
3249 ) -> Result<(), crate::platform::PlatformError> {
3250 Ok(())
3251 }
3252
3253 fn mark_dirty_region(&self, _region: crate::partial_renderer::DirtyRegion) {
3254 }
3256
3257 fn register_bitmap_font(&self, _font_data: &'static crate::graphics::BitmapFont) {
3258 unimplemented!("Not required in this test");
3259 }
3260
3261 fn register_font_from_memory(
3262 &self,
3263 _data: &'static [u8],
3264 ) -> Result<(), std::prelude::v1::Box<dyn std::error::Error>> {
3265 unimplemented!("Not required in this test");
3266 }
3267
3268 fn register_font_from_path(
3269 &self,
3270 _path: &std::path::Path,
3271 ) -> Result<(), std::prelude::v1::Box<dyn std::error::Error>> {
3272 unimplemented!("Not required in this test");
3273 }
3274
3275 fn resize(&self, _size: crate::api::PhysicalSize) -> Result<(), crate::api::PlatformError> {
3276 Ok(())
3277 }
3278
3279 fn scale_factor(&self) -> Option<crate::lengths::ScaleFactor> {
3280 None
3281 }
3282
3283 fn set_rendering_notifier(
3284 &self,
3285 _callback: std::prelude::v1::Box<dyn crate::api::RenderingNotifier>,
3286 ) -> Result<(), crate::api::SetRenderingNotifierError> {
3287 Ok(())
3288 }
3289
3290 fn set_window_adapter(
3291 &self,
3292 _window_adapter: &std::rc::Rc<dyn crate::window::WindowAdapter>,
3293 ) {
3294 unimplemented!("Not required in this test");
3295 }
3296
3297 fn slint_context(&self) -> Option<crate::SlintContext> {
3298 None
3299 }
3300
3301 fn supports_transformations(&self) -> bool {
3302 self.supports_transformations
3303 }
3304
3305 fn take_snapshot(
3306 &self,
3307 ) -> Result<crate::api::SharedPixelBuffer<crate::api::Rgba8Pixel>, crate::api::PlatformError>
3308 {
3309 unimplemented!("Not required in this test");
3310 }
3311
3312 fn text_input_byte_offset_for_position(
3313 &self,
3314 _text_input: Pin<&crate::items::TextInput>,
3315 _item_rc: &ItemRc,
3316 _pos: LogicalPoint,
3317 ) -> (usize, crate::items::TextCursorAffinity) {
3318 unimplemented!("Not required in this test");
3319 }
3320
3321 fn text_input_cursor_rect_for_byte_offset(
3322 &self,
3323 _text_input: Pin<&crate::items::TextInput>,
3324 _item_rc: &ItemRc,
3325 _byte_offset: usize,
3326 _affinity: crate::items::TextCursorAffinity,
3327 ) -> LogicalRect {
3328 unimplemented!("Not required in this test");
3329 }
3330
3331 fn text_size(
3332 &self,
3333 _text_item: Pin<&dyn crate::item_rendering::RenderString>,
3334 _item_rc: &crate::item_tree::ItemRc,
3335 _max_width: Option<crate::lengths::LogicalLength>,
3336 _text_wrap: crate::items::TextWrap,
3337 ) -> crate::lengths::LogicalSize {
3338 unimplemented!("Not required in this test");
3339 }
3340
3341 fn window_adapter(&self) -> Option<std::rc::Rc<dyn crate::window::WindowAdapter>> {
3342 unimplemented!("Not required in this test");
3343 }
3344 }
3345}