use crate::{ Bounds, DispatchPhase, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, ScrollWheelEvent, ViewContext, }; use smallvec::SmallVec; use std::sync::Arc; pub trait Interactive { fn listeners(&mut self) -> &mut MouseEventListeners; fn on_mouse_down( mut self, button: MouseButton, handler: impl Fn(&mut S, &MouseDownEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, { self.listeners() .mouse_down .push(Arc::new(move |view, event, bounds, phase, cx| { if phase == DispatchPhase::Bubble && event.button == button && bounds.contains_point(event.position) { handler(view, event, cx) } })); self } fn on_mouse_up( mut self, button: MouseButton, handler: impl Fn(&mut S, &MouseUpEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, { self.listeners() .mouse_up .push(Arc::new(move |view, event, bounds, phase, cx| { if phase == DispatchPhase::Bubble && event.button == button && bounds.contains_point(event.position) { handler(view, event, cx) } })); self } fn on_mouse_down_out( mut self, button: MouseButton, handler: impl Fn(&mut S, &MouseDownEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, { self.listeners() .mouse_down .push(Arc::new(move |view, event, bounds, phase, cx| { if phase == DispatchPhase::Capture && event.button == button && !bounds.contains_point(event.position) { handler(view, event, cx) } })); self } fn on_mouse_up_out( mut self, button: MouseButton, handler: impl Fn(&mut S, &MouseUpEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, { self.listeners() .mouse_up .push(Arc::new(move |view, event, bounds, phase, cx| { if phase == DispatchPhase::Capture && event.button == button && !bounds.contains_point(event.position) { handler(view, event, cx); } })); self } fn on_mouse_move( mut self, handler: impl Fn(&mut S, &MouseMoveEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, { self.listeners() .mouse_move .push(Arc::new(move |view, event, bounds, phase, cx| { if phase == DispatchPhase::Bubble && bounds.contains_point(event.position) { handler(view, event, cx); } })); self } fn on_scroll_wheel( mut self, handler: impl Fn(&mut S, &ScrollWheelEvent, &mut ViewContext) + Send + Sync + 'static, ) -> Self where Self: Sized, { self.listeners() .scroll_wheel .push(Arc::new(move |view, event, bounds, phase, cx| { if phase == DispatchPhase::Bubble && bounds.contains_point(event.position) { handler(view, event, cx); } })); self } } type MouseDownHandler = Arc< dyn Fn(&mut V, &MouseDownEvent, &Bounds, DispatchPhase, &mut ViewContext) + Send + Sync + 'static, >; type MouseUpHandler = Arc< dyn Fn(&mut V, &MouseUpEvent, &Bounds, DispatchPhase, &mut ViewContext) + Send + Sync + 'static, >; type MouseMoveHandler = Arc< dyn Fn(&mut V, &MouseMoveEvent, &Bounds, DispatchPhase, &mut ViewContext) + Send + Sync + 'static, >; type ScrollWheelHandler = Arc< dyn Fn(&mut V, &ScrollWheelEvent, &Bounds, DispatchPhase, &mut ViewContext) + Send + Sync + 'static, >; pub struct MouseEventListeners { mouse_down: SmallVec<[MouseDownHandler; 2]>, mouse_up: SmallVec<[MouseUpHandler; 2]>, mouse_move: SmallVec<[MouseMoveHandler; 2]>, scroll_wheel: SmallVec<[ScrollWheelHandler; 2]>, } impl MouseEventListeners { pub fn paint(&self, bounds: Bounds, cx: &mut ViewContext) { for handler in self.mouse_down.iter().cloned() { cx.on_mouse_event(move |view, event: &MouseDownEvent, phase, cx| { handler(view, event, &bounds, phase, cx); }) } for handler in self.mouse_up.iter().cloned() { cx.on_mouse_event(move |view, event: &MouseUpEvent, phase, cx| { handler(view, event, &bounds, phase, cx); }) } for handler in self.mouse_move.iter().cloned() { cx.on_mouse_event(move |view, event: &MouseMoveEvent, phase, cx| { handler(view, event, &bounds, phase, cx); }) } for handler in self.scroll_wheel.iter().cloned() { cx.on_mouse_event(move |view, event: &ScrollWheelEvent, phase, cx| { handler(view, event, &bounds, phase, cx); }) } } } impl Default for MouseEventListeners { fn default() -> Self { Self { mouse_down: Default::default(), mouse_up: Default::default(), mouse_move: Default::default(), scroll_wheel: Default::default(), } } }