1use std::any::Any;
4
5use dnd::{DndAction, DndDestinationRectangle, DndSurface};
6use mime::{self, AllowedMimeTypes, AsMimeTypes, ClipboardStoreData};
7
8use crate::{widget::tree::State, window, Element, Vector};
9
10#[derive(Debug)]
11pub struct IconSurface<E> {
12 pub element: E,
13 pub state: State,
14 pub offset: Vector,
15}
16
17pub type DynIconSurface = IconSurface<Box<dyn Any>>;
18
19impl<T: 'static, R: 'static> IconSurface<Element<'static, (), T, R>> {
20 pub fn new(
21 element: Element<'static, (), T, R>,
22 state: State,
23 offset: Vector,
24 ) -> Self {
25 Self {
26 element,
27 state,
28 offset,
29 }
30 }
31
32 fn upcast(self) -> DynIconSurface {
33 IconSurface {
34 element: Box::new(self.element),
35 state: self.state,
36 offset: self.offset,
37 }
38 }
39}
40
41impl DynIconSurface {
42 pub fn downcast<T: 'static, R: 'static>(
46 self,
47 ) -> IconSurface<Element<'static, (), T, R>> {
48 IconSurface {
49 element: *self
50 .element
51 .downcast()
52 .expect("drag-and-drop icon surface has invalid element type"),
53 state: self.state,
54 offset: self.offset,
55 }
56 }
57}
58
59pub trait Clipboard {
62 fn read(&self, kind: Kind) -> Option<String>;
64
65 fn write(&mut self, kind: Kind, contents: String);
67
68 fn read_data(
71 &self,
72 _kind: Kind,
73 _mimes: Vec<String>,
74 ) -> Option<(Vec<u8>, String)> {
75 None
76 }
77
78 fn write_data(
80 &mut self,
81 _kind: Kind,
82 _contents: ClipboardStoreData<
83 Box<dyn Send + Sync + 'static + mime::AsMimeTypes>,
84 >,
85 ) {
86 }
87
88 fn register_dnd_destination(
90 &self,
91 _surface: DndSurface,
92 _rectangles: Vec<DndDestinationRectangle>,
93 ) {
94 }
95
96 fn set_action(&self, _action: DndAction) {}
99
100 fn start_dnd(
102 &mut self,
103 _internal: bool,
104 _source_surface: Option<DndSource>,
105 _icon_surface: Option<DynIconSurface>,
106 _content: Box<dyn AsMimeTypes + Send + 'static>,
107 _actions: DndAction,
108 ) {
109 }
110
111 fn end_dnd(&self) {}
113
114 fn peek_dnd(&self, _mime: String) -> Option<(Vec<u8>, String)> {
118 None
119 }
120
121 fn request_logical_window_size(&self, _width: f32, _height: f32) {}
123}
124
125#[derive(Debug, Clone, Copy, PartialEq, Eq)]
127pub enum Kind {
128 Standard,
130 Primary,
134}
135
136pub fn start_dnd<T: 'static, R: 'static>(
139 clipboard: &mut dyn Clipboard,
140 internal: bool,
141 source_surface: Option<DndSource>,
142 icon_surface: Option<IconSurface<Element<'static, (), T, R>>>,
143 content: Box<dyn AsMimeTypes + Send + 'static>,
144 actions: DndAction,
145) {
146 clipboard.start_dnd(
147 internal,
148 source_surface,
149 icon_surface.map(IconSurface::upcast),
150 content,
151 actions,
152 );
153}
154
155#[derive(Debug, Clone, Copy)]
157pub struct Null;
158
159impl Clipboard for Null {
160 fn read(&self, _kind: Kind) -> Option<String> {
161 None
162 }
163
164 fn write(&mut self, _kind: Kind, _contents: String) {}
165}
166
167pub fn read_data<T: AllowedMimeTypes>(
169 clipboard: &mut dyn Clipboard,
170) -> Option<T> {
171 clipboard
172 .read_data(Kind::Standard, T::allowed().into())
173 .and_then(|data| T::try_from(data).ok())
174}
175
176pub fn read_primary_data<T: AllowedMimeTypes>(
178 clipboard: &mut dyn Clipboard,
179) -> Option<T> {
180 clipboard
181 .read_data(Kind::Primary, T::allowed().into())
182 .and_then(|data| T::try_from(data).ok())
183}
184
185pub fn peek_dnd<T: AllowedMimeTypes>(
187 clipboard: &mut dyn Clipboard,
188 mime: Option<String>,
189) -> Option<T> {
190 let mime = mime.or_else(|| T::allowed().first().cloned())?;
191 clipboard
192 .peek_dnd(mime)
193 .and_then(|data| T::try_from(data).ok())
194}
195
196#[derive(Debug, Clone)]
198pub enum DndSource {
199 Widget(crate::id::Id),
201 Surface(window::Id),
203}
204
205#[derive(Debug, Clone, Default)]
207pub struct DndDestinationRectangles {
208 rectangles: Vec<DndDestinationRectangle>,
210}
211
212impl DndDestinationRectangles {
213 pub fn new() -> Self {
215 Self::default()
216 }
217
218 pub fn with_capacity(capacity: usize) -> Self {
220 Self {
221 rectangles: Vec::with_capacity(capacity),
222 }
223 }
224
225 pub fn push(&mut self, rectangle: DndDestinationRectangle) {
227 self.rectangles.push(rectangle);
228 }
229
230 pub fn append(&mut self, other: &mut Vec<DndDestinationRectangle>) {
232 self.rectangles.append(other);
233 }
234
235 pub fn into_rectangles(mut self) -> Vec<DndDestinationRectangle> {
238 self.rectangles.reverse();
239 self.rectangles
240 }
241}
242
243impl AsRef<[DndDestinationRectangle]> for DndDestinationRectangles {
244 fn as_ref(&self) -> &[DndDestinationRectangle] {
245 &self.rectangles
246 }
247}