Skip to main content

ferroui_base/input/
context_requested_event_args.rs

1use super::{HoldingRoutedEventArgs, InputElement, PointerEventArgs, PointerType};
2use crate::interactivity::RoutedEventArgs;
3use crate::{ferro_routed_event_args, Point, Rect, Visual, WeakRef};
4use std::cell::RefCell;
5use std::rc::Rc;
6
7/// Provides event data for the context requested event.
8#[derive(Clone)]
9pub struct ContextRequestedEventArgs {
10    base: RoutedEventArgs,
11    pointer_event_args: Option<PointerEventArgs>,
12    is_holding: bool,
13    placement_rect: Rc<RefCell<Option<(WeakRef<Visual>, Rect)>>>,
14}
15
16ferro_routed_event_args!(ContextRequestedEventArgs: RoutedEventArgs);
17
18impl Default for ContextRequestedEventArgs {
19    fn default() -> Self {
20        Self::new()
21    }
22}
23
24impl ContextRequestedEventArgs {
25    /// Creates args for a context request that has no position, e.g. one
26    /// made with the keyboard.
27    pub fn new() -> Self {
28        Self {
29            base: RoutedEventArgs::with_event(InputElement::context_requested_event()),
30            pointer_event_args: None,
31            is_holding: false,
32            placement_rect: Rc::new(RefCell::new(None)),
33        }
34    }
35
36    /// Creates args for a context request made with a pointer.
37    pub fn from_pointer_event_args(pointer_event_args: &PointerEventArgs) -> Self {
38        Self { pointer_event_args: Some(pointer_event_args.clone()), ..Self::new() }
39    }
40
41    /// Creates args from other context requested args, keeping the position.
42    pub fn from_context_requested_event_args(context_requested_event_args: &ContextRequestedEventArgs) -> Self {
43        Self {
44            pointer_event_args: context_requested_event_args.pointer_event_args.clone(),
45            placement_rect: context_requested_event_args.placement_rect.clone(),
46            ..Self::new()
47        }
48    }
49
50    pub(crate) fn from_holding(hold_routed_event_args: &HoldingRoutedEventArgs) -> Self {
51        Self {
52            pointer_event_args: Some(hold_routed_event_args.pointer_event_args().clone()),
53            is_holding: true,
54            ..Self::new()
55        }
56    }
57
58    /// Gets the point on which the context was requested, relative to the
59    /// specified element (or to the root when `None`).
60    ///
61    /// Returns `None` if the context was not requested with a pointer, e.g.
62    /// when it was requested with the keyboard.
63    pub fn try_get_position(&self, relative_to: Option<&InputElement>) -> Option<Point> {
64        self.pointer_event_args.as_ref().map(|e| e.get_position(relative_to.map(|element| &****element)))
65    }
66
67    /// Supplies an explicit anchor for this menu request in `relative_to`'s
68    /// device-independent coordinates. A zero-size rectangle anchors at a point.
69    ///
70    /// This does not change whether the request originated from a pointer or
71    /// keyboard. The owner is weak, and shared event handles see the same anchor.
72    pub fn set_placement_rect(&self, relative_to: &Visual, rect: Rect) {
73        *self.placement_rect.borrow_mut() = Some((relative_to.to_ref().downgrade(), rect));
74    }
75
76    /// Gets this request's explicit anchor in the recipient's coordinates.
77    /// Returns `None` when no anchor was supplied, its owner expired, or the
78    /// recipient and owner do not share a visual coordinate system.
79    pub fn try_get_placement_rect(&self, relative_to: &Visual) -> Option<Rect> {
80        let (owner, rect) = self.placement_rect.borrow().clone()?;
81        let owner = owner.upgrade()?;
82        owner.transform_to_visual(relative_to).map(|transform| rect.transform_to_aabb(transform))
83    }
84
85    /// Restores the ordinary pointer or keyboard placement for this request.
86    pub fn clear_placement_rect(&self) {
87        self.placement_rect.borrow_mut().take();
88    }
89
90    /// Whether the context was requested by holding a pointer down.
91    ///
92    /// Internal in the reference, where the controls assembly sees it.
93    pub fn is_holding(&self) -> bool {
94        self.is_holding
95    }
96
97    #[allow(dead_code)]
98    pub fn pointer_type(&self) -> Option<PointerType> {
99        self.pointer_event_args.as_ref().map(|e| e.pointer().type_())
100    }
101}