use std::hash::Hash;
use std::sync::Arc;
use crate::core::element::{Element, ElementKind};
use crate::layout::drag_source_layout_hint::drag_source_snapshot_collapse_key;
use crate::layout::hash::LayoutHash;
use crate::style::{LayoutConstraints, Length, Style, StyleSlot};
use super::drag_source_layout::measure_drag_source;
use super::payload::{
DragCancelEvent, DragPayload, DragPreview, DragSlot, DragSlotAxis, DragStartEvent,
DragStartedEvent,
};
pub type DragStartHandler = Arc<dyn Fn(DragStartEvent) -> Option<Box<dyn DragPayload>>>;
#[derive(Clone)]
pub struct DragSource {
pub(crate) child: Option<Box<Element>>,
pub(crate) on_drag_start: Option<DragStartHandler>,
pub(crate) on_drag_cancel: Option<crate::callback::Callback<DragCancelEvent>>,
pub(crate) on_drag_started: Option<crate::callback::Callback<DragStartedEvent>>,
pub(crate) drag_group: Option<Arc<str>>,
pub(crate) preview: DragPreview,
pub(crate) dragging_style: StyleSlot,
pub(crate) drag_slot: DragSlot,
pub(crate) drag_slot_axis: DragSlotAxis,
pub(crate) preview_max_width: Option<u16>,
pub(crate) preview_max_height: Option<u16>,
pub(crate) threshold: u16,
pub(crate) enabled: bool,
}
impl Default for DragSource {
fn default() -> Self {
Self {
child: None,
on_drag_start: None,
on_drag_cancel: None,
on_drag_started: None,
drag_group: None,
preview: DragPreview::None,
dragging_style: StyleSlot::Inherit,
drag_slot: DragSlot::Collapse,
drag_slot_axis: DragSlotAxis::default(),
preview_max_width: None,
preview_max_height: None,
threshold: 3,
enabled: true,
}
}
}
impl DragSource {
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_start(
mut self,
cb: impl Fn(DragStartEvent) -> Option<Box<dyn DragPayload>> + 'static,
) -> Self {
self.on_drag_start = Some(Arc::new(cb));
self
}
pub fn on_drag_cancel(mut self, cb: crate::callback::Callback<DragCancelEvent>) -> Self {
self.on_drag_cancel = Some(cb);
self
}
pub fn on_drag_started(mut self, cb: crate::callback::Callback<DragStartedEvent>) -> Self {
self.on_drag_started = Some(cb);
self
}
pub fn drag_group(mut self, group: impl Into<Arc<str>>) -> Self {
self.drag_group = Some(group.into());
self
}
pub fn clear_drag_group(mut self) -> Self {
self.drag_group = None;
self
}
pub fn preview(mut self, preview: DragPreview) -> Self {
self.preview = preview;
self
}
pub fn preview_label(mut self, label: impl Into<Arc<str>>) -> Self {
self.preview = DragPreview::Label(label.into());
self
}
pub fn preview_snapshot(mut self) -> Self {
self.preview = DragPreview::SourceSnapshot;
self
}
pub fn no_preview(mut self) -> Self {
self.preview = DragPreview::None;
self
}
pub fn dragging_style(mut self, style: Style) -> Self {
self.dragging_style = StyleSlot::Replace(style);
self
}
pub fn extend_dragging_style(mut self, style: Style) -> Self {
self.dragging_style = StyleSlot::Extend(style);
self
}
pub fn inherit_dragging_style(mut self) -> Self {
self.dragging_style = StyleSlot::Inherit;
self
}
pub fn dragging_style_slot(mut self, slot: StyleSlot) -> Self {
self.dragging_style = slot;
self
}
pub fn drag_slot(mut self, slot: DragSlot) -> Self {
self.drag_slot = slot;
self
}
pub fn drag_slot_collapse(mut self) -> Self {
self.drag_slot = DragSlot::Collapse;
self
}
pub fn drag_slot_length(mut self, len: Length) -> Self {
self.drag_slot = DragSlot::Specified(len);
self
}
pub fn drag_slot_axis(mut self, axis: DragSlotAxis) -> Self {
self.drag_slot_axis = axis;
self
}
pub fn preview_max_width(mut self, max_width: Option<u16>) -> Self {
self.preview_max_width = max_width;
self
}
pub fn preview_max_height(mut self, max_height: Option<u16>) -> Self {
self.preview_max_height = max_height;
self
}
pub fn preview_max_size(mut self, max_width: Option<u16>, max_height: Option<u16>) -> Self {
self.preview_max_width = max_width;
self.preview_max_height = max_height;
self
}
pub fn threshold(mut self, threshold: u16) -> Self {
self.threshold = threshold;
self
}
pub fn enabled(mut self, enabled: bool) -> Self {
self.enabled = enabled;
self
}
}
impl From<DragSource> for Element {
fn from(value: DragSource) -> Self {
let (min_w, min_h) = measure_drag_source(&value, None, None, None);
let min_h = if matches!(value.preview, DragPreview::SourceSnapshot) {
0
} else {
min_h
};
Element::new(ElementKind::DragSource(value)).with_layout(
LayoutConstraints::default()
.min_width(Length::Px(min_w))
.min_height(Length::Px(min_h)),
)
}
}
impl LayoutHash for DragSource {
fn layout_hash(
&self,
hasher: &mut impl std::hash::Hasher,
recurse: &dyn Fn(&Element) -> Option<u64>,
) -> Option<()> {
self.enabled.hash(hasher);
self.on_drag_start.is_some().hash(hasher);
self.on_drag_cancel.is_some().hash(hasher);
self.on_drag_started.is_some().hash(hasher);
self.drag_group.hash(hasher);
self.preview.hash(hasher);
self.dragging_style.hash(hasher);
self.drag_slot.hash(hasher);
self.drag_slot_axis.hash(hasher);
self.preview_max_width.hash(hasher);
self.preview_max_height.hash(hasher);
self.threshold.hash(hasher);
if matches!(self.preview, DragPreview::SourceSnapshot) {
drag_source_snapshot_collapse_key().hash(hasher);
}
if let Some(child) = self.child.as_ref() {
recurse(child.as_ref())?.hash(hasher);
}
Some(())
}
}