use std::hash::Hash;
use std::rc::Rc;
use std::sync::Arc;
use crate::callback::Callback;
use crate::core::element::{Element, ElementKind};
use crate::layout::hash::LayoutHash;
use crate::style::{LayoutConstraints, Length, Style, StyleSlot};
use super::drop_target_layout::measure_drop_target;
use super::payload::{DragLeaveEvent, DragOverEvent, DragPayload, DropEvent, DropSlot};
pub type PayloadAcceptFn = Rc<dyn Fn(&dyn DragPayload) -> bool>;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum DropHighlight {
#[default]
None,
Fill,
Placeholder,
Overlay,
}
#[derive(Clone)]
pub struct DropTarget {
pub(crate) child: Option<Box<Element>>,
pub(crate) on_drag_over: Option<Callback<DragOverEvent>>,
pub(crate) on_drag_leave: Option<Callback<DragLeaveEvent>>,
pub(crate) on_drop: Option<Callback<DropEvent>>,
pub(crate) accept_group: Option<Arc<str>>,
pub(crate) can_accept: Option<PayloadAcceptFn>,
pub(crate) highlight: DropHighlight,
pub(crate) highlight_style: StyleSlot,
pub(crate) drop_slot: DropSlot,
pub(crate) enabled: bool,
}
impl Default for DropTarget {
fn default() -> Self {
Self {
child: None,
on_drag_over: None,
on_drag_leave: None,
on_drop: None,
accept_group: None,
can_accept: None,
highlight: DropHighlight::None,
highlight_style: StyleSlot::Inherit,
drop_slot: DropSlot::Child,
enabled: true,
}
}
}
impl DropTarget {
pub fn new() -> Self {
Self::default()
}
pub fn child(mut self, child: impl Into<Element>) -> Self {
self.child = Some(Box::new(child.into()));
self
}
pub fn on_drag_over(mut self, cb: Callback<DragOverEvent>) -> Self {
self.on_drag_over = Some(cb);
self
}
pub fn on_drag_leave(mut self, cb: Callback<DragLeaveEvent>) -> Self {
self.on_drag_leave = Some(cb);
self
}
pub fn on_drop(mut self, cb: Callback<DropEvent>) -> Self {
self.on_drop = Some(cb);
self
}
pub fn accept_group(mut self, group: impl Into<Arc<str>>) -> Self {
self.accept_group = Some(group.into());
self
}
pub fn clear_accept_group(mut self) -> Self {
self.accept_group = None;
self
}
pub fn can_accept(mut self, accept: PayloadAcceptFn) -> Self {
self.can_accept = Some(accept);
self
}
pub fn can_accept_with(mut self, accept: impl Fn(&dyn DragPayload) -> bool + 'static) -> Self {
self.can_accept = Some(Rc::new(accept));
self
}
pub fn clear_can_accept(mut self) -> Self {
self.can_accept = None;
self
}
pub fn highlight(mut self, highlight: DropHighlight) -> Self {
self.highlight = highlight;
self
}
pub fn highlight_style(mut self, style: Style) -> Self {
self.highlight_style = StyleSlot::Replace(style);
self
}
pub fn extend_highlight_style(mut self, style: Style) -> Self {
self.highlight_style = StyleSlot::Extend(style);
self
}
pub fn inherit_highlight_style(mut self) -> Self {
self.highlight_style = StyleSlot::Inherit;
self
}
pub fn highlight_style_slot(mut self, slot: StyleSlot) -> Self {
self.highlight_style = slot;
self
}
pub fn highlight_fill(mut self, style: Style) -> Self {
self.highlight = DropHighlight::Fill;
self.highlight_style = StyleSlot::Replace(style);
self
}
pub fn highlight_placeholder(mut self, style: Style) -> Self {
self.highlight = DropHighlight::Placeholder;
self.highlight_style = StyleSlot::Replace(style);
self
}
pub fn highlight_overlay(mut self, style: Style) -> Self {
self.highlight = DropHighlight::Overlay;
self.highlight_style = StyleSlot::Replace(style);
self
}
pub fn drop_slot(mut self, slot: DropSlot) -> Self {
self.drop_slot = slot;
self
}
pub fn drop_slot_source_preview(mut self) -> Self {
self.drop_slot = DropSlot::SourcePreview;
self
}
pub fn enabled(mut self, enabled: bool) -> Self {
self.enabled = enabled;
self
}
}
impl From<DropTarget> for Element {
fn from(value: DropTarget) -> Self {
let (min_w, min_h) = measure_drop_target(&value, None, None);
Element::new(ElementKind::DropTarget(value)).with_layout(
LayoutConstraints::default()
.min_width(Length::Px(min_w))
.min_height(Length::Px(min_h)),
)
}
}
impl LayoutHash for DropTarget {
fn layout_hash(
&self,
hasher: &mut impl std::hash::Hasher,
recurse: &dyn Fn(&Element) -> Option<u64>,
) -> Option<()> {
self.enabled.hash(hasher);
self.on_drag_over.is_some().hash(hasher);
self.on_drag_leave.is_some().hash(hasher);
self.on_drop.is_some().hash(hasher);
self.accept_group.hash(hasher);
self.can_accept.is_some().hash(hasher);
self.highlight.hash(hasher);
self.highlight_style.hash(hasher);
self.drop_slot.hash(hasher);
if let Some(child) = self.child.as_ref() {
recurse(child.as_ref())?.hash(hasher);
}
Some(())
}
}