use std::any::Any;
use dnd::{DndAction, DndDestinationRectangle, DndSurface};
use mime::{self, AllowedMimeTypes, AsMimeTypes, ClipboardStoreData};
use crate::{widget::tree::State, window, Element, Vector};
#[derive(Debug)]
pub struct IconSurface<E> {
pub element: E,
pub state: State,
pub offset: Vector,
}
pub type DynIconSurface = IconSurface<Box<dyn Any>>;
impl<T: 'static, R: 'static> IconSurface<Element<'static, (), T, R>> {
pub fn new(
element: Element<'static, (), T, R>,
state: State,
offset: Vector,
) -> Self {
Self {
element,
state,
offset,
}
}
fn upcast(self) -> DynIconSurface {
IconSurface {
element: Box::new(self.element),
state: self.state,
offset: self.offset,
}
}
}
impl DynIconSurface {
pub fn downcast<T: 'static, R: 'static>(
self,
) -> IconSurface<Element<'static, (), T, R>> {
IconSurface {
element: *self
.element
.downcast()
.expect("drag-and-drop icon surface has invalid element type"),
state: self.state,
offset: self.offset,
}
}
}
pub trait Clipboard {
fn read(&self, kind: Kind) -> Option<String>;
fn write(&mut self, kind: Kind, contents: String);
fn read_data(
&self,
_kind: Kind,
_mimes: Vec<String>,
) -> Option<(Vec<u8>, String)> {
None
}
fn write_data(
&mut self,
_kind: Kind,
_contents: ClipboardStoreData<
Box<dyn Send + Sync + 'static + mime::AsMimeTypes>,
>,
) {
}
fn register_dnd_destination(
&self,
_surface: DndSurface,
_rectangles: Vec<DndDestinationRectangle>,
) {
}
fn set_action(&self, _action: DndAction) {}
fn start_dnd(
&mut self,
_internal: bool,
_source_surface: Option<DndSource>,
_icon_surface: Option<DynIconSurface>,
_content: Box<dyn AsMimeTypes + Send + 'static>,
_actions: DndAction,
) {
}
fn end_dnd(&self) {}
fn peek_dnd(&self, _mime: String) -> Option<(Vec<u8>, String)> {
None
}
fn request_logical_window_size(&self, _width: f32, _height: f32) {}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Kind {
Standard,
Primary,
}
pub fn start_dnd<T: 'static, R: 'static>(
clipboard: &mut dyn Clipboard,
internal: bool,
source_surface: Option<DndSource>,
icon_surface: Option<IconSurface<Element<'static, (), T, R>>>,
content: Box<dyn AsMimeTypes + Send + 'static>,
actions: DndAction,
) {
clipboard.start_dnd(
internal,
source_surface,
icon_surface.map(IconSurface::upcast),
content,
actions,
);
}
#[derive(Debug, Clone, Copy)]
pub struct Null;
impl Clipboard for Null {
fn read(&self, _kind: Kind) -> Option<String> {
None
}
fn write(&mut self, _kind: Kind, _contents: String) {}
}
pub fn read_data<T: AllowedMimeTypes>(
clipboard: &mut dyn Clipboard,
) -> Option<T> {
clipboard
.read_data(Kind::Standard, T::allowed().into())
.and_then(|data| T::try_from(data).ok())
}
pub fn read_primary_data<T: AllowedMimeTypes>(
clipboard: &mut dyn Clipboard,
) -> Option<T> {
clipboard
.read_data(Kind::Primary, T::allowed().into())
.and_then(|data| T::try_from(data).ok())
}
pub fn peek_dnd<T: AllowedMimeTypes>(
clipboard: &mut dyn Clipboard,
mime: Option<String>,
) -> Option<T> {
let mime = mime.or_else(|| T::allowed().first().cloned())?;
clipboard
.peek_dnd(mime)
.and_then(|data| T::try_from(data).ok())
}
#[derive(Debug, Clone)]
pub enum DndSource {
Widget(crate::id::Id),
Surface(window::Id),
}
#[derive(Debug, Clone, Default)]
pub struct DndDestinationRectangles {
rectangles: Vec<DndDestinationRectangle>,
}
impl DndDestinationRectangles {
pub fn new() -> Self {
Self::default()
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
rectangles: Vec::with_capacity(capacity),
}
}
pub fn push(&mut self, rectangle: DndDestinationRectangle) {
self.rectangles.push(rectangle);
}
pub fn append(&mut self, other: &mut Vec<DndDestinationRectangle>) {
self.rectangles.append(other);
}
pub fn into_rectangles(mut self) -> Vec<DndDestinationRectangle> {
self.rectangles.reverse();
self.rectangles
}
}
impl AsRef<[DndDestinationRectangle]> for DndDestinationRectangles {
fn as_ref(&self) -> &[DndDestinationRectangle] {
&self.rectangles
}
}