Skip to main content

ferroui_controls/presentation_source/
presentation_source_cursor.rs

1use super::PresentationSource;
2use ferroui_base::input::text_input::ITextInputMethodImpl;
3use ferroui_base::input::{Cursor, FocusManager, IInputRoot, InputElement};
4use ferroui_base::platform::IOptionalFeatureProvider;
5use ferroui_base::{Point, Rect, Ref, Size};
6use std::rc::Rc;
7
8impl PresentationSource {
9    fn update_cursor(&self) {
10        let cursor = self.cursor_override.borrow().clone().or_else(|| self.cursor.borrow().clone());
11        if let Some(platform_impl) = self.platform_impl() {
12            platform_impl.set_cursor(cursor.map(|cursor| cursor.platform_impl().clone()));
13        }
14    }
15
16    fn set_cursor(&self, cursor: Option<Rc<Cursor>>) {
17        *self.cursor.borrow_mut() = cursor;
18        self.update_cursor();
19    }
20
21    /// This should only be used by the in-process drag source.
22    pub fn set_cursor_override(&self, cursor: Option<Rc<Cursor>>) {
23        *self.cursor_override.borrow_mut() = cursor;
24        self.update_cursor();
25    }
26}
27
28impl IInputRoot for PresentationSource {
29    fn hit_test_chrome_element(&self, point: Point) -> Option<ferroui_base::input::WindowDecorationsElementRole> {
30        // The root visual is cleared when the top level closes, but the platform can still
31        // hit-test the window.
32        let root_visual = self.root_visual()?;
33        let visual = root_visual.get_visual_at_filtered(point, &PresentationSource::chrome_hit_test_filter);
34        PresentationSource::get_chrome_role_from_visual(visual)
35    }
36
37    fn focus_manager(&self) -> Option<Rc<FocusManager>> {
38        Some(PresentationSource::focus_manager(self).clone())
39    }
40
41    fn pointer_over_element(&self) -> Option<Ref<InputElement>> {
42        self.pointer_over_element.borrow().clone()
43    }
44
45    fn set_pointer_over_element(&self, value: Option<Ref<InputElement>>) {
46        let old = self.pointer_over_element.replace(value);
47        drop(old);
48    }
49
50    fn cursor_element(&self) -> Option<Ref<InputElement>> {
51        self.cursor_element.borrow().clone()
52    }
53
54    fn set_cursor_element(&self, value: Option<Ref<InputElement>>) {
55        if *self.cursor_element.borrow() == value {
56            return;
57        }
58
59        if let Some(subscription) = self.cursor_element_subscription.borrow_mut().take() {
60            subscription.dispose();
61        }
62        let old = self.cursor_element.replace(value.clone());
63        drop(old);
64        if let Some(new) = &value {
65            let weak = self.this.clone();
66            let element = new.downgrade();
67            let subscription = new.property_changed(move |e| {
68                if e.property() == InputElement::cursor_property().as_property() {
69                    if let Some(source) = weak.upgrade() {
70                        source.set_cursor(element.upgrade().and_then(|element| element.cursor()));
71                    }
72                }
73            });
74            *self.cursor_element_subscription.borrow_mut() = Some(subscription);
75        }
76        self.set_cursor(value.and_then(|element| element.cursor()));
77    }
78
79    fn input_method(&self) -> Option<Rc<dyn ITextInputMethodImpl>> {
80        let platform_impl = self.platform_impl()?;
81        let provider: &dyn IOptionalFeatureProvider = &*platform_impl;
82        provider.try_get::<dyn ITextInputMethodImpl>()
83    }
84
85    fn root_element(&self) -> Ref<InputElement> {
86        PresentationSource::root_element(self)
87    }
88
89    fn try_root_element(&self) -> Option<Ref<InputElement>> {
90        self.root_visual()
91    }
92
93    fn focus_root(&self) -> Ref<InputElement> {
94        PresentationSource::focus_root(self)
95    }
96
97    fn pointer_over_invalidated(&self) {
98        let pre_processor = self.pointer_over_pre_processor.borrow().clone();
99        if let Some(pre_processor) = pre_processor {
100            pre_processor.scene_invalidated(Rect::from_position_size(Point::new(0.0, 0.0), Size::INFINITY));
101        }
102    }
103}