Skip to main content

ferroui_base/visual_tree/
visual_extensions.rs

1//! Extension methods for [`Visual`]: visual tree traversal, coordinate
2//! conversion and hit testing.
3//!
4//! This file ports both the visual tree extensions and the coordinate
5//! conversion extensions of the root namespace, as inherent methods of
6//! [`Visual`].
7
8use super::TransformedBounds;
9use crate::input::IInputRoot;
10use crate::layout::{ILayoutManager, ILayoutRoot};
11use crate::rendering::IPresentationSource;
12use crate::media::{Geometry, GeometryHitTestResult};
13use crate::platform::IPlatformSettings;
14use crate::{Matrix, ObjectType, PixelPoint, Point, Rect, Ref, Visual};
15use std::rc::Rc;
16
17/// The render transform of a visual, already adjusted for its transform
18/// origin, or `None` when the visual has none.
19///
20/// This is the single place the visual tree helpers and the managed hit
21/// tester get the render transform from.
22#[inline]
23fn render_transform(visual: &Visual) -> Option<Matrix> {
24    visual.render_transform().map(|transform| {
25        let origin = visual.render_transform_origin().to_pixels(visual.bounds().size());
26        let offset = Matrix::create_translation(origin.x, origin.y);
27        -offset * transform.value() * offset
28    })
29}
30
31/// The transform of a visual relative to its parent, excluding the
32/// translation to its position: the mirror transform (applied first) and
33/// the render transform.
34#[inline]
35fn local_render_transform(visual: &Visual) -> Matrix {
36    let mut result = Matrix::IDENTITY;
37
38    // This should be calculated BEFORE the render transform.
39    if visual.has_mirror_transform() {
40        let mirror_matrix = Matrix::new(-1.0, 0.0, 0.0, 1.0, visual.bounds().width, 0.0);
41        result *= mirror_matrix;
42    }
43
44    if let Some(render_transform) = render_transform(visual) {
45        result *= render_transform;
46    }
47
48    result
49}
50
51/// The transform from the coordinate space of a visual to the coordinate
52/// space of its parent.
53pub(crate) fn local_transform(visual: &Visual) -> Matrix {
54    let mut result = local_render_transform(visual);
55    let top_left = visual.bounds().top_left();
56
57    if top_left != Point::default() {
58        result *= Matrix::create_translation(top_left.x, top_left.y);
59    }
60
61    result
62}
63
64/// Iterates the visual ancestors of a visual, from its parent to the root.
65pub struct VisualAncestors {
66    next: Option<Ref<Visual>>,
67}
68
69impl Iterator for VisualAncestors {
70    type Item = Ref<Visual>;
71
72    fn next(&mut self) -> Option<Ref<Visual>> {
73        let current = self.next.take()?;
74        self.next = current.visual_parent();
75        Some(current)
76    }
77}
78
79/// Iterates the visual descendants of a visual in depth-first pre-order.
80pub struct VisualDescendants {
81    /// The snapshots of the children collections being enumerated, with the
82    /// index of the next child to visit in each.
83    stack: Vec<(Rc<Vec<Ref<Visual>>>, usize)>,
84    pending: Option<Ref<Visual>>,
85}
86
87impl Iterator for VisualDescendants {
88    type Item = Ref<Visual>;
89
90    fn next(&mut self) -> Option<Ref<Visual>> {
91        if let Some(pending) = self.pending.take() {
92            return Some(pending);
93        }
94
95        loop {
96            let (children, index) = self.stack.last_mut()?;
97            if *index >= children.len() {
98                self.stack.pop();
99                continue;
100            }
101
102            let child = children[*index].clone();
103            *index += 1;
104
105            if let Some(grandchildren) = child.visual_children_snapshot() {
106                if !grandchildren.is_empty() {
107                    self.stack.push((grandchildren, 0));
108                }
109            }
110
111            return Some(child);
112        }
113    }
114}
115
116impl Visual {
117    /// Calculates the distance from a visual's ancestor.
118    ///
119    /// Returns the number of steps from the visual to the ancestor, or
120    /// `None` if this visual is not a descendent of `ancestor`. With no
121    /// ancestor given, never matches and returns `None`.
122    pub fn calculate_distance_from_ancestor(&self, ancestor: Option<&Visual>) -> Option<usize> {
123        let mut result = 0;
124        let mut v = Some(self.to_ref());
125
126        while let Some(current) = v {
127            if ancestor.is_some_and(|a| std::ptr::eq::<Visual>(&*current, a)) {
128                return Some(result);
129            }
130            v = current.visual_parent();
131            result += 1;
132        }
133
134        None
135    }
136
137    /// Calculates the distance from a visual's root.
138    pub fn calculate_distance_from_root(&self) -> usize {
139        let mut result = 0;
140        let mut v = self.visual_parent();
141
142        while let Some(current) = v {
143            v = current.visual_parent();
144            result += 1;
145        }
146
147        result
148    }
149
150    /// Tries to get the first common ancestor of two visuals.
151    pub fn find_common_visual_ancestor(&self, target: &Visual) -> Option<Ref<Visual>> {
152        fn go_upwards(node: &mut Option<Ref<Visual>>, count: usize) {
153            for _ in 0..count {
154                *node = node.as_ref().and_then(|n| n.visual_parent());
155            }
156        }
157
158        let mut v = Some(self.to_ref());
159        let mut t = Some(target.to_ref());
160
161        // We want to find the lowest node first, then make sure that both
162        // nodes are at the same height. By doing that we can sometimes find
163        // out that the other node is our lowest common ancestor.
164        let first_height = self.calculate_distance_from_root();
165        let second_height = target.calculate_distance_from_root();
166
167        if first_height > second_height {
168            go_upwards(&mut v, first_height - second_height);
169        } else {
170            go_upwards(&mut t, second_height - first_height);
171        }
172
173        if v == t {
174            return v;
175        }
176
177        while let (Some(first), Some(second)) = (&v, &t) {
178            let first_parent = first.visual_parent();
179            let second_parent = second.visual_parent();
180
181            if first_parent == second_parent {
182                return first_parent;
183            }
184
185            v = first_parent;
186            t = second_parent;
187        }
188
189        None
190    }
191
192    /// Enumerates the ancestors of the visual in the visual tree.
193    pub fn get_visual_ancestors(&self) -> VisualAncestors {
194        VisualAncestors { next: self.visual_parent() }
195    }
196
197    /// Enumerates the visual and its ancestors in the visual tree.
198    pub fn get_self_and_visual_ancestors(&self) -> VisualAncestors {
199        VisualAncestors { next: Some(self.to_ref()) }
200    }
201
202    /// Finds the first ancestor of class `T`, optionally starting with the
203    /// visual itself.
204    pub fn find_ancestor_of_type<T: ObjectType>(&self, include_self: bool) -> Option<Ref<T>> {
205        self.find_ancestor_of_type_where::<T>(include_self, |_| true)
206    }
207
208    /// Finds the first ancestor of class `T` that matches a predicate,
209    /// optionally starting with the visual itself.
210    pub fn find_ancestor_of_type_where<T: ObjectType>(
211        &self,
212        include_self: bool,
213        predicate: impl Fn(&T) -> bool,
214    ) -> Option<Ref<T>> {
215        let mut parent = if include_self { Some(self.to_ref()) } else { self.visual_parent() };
216
217        while let Some(current) = parent {
218            if let Some(result) = current.downcast_ref::<T>() {
219                if predicate(result) {
220                    return current.downcast::<T>().ok();
221                }
222            }
223            parent = current.visual_parent();
224        }
225
226        None
227    }
228
229    /// Finds the first descendant of class `T` (depth first), optionally
230    /// starting with the visual itself.
231    pub fn find_descendant_of_type<T: ObjectType>(&self, include_self: bool) -> Option<Ref<T>> {
232        self.find_descendant_of_type_where::<T>(include_self, |_| true)
233    }
234
235    /// Finds the first descendant of class `T` that matches a predicate
236    /// (depth first), optionally starting with the visual itself.
237    pub fn find_descendant_of_type_where<T: ObjectType>(
238        &self,
239        include_self: bool,
240        predicate: impl Fn(&T) -> bool,
241    ) -> Option<Ref<T>> {
242        fn core<T: ObjectType>(visual: &Visual, predicate: &dyn Fn(&T) -> bool) -> Option<Ref<T>> {
243            let children = visual.visual_children_snapshot()?;
244
245            for child in children.iter() {
246                if let Some(result) = child.downcast_ref::<T>() {
247                    if predicate(result) {
248                        return child.cast::<T>();
249                    }
250                }
251
252                if let Some(child_result) = core::<T>(child, predicate) {
253                    return Some(child_result);
254                }
255            }
256
257            None
258        }
259
260        if include_self {
261            if let Some(result) = self.downcast_ref::<T>() {
262                if predicate(result) {
263                    return self.to_ref().downcast::<T>().ok();
264                }
265            }
266        }
267
268        core::<T>(self, &predicate)
269    }
270
271    /// Gets the bounds of the visual in the coordinate space of its root,
272    /// with the clip applied by its ancestors. Returns `None` if the visual
273    /// or one of its ancestors is invisible.
274    pub fn get_transformed_bounds(&self) -> Option<TransformedBounds> {
275        fn visit(visual: &Visual, clip: &mut Rect, transform: &mut Matrix) -> bool {
276            if !visual.is_visible() {
277                return false;
278            }
279
280            // The visual's bounds in local coordinates.
281            let bounds = Rect::from_size(visual.bounds().size());
282
283            // If the visual has no parent, we've reached the root. We start
284            // the clip rectangle with these bounds.
285            let Some(parent) = visual.visual_parent() else {
286                *clip = bounds;
287                return true;
288            };
289
290            // Otherwise recurse until the root visual is found, exiting
291            // early if one of the ancestors is invisible.
292            if !visit(&parent, clip, transform) {
293                return false;
294            }
295
296            // Calculate the transform for this control from its offset and
297            // render transform.
298            let render_transform = local_render_transform(visual);
299            let position = visual.bounds().position();
300
301            *transform = render_transform * Matrix::create_translation(position.x, position.y) * *transform;
302
303            // If the visual is clipped, update the clip bounds.
304            if visual.clip_to_bounds() {
305                let global_bounds = bounds.transform_to_aabb(*transform);
306                let clip_bounds = global_bounds.intersect(*clip);
307                *clip = clip.intersect(clip_bounds);
308            }
309
310            true
311        }
312
313        let mut clip = Rect::default();
314        let mut transform = Matrix::IDENTITY;
315
316        if visit(self, &mut clip, &mut transform) {
317            Some(TransformedBounds::new(Rect::from_size(self.bounds().size()), clip, transform))
318        } else {
319            None
320        }
321    }
322
323    /// Gets the first visible visual at a point, in the coordinates of this
324    /// visual.
325    pub fn get_visual_at(&self, p: Point) -> Option<Ref<Visual>> {
326        self.get_visual_at_filtered(p, &|x: &Visual| x.is_visible())
327    }
328
329    /// Gets the first visual at a point, in the coordinates of this visual.
330    ///
331    /// If `filter` returns false for a visual then the visual and all its
332    /// descendants are excluded from the results.
333    pub fn get_visual_at_filtered(&self, p: Point, filter: &dyn Fn(&Visual) -> bool) -> Option<Ref<Visual>> {
334        let source = self.presentation_source()?;
335        source.hit_tester().hit_test_first(p, self, Some(filter))
336    }
337
338    /// Gets the first visible visual intersecting a geometry, in the
339    /// coordinates of this visual, with the details of the intersection.
340    pub fn get_visual_at_geometry(&self, geometry: &Geometry) -> Option<GeometryHitTestResult> {
341        self.get_visual_at_geometry_filtered(geometry, &|x: &Visual| x.is_visible())
342    }
343
344    /// Gets the first visual intersecting a geometry, in the coordinates of
345    /// this visual, with the details of the intersection.
346    ///
347    /// If `filter` returns false for a visual then the visual and all its
348    /// descendants are excluded from the results.
349    pub fn get_visual_at_geometry_filtered(
350        &self,
351        geometry: &Geometry,
352        filter: &dyn Fn(&Visual) -> bool,
353    ) -> Option<GeometryHitTestResult> {
354        let source = self.presentation_source()?;
355        source.hit_tester().hit_test_first_geometry(geometry, self, Some(filter))
356    }
357
358    /// Enumerates the visible visuals at a point, in the coordinates of
359    /// this visual, topmost first.
360    pub fn get_visuals_at(&self, p: Point) -> Vec<Ref<Visual>> {
361        self.get_visuals_at_filtered(p, &|x: &Visual| x.is_visible())
362    }
363
364    /// Enumerates the visuals at a point, in the coordinates of this
365    /// visual, topmost first.
366    ///
367    /// If `filter` returns false for a visual then the visual and all its
368    /// descendants are excluded from the results.
369    pub fn get_visuals_at_filtered(&self, p: Point, filter: &dyn Fn(&Visual) -> bool) -> Vec<Ref<Visual>> {
370        match self.presentation_source() {
371            Some(source) => source.hit_tester().hit_test(p, self, Some(filter)),
372            None => Vec::new(),
373        }
374    }
375
376    /// Enumerates the visible visuals intersecting a geometry, in the
377    /// coordinates of this visual, topmost first, with the details of the
378    /// intersections.
379    pub fn get_visuals_at_geometry(&self, geometry: &Geometry) -> Vec<GeometryHitTestResult> {
380        self.get_visuals_at_geometry_filtered(geometry, &|x: &Visual| x.is_visible())
381    }
382
383    /// Enumerates the visuals intersecting a geometry, in the coordinates
384    /// of this visual, topmost first, with the details of the
385    /// intersections.
386    ///
387    /// If `filter` returns false for a visual then the visual and all its
388    /// descendants are excluded from the results.
389    pub fn get_visuals_at_geometry_filtered(
390        &self,
391        geometry: &Geometry,
392        filter: &dyn Fn(&Visual) -> bool,
393    ) -> Vec<GeometryHitTestResult> {
394        match self.presentation_source() {
395            Some(source) => source.hit_tester().hit_test_geometry(geometry, self, Some(filter)),
396            None => Vec::new(),
397        }
398    }
399
400    /// Gets a snapshot of the visual children of the visual.
401    pub fn get_visual_children(&self) -> Rc<Vec<Ref<Visual>>> {
402        self.visual_children_snapshot().unwrap_or_default()
403    }
404
405    /// Enumerates the descendants of the visual in the visual tree, in
406    /// depth-first pre-order.
407    pub fn get_visual_descendants(&self) -> VisualDescendants {
408        let mut stack = Vec::new();
409        if let Some(children) = self.visual_children_snapshot() {
410            if !children.is_empty() {
411                stack.push((children, 0));
412            }
413        }
414        VisualDescendants { stack, pending: None }
415    }
416
417    /// Enumerates the visual and its descendants in the visual tree, in
418    /// depth-first pre-order.
419    pub fn get_self_and_visual_descendants(&self) -> VisualDescendants {
420        let mut result = self.get_visual_descendants();
421        result.pending = Some(self.to_ref());
422        result
423    }
424
425    /// Gets the visual parent of the visual.
426    pub fn get_visual_parent(&self) -> Option<Ref<Visual>> {
427        self.visual_parent()
428    }
429
430    /// Gets the visual parent of the visual, if it is of class `T`.
431    pub fn get_visual_parent_of_type<T: ObjectType>(&self) -> Option<Ref<T>> {
432        self.visual_parent().and_then(|parent| parent.downcast::<T>().ok())
433    }
434
435    /// The presentation source the visual is attached to.
436    pub fn get_presentation_source(&self) -> Option<Rc<dyn IPresentationSource>> {
437        self.presentation_source()
438    }
439
440    /// The root visual of the presentation source the visual is attached
441    /// to.
442    pub fn get_visual_root(&self) -> Option<Ref<Visual>> {
443        self.presentation_source().and_then(|source| source.root_visual())
444    }
445
446    /// The layout root of the tree the visual is attached to.
447    pub fn get_layout_root(&self) -> Option<Rc<dyn ILayoutRoot>> {
448        self.presentation_source().map(|source| source.layout_root())
449    }
450
451    /// The layout manager of the presentation source of the visual, or
452    /// `None` when the visual is not attached to a visual root.
453    pub fn get_layout_manager(&self) -> Option<Rc<dyn ILayoutManager>> {
454        self.presentation_source().map(|source| source.layout_root().layout_manager())
455    }
456
457    /// The input root of the tree the visual is attached to.
458    pub fn get_input_root(&self) -> Option<Rc<dyn IInputRoot>> {
459        self.presentation_source().map(|source| source.input_root())
460    }
461
462    /// The platform settings of the tree the visual is attached to.
463    pub fn get_platform_settings(&self) -> Option<Rc<dyn IPlatformSettings>> {
464        self.presentation_source().and_then(|source| source.platform_settings())
465    }
466
467    /// Tests whether this visual is an ancestor of `target`.
468    pub fn is_visual_ancestor_of(&self, target: &Visual) -> bool {
469        let mut current = target.visual_parent();
470
471        while let Some(c) = current {
472            if std::ptr::eq::<Visual>(&*c, self) {
473                return true;
474            }
475            current = c.visual_parent();
476        }
477
478        false
479    }
480
481    /// Sorts visuals for hit testing: by descending Z index, and for equal
482    /// Z indices by descending position in the input, so that the topmost
483    /// visual comes first.
484    pub fn sort_by_z_index(elements: &[Ref<Visual>]) -> Vec<Ref<Visual>> {
485        let mut indexed: Vec<(i32, usize)> =
486            elements.iter().enumerate().map(|(index, element)| (element.z_index(), index)).collect();
487        indexed.sort_by(|x, y| y.0.cmp(&x.0).then(y.1.cmp(&x.1)));
488        indexed.into_iter().map(|(_, index)| elements[index].clone()).collect()
489    }
490
491    // --- coordinate conversion ----------------------------------------------
492
493    /// Converts a point from screen to client coordinates.
494    ///
495    /// Panics if the visual does not belong to a visual tree.
496    pub fn point_to_client(&self, point: PixelPoint) -> Point {
497        let (source, root) = self.source_and_root();
498        let root_point = source.point_to_client(point).unwrap_or_default();
499        root.translate_point(root_point, self).expect("the root is an ancestor of the visual")
500    }
501
502    /// Converts a point from client to screen coordinates.
503    ///
504    /// Panics if the visual does not belong to a visual tree.
505    pub fn point_to_screen(&self, point: Point) -> PixelPoint {
506        let (source, root) = self.source_and_root();
507        let p = self.translate_point(point, &root).expect("the root is an ancestor of the visual");
508        source.point_to_screen(p).unwrap_or_default()
509    }
510
511    /// Returns a transform that transforms the visual's coordinates into
512    /// the coordinates of the specified `to` visual, or `None` if the
513    /// visuals don't share a common ancestor.
514    pub fn transform_to_visual(&self, to: &Visual) -> Option<Matrix> {
515        let common = self.find_common_visual_ancestor(to)?;
516        let this_offset = Self::get_offset_from(&common, self);
517        let that_offset = Self::get_offset_from(&common, to);
518        let that_offset_inverted = that_offset.try_invert()?;
519
520        Some(that_offset_inverted * this_offset)
521    }
522
523    /// Translates a point relative to this visual to coordinates that are
524    /// relative to the specified visual, or returns `None` if the visuals
525    /// don't share a common ancestor.
526    pub fn translate_point(&self, point: Point, relative_to: &Visual) -> Option<Point> {
527        self.transform_to_visual(relative_to).map(|transform| point.transform(transform))
528    }
529
530    fn source_and_root(&self) -> (Rc<dyn crate::rendering::IPresentationSource>, Ref<Visual>) {
531        let source = self.presentation_source();
532        let root = source.as_ref().and_then(|s| s.root_visual());
533        match (source, root) {
534            (Some(source), Some(root)) => (source, root),
535            _ => panic!("Visual does not belong to a visual tree."),
536        }
537    }
538
539    /// Gets a transform from an ancestor to a descendent.
540    fn get_offset_from(ancestor: &Visual, visual: &Visual) -> Matrix {
541        let mut result = Matrix::IDENTITY;
542        let mut v = visual.to_ref();
543
544        while !std::ptr::eq::<Visual>(&*v, ancestor) {
545            result *= local_transform(&v);
546
547            v = match v.visual_parent() {
548                Some(parent) => parent,
549                None => panic!("'visual' is not a descendant of 'ancestor'."),
550            };
551        }
552
553        result
554    }
555}