use crate::event::EventContext;
use crate::view::node::{Listener, ViewNode};
use crate::widget::{BuildContext, Widget};
use std::rc::Rc;
type DragCallback = Rc<dyn Fn(&mut EventContext)>;
pub struct Draggable {
child: Box<dyn Widget>,
threshold: f32,
enabled: bool,
on_drag_start: Option<DragCallback>,
on_drag_move: Option<DragCallback>,
on_drag_end: Option<DragCallback>,
}
impl Draggable {
pub fn new(child: impl Widget + 'static) -> Self {
Self {
child: Box::new(child),
threshold: crate::event::DEFAULT_DRAG_THRESHOLD,
enabled: true,
on_drag_start: None,
on_drag_move: None,
on_drag_end: None,
}
}
pub fn threshold(mut self, px: f32) -> Self {
self.threshold = px.max(0.0);
self
}
pub fn enabled(mut self, v: bool) -> Self {
self.enabled = v;
self
}
pub fn on_drag_start<F: Fn(&mut EventContext) + 'static>(mut self, f: F) -> Self {
self.on_drag_start = Some(Rc::new(f));
self
}
pub fn on_drag_move<F: Fn(&mut EventContext) + 'static>(mut self, f: F) -> Self {
self.on_drag_move = Some(Rc::new(f));
self
}
pub fn on_drag_end<F: Fn(&mut EventContext) + 'static>(mut self, f: F) -> Self {
self.on_drag_end = Some(Rc::new(f));
self
}
}
impl Widget for Draggable {
fn key(&self) -> Option<&str> {
self.child.key()
}
fn build(&self, ctx: &mut BuildContext) -> ViewNode {
let mut node = ctx.child(0, self.child.as_ref());
if !self.enabled {
return node;
}
let threshold = self.threshold;
node.add_listener(
Listener::on_mouse_down(Rc::new(move |ctx: &mut EventContext| {
if matches!(
ctx.event(),
Some(crate::event::Event::MouseDown {
button: crate::event::MouseButton::Left,
..
})
) {
ctx.begin_drag_with_threshold(threshold);
}
}))
.builtin(),
);
if let Some(cb) = &self.on_drag_start {
node.add_listener(Listener::on_drag_start(Rc::clone(cb)).builtin());
}
if let Some(cb) = &self.on_drag_move {
node.add_listener(Listener::on_drag_move(Rc::clone(cb)).builtin());
}
if let Some(cb) = &self.on_drag_end {
node.add_listener(Listener::on_drag_end(Rc::clone(cb)).builtin());
}
node
}
}