use crate::platform;
pub struct DragController {
initial_margin: (i32, i32),
current_margin: (i32, i32),
click_pos: (i32, i32),
is_dragging: bool,
use_absolute: bool,
}
impl DragController {
pub fn new(initial_margin: (i32, i32), use_absolute: bool) -> Self {
Self {
initial_margin,
current_margin: initial_margin,
click_pos: (0, 0),
is_dragging: false,
use_absolute,
}
}
pub fn press(&mut self, event_root_pos: (i32, i32)) {
self.is_dragging = true;
self.initial_margin = self.current_margin;
if self.use_absolute
&& let Some(abs_pos) = platform::get_absolute_cursor_pos() {
self.click_pos = abs_pos;
return;
}
self.click_pos = event_root_pos;
}
pub fn motion(&mut self, event_root_pos: (i32, i32)) -> Option<(i32, i32)> {
if !self.is_dragging {
return None;
}
if self.use_absolute
&& let Some((abs_x, abs_y)) = platform::get_absolute_cursor_pos() {
let delta_x = abs_x - self.click_pos.0;
let delta_y = abs_y - self.click_pos.1;
let new_margin = (
self.initial_margin.0 + delta_x,
self.initial_margin.1 + delta_y,
);
self.current_margin = new_margin;
return Some(new_margin);
}
let (raw_x, raw_y) = event_root_pos;
let old_margin = self.current_margin;
let delta_x = raw_x - self.click_pos.0;
let delta_y = raw_y - self.click_pos.1;
let new_margin = (
self.initial_margin.0 + delta_x,
self.initial_margin.1 + delta_y,
);
let moved_x = new_margin.0 - old_margin.0;
let moved_y = new_margin.1 - old_margin.1;
self.click_pos.0 -= moved_x;
self.click_pos.1 -= moved_y;
self.current_margin = new_margin;
Some(new_margin)
}
pub fn release(&mut self) -> (i32, i32) {
self.is_dragging = false;
self.current_margin
}
pub fn current_margin(&self) -> (i32, i32) {
self.current_margin
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn compensated_drag_delta_calculation() {
let mut controller = DragController::new((50, 50), false);
controller.press((10, 10));
let m1 = controller.motion((15, 10)).unwrap();
assert_eq!(m1, (55, 50));
let m2 = controller.motion((10, 10)).unwrap();
assert_eq!(m2, (55, 50));
}
}