Skip to main content

ferroui_base/input/
input_extensions.rs

1//! Input hit testing: extension methods of [`InputElement`].
2
3use super::InputElement;
4use crate::media::{Geometry, GeometryHitTestResult};
5use crate::{Point, Ref, Visual};
6
7fn is_hit_test_visible(visual: &Visual) -> bool {
8    visual.is_visible()
9        && visual.is_attached_to_visual_tree()
10        && visual.downcast_ref::<InputElement>().is_some_and(InputElement::is_hit_test_visible)
11}
12
13fn is_hit_test_visible_enabled_only(visual: &Visual) -> bool {
14    is_hit_test_visible(visual)
15        && visual.downcast_ref::<InputElement>().is_some_and(InputElement::is_effectively_enabled)
16}
17
18fn hit_test_filter(enabled_elements_only: bool) -> fn(&Visual) -> bool {
19    if enabled_elements_only {
20        is_hit_test_visible_enabled_only
21    } else {
22        is_hit_test_visible
23    }
24}
25
26impl InputElement {
27    /// Returns the active input elements at a point on the element, in the
28    /// element's coordinates, topmost first. Only enabled elements are
29    /// considered.
30    pub fn get_input_elements_at(&self, p: Point) -> Vec<Ref<InputElement>> {
31        self.get_input_elements_at_with(p, true)
32    }
33
34    /// Returns the active input elements at a point on the element, in the
35    /// element's coordinates, topmost first.
36    ///
37    /// `enabled_elements_only` tells whether only enabled elements should
38    /// be considered.
39    pub fn get_input_elements_at_with(&self, p: Point, enabled_elements_only: bool) -> Vec<Ref<InputElement>> {
40        self.get_visuals_at_filtered(p, &hit_test_filter(enabled_elements_only))
41            .into_iter()
42            .filter_map(|visual| visual.downcast::<InputElement>().ok())
43            .collect()
44    }
45
46    /// Returns the active input elements intersecting a geometry on the
47    /// element, in the element's coordinates, topmost first, with the
48    /// details of the intersections.
49    ///
50    /// `enabled_elements_only` tells whether only enabled elements should
51    /// be considered.
52    pub fn get_input_elements_at_geometry(
53        &self,
54        geometry: &Geometry,
55        enabled_elements_only: bool,
56    ) -> Vec<GeometryHitTestResult> {
57        self.get_visuals_at_geometry_filtered(geometry, &hit_test_filter(enabled_elements_only))
58            .into_iter()
59            .filter(|x| x.visual_hit.is::<InputElement>())
60            .collect()
61    }
62
63    /// Returns the topmost active input element at a point on the element,
64    /// in the element's coordinates. Only enabled elements are considered.
65    pub fn input_hit_test(&self, p: Point) -> Option<Ref<InputElement>> {
66        self.input_hit_test_with(p, true)
67    }
68
69    /// Returns the topmost active input element at a point on the element,
70    /// in the element's coordinates.
71    ///
72    /// `enabled_elements_only` tells whether only enabled elements should
73    /// be considered.
74    pub fn input_hit_test_with(&self, p: Point, enabled_elements_only: bool) -> Option<Ref<InputElement>> {
75        self.get_visual_at_filtered(p, &hit_test_filter(enabled_elements_only))
76            .and_then(|visual| visual.downcast::<InputElement>().ok())
77    }
78
79    /// Returns the topmost active input element intersecting a geometry on
80    /// the element, in the element's coordinates, with the details of the
81    /// intersection.
82    ///
83    /// `enabled_elements_only` tells whether only enabled elements should
84    /// be considered.
85    pub fn input_hit_test_geometry(
86        &self,
87        geometry: &Geometry,
88        enabled_elements_only: bool,
89    ) -> Option<GeometryHitTestResult> {
90        self.get_visual_at_geometry_filtered(geometry, &hit_test_filter(enabled_elements_only))
91            .filter(|hit_test| hit_test.visual_hit.is::<InputElement>())
92    }
93
94    /// Returns the topmost active input element at a point on the element
95    /// that also passes a filter, in the element's coordinates.
96    ///
97    /// If `filter` returns false for a visual then the visual and all its
98    /// descendants are excluded from the results. `enabled_elements_only`
99    /// tells whether only enabled elements should be considered.
100    pub fn input_hit_test_filtered(
101        &self,
102        p: Point,
103        filter: &dyn Fn(&Visual) -> bool,
104        enabled_elements_only: bool,
105    ) -> Option<Ref<InputElement>> {
106        let hit_test_delegate = hit_test_filter(enabled_elements_only);
107
108        self.get_visual_at_filtered(p, &|x: &Visual| hit_test_delegate(x) && filter(x))
109            .and_then(|visual| visual.downcast::<InputElement>().ok())
110    }
111
112    /// Returns the topmost active input element intersecting a geometry on
113    /// the element that also passes a filter, in the element's coordinates.
114    ///
115    /// If `filter` returns false for a visual then the visual and all its
116    /// descendants are excluded from the results. `enabled_elements_only`
117    /// tells whether only enabled elements should be considered.
118    pub fn input_hit_test_geometry_filtered(
119        &self,
120        geometry: &Geometry,
121        filter: &dyn Fn(&Visual) -> bool,
122        enabled_elements_only: bool,
123    ) -> Option<Ref<InputElement>> {
124        let hit_test_delegate = hit_test_filter(enabled_elements_only);
125
126        self.get_visual_at_geometry_filtered(geometry, &|x: &Visual| hit_test_delegate(x) && filter(x))
127            .and_then(|hit_test| hit_test.visual_hit.downcast::<InputElement>().ok())
128    }
129}