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 item_array.iter().for_each(|item| {
213 item.apply_pin(base).as_ref().deinit(window_adapter);
214 });
215 window_adapter.renderer().free_graphics_resources(item_tree, &mut item_array.iter().map(|item| item.apply_pin(base))).expect(
216 "Fatal error encountered when freeing graphics resources while destroying Slint component",
217 );
218
219 if let Some(w) = window_adapter.internal(crate::InternalToken) {
220 w.unregister_item_tree(item_tree, &mut item_array.iter().map(|item| item.apply_pin(base)));
221 }
222
223 let window_inner = crate::window::WindowInner::from_pub(window_adapter.window());
225 let to_close_popups = window_inner
226 .active_popups()
227 .iter()
228 .filter_map(|p| p.parent_item.upgrade().is_none().then_some(p.popup_id))
229 .collect::<Vec<_>>();
230 for popup_id in to_close_popups {
231 window_inner.close_popup(popup_id);
232 }
233}
234
235fn find_sibling_outside_repeater(
236 component: &ItemTreeRc,
237 comp_ref_pin: Pin<VRef<ItemTreeVTable>>,
238 index: u32,
239 sibling_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
240 subtree_child: &dyn Fn(usize, usize) -> usize,
241) -> Option<ItemRc> {
242 assert_ne!(index, 0);
243
244 let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
245
246 let mut current_sibling = index;
247 loop {
248 current_sibling = sibling_step(&item_tree, current_sibling)?;
249
250 if let Some(node) = step_into_node(
251 component,
252 &comp_ref_pin,
253 current_sibling,
254 &item_tree,
255 subtree_child,
256 &core::convert::identity,
257 ) {
258 return Some(node);
259 }
260 }
261}
262
263fn step_into_node(
264 component: &ItemTreeRc,
265 comp_ref_pin: &Pin<VRef<ItemTreeVTable>>,
266 node_index: u32,
267 item_tree: &crate::item_tree::ItemTreeNodeArray,
268 subtree_child: &dyn Fn(usize, usize) -> usize,
269 wrap_around: &dyn Fn(ItemRc) -> ItemRc,
270) -> Option<ItemRc> {
271 match item_tree.get(node_index).expect("Invalid index passed to item tree") {
272 crate::item_tree::ItemTreeNode::Item { .. } => {
273 Some(ItemRc::new(component.clone(), node_index))
274 }
275 crate::item_tree::ItemTreeNode::DynamicTree { index, .. } => {
276 let range = comp_ref_pin.as_ref().get_subtree_range(*index);
277 let component_index = subtree_child(range.start, range.end);
278 let mut child_instance = Default::default();
279 comp_ref_pin.as_ref().get_subtree(*index, component_index, &mut child_instance);
280 child_instance
281 .upgrade()
282 .map(|child_instance| wrap_around(ItemRc::new_root(child_instance)))
283 }
284 }
285}
286
287pub enum ParentItemTraversalMode {
288 FindAllParents,
289 StopAtPopups,
290}
291
292#[repr(C)]
294#[derive(Clone)]
295pub struct ItemRc {
296 item_tree: vtable::VRc<ItemTreeVTable>,
297 index: u32,
298}
299
300impl core::fmt::Debug for ItemRc {
301 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
302 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
303 let mut debug = SharedString::new();
304 comp_ref_pin.as_ref().item_element_infos(self.index, &mut debug);
305
306 write!(f, "ItemRc{{ {:p}, {:?} {debug}}}", comp_ref_pin.as_ptr(), self.index)
307 }
308}
309
310impl ItemRc {
311 pub fn new(item_tree: vtable::VRc<ItemTreeVTable>, index: u32) -> Self {
313 Self { item_tree, index }
314 }
315
316 pub fn new_root(item_tree: vtable::VRc<ItemTreeVTable>) -> Self {
317 Self { item_tree, index: Self::root_index() }
318 }
319
320 #[inline(always)]
321 pub const fn root_index() -> u32 {
322 0
323 }
324
325 #[inline(always)]
326 pub fn is_root(&self) -> bool {
327 self.index == Self::root_index()
328 }
329
330 pub fn is_root_item_of(&self, item_tree: &VRc<ItemTreeVTable>) -> bool {
332 self.is_root() && VRc::ptr_eq(&self.item_tree, item_tree)
333 }
334
335 pub fn borrow<'a>(&'a self) -> Pin<ItemRef<'a>> {
337 #![allow(unsafe_code)]
338 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
339 let result = comp_ref_pin.as_ref().get_item_ref(self.index);
340 unsafe { core::mem::transmute::<Pin<ItemRef<'_>>, Pin<ItemRef<'a>>>(result) }
343 }
344
345 pub fn downcast<T: HasStaticVTable<ItemVTable>>(&self) -> Option<VRcMapped<ItemTreeVTable, T>> {
347 #![allow(unsafe_code)]
348 let item = self.borrow();
349 ItemRef::downcast_pin::<T>(item)?;
350
351 Some(vtable::VRc::map_dyn(self.item_tree.clone(), |comp_ref_pin| {
352 let result = comp_ref_pin.as_ref().get_item_ref(self.index);
353 let item =
356 unsafe { core::mem::transmute::<Pin<ItemRef<'_>>, Pin<ItemRef<'_>>>(result) };
357 ItemRef::downcast_pin::<T>(item).unwrap()
358 }))
359 }
360
361 pub fn downgrade(&self) -> ItemWeak {
362 ItemWeak { item_tree: VRc::downgrade(&self.item_tree), index: self.index }
363 }
364
365 pub fn parent_item(&self, find_mode: ParentItemTraversalMode) -> Option<ItemRc> {
369 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
370 let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
371
372 if let Some(parent_index) = item_tree.parent(self.index) {
373 return Some(ItemRc::new(self.item_tree.clone(), parent_index));
374 }
375
376 let mut r = ItemWeak::default();
378 comp_ref_pin.as_ref().parent_node(&mut r);
379 let parent = r.upgrade()?;
380 let comp_ref_pin = vtable::VRc::borrow_pin(&parent.item_tree);
381 let item_tree_array = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
382 if let Some(ItemTreeNode::DynamicTree { parent_index, .. }) =
383 item_tree_array.get(parent.index())
384 {
385 Some(ItemRc::new(parent.item_tree.clone(), *parent_index))
387 } else {
388 match find_mode {
391 ParentItemTraversalMode::FindAllParents => Some(parent),
392 ParentItemTraversalMode::StopAtPopups => None,
393 }
394 }
395 }
396
397 pub fn is_visible(&self) -> bool {
400 let (clip, geometry) = self.absolute_clip_rect_and_geometry();
401 let clip = clip.to_box2d();
402 let geometry = geometry.to_box2d();
403 !clip.is_empty()
404 && clip.max.x >= geometry.min.x
405 && clip.max.y >= geometry.min.y
406 && clip.min.x <= geometry.max.x
407 && clip.min.y <= geometry.max.y
408 }
409
410 pub(crate) fn is_visible_or_clipped_by_flickable(&self) -> bool {
412 if self.is_visible() {
413 return true;
414 }
415
416 let geometry = self.absolute_clip_rect_and_geometry().1.to_box2d();
420 let mut parent = self.parent_item(ParentItemTraversalMode::StopAtPopups);
421 while let Some(ancestor) = parent {
422 if ancestor.borrow().as_ref().clips_children() {
423 let (clip, ancestor_geo) = ancestor.absolute_clip_rect_and_geometry();
424 let clip = ancestor_geo.intersection(&clip).unwrap_or_default().to_box2d();
425 let item_in_clip = !clip.is_empty()
426 && clip.max.x >= geometry.min.x
427 && clip.max.y >= geometry.min.y
428 && clip.min.x <= geometry.max.x
429 && clip.min.y <= geometry.max.y;
430 if !item_in_clip {
431 return ancestor.downcast::<crate::items::Flickable>().is_some()
432 && ancestor.is_visible_or_clipped_by_flickable();
433 }
434 }
435 parent = ancestor.parent_item(ParentItemTraversalMode::StopAtPopups);
436 }
437
438 false
439 }
440
441 fn local_to_window_transform(&self, stop_condition: impl Fn(&Self) -> bool) -> ItemTransform {
449 let supports_transformations = self
450 .window_adapter()
451 .is_none_or(|adapter| adapter.renderer().supports_transformations());
452 let mut transform = ItemTransform::identity();
453 let mut current = self.clone();
454 while let Some(parent) = current.parent_item(ParentItemTraversalMode::StopAtPopups) {
455 if stop_condition(&parent) {
456 break;
457 }
458 if supports_transformations
459 && let Some(children_transform) = parent.children_transform()
460 {
461 transform = transform.then(&children_transform);
462 }
463 transform = transform.then_translate(parent.geometry().origin.to_vector().cast());
464 current = parent;
465 }
466 transform
467 }
468
469 fn absolute_clip_rect_and_geometry(&self) -> (LogicalRect, LogicalRect) {
472 let geometry = self
473 .local_to_window_transform(|_| false)
474 .outer_transformed_rect(&self.geometry().cast())
475 .cast();
476
477 let mut clip = LogicalRect::from_size((crate::Coord::MAX, crate::Coord::MAX).into());
479 let mut cur = self.parent_item(ParentItemTraversalMode::StopAtPopups);
480 while let Some(ref ancestor) = cur {
481 if ancestor.borrow().as_ref().clips_children() {
482 let (_, ancestor_geom) = ancestor.absolute_clip_rect_and_geometry();
483 clip = ancestor_geom.intersection(&clip).unwrap_or_default();
484 }
485 cur = ancestor.parent_item(ParentItemTraversalMode::StopAtPopups);
486 }
487
488 (clip, geometry)
489 }
490
491 pub fn is_accessible(&self) -> bool {
492 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
493 let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
494
495 if let Some(n) = &item_tree.get(self.index) {
496 match n {
497 ItemTreeNode::Item { is_accessible, .. } => *is_accessible,
498 ItemTreeNode::DynamicTree { .. } => false,
499 }
500 } else {
501 false
502 }
503 }
504
505 pub fn accessible_role(&self) -> crate::items::AccessibleRole {
506 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
507 comp_ref_pin.as_ref().accessible_role(self.index)
508 }
509
510 pub fn accessible_string_property(
511 &self,
512 what: crate::accessibility::AccessibleStringProperty,
513 ) -> Option<SharedString> {
514 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
515 let mut result = Default::default();
516 let ok = comp_ref_pin.as_ref().accessible_string_property(self.index, what, &mut result);
517 ok.then_some(result)
518 }
519
520 pub fn accessible_action(&self, action: &crate::accessibility::AccessibilityAction) {
521 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
522 comp_ref_pin.as_ref().accessibility_action(self.index, action);
523 }
524
525 pub fn supported_accessibility_actions(&self) -> SupportedAccessibilityAction {
526 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
527 comp_ref_pin.as_ref().supported_accessibility_actions(self.index)
528 }
529
530 fn raw_element_infos(&self) -> Option<SharedString> {
532 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
533 let mut result = SharedString::new();
534 comp_ref_pin.as_ref().item_element_infos(self.index, &mut result).then_some(result)
535 }
536
537 pub fn element_count(&self) -> Option<usize> {
538 self.raw_element_infos().map(|s| s.as_str().split("/").count())
539 }
540
541 pub fn element_type_names_and_ids(
542 &self,
543 element_index: usize,
544 ) -> Option<Vec<(SharedString, SharedString)>> {
545 self.raw_element_infos().map(|infos| {
546 infos
547 .as_str()
548 .split("/")
549 .nth(element_index)
550 .unwrap()
551 .split(";")
552 .map(|encoded_elem_info| {
553 let mut decoder = encoded_elem_info.split(',');
554 let type_name = decoder.next().unwrap().into();
555 let id = decoder.next().map(Into::into).unwrap_or_default();
556 (type_name, id)
557 })
558 .collect()
559 })
560 }
561
562 pub fn element_layout_kind(&self, element_index: usize) -> Option<SharedString> {
563 self.raw_element_infos().and_then(|infos| {
564 let first_debug_entry =
565 infos.as_str().split("/").nth(element_index)?.split(';').next()?;
566 let mut decoder = first_debug_entry.split(',');
567 let _type_name = decoder.next();
568 let _id = decoder.next();
569 decoder.next().filter(|s| !s.is_empty()).map(SharedString::from)
570 })
571 }
572
573 pub fn geometry(&self) -> LogicalRect {
574 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
575 comp_ref_pin.as_ref().item_geometry(self.index)
576 }
577
578 pub fn bounding_rect(
581 &self,
582 geometry: &LogicalRect,
583 window_adapter: &WindowAdapterRc,
584 ) -> LogicalRect {
585 self.borrow().as_ref().bounding_rect(window_adapter, self, *geometry)
586 }
587
588 pub fn map_to_native_window(&self, p: LogicalPoint) -> LogicalPoint {
592 let mut pos = self.map_to_item_tree_impl(p, |_| false);
593 if let Some(window_adapter) = self.window_adapter() {
595 let window_inner = crate::window::WindowInner::from_pub(window_adapter.window());
596 let active_popups = window_inner.active_popups();
597 for popup in active_popups.iter() {
598 if let crate::window::PopupWindowLocation::ChildWindow(location) = &popup.location {
599 let popup_item = ItemRc::new_root(popup.component.clone());
600
601 if popup_item.is_root_item_of(self.item_tree()) {
604 pos += location.to_vector();
605 } else {
606 let mut current = ItemRc::new_root(self.item_tree.clone());
607 while let Some(parent) =
609 current.parent_item(ParentItemTraversalMode::StopAtPopups)
610 {
611 if popup_item.is_root_item_of(parent.item_tree()) {
612 pos += location.to_vector();
613 break;
614 }
615
616 current = ItemRc::new_root(parent.item_tree);
618 }
619 }
620 }
621 }
622 }
623 pos
624 }
625
626 pub fn map_to_window(&self, p: LogicalPoint) -> LogicalPoint {
629 self.map_to_item_tree_impl(p, |_| false)
630 }
631
632 pub fn map_to_item_tree(
635 &self,
636 p: LogicalPoint,
637 item_tree: &vtable::VRc<ItemTreeVTable>,
638 ) -> LogicalPoint {
639 self.map_to_item_tree_impl(p, |current| current.is_root_item_of(item_tree))
640 }
641
642 fn map_to_ancestor(&self, p: LogicalPoint, ancestor: &Self) -> LogicalPoint {
646 self.map_to_item_tree_impl(p, |parent| parent == ancestor)
647 }
648
649 fn map_to_item_tree_impl(
650 &self,
651 p: LogicalPoint,
652 stop_condition: impl Fn(&Self) -> bool,
653 ) -> LogicalPoint {
654 if stop_condition(self) {
655 return p;
656 }
657 self.local_to_window_transform(stop_condition).transform_point(p.cast()).cast()
658 }
659
660 pub fn index(&self) -> u32 {
662 self.index
663 }
664 pub fn item_tree(&self) -> &vtable::VRc<ItemTreeVTable> {
666 &self.item_tree
667 }
668
669 fn find_child(
671 &self,
672 child_access: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
673 child_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
674 subtree_child: &dyn Fn(usize, usize) -> usize,
675 ) -> Option<Self> {
676 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
677 let item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
678
679 let mut current_child_index = child_access(&item_tree, self.index())?;
680 loop {
681 if let Some(item) = step_into_node(
682 self.item_tree(),
683 &comp_ref_pin,
684 current_child_index,
685 &item_tree,
686 subtree_child,
687 &core::convert::identity,
688 ) {
689 return Some(item);
690 }
691 current_child_index = child_step(&item_tree, current_child_index)?;
692 }
693 }
694
695 pub fn first_child(&self) -> Option<Self> {
697 self.find_child(
698 &|item_tree, index| item_tree.first_child(index),
699 &|item_tree, index| item_tree.next_sibling(index),
700 &|start, _| start,
701 )
702 }
703
704 pub fn last_child(&self) -> Option<Self> {
706 self.find_child(
707 &|item_tree, index| item_tree.last_child(index),
708 &|item_tree, index| item_tree.previous_sibling(index),
709 &|_, end| end.wrapping_sub(1),
710 )
711 }
712
713 fn find_sibling(
714 &self,
715 sibling_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
716 subtree_step: &dyn Fn(usize) -> usize,
717 subtree_child: &dyn Fn(usize, usize) -> usize,
718 ) -> Option<Self> {
719 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
720 if self.is_root() {
721 let mut parent_item = Default::default();
722 comp_ref_pin.as_ref().parent_node(&mut parent_item);
723 let current_component_subtree_index = comp_ref_pin.as_ref().subtree_index();
724 if let Some(parent_item) = parent_item.upgrade() {
725 let parent = parent_item.item_tree();
726 let parent_ref_pin = vtable::VRc::borrow_pin(parent);
727 let parent_item_index = parent_item.index();
728 let parent_item_tree = crate::item_tree::ItemTreeNodeArray::new(&parent_ref_pin);
729
730 let subtree_index = match parent_item_tree.get(parent_item_index)? {
731 crate::item_tree::ItemTreeNode::Item { .. } => {
732 return None;
734 }
735 crate::item_tree::ItemTreeNode::DynamicTree { index, .. } => *index,
736 };
737
738 let next_subtree_index = subtree_step(current_component_subtree_index);
739
740 let mut next_subtree_instance = Default::default();
742 parent_ref_pin.as_ref().get_subtree(
743 subtree_index,
744 next_subtree_index,
745 &mut next_subtree_instance,
746 );
747 if let Some(next_subtree_instance) = next_subtree_instance.upgrade() {
748 return Some(ItemRc::new_root(next_subtree_instance));
749 }
750
751 find_sibling_outside_repeater(
753 parent,
754 parent_ref_pin,
755 parent_item_index,
756 sibling_step,
757 subtree_child,
758 )
759 } else {
760 None }
762 } else {
763 find_sibling_outside_repeater(
764 self.item_tree(),
765 comp_ref_pin,
766 self.index(),
767 sibling_step,
768 subtree_child,
769 )
770 }
771 }
772
773 pub fn previous_sibling(&self) -> Option<Self> {
775 self.find_sibling(
776 &|item_tree, index| item_tree.previous_sibling(index),
777 &|index| index.wrapping_sub(1),
778 &|_, end| end.wrapping_sub(1),
779 )
780 }
781
782 pub fn next_sibling(&self) -> Option<Self> {
784 self.find_sibling(
785 &|item_tree, index| item_tree.next_sibling(index),
786 &|index| index.saturating_add(1),
787 &|start, _| start,
788 )
789 }
790
791 fn move_focus(
792 &self,
793 focus_step: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
794 subtree_step: &dyn Fn(ItemRc) -> Option<ItemRc>,
795 subtree_child: &dyn Fn(usize, usize) -> usize,
796 step_in: &dyn Fn(ItemRc) -> ItemRc,
797 step_out: &dyn Fn(&crate::item_tree::ItemTreeNodeArray, u32) -> Option<u32>,
798 ) -> Self {
799 let mut component = self.item_tree().clone();
800 let mut comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
801 let mut item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
802
803 let mut to_focus = self.index();
804
805 'in_tree: loop {
806 if let Some(next) = focus_step(&item_tree, to_focus) {
807 if let Some(item) = step_into_node(
808 &component,
809 &comp_ref_pin,
810 next,
811 &item_tree,
812 subtree_child,
813 step_in,
814 ) {
815 return item;
816 }
817 to_focus = next;
818 } else {
820 let mut root = ItemRc::new_root(component);
822 if let Some(item) = subtree_step(root.clone()) {
823 return step_in(item);
825 }
826
827 let root_component = root.item_tree();
829 let root_comp_ref = vtable::VRc::borrow_pin(root_component);
830 let mut parent_node = Default::default();
831 root_comp_ref.as_ref().parent_node(&mut parent_node);
832
833 while let Some(parent) = parent_node.upgrade() {
834 component = parent.item_tree().clone();
836 comp_ref_pin = vtable::VRc::borrow_pin(&component);
837 item_tree = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
838
839 let index = parent.index();
840
841 if !matches!(item_tree.get(index), Some(ItemTreeNode::DynamicTree { .. })) {
842 break;
844 }
845
846 if let Some(next) = step_out(&item_tree, index) {
847 if let Some(item) = step_into_node(
848 parent.item_tree(),
849 &comp_ref_pin,
850 next,
851 &item_tree,
852 subtree_child,
853 step_in,
854 ) {
855 return item;
857 } else {
858 to_focus = parent.index();
860 continue 'in_tree; }
862 }
863
864 root = ItemRc::new_root(component.clone());
865 if let Some(item) = subtree_step(root.clone()) {
866 return step_in(item);
867 }
868
869 let root_component = root.item_tree();
871 let root_comp_ref = vtable::VRc::borrow_pin(root_component);
872 parent_node = Default::default();
873 root_comp_ref.as_ref().parent_node(&mut parent_node);
874 }
875
876 return step_in(root);
878 }
879 }
880 }
881
882 pub fn previous_focus_item(&self) -> Self {
884 self.move_focus(
885 &|item_tree, index| {
886 crate::item_focus::default_previous_in_local_focus_chain(index, item_tree)
887 },
888 &|root| root.previous_sibling(),
889 &|_, end| end.wrapping_sub(1),
890 &|root| {
891 let mut current = root;
892 loop {
893 if let Some(next) = current.last_child() {
894 current = next;
895 } else {
896 return current;
897 }
898 }
899 },
900 &|item_tree, index| item_tree.parent(index),
901 )
902 }
903
904 pub fn next_focus_item(&self) -> Self {
906 self.move_focus(
907 &|item_tree, index| {
908 crate::item_focus::default_next_in_local_focus_chain(index, item_tree)
909 },
910 &|root| root.next_sibling(),
911 &|start, _| start,
912 &core::convert::identity,
913 &|item_tree, index| crate::item_focus::step_out_of_node(index, item_tree),
914 )
915 }
916
917 pub fn window_adapter(&self) -> Option<WindowAdapterRc> {
918 let comp_ref_pin = vtable::VRc::borrow_pin(&self.item_tree);
919 let mut result = None;
920 comp_ref_pin.as_ref().window_adapter(false, &mut result);
921 result
922 }
923
924 fn visit_descendants_impl<R>(
927 &self,
928 visitor: &mut impl FnMut(&ItemRc) -> ControlFlow<R>,
929 ) -> Option<R> {
930 let mut result = None;
931
932 let mut actual_visitor = |item_tree: &ItemTreeRc,
933 index: u32,
934 _item_pin: core::pin::Pin<ItemRef>|
935 -> VisitChildrenResult {
936 let item_rc = ItemRc::new(item_tree.clone(), index);
937
938 match visitor(&item_rc) {
939 ControlFlow::Continue(_) => {
940 if let Some(x) = item_rc.visit_descendants_impl(visitor) {
941 result = Some(x);
942 return VisitChildrenResult::abort(index, 0);
943 }
944 }
945 ControlFlow::Break(x) => {
946 result = Some(x);
947 return VisitChildrenResult::abort(index, 0);
948 }
949 }
950
951 VisitChildrenResult::CONTINUE
952 };
953 vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);
954
955 VRc::borrow_pin(self.item_tree()).as_ref().visit_children_item(
956 self.index() as isize,
957 TraversalOrder::BackToFront,
958 actual_visitor,
959 );
960
961 result
962 }
963
964 pub fn visit_descendants<R>(
974 &self,
975 mut visitor: impl FnMut(&ItemRc) -> ControlFlow<R>,
976 ) -> Option<R> {
977 ensure_item_tree_instantiated(self.item_tree());
978 self.visit_descendants_impl(&mut visitor)
979 }
980
981 pub fn children_transform(&self) -> Option<ItemTransform> {
984 self.downcast::<crate::items::Transform>().map(|transform_item| {
985 let item = transform_item.as_pin_ref();
986 let origin = item.transform_origin().to_euclid().to_vector().cast::<f32>();
987 ItemTransform::translation(-origin.x, -origin.y)
988 .cast()
989 .then_scale(item.transform_scale_x(), item.transform_scale_y())
990 .then_rotate(euclid::Angle { radians: item.transform_rotation().to_radians() })
991 .then_translate(origin)
992 })
993 }
994
995 pub fn inverse_children_transform(&self) -> Option<ItemTransform> {
1000 self.children_transform()
1001 .and_then(|child_transform| child_transform.inverse())
1003 }
1004
1005 pub(crate) fn try_scroll_into_visible(&self) {
1006 let mut parent = self.parent_item(ParentItemTraversalMode::StopAtPopups);
1007 while let Some(item_rc) = parent.as_ref() {
1008 let item_ref = item_rc.borrow();
1009 if let Some(flickable) = vtable::VRef::downcast_pin::<crate::items::Flickable>(item_ref)
1010 {
1011 let geo = self.geometry();
1012
1013 flickable.reveal_points(
1014 item_rc,
1015 &[
1016 self.map_to_ancestor(
1017 LogicalPoint::new(
1018 geo.origin.x - flickable.viewport_x().0,
1019 geo.origin.y - flickable.viewport_y().0,
1020 ),
1021 item_rc,
1022 ),
1023 self.map_to_ancestor(
1024 LogicalPoint::new(
1025 geo.max_x() - flickable.viewport_x().0,
1026 geo.max_y() - flickable.viewport_y().0,
1027 ),
1028 item_rc,
1029 ),
1030 ],
1031 );
1032 }
1033
1034 parent = item_rc.parent_item(ParentItemTraversalMode::StopAtPopups);
1035 }
1036 }
1037}
1038
1039impl PartialEq for ItemRc {
1040 fn eq(&self, other: &Self) -> bool {
1041 VRc::ptr_eq(&self.item_tree, &other.item_tree) && self.index == other.index
1042 }
1043}
1044
1045impl Eq for ItemRc {}
1046
1047#[derive(Clone, Default)]
1049#[repr(C)]
1050pub struct ItemWeak {
1051 item_tree: crate::item_tree::ItemTreeWeak,
1052 index: u32,
1053}
1054
1055impl ItemWeak {
1056 pub fn upgrade(&self) -> Option<ItemRc> {
1057 self.item_tree.upgrade().map(|c| ItemRc::new(c, self.index))
1058 }
1059}
1060
1061impl PartialEq for ItemWeak {
1062 fn eq(&self, other: &Self) -> bool {
1063 VWeak::ptr_eq(&self.item_tree, &other.item_tree) && self.index == other.index
1064 }
1065}
1066
1067impl Eq for ItemWeak {}
1068
1069#[repr(u8)]
1070#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1071pub enum TraversalOrder {
1072 BackToFront,
1073 FrontToBack,
1074}
1075
1076#[repr(transparent)]
1085#[derive(Copy, Clone, Eq, PartialEq)]
1086pub struct VisitChildrenResult(u64);
1087impl VisitChildrenResult {
1088 pub const CONTINUE: Self = Self(u64::MAX);
1090
1091 pub fn abort(item_index: u32, index_within_repeater: usize) -> Self {
1093 assert!(index_within_repeater < u32::MAX as usize);
1094 Self(item_index as u64 | (index_within_repeater as u64) << 32)
1095 }
1096 pub fn has_aborted(&self) -> bool {
1098 self.0 != Self::CONTINUE.0
1099 }
1100 pub fn aborted_index(&self) -> Option<usize> {
1101 if self.0 != Self::CONTINUE.0 { Some((self.0 & 0xffff_ffff) as usize) } else { None }
1102 }
1103 pub fn aborted_indexes(&self) -> Option<(usize, usize)> {
1104 if self.0 != Self::CONTINUE.0 {
1105 Some(((self.0 & 0xffff_ffff) as usize, (self.0 >> 32) as usize))
1106 } else {
1107 None
1108 }
1109 }
1110}
1111impl core::fmt::Debug for VisitChildrenResult {
1112 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1113 if self.0 == Self::CONTINUE.0 {
1114 write!(f, "CONTINUE")
1115 } else {
1116 write!(f, "({},{})", (self.0 & 0xffff_ffff) as usize, (self.0 >> 32) as usize)
1117 }
1118 }
1119}
1120
1121#[repr(u8)]
1124#[derive(Debug)]
1125pub enum ItemTreeNode {
1126 Item {
1128 is_accessible: bool,
1130
1131 children_count: u32,
1133
1134 children_index: u32,
1136
1137 parent_index: u32,
1139
1140 item_array_index: u32,
1142 },
1143 DynamicTree {
1146 index: u32,
1148
1149 parent_index: u32,
1151 },
1152}
1153
1154impl ItemTreeNode {
1155 pub fn parent_index(&self) -> u32 {
1156 match self {
1157 ItemTreeNode::Item { parent_index, .. } => *parent_index,
1158 ItemTreeNode::DynamicTree { parent_index, .. } => *parent_index,
1159 }
1160 }
1161}
1162
1163pub struct ItemTreeNodeArray<'a> {
1166 node_array: &'a [ItemTreeNode],
1167}
1168
1169impl<'a> ItemTreeNodeArray<'a> {
1170 pub fn new(comp_ref_pin: &'a Pin<VRef<'a, ItemTreeVTable>>) -> Self {
1172 Self { node_array: comp_ref_pin.as_ref().get_item_tree().as_slice() }
1173 }
1174
1175 pub fn get(&self, index: u32) -> Option<&ItemTreeNode> {
1177 self.node_array.get(index as usize)
1178 }
1179
1180 pub fn parent(&self, index: u32) -> Option<u32> {
1182 let index = index as usize;
1183 (index < self.node_array.len() && index != ItemRc::root_index() as usize)
1184 .then(|| self.node_array[index].parent_index())
1185 }
1186
1187 pub fn next_sibling(&self, index: u32) -> Option<u32> {
1189 if let Some(parent_index) = self.parent(index) {
1190 match self.node_array[parent_index as usize] {
1191 ItemTreeNode::Item { children_index, children_count, .. } => {
1192 (index < (children_count + children_index - 1)).then_some(index + 1)
1193 }
1194 ItemTreeNode::DynamicTree { .. } => {
1195 unreachable!("Parent in same item tree is a repeater.")
1196 }
1197 }
1198 } else {
1199 None }
1201 }
1202
1203 pub fn previous_sibling(&self, index: u32) -> Option<u32> {
1205 if let Some(parent_index) = self.parent(index) {
1206 match self.node_array[parent_index as usize] {
1207 ItemTreeNode::Item { children_index, .. } => {
1208 (index > children_index).then_some(index - 1)
1209 }
1210 ItemTreeNode::DynamicTree { .. } => {
1211 unreachable!("Parent in same item tree is a repeater.")
1212 }
1213 }
1214 } else {
1215 None }
1217 }
1218
1219 pub fn first_child(&self, index: u32) -> Option<u32> {
1222 match self.node_array.get(index as usize)? {
1223 ItemTreeNode::Item { children_index, children_count, .. } => {
1224 (*children_count != 0).then_some(*children_index as _)
1225 }
1226 ItemTreeNode::DynamicTree { .. } => None,
1227 }
1228 }
1229
1230 pub fn last_child(&self, index: u32) -> Option<u32> {
1233 match self.node_array.get(index as usize)? {
1234 ItemTreeNode::Item { children_index, children_count, .. } => {
1235 if *children_count != 0 {
1236 Some(*children_index + *children_count - 1)
1237 } else {
1238 None
1239 }
1240 }
1241 ItemTreeNode::DynamicTree { .. } => None,
1242 }
1243 }
1244
1245 pub fn node_count(&self) -> usize {
1247 self.node_array.len()
1248 }
1249}
1250
1251impl<'a> From<&'a [ItemTreeNode]> for ItemTreeNodeArray<'a> {
1252 fn from(item_tree: &'a [ItemTreeNode]) -> Self {
1253 Self { node_array: item_tree }
1254 }
1255}
1256
1257#[cfg_attr(not(feature = "ffi"), i_slint_core_macros::remove_extern)]
1258#[vtable]
1259#[repr(C)]
1260pub struct ItemVisitorVTable {
1262 visit_item: extern "C" fn(
1269 VRefMut<ItemVisitorVTable>,
1270 item_tree: &VRc<ItemTreeVTable, vtable::Dyn>,
1271 index: u32,
1272 item: Pin<VRef<ItemVTable>>,
1273 ) -> VisitChildrenResult,
1274 drop: extern "C" fn(VRefMut<ItemVisitorVTable>),
1276}
1277
1278pub type ItemVisitorRefMut<'a> = vtable::VRefMut<'a, ItemVisitorVTable>;
1280
1281impl<T: FnMut(&ItemTreeRc, u32, Pin<ItemRef>) -> VisitChildrenResult> ItemVisitor for T {
1282 fn visit_item(
1283 &mut self,
1284 item_tree: &ItemTreeRc,
1285 index: u32,
1286 item: Pin<ItemRef>,
1287 ) -> VisitChildrenResult {
1288 self(item_tree, index, item)
1289 }
1290}
1291pub enum ItemVisitorResult<State> {
1292 Continue(State),
1293 SkipChildren,
1294 Abort,
1295}
1296
1297pub fn visit_items<State>(
1303 item_tree: &ItemTreeRc,
1304 order: TraversalOrder,
1305 mut visitor: impl FnMut(&ItemTreeRc, Pin<ItemRef>, u32, &State) -> ItemVisitorResult<State>,
1306 state: State,
1307) -> VisitChildrenResult {
1308 visit_internal(item_tree, order, &mut visitor, -1, &state)
1309}
1310
1311fn visit_internal<State>(
1312 item_tree: &ItemTreeRc,
1313 order: TraversalOrder,
1314 visitor: &mut impl FnMut(&ItemTreeRc, Pin<ItemRef>, u32, &State) -> ItemVisitorResult<State>,
1315 index: isize,
1316 state: &State,
1317) -> VisitChildrenResult {
1318 let mut actual_visitor =
1319 |item_tree: &ItemTreeRc, index: u32, item: Pin<ItemRef>| -> VisitChildrenResult {
1320 match visitor(item_tree, item, index, state) {
1321 ItemVisitorResult::Continue(state) => {
1322 visit_internal(item_tree, order, visitor, index as isize, &state)
1323 }
1324 ItemVisitorResult::SkipChildren => VisitChildrenResult::CONTINUE,
1325 ItemVisitorResult::Abort => VisitChildrenResult::abort(index, 0),
1326 }
1327 };
1328 vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);
1329 VRc::borrow_pin(item_tree).as_ref().visit_children_item(index, order, actual_visitor)
1330}
1331
1332pub fn visit_item_tree<Base>(
1341 base: Pin<&Base>,
1342 item_tree: &ItemTreeRc,
1343 item_tree_array: &[ItemTreeNode],
1344 index: isize,
1345 order: TraversalOrder,
1346 mut visitor: vtable::VRefMut<ItemVisitorVTable>,
1347 visit_dynamic: impl Fn(
1348 Pin<&Base>,
1349 TraversalOrder,
1350 vtable::VRefMut<ItemVisitorVTable>,
1351 u32,
1352 ) -> VisitChildrenResult,
1353) -> VisitChildrenResult {
1354 let mut visit_at_index = |idx: u32| -> VisitChildrenResult {
1355 match &item_tree_array[idx as usize] {
1356 ItemTreeNode::Item { .. } => {
1357 let item = crate::items::ItemRc::new(item_tree.clone(), idx);
1358 visitor.visit_item(item_tree, idx, item.borrow())
1359 }
1360 ItemTreeNode::DynamicTree { index, .. } => {
1361 if let Some(sub_idx) =
1362 visit_dynamic(base, order, visitor.borrow_mut(), *index).aborted_index()
1363 {
1364 VisitChildrenResult::abort(idx, sub_idx)
1365 } else {
1366 VisitChildrenResult::CONTINUE
1367 }
1368 }
1369 }
1370 };
1371 if index == -1 {
1372 visit_at_index(0)
1373 } else {
1374 match &item_tree_array[index as usize] {
1375 ItemTreeNode::Item { children_index, children_count, .. } => {
1376 for c in 0..*children_count {
1377 let idx = match order {
1378 TraversalOrder::BackToFront => *children_index + c,
1379 TraversalOrder::FrontToBack => *children_index + *children_count - c - 1,
1380 };
1381 let maybe_abort_index = visit_at_index(idx);
1382 if maybe_abort_index.has_aborted() {
1383 return maybe_abort_index;
1384 }
1385 }
1386 }
1387 ItemTreeNode::DynamicTree { .. } => panic!("should not be called with dynamic items"),
1388 };
1389 VisitChildrenResult::CONTINUE
1390 }
1391}
1392
1393#[cfg(feature = "ffi")]
1394pub(crate) mod ffi {
1395 #![allow(unsafe_code)]
1396
1397 use super::*;
1398 use core::ffi::c_void;
1399
1400 #[unsafe(no_mangle)]
1402 pub unsafe extern "C" fn slint_register_item_tree(
1403 item_tree_rc: &ItemTreeRc,
1404 window_handle: *const crate::window::ffi::WindowAdapterRcOpaque,
1405 ) {
1406 unsafe {
1407 let window_adapter = (window_handle as *const WindowAdapterRc).as_ref().cloned();
1408 super::register_item_tree(item_tree_rc, window_adapter)
1409 }
1410 }
1411
1412 #[unsafe(no_mangle)]
1414 pub unsafe extern "C" fn slint_unregister_item_tree(
1415 component: ItemTreeRefPin,
1416 item_array: Slice<vtable::VOffset<u8, ItemVTable, vtable::AllowPin>>,
1417 window_handle: *const crate::window::ffi::WindowAdapterRcOpaque,
1418 ) {
1419 unsafe {
1420 let window_adapter = &*(window_handle as *const WindowAdapterRc);
1421 super::unregister_item_tree(
1422 core::pin::Pin::new_unchecked(&*(component.as_ptr() as *const u8)),
1423 core::pin::Pin::into_inner(component),
1424 item_array.as_slice(),
1425 window_adapter,
1426 )
1427 }
1428 }
1429
1430 #[unsafe(no_mangle)]
1434 pub unsafe extern "C" fn slint_visit_item_tree(
1435 item_tree: &ItemTreeRc,
1436 item_tree_array: Slice<ItemTreeNode>,
1437 index: isize,
1438 order: TraversalOrder,
1439 visitor: VRefMut<ItemVisitorVTable>,
1440 visit_dynamic: extern "C" fn(
1441 base: *const c_void,
1442 order: TraversalOrder,
1443 visitor: vtable::VRefMut<ItemVisitorVTable>,
1444 dyn_index: u32,
1445 ) -> VisitChildrenResult,
1446 ) -> VisitChildrenResult {
1447 crate::item_tree::visit_item_tree(
1448 VRc::as_pin_ref(item_tree),
1449 item_tree,
1450 item_tree_array.as_slice(),
1451 index,
1452 order,
1453 visitor,
1454 |a, b, c, d| visit_dynamic(a.get_ref() as *const vtable::Dyn as *const c_void, b, c, d),
1455 )
1456 }
1457}
1458
1459#[cfg(test)]
1460mod tests {
1461 use super::*;
1462 use crate::Property;
1463 use crate::api::LogicalPosition;
1464 use crate::api::Window;
1465 use crate::items::{Clip, Transform, WindowItem};
1466 use crate::lengths::LogicalLength;
1467 use crate::lengths::LogicalSize;
1468 use euclid::Point2D;
1469 use std::{rc::Rc, vec};
1470
1471 const GEOMETRY_POSITION_X: f32 = 6.;
1472 const GEOMETRY_POSITION_Y: f32 = 27.;
1473 const GEOMETRY_WIDTH: f32 = 33.;
1474 const GEOMETRY_HEIGHT: f32 = 42.;
1475
1476 #[derive(Default)]
1477 struct Renderer {
1478 supports_transformations: bool,
1479 }
1480
1481 struct WindowAdapter {
1482 renderer: Renderer,
1483 window: Window,
1484 }
1485
1486 impl WindowAdapter {
1487 fn new() -> Rc<Self> {
1488 Self::new_with_transformations(false)
1489 }
1490
1491 fn new_with_transformations(supports_transformations: bool) -> Rc<Self> {
1492 Rc::<Self>::new_cyclic(|w| Self {
1493 window: Window::new(w.clone()),
1494 renderer: Renderer { supports_transformations },
1495 })
1496 }
1497 }
1498
1499 impl crate::window::WindowAdapter for WindowAdapter {
1500 fn window(&self) -> &crate::api::Window {
1501 &self.window
1502 }
1503
1504 fn size(&self) -> crate::api::PhysicalSize {
1505 crate::api::PhysicalSize::new(100, 100)
1506 }
1507
1508 fn renderer(&self) -> &dyn crate::platform::Renderer {
1509 &self.renderer
1510 }
1511 }
1512
1513 struct TestItemTree {
1514 parent_component: Option<ItemTreeWeak>,
1515 item_tree: Vec<ItemTreeNode>,
1517 subtrees: std::cell::RefCell<Vec<Vec<vtable::VRc<ItemTreeVTable, TestItemTree>>>>,
1519 subtree_index: usize,
1520
1521 window_adapter: std::rc::Weak<dyn crate::window::WindowAdapter>,
1522 window_item: Option<crate::items::WindowItem>,
1523 }
1524
1525 impl ItemTree for TestItemTree {
1526 fn visit_children_item(
1527 self: core::pin::Pin<&Self>,
1528 _1: isize,
1529 _2: crate::item_tree::TraversalOrder,
1530 _3: vtable::VRefMut<crate::item_tree::ItemVisitorVTable>,
1531 ) -> crate::item_tree::VisitChildrenResult {
1532 unimplemented!("Not needed for this test")
1533 }
1534
1535 fn get_item_ref(
1536 self: core::pin::Pin<&Self>,
1537 index: u32,
1538 ) -> core::pin::Pin<vtable::VRef<'_, super::ItemVTable>> {
1539 if index == 0 {
1540 return Pin::new(VRef::new(
1541 self.get_ref().window_item.as_ref().expect("Not needed for this test"),
1542 ));
1543 }
1544 unimplemented!("Not needed for this test")
1545 }
1546
1547 fn get_item_tree(self: core::pin::Pin<&Self>) -> Slice<'_, ItemTreeNode> {
1548 Slice::from_slice(&self.get_ref().item_tree)
1549 }
1550
1551 fn parent_node(self: core::pin::Pin<&Self>, result: &mut ItemWeak) {
1552 if let Some(parent_item) = self.parent_component.as_ref().and_then(|w| w.upgrade()) {
1553 *result = ItemRc::new(parent_item, self.item_tree[0].parent_index()).downgrade();
1554 }
1555 }
1556
1557 fn embed_component(
1558 self: core::pin::Pin<&Self>,
1559 _parent_component: &ItemTreeWeak,
1560 _item_tree_index: u32,
1561 ) -> bool {
1562 false
1563 }
1564
1565 fn ensure_instantiated(self: core::pin::Pin<&Self>) -> bool {
1566 false
1567 }
1568
1569 fn layout_info(self: core::pin::Pin<&Self>, o: Orientation) -> LayoutInfo {
1570 if let Some(wi) = &self.window_item {
1571 match o {
1572 Orientation::Horizontal => {
1573 return LayoutInfo {
1574 max: wi.width.get_internal().0,
1575 max_percent: 100.,
1576 min: wi.width.get_internal().0,
1577 min_percent: 100.,
1578 preferred: wi.width.get_internal().0,
1579 stretch: 1.,
1580 };
1581 }
1582 Orientation::Vertical => {
1583 return LayoutInfo {
1584 max: wi.height.get_internal().0,
1585 max_percent: 100.,
1586 min: wi.height.get_internal().0,
1587 min_percent: 100.,
1588 preferred: wi.height.get_internal().0,
1589 stretch: 1.,
1590 };
1591 }
1592 }
1593 }
1594 unimplemented!("Not needed for this test")
1595 }
1596
1597 fn subtree_index(self: core::pin::Pin<&Self>) -> usize {
1598 self.subtree_index
1599 }
1600
1601 fn get_subtree_range(self: core::pin::Pin<&Self>, subtree_index: u32) -> IndexRange {
1602 (0..self.subtrees.borrow()[subtree_index as usize].len()).into()
1603 }
1604
1605 fn get_subtree(
1606 self: core::pin::Pin<&Self>,
1607 subtree_index: u32,
1608 component_index: usize,
1609 result: &mut ItemTreeWeak,
1610 ) {
1611 if let Some(vrc) = self.subtrees.borrow()[subtree_index as usize].get(component_index) {
1612 *result = vtable::VRc::downgrade(&vtable::VRc::into_dyn(vrc.clone()))
1613 }
1614 }
1615
1616 fn accessible_role(self: Pin<&Self>, _: u32) -> AccessibleRole {
1617 unimplemented!("Not needed for this test")
1618 }
1619
1620 fn accessible_string_property(
1621 self: Pin<&Self>,
1622 _: u32,
1623 _: AccessibleStringProperty,
1624 _: &mut SharedString,
1625 ) -> bool {
1626 false
1627 }
1628
1629 fn item_element_infos(self: Pin<&Self>, _: u32, _: &mut SharedString) -> bool {
1630 false
1631 }
1632
1633 fn window_adapter(
1634 self: Pin<&Self>,
1635 _do_create: bool,
1636 result: &mut Option<WindowAdapterRc>,
1637 ) {
1638 *result = self.window_adapter.upgrade()
1639 }
1640
1641 fn item_geometry(self: Pin<&Self>, _: u32) -> LogicalRect {
1642 LogicalRect::new(
1643 euclid::Point2D::new(GEOMETRY_POSITION_X, GEOMETRY_POSITION_Y),
1644 euclid::Size2D::new(GEOMETRY_WIDTH, GEOMETRY_HEIGHT),
1645 )
1646 }
1647
1648 fn accessibility_action(self: core::pin::Pin<&Self>, _: u32, _: &AccessibilityAction) {
1649 unimplemented!("Not needed for this test")
1650 }
1651
1652 fn supported_accessibility_actions(
1653 self: core::pin::Pin<&Self>,
1654 _: u32,
1655 ) -> SupportedAccessibilityAction {
1656 unimplemented!("Not needed for this test")
1657 }
1658 }
1659
1660 crate::item_tree::ItemTreeVTable_static!(static TEST_COMPONENT_VT for TestItemTree);
1661
1662 fn create_one_node_component(
1663 window_item: Option<WindowItem>,
1664 ) -> (std::rc::Rc<WindowAdapter>, VRc<ItemTreeVTable, vtable::Dyn>) {
1665 let window_adapter = WindowAdapter::new();
1666 let component = VRc::new(TestItemTree {
1667 parent_component: None,
1668 item_tree: vec![ItemTreeNode::Item {
1669 is_accessible: false,
1670 children_count: 0,
1671 children_index: 1,
1672 parent_index: 0,
1673 item_array_index: 0,
1674 }],
1675 subtrees: std::cell::RefCell::new(Vec::new()),
1676 subtree_index: usize::MAX,
1677
1678 window_adapter: Rc::downgrade(&window_adapter) as _,
1679 window_item,
1680 });
1681 (window_adapter, VRc::into_dyn(component))
1682 }
1683
1684 #[test]
1685 fn test_tree_traversal_one_node_structure() {
1686 let component = create_one_node_component(None).1;
1687
1688 let item = ItemRc::new_root(component.clone());
1689
1690 assert!(item.first_child().is_none());
1691 assert!(item.last_child().is_none());
1692 assert!(item.previous_sibling().is_none());
1693 assert!(item.next_sibling().is_none());
1694 }
1695
1696 #[test]
1697 fn test_tree_traversal_one_node_forward_focus() {
1698 let component = create_one_node_component(None).1;
1699
1700 let item = ItemRc::new_root(component.clone());
1701
1702 assert_eq!(item.next_focus_item(), item);
1704 }
1705
1706 #[test]
1707 fn test_tree_traversal_one_node_backward_focus() {
1708 let component = create_one_node_component(None).1;
1709
1710 let item = ItemRc::new_root(component.clone());
1711
1712 assert_eq!(item.previous_focus_item(), item);
1714 }
1715
1716 fn create_children_nodes() -> VRc<ItemTreeVTable, vtable::Dyn> {
1717 let component = VRc::new(TestItemTree {
1718 parent_component: None,
1719 item_tree: vec![
1720 ItemTreeNode::Item {
1722 is_accessible: false,
1723 children_count: 3,
1724 children_index: 1,
1725 parent_index: 0,
1726 item_array_index: 0, },
1728 ItemTreeNode::Item {
1730 is_accessible: false,
1731 children_count: 0,
1732 children_index: 4, parent_index: 0, item_array_index: 1, },
1736 ItemTreeNode::Item {
1738 is_accessible: false,
1739 children_count: 0,
1740 children_index: 4, parent_index: 0, item_array_index: 2,
1743 },
1744 ItemTreeNode::Item {
1746 is_accessible: false,
1747 children_count: 0,
1748 children_index: 4, parent_index: 0, item_array_index: 3,
1751 },
1752 ],
1753 subtrees: std::cell::RefCell::new(Vec::new()),
1754 subtree_index: usize::MAX,
1755
1756 window_adapter: Rc::downgrade(&WindowAdapter::new()) as _,
1757 window_item: None,
1758 });
1759 VRc::into_dyn(component)
1760 }
1761
1762 #[test]
1763 fn test_tree_traversal_children_nodes_structure() {
1764 let component: VRc<ItemTreeVTable> = create_children_nodes();
1765
1766 let item = ItemRc::new_root(component.clone());
1768 assert!(item.previous_sibling().is_none());
1769 assert!(item.next_sibling().is_none());
1770
1771 let fc = item.first_child().unwrap();
1772 assert_eq!(fc.index(), 1);
1773 assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
1774
1775 let fcn = fc.next_sibling().unwrap();
1776 assert_eq!(fcn.index(), 2);
1777
1778 let lc = item.last_child().unwrap();
1779 assert_eq!(lc.index(), 3);
1780 assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
1781
1782 let lcp = lc.previous_sibling().unwrap();
1783 assert!(VRc::ptr_eq(lcp.item_tree(), item.item_tree()));
1784 assert_eq!(lcp.index(), 2);
1785
1786 assert!(fc.first_child().is_none());
1788 assert!(fc.last_child().is_none());
1789 assert!(fc.previous_sibling().is_none());
1790 assert_eq!(fc.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);
1791
1792 assert_eq!(fcn, lcp);
1794 assert_eq!(lcp.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);
1795 assert_eq!(fcn.previous_sibling().unwrap(), fc);
1796 assert_eq!(fcn.next_sibling().unwrap(), lc);
1797
1798 assert!(lc.first_child().is_none());
1800 assert!(lc.last_child().is_none());
1801 assert!(lc.next_sibling().is_none());
1802 assert_eq!(lc.parent_item(ParentItemTraversalMode::StopAtPopups).unwrap(), item);
1803 }
1804
1805 #[test]
1806 fn test_tree_traversal_children_nodes_forward_focus() {
1807 let component = create_children_nodes();
1808
1809 let item = ItemRc::new_root(component.clone());
1810 let fc = item.first_child().unwrap();
1811 let fcn = fc.next_sibling().unwrap();
1812 let lc = item.last_child().unwrap();
1813
1814 let mut cursor = item.clone();
1815
1816 cursor = cursor.next_focus_item();
1817 assert_eq!(cursor, fc);
1818
1819 cursor = cursor.next_focus_item();
1820 assert_eq!(cursor, fcn);
1821
1822 cursor = cursor.next_focus_item();
1823 assert_eq!(cursor, lc);
1824
1825 cursor = cursor.next_focus_item();
1826 assert_eq!(cursor, item);
1827 }
1828
1829 #[test]
1830 fn test_tree_traversal_children_nodes_backward_focus() {
1831 let component = create_children_nodes();
1832
1833 let item = ItemRc::new_root(component.clone());
1834 let fc = item.first_child().unwrap();
1835 let fcn = fc.next_sibling().unwrap();
1836 let lc = item.last_child().unwrap();
1837
1838 let mut cursor = item.clone();
1839
1840 cursor = cursor.previous_focus_item();
1841 assert_eq!(cursor, lc);
1842
1843 cursor = cursor.previous_focus_item();
1844 assert_eq!(cursor, fcn);
1845
1846 cursor = cursor.previous_focus_item();
1847 assert_eq!(cursor, fc);
1848
1849 cursor = cursor.previous_focus_item();
1850 assert_eq!(cursor, item);
1851 }
1852
1853 fn create_empty_subtree() -> VRc<ItemTreeVTable, vtable::Dyn> {
1854 let component = vtable::VRc::new(TestItemTree {
1855 parent_component: None,
1856 item_tree: vec![
1857 ItemTreeNode::Item {
1858 is_accessible: false,
1859 children_count: 1,
1860 children_index: 1,
1861 parent_index: 0,
1862 item_array_index: 0,
1863 },
1864 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1865 ],
1866 subtrees: std::cell::RefCell::new(vec![Vec::new()]),
1867 subtree_index: usize::MAX,
1868
1869 window_adapter: Rc::downgrade(&WindowAdapter::new()) as _,
1870 window_item: None,
1871 });
1872 vtable::VRc::into_dyn(component)
1873 }
1874
1875 #[test]
1876 fn test_tree_traversal_empty_subtree_structure() {
1877 let component = create_empty_subtree();
1878
1879 let item = ItemRc::new_root(component.clone());
1881 assert!(item.previous_sibling().is_none());
1882 assert!(item.next_sibling().is_none());
1883 assert!(item.first_child().is_none());
1884 assert!(item.last_child().is_none());
1885
1886 assert!(item.previous_focus_item() == item);
1888 assert!(item.next_focus_item() == item);
1889 }
1890
1891 #[test]
1892 fn test_tree_traversal_empty_subtree_forward_focus() {
1893 let component = create_empty_subtree();
1894
1895 let item = ItemRc::new_root(component.clone());
1897
1898 assert!(item.next_focus_item() == item);
1899 }
1900
1901 #[test]
1902 fn test_tree_traversal_empty_subtree_backward_focus() {
1903 let component = create_empty_subtree();
1904
1905 let item = ItemRc::new_root(component.clone());
1907
1908 assert!(item.previous_focus_item() == item);
1909 }
1910
1911 fn create_item_subtree_item() -> VRc<ItemTreeVTable, vtable::Dyn> {
1912 let window_adapter = WindowAdapter::new();
1913 let weak_adapter =
1914 Rc::downgrade(&window_adapter) as std::rc::Weak<dyn crate::window::WindowAdapter>;
1915 let component = VRc::new(TestItemTree {
1916 parent_component: None,
1917 item_tree: vec![
1918 ItemTreeNode::Item {
1920 is_accessible: false,
1921 children_count: 3,
1922 children_index: 1,
1923 parent_index: 0,
1924 item_array_index: 0,
1925 },
1926 ItemTreeNode::Item {
1928 is_accessible: false,
1929 children_count: 0,
1930 children_index: 4, parent_index: 0, item_array_index: 0,
1933 },
1934 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
1935 ItemTreeNode::Item {
1936 is_accessible: false,
1937 children_count: 0,
1938 children_index: 4,
1939 parent_index: 0, item_array_index: 0,
1941 },
1942 ],
1943 subtrees: std::cell::RefCell::new(Vec::new()),
1944 subtree_index: usize::MAX,
1945
1946 window_adapter: weak_adapter.clone(),
1947 window_item: None,
1948 });
1949
1950 component.as_pin_ref().subtrees.replace(vec![vec![VRc::new(TestItemTree {
1951 parent_component: Some(VRc::downgrade(&VRc::into_dyn(component.clone()))),
1952 item_tree: vec![ItemTreeNode::Item {
1953 is_accessible: false,
1954 children_count: 0,
1955 children_index: 1,
1956 parent_index: 2,
1957 item_array_index: 0,
1958 }],
1959 subtrees: std::cell::RefCell::new(Vec::new()),
1960 subtree_index: 0,
1961
1962 window_adapter: weak_adapter,
1963 window_item: None,
1964 })]]);
1965
1966 VRc::into_dyn(component)
1967 }
1968
1969 #[test]
1970 fn test_tree_traversal_item_subtree_item_structure() {
1971 let component = create_item_subtree_item();
1972
1973 let item = ItemRc::new_root(component.clone());
1975 assert!(item.previous_sibling().is_none());
1976 assert!(item.next_sibling().is_none());
1977
1978 let fc = item.first_child().unwrap();
1979 assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
1980 assert_eq!(fc.index(), 1);
1981
1982 let lc = item.last_child().unwrap();
1983 assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
1984 assert_eq!(lc.index(), 3);
1985
1986 let fcn = fc.next_sibling().unwrap();
1987 let lcp = lc.previous_sibling().unwrap();
1988
1989 assert_eq!(fcn, lcp);
1990 assert!(!VRc::ptr_eq(fcn.item_tree(), item.item_tree()));
1991
1992 let last = fcn.next_sibling().unwrap();
1993 assert_eq!(last, lc);
1994
1995 let first = lcp.previous_sibling().unwrap();
1996 assert_eq!(first, fc);
1997 }
1998
1999 #[test]
2000 fn test_tree_traversal_item_subtree_item_forward_focus() {
2001 let component = create_item_subtree_item();
2002
2003 let item = ItemRc::new_root(component.clone());
2004 let fc = item.first_child().unwrap();
2005 let lc = item.last_child().unwrap();
2006 let fcn = fc.next_sibling().unwrap();
2007
2008 let mut cursor = item.clone();
2009
2010 cursor = cursor.next_focus_item();
2011 assert_eq!(cursor, fc);
2012
2013 cursor = cursor.next_focus_item();
2014 assert_eq!(cursor, fcn);
2015
2016 cursor = cursor.next_focus_item();
2017 assert_eq!(cursor, lc);
2018
2019 cursor = cursor.next_focus_item();
2020 assert_eq!(cursor, item);
2021 }
2022
2023 #[test]
2024 fn test_tree_traversal_item_subtree_item_backward_focus() {
2025 let component = create_item_subtree_item();
2026
2027 let item = ItemRc::new_root(component.clone());
2028 let fc = item.first_child().unwrap();
2029 let lc = item.last_child().unwrap();
2030 let fcn = fc.next_sibling().unwrap();
2031
2032 let mut cursor = item.clone();
2033
2034 cursor = cursor.previous_focus_item();
2035 assert_eq!(cursor, lc);
2036
2037 cursor = cursor.previous_focus_item();
2038 assert_eq!(cursor, fcn);
2039
2040 cursor = cursor.previous_focus_item();
2041 assert_eq!(cursor, fc);
2042
2043 cursor = cursor.previous_focus_item();
2044 assert_eq!(cursor, item);
2045 }
2046
2047 fn create_nested_subtrees() -> VRc<ItemTreeVTable, vtable::Dyn> {
2048 let window_adapter = WindowAdapter::new();
2053 let weak_adapter =
2054 Rc::downgrade(&window_adapter) as std::rc::Weak<dyn crate::window::WindowAdapter>;
2055
2056 let component = VRc::new(TestItemTree {
2057 parent_component: None,
2058 item_tree: vec![
2059 ItemTreeNode::Item {
2061 is_accessible: false,
2062 children_count: 3,
2063 children_index: 1,
2064 parent_index: 0,
2065 item_array_index: 0,
2066 },
2067 ItemTreeNode::Item {
2069 is_accessible: false,
2070 children_count: 0,
2071 children_index: 4,
2072 parent_index: 0,
2073 item_array_index: 0,
2074 },
2075 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
2078 ItemTreeNode::Item {
2080 is_accessible: false,
2081 children_count: 0,
2082 children_index: 4,
2083 parent_index: 0,
2084 item_array_index: 0,
2085 },
2086 ],
2087 subtrees: std::cell::RefCell::new(Vec::new()),
2088 subtree_index: usize::MAX,
2089
2090 window_adapter: weak_adapter.clone(),
2091 window_item: None,
2092 });
2093
2094 let sub_component1 = VRc::new(TestItemTree {
2095 parent_component: Some(VRc::downgrade(&VRc::into_dyn(component.clone()))),
2096 item_tree: vec![
2097 ItemTreeNode::Item {
2099 is_accessible: false,
2100 children_count: 1,
2101 children_index: 1,
2102 parent_index: 2,
2103 item_array_index: 0,
2104 },
2105 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
2108 ],
2109 subtrees: std::cell::RefCell::new(Vec::new()),
2110 subtree_index: usize::MAX,
2111
2112 window_adapter: weak_adapter.clone(),
2113 window_item: None,
2114 });
2115 let sub_component2 = VRc::new(TestItemTree {
2116 parent_component: Some(VRc::downgrade(&VRc::into_dyn(sub_component1.clone()))),
2117 item_tree: vec![
2118 ItemTreeNode::Item {
2119 is_accessible: false,
2120 children_count: 1,
2121 children_index: 1,
2122 parent_index: 1,
2123 item_array_index: 0,
2124 },
2125 ItemTreeNode::Item {
2126 is_accessible: false,
2127 children_count: 0,
2128 children_index: 2,
2129 parent_index: 0,
2130 item_array_index: 0,
2131 },
2132 ],
2133 subtrees: std::cell::RefCell::new(Vec::new()),
2134 subtree_index: usize::MAX,
2135
2136 window_adapter: weak_adapter,
2137 window_item: None,
2138 });
2139
2140 sub_component1.as_pin_ref().subtrees.replace(vec![vec![sub_component2]]);
2141 component.as_pin_ref().subtrees.replace(vec![vec![sub_component1]]);
2142
2143 VRc::into_dyn(component)
2144 }
2145
2146 #[test]
2147 fn test_tree_traversal_nested_subtrees_structure() {
2148 let component = create_nested_subtrees();
2149
2150 let item = ItemRc::new_root(component.clone());
2152 assert!(item.previous_sibling().is_none());
2153 assert!(item.next_sibling().is_none());
2154
2155 let fc = item.first_child().unwrap();
2156 assert!(VRc::ptr_eq(fc.item_tree(), item.item_tree()));
2157 assert_eq!(fc.index(), 1);
2158
2159 let lc = item.last_child().unwrap();
2160 assert!(VRc::ptr_eq(lc.item_tree(), item.item_tree()));
2161 assert_eq!(lc.index(), 3);
2162
2163 let fcn = fc.next_sibling().unwrap();
2164 let lcp = lc.previous_sibling().unwrap();
2165
2166 assert_eq!(fcn, lcp);
2167 assert!(!VRc::ptr_eq(fcn.item_tree(), item.item_tree()));
2168
2169 let last = fcn.next_sibling().unwrap();
2170 assert_eq!(last, lc);
2171
2172 let first = lcp.previous_sibling().unwrap();
2173 assert_eq!(first, fc);
2174
2175 let nested_root = fcn.first_child().unwrap();
2177 assert_eq!(nested_root, fcn.last_child().unwrap());
2178 assert!(nested_root.next_sibling().is_none());
2179 assert!(nested_root.previous_sibling().is_none());
2180 assert!(!VRc::ptr_eq(nested_root.item_tree(), item.item_tree()));
2181 assert!(!VRc::ptr_eq(nested_root.item_tree(), fcn.item_tree()));
2182
2183 let nested_child = nested_root.first_child().unwrap();
2184 assert_eq!(nested_child, nested_root.last_child().unwrap());
2185 assert!(VRc::ptr_eq(nested_root.item_tree(), nested_child.item_tree()));
2186 }
2187
2188 #[test]
2189 fn test_tree_traversal_nested_subtrees_forward_focus() {
2190 let component = create_nested_subtrees();
2191
2192 let item = ItemRc::new_root(component.clone());
2194 let fc = item.first_child().unwrap();
2195 let fcn = fc.next_sibling().unwrap();
2196 let lc = item.last_child().unwrap();
2197 let nested_root = fcn.first_child().unwrap();
2198 let nested_child = nested_root.first_child().unwrap();
2199
2200 let mut cursor = item.clone();
2202
2203 cursor = cursor.next_focus_item();
2204 assert_eq!(cursor, fc);
2205
2206 cursor = cursor.next_focus_item();
2207 assert_eq!(cursor, fcn);
2208
2209 cursor = cursor.next_focus_item();
2210 assert_eq!(cursor, nested_root);
2211
2212 cursor = cursor.next_focus_item();
2213 assert_eq!(cursor, nested_child);
2214
2215 cursor = cursor.next_focus_item();
2216 assert_eq!(cursor, lc);
2217
2218 cursor = cursor.next_focus_item();
2219 assert_eq!(cursor, item);
2220 }
2221
2222 #[test]
2223 fn test_tree_traversal_nested_subtrees_backward_focus() {
2224 let component = create_nested_subtrees();
2225
2226 let item = ItemRc::new_root(component.clone());
2228 let fc = item.first_child().unwrap();
2229 let fcn = fc.next_sibling().unwrap();
2230 let lc = item.last_child().unwrap();
2231 let nested_root = fcn.first_child().unwrap();
2232 let nested_child = nested_root.first_child().unwrap();
2233
2234 let mut cursor = item.clone();
2236
2237 cursor = cursor.previous_focus_item();
2238 assert_eq!(cursor, lc);
2239
2240 cursor = cursor.previous_focus_item();
2241 assert_eq!(cursor, nested_child);
2242
2243 cursor = cursor.previous_focus_item();
2244 assert_eq!(cursor, nested_root);
2245
2246 cursor = cursor.previous_focus_item();
2247 assert_eq!(cursor, fcn);
2248
2249 cursor = cursor.previous_focus_item();
2250 assert_eq!(cursor, fc);
2251
2252 cursor = cursor.previous_focus_item();
2253 assert_eq!(cursor, item);
2254 }
2255
2256 fn create_subtrees_item() -> VRc<ItemTreeVTable, vtable::Dyn> {
2257 let window_adapter = WindowAdapter::new();
2258 let weak_adapter =
2259 Rc::downgrade(&window_adapter) as std::rc::Weak<dyn crate::window::WindowAdapter>;
2260
2261 let component = VRc::new(TestItemTree {
2262 parent_component: None,
2263 item_tree: vec![
2264 ItemTreeNode::Item {
2265 is_accessible: false,
2266 children_count: 2,
2267 children_index: 1,
2268 parent_index: 0,
2269 item_array_index: 0,
2270 },
2271 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
2272 ItemTreeNode::Item {
2273 is_accessible: false,
2274 children_count: 0,
2275 children_index: 4,
2276 parent_index: 0,
2277 item_array_index: 0,
2278 },
2279 ],
2280 subtrees: std::cell::RefCell::new(Vec::new()),
2281 subtree_index: usize::MAX,
2282
2283 window_adapter: weak_adapter.clone(),
2284 window_item: None,
2285 });
2286
2287 component.as_pin_ref().subtrees.replace(vec![vec![
2288 VRc::new(TestItemTree {
2289 parent_component: Some(VRc::downgrade(&VRc::into_dyn(component.clone()))),
2290 item_tree: vec![ItemTreeNode::Item {
2291 is_accessible: false,
2292 children_count: 0,
2293 children_index: 1,
2294 parent_index: 1,
2295 item_array_index: 0,
2296 }],
2297 subtrees: std::cell::RefCell::new(Vec::new()),
2298 subtree_index: 0,
2299
2300 window_adapter: weak_adapter.clone(),
2301 window_item: None,
2302 }),
2303 VRc::new(TestItemTree {
2304 parent_component: Some(VRc::downgrade(&VRc::into_dyn(component.clone()))),
2305 item_tree: vec![ItemTreeNode::Item {
2306 is_accessible: false,
2307 children_count: 0,
2308 children_index: 1,
2309 parent_index: 1,
2310 item_array_index: 0,
2311 }],
2312 subtrees: std::cell::RefCell::new(Vec::new()),
2313 subtree_index: 1,
2314
2315 window_adapter: weak_adapter.clone(),
2316 window_item: None,
2317 }),
2318 VRc::new(TestItemTree {
2319 parent_component: Some(VRc::downgrade(&VRc::into_dyn(component.clone()))),
2320 item_tree: vec![ItemTreeNode::Item {
2321 is_accessible: false,
2322 children_count: 0,
2323 children_index: 1,
2324 parent_index: 1,
2325 item_array_index: 0,
2326 }],
2327 subtrees: std::cell::RefCell::new(Vec::new()),
2328 subtree_index: 2,
2329
2330 window_adapter: weak_adapter,
2331 window_item: None,
2332 }),
2333 ]]);
2334
2335 VRc::into_dyn(component)
2336 }
2337
2338 #[test]
2339 fn test_tree_traversal_subtrees_item_structure() {
2340 let component = create_subtrees_item();
2341
2342 let item = ItemRc::new_root(component.clone());
2344 assert!(item.previous_sibling().is_none());
2345 assert!(item.next_sibling().is_none());
2346
2347 let sub1 = item.first_child().unwrap();
2348 assert_eq!(sub1.index(), 0);
2349 assert!(!VRc::ptr_eq(sub1.item_tree(), item.item_tree()));
2350
2351 let sub2 = sub1.next_sibling().unwrap();
2354 assert_eq!(sub2.index(), 0);
2355 assert!(!VRc::ptr_eq(sub1.item_tree(), sub2.item_tree()));
2356 assert!(!VRc::ptr_eq(item.item_tree(), sub2.item_tree()));
2357
2358 assert!(sub2.previous_sibling() == Some(sub1.clone()));
2359
2360 let sub3 = sub2.next_sibling().unwrap();
2361 assert_eq!(sub3.index(), 0);
2362 assert!(!VRc::ptr_eq(sub1.item_tree(), sub2.item_tree()));
2363 assert!(!VRc::ptr_eq(sub2.item_tree(), sub3.item_tree()));
2364 assert!(!VRc::ptr_eq(item.item_tree(), sub3.item_tree()));
2365
2366 assert_eq!(sub3.previous_sibling().unwrap(), sub2.clone());
2367 }
2368
2369 #[test]
2370 fn test_component_item_tree_root_only() {
2371 let nodes = vec![ItemTreeNode::Item {
2372 is_accessible: false,
2373 children_count: 0,
2374 children_index: 1,
2375 parent_index: 0,
2376 item_array_index: 0,
2377 }];
2378
2379 let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
2380
2381 assert_eq!(tree.first_child(0), None);
2382 assert_eq!(tree.last_child(0), None);
2383 assert_eq!(tree.previous_sibling(0), None);
2384 assert_eq!(tree.next_sibling(0), None);
2385 assert_eq!(tree.parent(0), None);
2386 }
2387
2388 #[test]
2389 fn test_component_item_tree_one_child() {
2390 let nodes = vec![
2391 ItemTreeNode::Item {
2392 is_accessible: false,
2393 children_count: 1,
2394 children_index: 1,
2395 parent_index: 0,
2396 item_array_index: 0,
2397 },
2398 ItemTreeNode::Item {
2399 is_accessible: false,
2400 children_count: 0,
2401 children_index: 2,
2402 parent_index: 0,
2403 item_array_index: 0,
2404 },
2405 ];
2406
2407 let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
2408
2409 assert_eq!(tree.first_child(0), Some(1));
2410 assert_eq!(tree.last_child(0), Some(1));
2411 assert_eq!(tree.previous_sibling(0), None);
2412 assert_eq!(tree.next_sibling(0), None);
2413 assert_eq!(tree.parent(0), None);
2414 assert_eq!(tree.previous_sibling(1), None);
2415 assert_eq!(tree.next_sibling(1), None);
2416 assert_eq!(tree.parent(1), Some(0));
2417 }
2418
2419 #[test]
2420 fn test_component_item_tree_tree_children() {
2421 let nodes = vec![
2422 ItemTreeNode::Item {
2423 is_accessible: false,
2424 children_count: 3,
2425 children_index: 1,
2426 parent_index: 0,
2427 item_array_index: 0,
2428 },
2429 ItemTreeNode::Item {
2430 is_accessible: false,
2431 children_count: 0,
2432 children_index: 4,
2433 parent_index: 0,
2434 item_array_index: 0,
2435 },
2436 ItemTreeNode::Item {
2437 is_accessible: false,
2438 children_count: 0,
2439 children_index: 4,
2440 parent_index: 0,
2441 item_array_index: 0,
2442 },
2443 ItemTreeNode::Item {
2444 is_accessible: false,
2445 children_count: 0,
2446 children_index: 4,
2447 parent_index: 0,
2448 item_array_index: 0,
2449 },
2450 ];
2451
2452 let tree: ItemTreeNodeArray = (nodes.as_slice()).into();
2453
2454 assert_eq!(tree.first_child(0), Some(1));
2455 assert_eq!(tree.last_child(0), Some(3));
2456 assert_eq!(tree.previous_sibling(0), None);
2457 assert_eq!(tree.next_sibling(0), None);
2458 assert_eq!(tree.parent(0), None);
2459
2460 assert_eq!(tree.previous_sibling(1), None);
2461 assert_eq!(tree.next_sibling(1), Some(2));
2462 assert_eq!(tree.parent(1), Some(0));
2463
2464 assert_eq!(tree.previous_sibling(2), Some(1));
2465 assert_eq!(tree.next_sibling(2), Some(3));
2466 assert_eq!(tree.parent(2), Some(0));
2467
2468 assert_eq!(tree.previous_sibling(3), Some(2));
2469 assert_eq!(tree.next_sibling(3), None);
2470 assert_eq!(tree.parent(3), Some(0));
2471 }
2472
2473 fn create_subsubtree_items(
2475 window_adapter: Option<std::rc::Rc<WindowAdapter>>,
2476 ) -> (std::rc::Rc<WindowAdapter>, VRc<ItemTreeVTable>) {
2477 let window_adapter = window_adapter.unwrap_or(WindowAdapter::new());
2478 let mut window_item = WindowItem::default();
2479 window_item.width = Property::new(LogicalLength::new(30.));
2480 window_item.height = Property::new(LogicalLength::new(30.));
2481 (
2482 window_adapter.clone(),
2483 VRc::into_dyn(VRc::new(TestItemTree {
2484 parent_component: None,
2485 item_tree: vec![
2486 ItemTreeNode::Item {
2488 is_accessible: false,
2489 children_count: 1,
2490 children_index: 1,
2491 parent_index: 0,
2492 item_array_index: 0,
2493 },
2494 ItemTreeNode::Item {
2496 is_accessible: false,
2497 children_count: 1,
2498 children_index: 2, parent_index: 0,
2500 item_array_index: 1,
2501 },
2502 ItemTreeNode::Item {
2504 is_accessible: false,
2505 children_count: 0,
2506 children_index: 3, parent_index: 1,
2508 item_array_index: 2,
2509 },
2510 ],
2511 subtrees: std::cell::RefCell::new(Vec::new()),
2512 subtree_index: usize::MAX,
2513 window_adapter: Rc::downgrade(&window_adapter) as _,
2514 window_item: Some(window_item),
2515 })),
2516 )
2517 }
2518
2519 struct TransformTestItemTree {
2520 item_tree: Vec<ItemTreeNode>,
2521 geometries: Vec<LogicalRect>,
2522 window_adapter: std::rc::Weak<dyn crate::window::WindowAdapter>,
2523 root: WindowItem,
2524 transform: Transform,
2525 clip: Clip,
2526 leaf: WindowItem,
2527 }
2528
2529 impl ItemTree for TransformTestItemTree {
2530 fn visit_children_item(
2531 self: Pin<&Self>,
2532 _index: isize,
2533 _order: TraversalOrder,
2534 _visitor: vtable::VRefMut<ItemVisitorVTable>,
2535 ) -> VisitChildrenResult {
2536 unimplemented!("Not needed for this test")
2537 }
2538
2539 fn get_item_ref(self: Pin<&Self>, index: u32) -> Pin<VRef<'_, ItemVTable>> {
2540 let this = self.get_ref();
2541 match index {
2542 0 => Pin::new(VRef::new(&this.root)),
2543 1 => Pin::new(VRef::new(&this.transform)),
2544 2 => Pin::new(VRef::new(&this.clip)),
2545 3 => Pin::new(VRef::new(&this.leaf)),
2546 _ => unimplemented!("Not needed for this test"),
2547 }
2548 }
2549
2550 fn get_item_tree(self: Pin<&Self>) -> Slice<'_, ItemTreeNode> {
2551 Slice::from_slice(&self.get_ref().item_tree)
2552 }
2553
2554 fn parent_node(self: Pin<&Self>, _result: &mut ItemWeak) {}
2555
2556 fn embed_component(
2557 self: Pin<&Self>,
2558 _parent_component: &ItemTreeWeak,
2559 _item_tree_index: u32,
2560 ) -> bool {
2561 false
2562 }
2563
2564 fn layout_info(self: Pin<&Self>, _orientation: Orientation) -> LayoutInfo {
2565 unimplemented!("Not needed for this test")
2566 }
2567
2568 fn subtree_index(self: Pin<&Self>) -> usize {
2569 usize::MAX
2570 }
2571
2572 fn get_subtree_range(self: Pin<&Self>, _subtree_index: u32) -> IndexRange {
2573 (0..0).into()
2574 }
2575
2576 fn get_subtree(
2577 self: Pin<&Self>,
2578 _subtree_index: u32,
2579 _component_index: usize,
2580 _result: &mut ItemTreeWeak,
2581 ) {
2582 unimplemented!("Not needed for this test")
2583 }
2584
2585 fn accessible_role(self: Pin<&Self>, _index: u32) -> AccessibleRole {
2586 unimplemented!("Not needed for this test")
2587 }
2588
2589 fn accessible_string_property(
2590 self: Pin<&Self>,
2591 _index: u32,
2592 _what: AccessibleStringProperty,
2593 _result: &mut SharedString,
2594 ) -> bool {
2595 false
2596 }
2597
2598 fn item_element_infos(self: Pin<&Self>, _index: u32, _result: &mut SharedString) -> bool {
2599 false
2600 }
2601
2602 fn ensure_instantiated(self: Pin<&Self>) -> bool {
2603 false
2604 }
2605
2606 fn window_adapter(
2607 self: Pin<&Self>,
2608 _do_create: bool,
2609 result: &mut Option<WindowAdapterRc>,
2610 ) {
2611 *result = self.window_adapter.upgrade()
2612 }
2613
2614 fn item_geometry(self: Pin<&Self>, index: u32) -> LogicalRect {
2615 self.geometries[index as usize]
2616 }
2617
2618 fn accessibility_action(self: Pin<&Self>, _index: u32, _action: &AccessibilityAction) {
2619 unimplemented!("Not needed for this test")
2620 }
2621
2622 fn supported_accessibility_actions(
2623 self: Pin<&Self>,
2624 _index: u32,
2625 ) -> SupportedAccessibilityAction {
2626 unimplemented!("Not needed for this test")
2627 }
2628 }
2629
2630 crate::item_tree::ItemTreeVTable_static!(static TRANSFORM_TEST_COMPONENT_VT for TransformTestItemTree);
2631
2632 fn create_transform_test_items() -> (std::rc::Rc<WindowAdapter>, VRc<ItemTreeVTable>) {
2633 let window_adapter = WindowAdapter::new_with_transformations(true);
2634
2635 let mut transform = Transform::default();
2636 transform.transform_scale_x = Property::new(2.);
2637 transform.transform_scale_y = Property::new(3.);
2638 transform.transform_rotation = Property::new(0.);
2639 transform.transform_origin = Property::new(LogicalPosition::new(0., 0.));
2640
2641 let mut clip = Clip::default();
2642 clip.clip = Property::new(true);
2643
2644 (
2645 window_adapter.clone(),
2646 VRc::into_dyn(VRc::new(TransformTestItemTree {
2647 item_tree: vec![
2648 ItemTreeNode::Item {
2649 is_accessible: false,
2650 children_count: 1,
2651 children_index: 1,
2652 parent_index: 0,
2653 item_array_index: 0,
2654 },
2655 ItemTreeNode::Item {
2656 is_accessible: false,
2657 children_count: 1,
2658 children_index: 2,
2659 parent_index: 0,
2660 item_array_index: 1,
2661 },
2662 ItemTreeNode::Item {
2663 is_accessible: false,
2664 children_count: 1,
2665 children_index: 3,
2666 parent_index: 1,
2667 item_array_index: 2,
2668 },
2669 ItemTreeNode::Item {
2670 is_accessible: false,
2671 children_count: 0,
2672 children_index: 4,
2673 parent_index: 2,
2674 item_array_index: 3,
2675 },
2676 ],
2677 geometries: vec![
2678 LogicalRect::new(Point2D::new(0., 0.), LogicalSize::new(100., 100.)),
2679 LogicalRect::new(Point2D::new(10., 20.), LogicalSize::new(40., 40.)),
2680 LogicalRect::new(Point2D::new(5., 6.), LogicalSize::new(20., 20.)),
2681 LogicalRect::new(Point2D::new(8., 4.), LogicalSize::new(10., 10.)),
2682 ],
2683 window_adapter: Rc::downgrade(&window_adapter) as _,
2684 root: WindowItem::default(),
2685 transform,
2686 clip,
2687 leaf: WindowItem::default(),
2688 })),
2689 )
2690 }
2691
2692 fn assert_point_approx_eq(actual: LogicalPoint, expected: LogicalPoint) {
2693 const EPSILON: f32 = 0.0001;
2694 assert!(
2695 (actual.x - expected.x).abs() < EPSILON,
2696 "actual x {}, expected x {}",
2697 actual.x,
2698 expected.x
2699 );
2700 assert!(
2701 (actual.y - expected.y).abs() < EPSILON,
2702 "actual y {}, expected y {}",
2703 actual.y,
2704 expected.y
2705 );
2706 }
2707
2708 #[test]
2709 fn test_map_to_ancestor() {
2710 let (_window_adapter, item_tree) = create_subsubtree_items(None);
2711 let root = ItemRc::new_root(item_tree);
2712 let first_child = root.first_child().unwrap();
2713 let first_child_of_first_child = first_child.first_child().unwrap();
2714
2715 {
2716 let point = first_child.map_to_ancestor(Point2D::new(6., 19.), &root);
2717 assert_eq!(point.x, 6.);
2718 assert_eq!(point.y, 19.);
2719 }
2720
2721 {
2722 let point =
2723 first_child_of_first_child.map_to_ancestor(Point2D::new(27., -10.), &first_child);
2724 assert_eq!(point.x, 27.);
2725 assert_eq!(point.y, -10.);
2726 }
2727
2728 {
2729 let point = first_child_of_first_child.map_to_ancestor(Point2D::new(27., -10.), &root);
2731 assert_eq!(point.x, GEOMETRY_POSITION_X + 27.);
2733 assert_eq!(point.y, GEOMETRY_POSITION_Y - 10.);
2734 }
2735 }
2736
2737 #[test]
2738 fn test_map_to_window() {
2739 let (_window_adapter, item_tree) = create_subsubtree_items(None);
2740 let root = ItemRc::new_root(item_tree);
2741 let first_child = root.first_child().unwrap();
2742 let first_child_of_first_child = first_child.first_child().unwrap();
2743
2744 let point = first_child_of_first_child.map_to_window(Point2D::new(-5., 7.));
2745 assert_eq!(point.x, GEOMETRY_POSITION_X + GEOMETRY_POSITION_X - 5.);
2747 assert_eq!(point.y, GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y + 7.);
2748 }
2749
2750 #[test]
2751 fn test_map_to_window_through_transform_roundtrip() {
2752 let (_window_adapter, item_tree) = create_transform_test_items();
2753 let root = ItemRc::new_root(item_tree);
2754 let transform = root.first_child().unwrap();
2755 let clip = transform.first_child().unwrap();
2756 let leaf = clip.first_child().unwrap();
2757
2758 let local_point = Point2D::new(4., 5.);
2759 let window_point = leaf.map_to_window(local_point);
2760 assert_point_approx_eq(window_point, Point2D::new(28., 53.));
2761 }
2762
2763 #[test]
2764 fn test_visibility_with_clip_under_transform() {
2765 let (_window_adapter, item_tree) = create_transform_test_items();
2766 let root = ItemRc::new_root(item_tree);
2767 let transform = root.first_child().unwrap();
2768 let clip = transform.first_child().unwrap();
2769 let leaf = clip.first_child().unwrap();
2770
2771 assert!(leaf.is_visible());
2772
2773 let hidden_point = leaf.map_to_window(Point2D::new(25., 25.));
2774 let (clip_rect, leaf_geometry) = leaf.absolute_clip_rect_and_geometry();
2775 assert!(clip_rect.intersection(&leaf_geometry).is_some());
2776 assert!(!clip_rect.contains(hidden_point));
2777 }
2778
2779 #[test]
2780 fn test_map_to_native_window_popup() {
2781 const POPUP_LOCATION: LogicalPosition = LogicalPosition::new(20., 33.);
2782 let mut window_item = WindowItem::default();
2783 window_item.width = Property::new(LogicalLength::new(30.));
2784 window_item.height = Property::new(LogicalLength::new(30.));
2785 let (window_adapter, parent) = create_one_node_component(Some(window_item));
2787 let popup_component = create_subsubtree_items(Some(window_adapter.clone())).1;
2788 window_adapter.window.0.show_popup(
2789 &popup_component,
2790 alloc::boxed::Box::new(move || POPUP_LOCATION),
2791 crate::items::PopupClosePolicy::NoAutoClose,
2792 &ItemRc::new_root(parent.clone()),
2793 crate::window::WindowKind::Popup,
2794 alloc::boxed::Box::new(|_| {}),
2795 );
2796
2797 let root = ItemRc::new_root(popup_component);
2798 let first_child = root.first_child().unwrap();
2799 let first_child_of_first_child = first_child.first_child().unwrap();
2800
2801 let active_popups = window_adapter.window.0.active_popups();
2803 assert_eq!(active_popups.len(), 1);
2804 let popup = active_popups.first().unwrap();
2805 assert!(matches!(popup.location, crate::window::PopupWindowLocation::ChildWindow { .. }));
2806
2807 let point = first_child_of_first_child.map_to_native_window(Point2D::new(3., -82.));
2810 assert_eq!(
2811 point.x,
2812 POPUP_LOCATION.x + GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + 3.
2814 );
2815 assert_eq!(
2816 point.y,
2817 POPUP_LOCATION.y + GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y
2818 - 82.
2819 );
2820 }
2821
2822 #[test]
2823 fn test_map_to_window_popup() {
2824 const POPUP_LOCATION: LogicalPosition = LogicalPosition::new(20., 33.);
2825 let (window_adapter, item_tree) = create_subsubtree_items(None);
2826 window_adapter.window.0.show_popup(
2827 &item_tree,
2828 alloc::boxed::Box::new(move || POPUP_LOCATION),
2829 crate::items::PopupClosePolicy::NoAutoClose,
2830 &ItemRc::new_root(item_tree.clone()),
2831 crate::window::WindowKind::Popup,
2832 alloc::boxed::Box::new(|_| {}),
2833 );
2834
2835 let root = ItemRc::new_root(item_tree);
2836 let first_child = root.first_child().unwrap();
2837 let first_child_of_first_child = first_child.first_child().unwrap();
2838
2839 let active_popups = window_adapter.window.0.active_popups();
2841 assert_eq!(active_popups.len(), 1);
2842 let popup = active_popups.first().unwrap();
2843 assert!(matches!(popup.location, crate::window::PopupWindowLocation::ChildWindow { .. }));
2844
2845 let point = first_child_of_first_child.map_to_window(Point2D::new(3., -82.));
2848 assert_eq!(point.x, GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + 3.);
2851 assert_eq!(point.y, GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y - 82.);
2852 }
2853
2854 fn create_subsubtree_items_dynamic_elements(
2856 window_adapter: Rc<WindowAdapter>,
2857 ) -> VRc<ItemTreeVTable> {
2858 let weak_adapter =
2859 Rc::downgrade(&window_adapter) as std::rc::Weak<dyn crate::window::WindowAdapter>;
2860 let mut window_item = WindowItem::default();
2861 window_item.width = Property::new(LogicalLength::new(30.));
2862 window_item.height = Property::new(LogicalLength::new(30.));
2863
2864 let item_tree = VRc::new(TestItemTree {
2865 parent_component: None,
2866 item_tree: vec![
2867 ItemTreeNode::Item {
2869 is_accessible: false,
2870 children_count: 1,
2871 children_index: 1,
2872 parent_index: 0,
2873 item_array_index: 0,
2874 },
2875 ItemTreeNode::DynamicTree { index: 0, parent_index: 0 },
2877 ],
2878 subtrees: std::cell::RefCell::new(Vec::new()),
2879 subtree_index: usize::MAX,
2880 window_adapter: weak_adapter.clone(),
2881 window_item: Some(window_item),
2882 });
2883
2884 item_tree.as_pin_ref().subtrees.replace(vec![vec![VRc::new(TestItemTree {
2885 parent_component: Some(VRc::downgrade(&VRc::into_dyn(item_tree.clone()))),
2886 item_tree: vec![
2887 ItemTreeNode::Item {
2889 is_accessible: false,
2890 children_count: 1,
2891 children_index: 1,
2892 parent_index: 1, item_array_index: 0,
2894 },
2895 ItemTreeNode::Item {
2897 is_accessible: false,
2898 children_count: 0,
2899 children_index: 0,
2900 parent_index: 0,
2901 item_array_index: 1,
2902 },
2903 ],
2904 subtrees: std::cell::RefCell::new(Vec::new()),
2905 subtree_index: 0,
2906
2907 window_adapter: weak_adapter,
2908 window_item: None,
2909 })]]);
2910
2911 VRc::into_dyn(item_tree)
2912 }
2913
2914 #[test]
2917 fn test_map_to_native_window_popup_dynamic_element() {
2918 const POPUP_LOCATION: LogicalPosition = LogicalPosition::new(20., 33.);
2919
2920 let mut window_item = WindowItem::default();
2921 window_item.width = Property::new(LogicalLength::new(30.));
2922 window_item.height = Property::new(LogicalLength::new(30.));
2923
2924 let (window_adapter, parent) = create_one_node_component(Some(window_item));
2926 let popup_component = create_subsubtree_items_dynamic_elements(window_adapter.clone());
2927 window_adapter.window.0.show_popup(
2928 &popup_component,
2929 alloc::boxed::Box::new(move || POPUP_LOCATION),
2930 crate::items::PopupClosePolicy::NoAutoClose,
2931 &ItemRc::new_root(parent.clone()),
2932 crate::window::WindowKind::Popup,
2933 alloc::boxed::Box::new(|_| {}),
2934 );
2935
2936 let active_popups = window_adapter.window.0.active_popups();
2938 assert_eq!(active_popups.len(), 1);
2939 let popup = active_popups.first().unwrap();
2940 assert!(matches!(popup.location, crate::window::PopupWindowLocation::ChildWindow { .. }));
2941
2942 let root = ItemRc::new_root(popup_component);
2943 let first_child = root.first_child().unwrap();
2944 let comp_ref_pin = vtable::VRc::borrow_pin(&root.item_tree);
2946 let item_tree_array = crate::item_tree::ItemTreeNodeArray::new(&comp_ref_pin);
2947 assert!(matches!(
2948 item_tree_array.get(1).expect("Must be one element"),
2949 ItemTreeNode::DynamicTree { .. }
2950 ));
2951 let first_child_of_first_child = first_child.first_child().expect("We have one child");
2953
2954 let point = first_child_of_first_child.map_to_native_window(Point2D::new(3., -82.));
2957 assert_eq!(
2958 point.x,
2959 POPUP_LOCATION.x + GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + GEOMETRY_POSITION_X + 3.
2961 );
2962 assert_eq!(
2963 point.y,
2964 POPUP_LOCATION.y + GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y + GEOMETRY_POSITION_Y
2965 - 82.
2966 );
2967 }
2968
2969 impl crate::renderer::RendererSealed for Renderer {
2970 fn char_size(
2971 &self,
2972 _text_item: Pin<&dyn crate::item_rendering::HasFont>,
2973 _item_rc: &crate::item_tree::ItemRc,
2974 _ch: char,
2975 ) -> LogicalSize {
2976 LogicalSize::new(5., 10.)
2977 }
2978
2979 fn font_metrics(
2980 &self,
2981 _font_request: crate::graphics::FontRequest,
2982 ) -> crate::items::FontMetrics {
2983 crate::items::FontMetrics { ..Default::default() }
2984 }
2985
2986 fn free_graphics_resources(
2987 &self,
2988 _component: ItemTreeRef,
2989 _items: &mut dyn Iterator<Item = Pin<crate::items::ItemRef<'_>>>,
2990 ) -> Result<(), crate::platform::PlatformError> {
2991 Ok(())
2992 }
2993
2994 fn mark_dirty_region(&self, _region: crate::partial_renderer::DirtyRegion) {
2995 }
2997
2998 fn register_bitmap_font(&self, _font_data: &'static crate::graphics::BitmapFont) {
2999 unimplemented!("Not required in this test");
3000 }
3001
3002 fn register_font_from_memory(
3003 &self,
3004 _data: &'static [u8],
3005 ) -> Result<(), std::prelude::v1::Box<dyn std::error::Error>> {
3006 unimplemented!("Not required in this test");
3007 }
3008
3009 fn register_font_from_path(
3010 &self,
3011 _path: &std::path::Path,
3012 ) -> Result<(), std::prelude::v1::Box<dyn std::error::Error>> {
3013 unimplemented!("Not required in this test");
3014 }
3015
3016 fn resize(&self, _size: crate::api::PhysicalSize) -> Result<(), crate::api::PlatformError> {
3017 Ok(())
3018 }
3019
3020 fn scale_factor(&self) -> Option<crate::lengths::ScaleFactor> {
3021 None
3022 }
3023
3024 fn set_rendering_notifier(
3025 &self,
3026 _callback: std::prelude::v1::Box<dyn crate::api::RenderingNotifier>,
3027 ) -> Result<(), crate::api::SetRenderingNotifierError> {
3028 Ok(())
3029 }
3030
3031 fn set_window_adapter(
3032 &self,
3033 _window_adapter: &std::rc::Rc<dyn crate::window::WindowAdapter>,
3034 ) {
3035 unimplemented!("Not required in this test");
3036 }
3037
3038 fn slint_context(&self) -> Option<crate::SlintContext> {
3039 None
3040 }
3041
3042 fn supports_transformations(&self) -> bool {
3043 self.supports_transformations
3044 }
3045
3046 fn take_snapshot(
3047 &self,
3048 ) -> Result<crate::api::SharedPixelBuffer<crate::api::Rgba8Pixel>, crate::api::PlatformError>
3049 {
3050 unimplemented!("Not required in this test");
3051 }
3052
3053 fn text_input_byte_offset_for_position(
3054 &self,
3055 _text_input: Pin<&crate::items::TextInput>,
3056 _item_rc: &ItemRc,
3057 _pos: LogicalPoint,
3058 ) -> usize {
3059 unimplemented!("Not required in this test");
3060 }
3061
3062 fn text_input_cursor_rect_for_byte_offset(
3063 &self,
3064 _text_input: Pin<&crate::items::TextInput>,
3065 _item_rc: &ItemRc,
3066 _byte_offset: usize,
3067 ) -> LogicalRect {
3068 unimplemented!("Not required in this test");
3069 }
3070
3071 fn text_size(
3072 &self,
3073 _text_item: Pin<&dyn crate::item_rendering::RenderString>,
3074 _item_rc: &crate::item_tree::ItemRc,
3075 _max_width: Option<crate::lengths::LogicalLength>,
3076 _text_wrap: crate::items::TextWrap,
3077 ) -> crate::lengths::LogicalSize {
3078 unimplemented!("Not required in this test");
3079 }
3080
3081 fn window_adapter(&self) -> Option<std::rc::Rc<dyn crate::window::WindowAdapter>> {
3082 unimplemented!("Not required in this test");
3083 }
3084 }
3085}