1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
//! Access the clipboard.

use std::any::Any;

use dnd::{DndDestinationRectangle, DndSurface};
use iced_core::clipboard::DndSource;
use window_clipboard::mime::{AllowedMimeTypes, AsMimeTypes};

use crate::{oneshot, task, Action, Task};

/// An action to be performed on the system.
pub enum DndAction {
    /// Register a Dnd destination.
    RegisterDndDestination {
        /// The surface to register.
        surface: DndSurface,
        /// The rectangles to register.
        rectangles: Vec<DndDestinationRectangle>,
    },
    /// Start a Dnd operation.
    StartDnd {
        /// Whether the Dnd operation is internal.
        internal: bool,
        /// The source surface of the Dnd operation.
        source_surface: Option<DndSource>,
        /// The icon surface of the Dnd operation.
        icon_surface: Option<Box<dyn Any + Send>>,
        /// The content of the Dnd operation.
        content: Box<dyn AsMimeTypes + Send + 'static>,
        /// The actions of the Dnd operation.
        actions: dnd::DndAction,
    },
    /// End a Dnd operation.
    EndDnd,
    /// Peek the current Dnd operation.
    PeekDnd(
        String,
        oneshot::Sender<Option<(Vec<u8>, String)>>,
        // Box<dyn Fn(Option<(Vec<u8>, String)>) -> T + Send + 'static>,
    ),
    /// Set the action of the Dnd operation.
    SetAction(dnd::DndAction),
}

impl std::fmt::Debug for DndAction {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::RegisterDndDestination {
                surface,
                rectangles,
            } => f
                .debug_struct("RegisterDndDestination")
                .field("surface", surface)
                .field("rectangles", rectangles)
                .finish(),
            Self::StartDnd {
                internal,
                source_surface,
                icon_surface,
                content: _,
                actions,
            } => f
                .debug_struct("StartDnd")
                .field("internal", internal)
                .field("source_surface", source_surface)
                .field("icon_surface", icon_surface)
                .field("actions", actions)
                .finish(),
            Self::EndDnd => f.write_str("EndDnd"),
            Self::PeekDnd(mime, _) => {
                f.debug_struct("PeekDnd").field("mime", mime).finish()
            }
            Self::SetAction(a) => f.debug_tuple("SetAction").field(a).finish(),
        }
    }
}

/// Read the current contents of the Dnd operation.
pub fn peek_dnd<T: AllowedMimeTypes>() -> Task<Option<T>> {
    task::oneshot(|tx| {
        Action::Dnd(DndAction::PeekDnd(
            T::allowed()
                .first()
                .map_or_else(String::new, std::string::ToString::to_string),
            tx,
        ))
    })
    .map(|data| data.and_then(|data| T::try_from(data).ok()))
}

/// Register a Dnd destination.
pub fn register_dnd_destination<Message>(
    surface: DndSurface,
    rectangles: Vec<DndDestinationRectangle>,
) -> Task<Message> {
    task::effect(Action::Dnd(DndAction::RegisterDndDestination {
        surface,
        rectangles,
    }))
}

/// Start a Dnd operation.
pub fn start_dnd<Message>(
    internal: bool,
    source_surface: Option<DndSource>,
    icon_surface: Option<Box<dyn Any + Send>>,
    content: Box<dyn AsMimeTypes + Send + 'static>,
    actions: dnd::DndAction,
) -> Task<Message> {
    task::effect(Action::Dnd(DndAction::StartDnd {
        internal,
        source_surface,
        icon_surface,
        content,
        actions,
    }))
}

/// End a Dnd operation.
pub fn end_dnd<Message>() -> Task<Message> {
    task::effect(Action::Dnd(DndAction::EndDnd))
}

/// Set the action of the Dnd operation.
pub fn set_action<Message>(a: dnd::DndAction) -> Task<Message> {
    task::effect(Action::Dnd(DndAction::SetAction(a)))
}