use crate::core::hooks::SettleFlag;
use crate::core::registry::ZoneRegistry;
use crate::core::state::DndContext;
use crate::core::types::{DragMode, DragSessionId, DropEffect, DropOutcome, Point, ZoneId};
use crate::core::world::{DndWorld, WindowKey};
pub(crate) const RELEASE_RECOVERY_MOVES: u8 = 3;
pub(crate) enum DropCompletion<'a, T: Clone + 'static> {
None,
Local(DragSessionId),
World {
world: &'a DndWorld<T>,
session: Option<DragSessionId>,
},
}
impl<T: Clone + 'static> Copy for DropCompletion<'_, T> {}
impl<T: Clone + 'static> Clone for DropCompletion<'_, T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: Clone + 'static> DropCompletion<'_, T> {
fn commit(self, dnd: &mut DndContext<T>) {
match self {
Self::None => {}
Self::Local(session) => {
dnd.commit_source(session, true);
}
Self::World {
world,
session: Some(session),
} => {
world.commit_session(session, true);
}
Self::World {
world: _,
session: None,
} => {}
}
}
fn finalize(self, dnd: &mut DndContext<T>) {
match self {
Self::None => {}
Self::Local(session) => {
dnd.finalize_source(session);
}
Self::World {
world,
session: Some(session),
} => {
world.finalize_session(session);
}
Self::World {
world,
session: None,
} => world.finish_untracked(true),
}
}
}
pub(crate) struct SettleRoute<'a, T: Clone + 'static> {
pub(crate) flag: Option<SettleFlag<T>>,
pub(crate) owner: Option<(&'a DndWorld<T>, WindowKey)>,
}
pub(crate) fn deliver_drop<T: Clone + PartialEq + 'static>(
registry: ZoneRegistry<T>,
dnd: &mut DndContext<T>,
settle: SettleRoute<'_, T>,
completion: DropCompletion<'_, T>,
target: ZoneId,
point: Point,
effect: DropEffect,
) -> bool {
let Some(record) = registry.get(target) else {
return false;
};
let Some(p) = dnd.payload() else {
return false;
};
if !record.accepts_payload(&p) {
return false;
}
let target_rect = registry.cached_rect(target);
let origin = target_rect.map(|r| r.origin()).unwrap_or_default();
let mode = dnd.mode();
let grab = dnd.grab();
let settle_to = match settle.flag {
Some(f) if mode == DragMode::Pointer && f.is_armed() => target_rect,
_ => None,
};
let taken = match settle_to {
Some(to) => {
if let Some((world, key)) = settle.owner {
world.claim_settle(key);
}
dnd.take_settling(to)
}
None => dnd.take(),
};
if let Some((p, from)) = taken {
completion.commit(dnd);
record.on_drop.call(DropOutcome {
payload: p,
from,
to: target,
effect,
mode,
client: point,
element: point - origin,
grab,
edge: None,
});
completion.finalize(dnd);
return true;
}
false
}