Skip to main content

ferroui_controls/presentation_source/
presentation_source_input.rs

1use super::PresentationSource;
2use ferroui_base::input::raw::{IRawInputEventArgs, RawPointerEventArgs};
3use ferroui_base::input::{IInputRoot, InputElement};
4use ferroui_base::logging::{LogArea, LogEventLevel, Logger};
5use ferroui_base::threading::Dispatcher;
6use ferroui_base::Ref;
7use std::rc::Rc;
8
9impl PresentationSource {
10    /// The source as the input root of its tree.
11    pub fn input_root(&self) -> Rc<dyn IInputRoot> {
12        self.rc()
13    }
14
15    /// Handles input from the platform implementation of the top-level.
16    fn handle_input_core(&self, e: Rc<dyn IRawInputEventArgs>) {
17        if let Some(pointer_args) = e.downcast_ref::<RawPointerEventArgs>() {
18            let hit_test_element = self.root_element().input_hit_test_with(pointer_args.position(), false);
19            let first_enabled_ancestor = first_enabled_ancestor(hit_test_element.clone());
20
21            pointer_args.set_input_hit_test_result(hit_test_element, first_enabled_ancestor);
22        }
23
24        if let Some(input_manager) = &self.input_manager {
25            input_manager.process_input(e);
26        }
27    }
28
29    pub(super) fn handle_input(&self, e: Rc<dyn IRawInputEventArgs>) {
30        if self.platform_impl().is_some() {
31            let this = self.rc();
32            // The dispatcher runs the callback right away (send priority);
33            // it only fails when the dispatcher has shut down.
34            let _ = Dispatcher::ui_thread().invoke_local(move || this.handle_input_core(e));
35        } else if let Some(logger) = Logger::try_get(LogEventLevel::Warning, LogArea::CONTROL) {
36            logger.log(None, "PlatformImpl is null, couldn't handle input.");
37        }
38    }
39
40    /// The element keyboard input is sent to when nothing is focused.
41    ///
42    /// # Panics
43    /// Panics when the element has been dropped.
44    pub fn focus_root(&self) -> Ref<InputElement> {
45        self.focus_root.upgrade().expect("the focus root of the presentation source has been dropped")
46    }
47}
48
49fn first_enabled_ancestor(hit_test_element: Option<Ref<InputElement>>) -> Option<Ref<InputElement>> {
50    let mut candidate = hit_test_element;
51    while let Some(element) = &candidate {
52        if element.is_effectively_enabled() {
53            break;
54        }
55        candidate = element.visual_parent().and_then(|parent| parent.downcast::<InputElement>().ok());
56    }
57    candidate
58}