use dioxus::prelude::*;
use crate::core::components::{DropCompletion, SettleRoute};
use crate::core::types::{effective_effect, DragMode, Point, ZoneId};
use super::geometry::WindowKey;
use super::state::{DndWorld, ZoneLocation};
impl<T: Clone + 'static> DndWorld<T> {
pub fn modifiers(&self) -> Modifiers {
self.active
.read()
.as_ref()
.map_or_else(Modifiers::empty, |active| active.modifiers)
}
pub fn update_modifiers(&self, modifiers: Modifiers) {
if !self.ctx.dragging() {
return;
}
let mut active = self.active;
let Some(mut current) = *active.peek() else {
return;
};
if current.modifiers != modifiers {
current.modifiers = modifiers;
active.set(Some(current));
}
}
pub fn track_global(&self, global: Point) {
if !self.bridging_enabled() {
return;
}
let mut ctx = self.ctx;
if !ctx.dragging() || ctx.mode() != DragMode::Pointer {
return;
}
let Some(origin) = self.active_record() else {
return;
};
let mut global_pointer = self.global_pointer;
if *global_pointer.peek() != Some(global) {
global_pointer.set(Some(global));
}
if let Some(local) = origin.geometry.to_client(global) {
ctx.update_pointer(local);
}
let location = self.resolve_global(global).and_then(|(rec, local)| {
rec.registry.hit_test(local).map(|zone| ZoneLocation {
window: rec.key,
zone,
})
});
match location {
Some(location) => self.enter_location(location),
None => self.clear_hover(),
}
}
pub fn drop_at_global(&self, global: Point) -> Option<ZoneId>
where
T: PartialEq,
{
if !self.bridging_enabled() {
return None;
}
let mut ctx = self.ctx;
if !ctx.dragging() || ctx.mode() != DragMode::Pointer {
return None;
}
self.track_global(global);
let session = self.drag_session();
let Some((rec, local)) = self.resolve_global(global) else {
match session {
Some(session) => {
self.finish_session(session, false);
}
None => self.finish_untracked(false),
}
return None;
};
let target = rec.registry.hit_test(local).or_else(|| {
ctx.payload()
.and_then(|p| rec.registry.hit_test_closest(local, &p, 48.0))
});
let modifiers = self
.active
.peek()
.as_ref()
.map_or_else(Modifiers::empty, |active| active.modifiers);
let effect = effective_effect(ctx.effect(), modifiers);
let delivered = target.filter(|t| {
crate::core::components::deliver_drop(
rec.registry,
&mut ctx,
SettleRoute {
flag: Some(rec.settle),
owner: Some((self, rec.key)),
},
DropCompletion::World {
world: self,
session,
},
*t,
local,
effect,
)
});
match delivered {
Some(zone) => Some(zone),
None => {
match session {
Some(session) => {
self.finish_session(session, false);
}
None => self.finish_untracked(false),
}
None
}
}
}
pub fn cancel_drag(&self) {
if let Some(session) = self.drag_session() {
self.finish_session(session, false);
} else if self.ctx.dragging() {
self.finish_untracked(false);
}
}
pub fn origin_window(&self) -> Option<WindowKey> {
(self.ctx.dragging() || self.ctx.settling().is_some())
.then(|| self.active.peek().as_ref().map(|active| active.origin))
.flatten()
}
}