diff --git a/gpui/src/elements/mouse_event_handler.rs b/gpui/src/elements/mouse_event_handler.rs index 629a9824ff..48deef18a2 100644 --- a/gpui/src/elements/mouse_event_handler.rs +++ b/gpui/src/elements/mouse_event_handler.rs @@ -9,12 +9,14 @@ pub struct MouseEventHandler { state: ValueHandle, child: ElementBox, click_handler: Option>, + drag_handler: Option>, } #[derive(Clone, Copy, Debug, Default)] pub struct MouseState { pub hovered: bool, pub clicked: bool, + prev_drag_position: Option, } impl MouseEventHandler { @@ -30,6 +32,7 @@ impl MouseEventHandler { state: state_handle, child, click_handler: None, + drag_handler: None, } } @@ -37,6 +40,11 @@ impl MouseEventHandler { self.click_handler = Some(Box::new(handler)); self } + + pub fn on_drag(mut self, handler: impl FnMut(Vector2F, &mut EventContext) + 'static) -> Self { + self.drag_handler = Some(Box::new(handler)); + self + } } impl Element for MouseEventHandler { @@ -69,6 +77,7 @@ impl Element for MouseEventHandler { cx: &mut EventContext, ) -> bool { let click_handler = self.click_handler.as_mut(); + let drag_handler = self.drag_handler.as_mut(); let handled_in_child = self.child.dispatch_event(event, cx); @@ -86,6 +95,7 @@ impl Element for MouseEventHandler { Event::LeftMouseDown { position, .. } => { if !handled_in_child && bounds.contains_point(*position) { state.clicked = true; + state.prev_drag_position = Some(*position); cx.notify(); true } else { @@ -93,6 +103,7 @@ impl Element for MouseEventHandler { } } Event::LeftMouseUp { position, .. } => { + state.prev_drag_position = None; if !handled_in_child && state.clicked { state.clicked = false; cx.notify(); @@ -106,6 +117,20 @@ impl Element for MouseEventHandler { handled_in_child } } + Event::LeftMouseDragged { position, .. } => { + if !handled_in_child && state.clicked { + let prev_drag_position = state.prev_drag_position.replace(*position); + if let Some((handler, prev_position)) = drag_handler.zip(prev_drag_position) { + let delta = *position - prev_position; + if !delta.is_zero() { + (handler)(delta, cx); + } + } + true + } else { + handled_in_child + } + } _ => handled_in_child, }) }