use dioxus::prelude::*;
use super::session::SourceCompletion;
use super::types::{DragMode, DropEffect, Point, PointerKind, Rect, ZoneId};
#[derive(Store, Debug, Clone, PartialEq)]
pub struct DragState<T: 'static> {
pub payload: Option<T>,
pub source: Option<ZoneId>,
pub over: Option<ZoneId>,
pub pointer: Point,
pub grab: Point,
pub effect: DropEffect,
pub mode: DragMode,
pub pointer_kind: PointerKind,
pub source_rect: Option<Rect>,
pub refocus: Option<T>,
pub settle: Option<Rect>,
}
impl<T> Default for DragState<T> {
fn default() -> Self {
Self {
payload: None,
source: None,
over: None,
pointer: Point::default(),
grab: Point::default(),
effect: DropEffect::default(),
mode: DragMode::default(),
pointer_kind: PointerKind::default(),
source_rect: None,
refocus: None,
settle: None,
}
}
}
pub struct DndContext<T: Clone + 'static> {
state: Store<DragState<T>>,
announcement: Signal<String>,
pub(super) completion: Signal<Option<SourceCompletion>>,
}
impl<T: Clone + 'static> Copy for DndContext<T> {}
impl<T: Clone + 'static> Clone for DndContext<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: Clone + 'static> PartialEq for DndContext<T> {
fn eq(&self, other: &Self) -> bool {
self.announcement == other.announcement
}
}
impl<T: Clone + 'static> DndContext<T> {
pub fn from_parts(state: Store<DragState<T>>, announcement: Signal<String>) -> Self {
Self {
state,
announcement,
completion: Signal::new(None),
}
}
pub fn start(
&mut self,
payload: T,
source: Option<ZoneId>,
pointer: Point,
grab: Point,
effect: DropEffect,
mode: DragMode,
) {
self.state.set(DragState {
payload: Some(payload),
source,
over: None,
pointer,
grab,
effect,
mode,
pointer_kind: PointerKind::default(),
source_rect: None,
refocus: None,
settle: None,
});
}
pub fn set_pointer_kind(&mut self, kind: PointerKind) {
self.state.pointer_kind().set(kind);
}
pub fn request_refocus(&mut self, payload: T) {
self.state.refocus().set(Some(payload));
}
pub fn claim_refocus(&mut self, payload: &T) -> bool
where
T: PartialEq,
{
let mut refocus = self.state.refocus();
let hit = refocus.peek().as_ref() == Some(payload);
if hit {
refocus.set(None);
}
hit
}
pub fn set_source_rect(&mut self, rect: Option<Rect>) {
self.state.source_rect().set(rect);
}
pub fn update_pointer(&mut self, pointer: Point) {
if pointer.x == 0.0 && pointer.y == 0.0 {
return;
}
self.state.pointer().set(pointer);
}
pub fn enter(&mut self, zone: ZoneId) {
self.state.over().set(Some(zone));
}
pub fn leave(&mut self, zone: ZoneId) {
let mut over = self.state.over();
if *over.peek() == Some(zone) {
over.set(None);
}
}
pub fn take(&mut self) -> Option<(T, Option<ZoneId>)> {
let (payload, source) = {
let mut s = self.state.write();
(s.payload.take(), s.source)
};
let payload = payload?;
self.state.set(DragState::default());
Some((payload, source))
}
pub fn take_settling(&mut self, to: Rect) -> Option<(T, Option<ZoneId>)> {
let mut s = self.state.write();
let payload = s.payload.clone()?;
let source = s.source;
s.over = None;
s.settle = Some(to);
Some((payload, source))
}
pub fn retarget_settle(&mut self, to: Rect) {
let mut settle = self.state.settle();
if settle.peek().is_some() && *settle.peek() != Some(to) {
settle.set(Some(to));
}
}
pub fn finish_settle(&mut self) {
if self.state.settle().peek().is_some() {
self.state.set(DragState::default());
}
}
pub(crate) fn alive(&self) -> bool {
self.announcement.try_peek().is_ok()
}
pub fn cancel(&mut self) {
self.state.set(DragState::default());
}
pub fn dragging(&self) -> bool {
self.state.payload().is_some() && self.state.settle().is_none()
}
pub fn settling(&self) -> Option<Rect> {
self.state.settle().cloned()
}
pub(crate) fn settling_peek(&self) -> bool {
self.state.settle().peek().is_some()
}
pub fn payload(&self) -> Option<T> {
self.state.payload().cloned()
}
pub fn over(&self) -> Option<ZoneId> {
self.state.over().cloned()
}
pub fn source(&self) -> Option<ZoneId> {
self.state.source().cloned()
}
pub fn pointer(&self) -> Point {
self.state.pointer().cloned()
}
pub fn grab(&self) -> Point {
self.state.grab().cloned()
}
pub fn source_rect(&self) -> Option<Rect> {
self.state.source_rect().cloned()
}
pub fn effect(&self) -> DropEffect {
self.state.effect().cloned()
}
pub fn mode(&self) -> DragMode {
self.state.mode().cloned()
}
pub fn pointer_kind(&self) -> PointerKind {
self.state.pointer_kind().cloned()
}
pub fn announce(&mut self, msg: impl Into<String>) {
self.announcement.set(msg.into());
}
pub fn announcement(&self) -> String {
self.announcement.read().clone()
}
}