1use super::raw::{IDragDropDevice, IRawInputEventArgs, RawDragEvent, RawDragEventType};
2use super::{DragDrop, DragDropEffects, DragEventArgs, IDataTransfer, IInputDevice, IInputRoot, KeyModifiers};
3use crate::interactivity::{Interactive, RoutedEvent};
4use crate::{Point, Ref};
5use std::any::Any;
6use std::cell::RefCell;
7use std::rc::Rc;
8
9crate::ferro_thread_local! {
10 static INSTANCE: Rc<DragDropDevice> = Rc::new(DragDropDevice { last_target: RefCell::new(None) });
11}
12
13pub struct DragDropDevice {
18 last_target: RefCell<Option<Ref<Interactive>>>,
19}
20
21impl DragDropDevice {
22 pub fn instance() -> Rc<DragDropDevice> {
24 INSTANCE.with(Rc::clone)
25 }
26
27 fn last_target(&self) -> Option<Ref<Interactive>> {
28 self.last_target.borrow().clone()
29 }
30
31 fn set_last_target(&self, value: Option<Ref<Interactive>>) {
32 let old = self.last_target.replace(value);
33 drop(old);
34 }
35
36 fn get_target(root: &Rc<dyn IInputRoot>, local: Point) -> Option<Ref<Interactive>> {
37 let hit = root.root_element().input_hit_test(local)?;
38 let target = hit.get_self_and_visual_ancestors().find_map(|visual| visual.downcast::<Interactive>().ok())?;
39
40 if DragDrop::get_allow_drop(&target) {
41 Some(target)
42 } else {
43 None
44 }
45 }
46
47 fn raise_drag_event(
48 target: Option<&Ref<Interactive>>,
49 input_root: &Rc<dyn IInputRoot>,
50 point: Point,
51 routed_event: &RoutedEvent<DragEventArgs>,
52 operation: DragDropEffects,
53 data_transfer: &Rc<dyn IDataTransfer>,
54 modifiers: KeyModifiers,
55 ) -> DragDropEffects {
56 let Some(target) = target else {
57 return DragDropEffects::NONE;
58 };
59
60 let Some(p) = input_root.root_element().translate_point(point, target) else {
61 return DragDropEffects::NONE;
62 };
63
64 let args = DragEventArgs::new(Some(routed_event), data_transfer.clone(), target.clone(), p, modifiers);
65 args.set_drag_effects(operation);
66
67 target.raise_event(&args);
68 args.drag_effects()
69 }
70
71 fn drag_enter(
72 &self,
73 input_root: &Rc<dyn IInputRoot>,
74 point: Point,
75 data: &Rc<dyn IDataTransfer>,
76 effects: DragDropEffects,
77 modifiers: KeyModifiers,
78 ) -> DragDropEffects {
79 let target = Self::get_target(input_root, point);
80 self.set_last_target(target.clone());
81 Self::raise_drag_event(
82 target.as_ref(),
83 input_root,
84 point,
85 DragDrop::drag_enter_event(),
86 effects,
87 data,
88 modifiers,
89 )
90 }
91
92 fn drag_over(
93 &self,
94 input_root: &Rc<dyn IInputRoot>,
95 point: Point,
96 data: &Rc<dyn IDataTransfer>,
97 effects: DragDropEffects,
98 modifiers: KeyModifiers,
99 ) -> DragDropEffects {
100 let target = Self::get_target(input_root, point);
101 let last_target = self.last_target();
102
103 if target == last_target {
104 return Self::raise_drag_event(
105 target.as_ref(),
106 input_root,
107 point,
108 DragDrop::drag_over_event(),
109 effects,
110 data,
111 modifiers,
112 );
113 }
114
115 let _finally = Finally(|| self.set_last_target(target.clone()));
117
118 if last_target.is_some() {
119 Self::raise_drag_event(
120 last_target.as_ref(),
121 input_root,
122 point,
123 DragDrop::drag_leave_event(),
124 effects,
125 data,
126 modifiers,
127 );
128 }
129
130 Self::raise_drag_event(
131 target.as_ref(),
132 input_root,
133 point,
134 DragDrop::drag_enter_event(),
135 effects,
136 data,
137 modifiers,
138 )
139 }
140
141 fn drag_leave(
142 &self,
143 input_root: &Rc<dyn IInputRoot>,
144 point: Point,
145 data: &Rc<dyn IDataTransfer>,
146 effects: DragDropEffects,
147 modifiers: KeyModifiers,
148 ) {
149 let last_target = self.last_target();
150 if last_target.is_none() {
151 return;
152 }
153
154 let _finally = Finally(|| self.set_last_target(None));
155
156 Self::raise_drag_event(
157 last_target.as_ref(),
158 input_root,
159 point,
160 DragDrop::drag_leave_event(),
161 effects,
162 data,
163 modifiers,
164 );
165 }
166
167 fn drop(
168 &self,
169 input_root: &Rc<dyn IInputRoot>,
170 point: Point,
171 data: &Rc<dyn IDataTransfer>,
172 effects: DragDropEffects,
173 modifiers: KeyModifiers,
174 ) -> DragDropEffects {
175 let last_target = self.last_target();
176 let _finally = Finally(|| self.set_last_target(None));
177
178 Self::raise_drag_event(last_target.as_ref(), input_root, point, DragDrop::drop_event(), effects, data, modifiers)
179 }
180
181 fn process_raw_drag_event(&self, e: &RawDragEvent) {
182 let (root, location, data, effects, modifiers) =
183 (e.root(), e.location(), e.data_transfer(), e.effects(), e.key_modifiers());
184
185 match e.type_() {
186 RawDragEventType::DragEnter => e.set_effects(self.drag_enter(root, location, data, effects, modifiers)),
187 RawDragEventType::DragOver => e.set_effects(self.drag_over(root, location, data, effects, modifiers)),
188 RawDragEventType::DragLeave => self.drag_leave(root, location, data, effects, modifiers),
189 RawDragEventType::Drop => e.set_effects(self.drop(root, location, data, effects, modifiers)),
190 }
191 }
192}
193
194struct Finally<F: FnMut()>(F);
197
198impl<F: FnMut()> Drop for Finally<F> {
199 fn drop(&mut self) {
200 (self.0)()
201 }
202}
203
204impl IInputDevice for DragDropDevice {
205 fn process_raw_event(&self, e: &dyn IRawInputEventArgs) {
206 if !e.handled() {
207 if let Some(margs) = e.downcast_ref::<RawDragEvent>() {
208 self.process_raw_drag_event(margs);
209 }
210 }
211 }
212
213 fn as_any(&self) -> &dyn Any {
214 self
215 }
216}
217
218impl IDragDropDevice for DragDropDevice {}