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