1#![allow(clippy::vec_init_then_push)]
2
3use std::any::Any;
4use std::sync::Mutex;
5
6use smallvec::smallvec;
7
8use crate::draw::Primitive;
9use crate::event::{Event, Key};
10use crate::layout::{Rectangle, Size};
11use crate::node::{GenericNode, IntoNode, Node};
12use crate::style::{StyleState, Stylesheet};
13use crate::widget::{frame::Frame, Context, StateVec, Widget};
14
15pub trait DragDropId: 'static + Copy + Any + Send + Sync {}
17
18pub struct DragDropContext<T: DragDropId> {
22 data: Mutex<Option<(T, (f32, f32))>>,
23}
24
25pub struct Drag<'a, T: DragDropId, Message> {
27 context: Option<&'a DragDropContext<T>>,
28 data: Option<T>,
29 content: Option<Frame<'a, Message>>,
30}
31
32pub struct DragState<T> {
34 dragging: Option<T>,
35 origin: (f32, f32),
36 offset: (f32, f32),
37}
38
39pub struct Drop<'a, T: DragDropId, Message, OnAccept, OnDrop> {
41 context: Option<&'a DragDropContext<T>>,
42 accept: OnAccept,
43 drop: OnDrop,
44 content: Option<Frame<'a, Message>>,
45}
46
47pub struct DropState<T> {
49 hovering: Option<(T, (f32, f32))>,
50 mouse_over: bool,
51}
52
53impl<'a, T: DragDropId, Message: 'a> Drag<'a, T, Message> {
54 pub fn new(context: &'a DragDropContext<T>, data: T, content: impl IntoNode<'a, Message>) -> Self {
56 Self {
57 context: Some(context),
58 data: Some(data),
59 content: Some(Frame::new(content)),
60 }
61 }
62
63 pub fn context(mut self, context: &'a DragDropContext<T>) -> Self {
65 self.context = Some(context);
66 self
67 }
68
69 pub fn val(mut self, value: T) -> Self {
71 self.data = Some(value);
72 self
73 }
74
75 pub fn extend<I: IntoIterator<Item = N>, N: IntoNode<'a, Message>>(mut self, iter: I) -> Self {
77 if self.content.is_none() {
78 self.content = iter.into_iter().next().map(Frame::new);
79 }
80 self
81 }
82
83 fn content(&self) -> &Frame<'a, Message> {
84 self.content.as_ref().expect("content of `Drag` must be set")
85 }
86
87 fn content_mut(&mut self) -> &mut Frame<'a, Message> {
88 self.content.as_mut().expect("content of `Drag` must be set")
89 }
90}
91
92impl<'a, T: DragDropId, Message: 'a, OnAccept: 'a, OnDrop: 'a> Drop<'a, T, Message, OnAccept, OnDrop>
93where
94 OnAccept: Fn(T) -> bool,
95 OnDrop: Fn(T, (f32, f32)) -> Message,
96{
97 pub fn new(
99 context: &'a DragDropContext<T>,
100 accept: OnAccept,
101 drop: OnDrop,
102 content: impl IntoNode<'a, Message>,
103 ) -> Self {
104 Self {
105 context: Some(context),
106 accept,
107 drop,
108 content: Some(Frame::new(content)),
109 }
110 }
111
112 pub fn context(mut self, context: &'a DragDropContext<T>) -> Self {
114 self.context = Some(context);
115 self
116 }
117
118 pub fn on_accept<N: Fn(T) -> bool>(self, on_accept: N) -> Drop<'a, T, Message, N, OnDrop> {
120 Drop {
121 context: self.context,
122 accept: on_accept,
123 drop: self.drop,
124 content: self.content,
125 }
126 }
127
128 pub fn on_drop<N: Fn(T, (f32, f32)) -> Message>(self, on_drop: N) -> Drop<'a, T, Message, OnAccept, N> {
132 Drop {
133 context: self.context,
134 accept: self.accept,
135 drop: on_drop,
136 content: self.content,
137 }
138 }
139
140 pub fn extend<I: IntoIterator<Item = N>, N: IntoNode<'a, Message>>(mut self, iter: I) -> Self {
142 if self.content.is_none() {
143 self.content = iter.into_iter().next().map(Frame::new);
144 }
145 self
146 }
147
148 fn content(&self) -> &Frame<'a, Message> {
149 self.content.as_ref().expect("content of `Drop` must be set")
150 }
151
152 fn content_mut(&mut self) -> &mut Frame<'a, Message> {
153 self.content.as_mut().expect("content of `Drop` must be set")
154 }
155}
156
157impl<'a, T: DragDropId, Message> Default for Drag<'a, T, Message> {
158 fn default() -> Self {
159 Self {
160 context: None,
161 data: None,
162 content: None,
163 }
164 }
165}
166
167impl<'a, T: DragDropId + Send + Sync, Message: 'a> Widget<'a, Message> for Drag<'a, T, Message> {
168 type State = DragState<T>;
169
170 fn mount(&self) -> Self::State {
171 DragState::<T>::default()
172 }
173
174 fn widget(&self) -> &'static str {
175 "drag"
176 }
177
178 fn state(&self, state: &DragState<T>) -> StateVec {
179 if state.dragging.is_some() {
180 smallvec![StyleState::Drag]
181 } else {
182 smallvec![]
183 }
184 }
185
186 fn len(&self) -> usize {
187 self.content().len()
188 }
189
190 fn visit_children(&mut self, visitor: &mut dyn FnMut(&mut dyn GenericNode<'a, Message>)) {
191 self.content_mut().visit_children(visitor);
192 }
193
194 fn size(&self, _: &DragState<T>, style: &Stylesheet) -> (Size, Size) {
195 self.content().size(&(), style)
196 }
197
198 fn event(
199 &mut self,
200 state: &mut DragState<T>,
201 layout: Rectangle,
202 clip: Rectangle,
203 style: &Stylesheet,
204 event: Event,
205 context: &mut Context<Message>,
206 ) {
207 match event {
208 Event::Press(Key::LeftMouseButton) => {
209 let (x, y) = context.cursor();
210 if layout.point_inside(x, y) && clip.point_inside(x, y) {
211 self.context
212 .as_ref()
213 .expect("context of `Drag` must be set")
214 .data
215 .lock()
216 .unwrap()
217 .replace((
218 self.data.expect("data of `Drag` must be set"),
219 (context.cursor.0 - layout.left, context.cursor.1 - layout.top),
220 ));
221 state.origin = context.cursor;
222 state.offset = (0.0, 0.0);
223 state.dragging = Some(self.data.expect("data of `Drag` must be set"));
224 context.redraw();
225 }
226 }
227
228 Event::Cursor(x, y) if state.dragging.is_some() => {
229 state.offset = (x - state.origin.0, y - state.origin.1);
230 context.redraw();
231 }
232
233 Event::Release(Key::LeftMouseButton) if state.dragging.is_some() => {
234 state.dragging.take();
235 self.context
236 .as_ref()
237 .expect("context of `Drag` must be set")
238 .data
239 .lock()
240 .unwrap()
241 .take();
242 context.redraw();
243 }
244
245 _ => (),
246 }
247
248 self.content_mut().event(&mut (), layout, clip, style, event, context);
249 }
250
251 fn draw(
252 &mut self,
253 state: &mut DragState<T>,
254 layout: Rectangle,
255 clip: Rectangle,
256 style: &Stylesheet,
257 ) -> Vec<Primitive<'a>> {
258 if state.dragging.is_some() {
259 let (dx, dy) = state.offset;
260 let mut result = Vec::new();
261 result.push(Primitive::LayerUp);
262 result.extend(self.content_mut().draw(&mut (), layout.translate(dx, dy), clip, style));
263 result.push(Primitive::LayerDown);
264 result
265 } else {
266 self.content_mut().draw(&mut (), layout, clip, style)
267 }
268 }
269}
270
271impl<'a, T: DragDropId, Message> Default for Drop<'a, T, Message, fn(T) -> bool, fn(T, (f32, f32)) -> Message> {
272 fn default() -> Self {
273 Self {
274 context: None,
275 accept: |_| true,
276 drop: |_, _| panic!("on_drop of `Drop` must be set"),
277 content: None,
278 }
279 }
280}
281
282impl<'a, T, Message: 'a, OnAccept, OnDrop> Widget<'a, Message> for Drop<'a, T, Message, OnAccept, OnDrop>
283where
284 T: DragDropId + Send + Sync,
285 OnAccept: 'a + Send + Fn(T) -> bool,
286 OnDrop: 'a + Send + Fn(T, (f32, f32)) -> Message,
287{
288 type State = DropState<T>;
289
290 fn mount(&self) -> DropState<T> {
291 DropState::<T>::default()
292 }
293
294 fn widget(&self) -> &'static str {
295 "drop"
296 }
297
298 fn state(&self, state: &DropState<T>) -> StateVec {
299 if state.hovering.is_some() {
300 smallvec![StyleState::Drop]
301 } else if state.mouse_over {
302 smallvec![StyleState::DropDenied]
303 } else {
304 smallvec![]
305 }
306 }
307
308 fn len(&self) -> usize {
309 self.content().len()
310 }
311
312 fn visit_children(&mut self, visitor: &mut dyn FnMut(&mut dyn GenericNode<'a, Message>)) {
313 self.content_mut().visit_children(visitor);
314 }
315
316 fn size(&self, _: &DropState<T>, style: &Stylesheet) -> (Size, Size) {
317 self.content().size(&(), style)
318 }
319
320 fn event(
321 &mut self,
322 state: &mut DropState<T>,
323 layout: Rectangle,
324 clip: Rectangle,
325 style: &Stylesheet,
326 event: Event,
327 context: &mut Context<Message>,
328 ) {
329 match event {
330 Event::Cursor(x, y) => {
331 let inside = layout.point_inside(x, y) && clip.point_inside(x, y);
332 if inside && !state.mouse_over {
333 if let Some(data) = *self
334 .context
335 .as_ref()
336 .expect("context of `Drop` must be set")
337 .data
338 .lock()
339 .unwrap()
340 {
341 if (self.accept)(data.0) {
342 state.hovering = Some(data);
343 }
344 }
345 } else if !inside && state.mouse_over {
346 state.hovering = None;
347 }
348 state.mouse_over = inside;
349 }
350
351 Event::Release(Key::LeftMouseButton) => {
352 if let Some(data) = state.hovering.take() {
353 context.push((self.drop)(
354 data.0,
355 (
356 context.cursor.0 - (data.1).0 - layout.left,
357 context.cursor.1 - (data.1).1 - layout.top,
358 ),
359 ));
360 }
361 }
362
363 _ => (),
364 }
365
366 self.content_mut().event(&mut (), layout, clip, style, event, context)
367 }
368
369 fn draw(
370 &mut self,
371 _: &mut DropState<T>,
372 layout: Rectangle,
373 clip: Rectangle,
374 style: &Stylesheet,
375 ) -> Vec<Primitive<'a>> {
376 self.content_mut().draw(&mut (), layout, clip, style)
377 }
378}
379
380impl<'a, T: DragDropId + Send + Sync, Message: 'a> IntoNode<'a, Message> for Drag<'a, T, Message> {
381 fn into_node(self) -> Node<'a, Message> {
382 Node::from_widget(self)
383 }
384}
385
386impl<'a, T: DragDropId + Send + Sync, Message: 'a, OnAccept: 'a, OnDrop: 'a> IntoNode<'a, Message>
387 for Drop<'a, T, Message, OnAccept, OnDrop>
388where
389 OnAccept: Send + Fn(T) -> bool,
390 OnDrop: Send + Fn(T, (f32, f32)) -> Message,
391{
392 fn into_node(self) -> Node<'a, Message> {
393 Node::from_widget(self)
394 }
395}
396
397impl<T: 'static + Copy + Send + Sync> DragDropId for T {}
398
399impl<T: DragDropId> Default for DragDropContext<T> {
400 fn default() -> Self {
401 Self { data: Mutex::new(None) }
402 }
403}
404
405impl<T: DragDropId> Default for DragState<T> {
406 fn default() -> Self {
407 Self {
408 dragging: None,
409 origin: (0.0, 0.0),
410 offset: (0.0, 0.0),
411 }
412 }
413}
414
415impl<T: DragDropId> Default for DropState<T> {
416 fn default() -> Self {
417 Self {
418 hovering: None,
419 mouse_over: false,
420 }
421 }
422}