use crate::ecs::pointer::PhysicalPoint;
use bevy_ecs::prelude::*;
use std::sync::{Arc, Mutex};
use std::time::Instant;
#[derive(Debug, Clone)]
pub enum DragTransition {
Started {
entity: Entity,
start_pos: PhysicalPoint,
timestamp: Instant,
},
Ended {
entity: Entity,
end_pos: PhysicalPoint,
cancelled: bool,
},
}
#[derive(Debug)]
pub struct DragAccumulator {
accumulated_delta: PhysicalPoint,
current_dragging_entity: Option<Entity>,
current_pos: PhysicalPoint,
pending_transition: Option<DragTransition>,
}
impl DragAccumulator {
pub fn new() -> Self {
Self {
accumulated_delta: PhysicalPoint::new(0, 0),
current_dragging_entity: None,
current_pos: PhysicalPoint::new(0, 0),
pending_transition: None,
}
}
pub fn accumulate_delta(&mut self, delta: PhysicalPoint) {
self.accumulated_delta.x += delta.x;
self.accumulated_delta.y += delta.y;
}
pub fn update_position(&mut self, pos: PhysicalPoint) {
self.current_pos = pos;
}
pub fn set_transition(&mut self, transition: DragTransition) {
match &transition {
DragTransition::Started { entity, .. } => {
self.current_dragging_entity = Some(*entity);
}
DragTransition::Ended { .. } => {
self.current_dragging_entity = None;
}
}
self.pending_transition = Some(transition);
}
pub fn flush(&mut self) -> FlushResult {
let delta = self.accumulated_delta;
let transition = self.pending_transition.take();
let entity = self.current_dragging_entity;
let position = self.current_pos;
self.accumulated_delta = PhysicalPoint::new(0, 0);
FlushResult {
delta,
transition,
current_dragging_entity: entity,
current_position: position,
}
}
}
impl Default for DragAccumulator {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug)]
pub struct FlushResult {
pub delta: PhysicalPoint,
pub transition: Option<DragTransition>,
pub current_dragging_entity: Option<Entity>,
pub current_position: PhysicalPoint,
}
#[derive(Resource, Clone)]
pub struct DragAccumulatorResource {
inner: Arc<Mutex<DragAccumulator>>,
}
impl DragAccumulatorResource {
pub fn new() -> Self {
Self {
inner: Arc::new(Mutex::new(DragAccumulator::new())),
}
}
pub fn accumulate_delta(&self, delta: PhysicalPoint) {
if let Ok(mut acc) = self.inner.lock() {
acc.accumulate_delta(delta);
}
}
pub fn update_position(&self, pos: PhysicalPoint) {
if let Ok(mut acc) = self.inner.lock() {
acc.update_position(pos);
}
}
pub fn set_transition(&self, transition: DragTransition) {
if let Ok(mut acc) = self.inner.lock() {
acc.set_transition(transition);
}
}
pub fn flush(&self) -> Option<FlushResult> {
self.inner.lock().ok().map(|mut acc| acc.flush())
}
}
impl Default for DragAccumulatorResource {
fn default() -> Self {
Self::new()
}
}