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