Skip to main content

ferroui_base/input/
drag_drop.rs

1use super::platform::IPlatformDragSource;
2use super::{DragDropEffects, DragEventArgs, IDataTransfer, LocalBoxFuture, PointerPressedEventArgs};
3use crate::interactivity::{Interactive, RoutedEvent, RoutedEventHandlerToken, RoutingStrategies};
4use crate::{
5    ferro_property, ferro_routed_event, AttachedProperty, FerroLocator, FerroProperty, LocatorExtensions,
6    StyledPropertyOptions,
7};
8use std::rc::Rc;
9
10/// Defines the attached property and the routed events of drag-and-drop,
11/// and starts drag-and-drop operations.
12pub struct DragDrop;
13
14crate::ferro_static_type!(DragDrop);
15
16impl DragDrop {
17    ferro_routed_event!(
18        /// Event which is raised, when a drag-and-drop operation enters the
19        /// element.
20        pub fn drag_enter_event() -> RoutedEvent<DragEventArgs> {
21            RoutedEvent::register::<DragDrop, _>("DragEnter", RoutingStrategies::BUBBLE)
22        }
23    );
24
25    ferro_routed_event!(
26        /// Event which is raised, when a drag-and-drop operation leaves the
27        /// element.
28        pub fn drag_leave_event() -> RoutedEvent<DragEventArgs> {
29            RoutedEvent::register::<DragDrop, _>("DragLeave", RoutingStrategies::BUBBLE)
30        }
31    );
32
33    ferro_routed_event!(
34        /// Event which is raised, when a drag-and-drop operation is updated
35        /// while over the element.
36        pub fn drag_over_event() -> RoutedEvent<DragEventArgs> {
37            RoutedEvent::register::<DragDrop, _>("DragOver", RoutingStrategies::BUBBLE)
38        }
39    );
40
41    ferro_routed_event!(
42        /// Event which is raised, when a drag-and-drop operation should
43        /// complete over the element.
44        pub fn drop_event() -> RoutedEvent<DragEventArgs> {
45            RoutedEvent::register::<DragDrop, _>("Drop", RoutingStrategies::BUBBLE)
46        }
47    );
48
49}
50
51crate::ferro_properties! { impl DragDrop {
52    ferro_property!(
53        /// Defines the `AllowDrop` attached property: whether the element
54        /// can be the target of a drag-and-drop operation. It is inherited.
55        pub fn allow_drop_property() -> AttachedProperty<bool> {
56            FerroProperty::register_attached_with::<DragDrop, Interactive, _>(
57                "AllowDrop",
58                StyledPropertyOptions::new(false).inherits(true),
59            )
60        }
61    );
62} }
63
64impl DragDrop {
65    /// Gets a value indicating whether the given element can be used as
66    /// the target of a drag-and-drop operation.
67    pub fn get_allow_drop(interactive: &Interactive) -> bool {
68        interactive.get_value(Self::allow_drop_property())
69    }
70
71    /// Sets a value indicating whether the given element can be used as
72    /// the target of a drag-and-drop operation.
73    pub fn set_allow_drop(interactive: &Interactive, value: bool) {
74        interactive.set_value(Self::allow_drop_property(), value)
75    }
76
77    /// Adds a handler for the DragEnter attached event.
78    pub fn add_drag_enter_handler(
79        element: &Interactive,
80        handler: impl Fn(&Interactive, &DragEventArgs) + 'static,
81    ) -> RoutedEventHandlerToken {
82        element.add_handler(Self::drag_enter_event(), handler)
83    }
84
85    /// Removes a handler for the DragEnter attached event.
86    pub fn remove_drag_enter_handler(element: &Interactive, handler: RoutedEventHandlerToken) {
87        element.remove_handler(Self::drag_enter_event(), handler);
88    }
89
90    /// Adds a handler for the DragLeave attached event.
91    pub fn add_drag_leave_handler(
92        element: &Interactive,
93        handler: impl Fn(&Interactive, &DragEventArgs) + 'static,
94    ) -> RoutedEventHandlerToken {
95        element.add_handler(Self::drag_leave_event(), handler)
96    }
97
98    /// Removes a handler for the DragLeave attached event.
99    pub fn remove_drag_leave_handler(element: &Interactive, handler: RoutedEventHandlerToken) {
100        element.remove_handler(Self::drag_leave_event(), handler);
101    }
102
103    /// Adds a handler for the DragOver attached event.
104    pub fn add_drag_over_handler(
105        element: &Interactive,
106        handler: impl Fn(&Interactive, &DragEventArgs) + 'static,
107    ) -> RoutedEventHandlerToken {
108        element.add_handler(Self::drag_over_event(), handler)
109    }
110
111    /// Removes a handler for the DragOver attached event.
112    pub fn remove_drag_over_handler(element: &Interactive, handler: RoutedEventHandlerToken) {
113        element.remove_handler(Self::drag_over_event(), handler);
114    }
115
116    /// Adds a handler for the Drop attached event.
117    pub fn add_drop_handler(
118        element: &Interactive,
119        handler: impl Fn(&Interactive, &DragEventArgs) + 'static,
120    ) -> RoutedEventHandlerToken {
121        element.add_handler(Self::drop_event(), handler)
122    }
123
124    /// Removes a handler for the Drop attached event.
125    pub fn remove_drop_handler(element: &Interactive, handler: RoutedEventHandlerToken) {
126        element.remove_handler(Self::drop_event(), handler);
127    }
128
129    /// Starts a dragging operation with the given data transfer and
130    /// returns its result.
131    ///
132    /// `trigger_event` is the pointer pressed event that triggered the
133    /// operation. `data_transfer` is automatically disposed when the
134    /// operation completes: it must NOT be disposed by the caller.
135    /// `allowed_effects` are the effects the source allows.
136    pub fn do_drag_drop_async(
137        trigger_event: &PointerPressedEventArgs,
138        data_transfer: Rc<dyn IDataTransfer>,
139        allowed_effects: DragDropEffects,
140    ) -> LocalBoxFuture<DragDropEffects> {
141        let Some(drag_source) = FerroLocator::current().get_service::<dyn IPlatformDragSource>() else {
142            data_transfer.dispose();
143            return Box::pin(std::future::ready(DragDropEffects::NONE));
144        };
145
146        drag_source.do_drag_drop_async(trigger_event, data_transfer, allowed_effects)
147    }
148}