Add in-window on-move-out mouse handler concept

Julia created

Change summary

crates/editor/src/element.rs                    |  3 ++
crates/gpui/src/elements/mouse_event_handler.rs | 10 ++++++
crates/gpui/src/presenter.rs                    | 17 ++++++++++-
crates/gpui/src/scene/mouse_event.rs            | 13 +++++++++
crates/gpui/src/scene/mouse_region.rs           | 27 ++++++++++++++++++
5 files changed, 66 insertions(+), 4 deletions(-)

Detailed changes

crates/editor/src/element.rs 🔗

@@ -190,6 +190,9 @@ impl EditorElement {
                         }
                     }
                 })
+                .on_move_out(|e, cx| {
+                    println!("on move out");
+                })
                 .on_scroll({
                     let position_map = position_map.clone();
                     move |e, cx| {

crates/gpui/src/elements/mouse_event_handler.rs 🔗

@@ -7,7 +7,7 @@ use crate::{
     platform::CursorStyle,
     scene::{
         CursorRegion, HandlerSet, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseHover,
-        MouseMove, MouseScrollWheel, MouseUp, MouseUpOut,
+        MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut,
     },
     DebugContext, Element, ElementBox, EventContext, LayoutContext, MeasurementContext,
     MouseButton, MouseRegion, MouseState, PaintContext, RenderContext, SizeConstraint, View,
@@ -82,6 +82,14 @@ impl<Tag> MouseEventHandler<Tag> {
         self
     }
 
+    pub fn on_move_out(
+        mut self,
+        handler: impl Fn(MouseMoveOut, &mut EventContext) + 'static,
+    ) -> Self {
+        self.handlers = self.handlers.on_move_out(handler);
+        self
+    }
+
     pub fn on_down(
         mut self,
         button: MouseButton,

crates/gpui/src/presenter.rs 🔗

@@ -8,7 +8,7 @@ use crate::{
     platform::{CursorStyle, Event},
     scene::{
         CursorRegion, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseEvent, MouseHover,
-        MouseMove, MouseScrollWheel, MouseUp, MouseUpOut, Scene,
+        MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, Scene,
     },
     text_layout::TextLayoutCache,
     Action, AnyModelHandle, AnyViewHandle, AnyWeakModelHandle, AnyWeakViewHandle, Appearance,
@@ -245,8 +245,11 @@ impl Presenter {
         //  -> Also updates mouse-related state
         match &event {
             Event::KeyDown(e) => return cx.dispatch_key_down(self.window_id, e),
+
             Event::KeyUp(e) => return cx.dispatch_key_up(self.window_id, e),
+
             Event::ModifiersChanged(e) => return cx.dispatch_modifiers_changed(self.window_id, e),
+
             Event::MouseDown(e) => {
                 // Click events are weird because they can be fired after a drag event.
                 // MDN says that browsers handle this by starting from 'the most
@@ -279,6 +282,7 @@ impl Presenter {
                     platform_event: e.clone(),
                 }));
             }
+
             Event::MouseUp(e) => {
                 // NOTE: The order of event pushes is important! MouseUp events MUST be fired
                 // before click events, and so the MouseUp events need to be pushed before
@@ -296,6 +300,7 @@ impl Presenter {
                     platform_event: e.clone(),
                 }));
             }
+
             Event::MouseMoved(
                 e @ MouseMovedEvent {
                     position,
@@ -347,9 +352,13 @@ impl Presenter {
                     platform_event: e.clone(),
                     started: false,
                 }));
+                mouse_events.push(MouseEvent::MoveOut(MouseMoveOut {
+                    region: Default::default(),
+                }));
 
                 self.last_mouse_moved_event = Some(event.clone());
             }
+
             Event::ScrollWheel(e) => mouse_events.push(MouseEvent::ScrollWheel(MouseScrollWheel {
                 region: Default::default(),
                 platform_event: e.clone(),
@@ -407,6 +416,7 @@ impl Presenter {
                         }
                     }
                 }
+
                 MouseEvent::Down(_) | MouseEvent::Up(_) => {
                     for (region, _) in self.mouse_regions.iter().rev() {
                         if region.bounds.contains_point(self.mouse_position) {
@@ -417,6 +427,7 @@ impl Presenter {
                         }
                     }
                 }
+
                 MouseEvent::Click(e) => {
                     // Only raise click events if the released button is the same as the one stored
                     if self
@@ -439,6 +450,7 @@ impl Presenter {
                         }
                     }
                 }
+
                 MouseEvent::Drag(_) => {
                     for (mouse_region, _) in self.mouse_regions.iter().rev() {
                         if self.clicked_region_ids.contains(&mouse_region.id()) {
@@ -447,7 +459,7 @@ impl Presenter {
                     }
                 }
 
-                MouseEvent::UpOut(_) | MouseEvent::DownOut(_) => {
+                MouseEvent::MoveOut(_) | MouseEvent::UpOut(_) | MouseEvent::DownOut(_) => {
                     for (mouse_region, _) in self.mouse_regions.iter().rev() {
                         // NOT contains
                         if !mouse_region.bounds.contains_point(self.mouse_position) {
@@ -455,6 +467,7 @@ impl Presenter {
                         }
                     }
                 }
+
                 _ => {
                     for (mouse_region, _) in self.mouse_regions.iter().rev() {
                         // Contains

crates/gpui/src/scene/mouse_event.rs 🔗

@@ -21,6 +21,11 @@ impl Deref for MouseMove {
     }
 }
 
+#[derive(Debug, Default, Clone)]
+pub struct MouseMoveOut {
+    pub region: RectF,
+}
+
 #[derive(Debug, Default, Clone)]
 pub struct MouseDrag {
     pub region: RectF,
@@ -138,6 +143,7 @@ impl Deref for MouseScrollWheel {
 #[derive(Debug, Clone)]
 pub enum MouseEvent {
     Move(MouseMove),
+    MoveOut(MouseMoveOut),
     Drag(MouseDrag),
     Hover(MouseHover),
     Down(MouseDown),
@@ -152,6 +158,7 @@ impl MouseEvent {
     pub fn set_region(&mut self, region: RectF) {
         match self {
             MouseEvent::Move(r) => r.region = region,
+            MouseEvent::MoveOut(r) => r.region = region,
             MouseEvent::Drag(r) => r.region = region,
             MouseEvent::Hover(r) => r.region = region,
             MouseEvent::Down(r) => r.region = region,
@@ -168,6 +175,7 @@ impl MouseEvent {
     pub fn is_capturable(&self) -> bool {
         match self {
             MouseEvent::Move(_) => true,
+            MouseEvent::MoveOut(_) => false,
             MouseEvent::Drag(_) => true,
             MouseEvent::Hover(_) => false,
             MouseEvent::Down(_) => true,
@@ -185,6 +193,10 @@ impl MouseEvent {
         discriminant(&MouseEvent::Move(Default::default()))
     }
 
+    pub fn move_out_disc() -> Discriminant<MouseEvent> {
+        discriminant(&MouseEvent::MoveOut(Default::default()))
+    }
+
     pub fn drag_disc() -> Discriminant<MouseEvent> {
         discriminant(&MouseEvent::Drag(Default::default()))
     }
@@ -220,6 +232,7 @@ impl MouseEvent {
     pub fn handler_key(&self) -> HandlerKey {
         match self {
             MouseEvent::Move(_) => HandlerKey::new(Self::move_disc(), None),
+            MouseEvent::MoveOut(_) => HandlerKey::new(Self::move_out_disc(), None),
             MouseEvent::Drag(e) => HandlerKey::new(Self::drag_disc(), e.pressed_button),
             MouseEvent::Hover(_) => HandlerKey::new(Self::hover_disc(), None),
             MouseEvent::Down(e) => HandlerKey::new(Self::down_disc(), Some(e.button)),

crates/gpui/src/scene/mouse_region.rs 🔗

@@ -12,7 +12,7 @@ use super::{
         MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseEvent, MouseHover, MouseMove, MouseUp,
         MouseUpOut,
     },
-    MouseScrollWheel,
+    MouseMoveOut, MouseScrollWheel,
 };
 
 #[derive(Clone)]
@@ -124,6 +124,14 @@ impl MouseRegion {
         self
     }
 
+    pub fn on_move_out(
+        mut self,
+        handler: impl Fn(MouseMoveOut, &mut EventContext) + 'static,
+    ) -> Self {
+        self.handlers = self.handlers.on_move_out(handler);
+        self
+    }
+
     pub fn on_scroll(
         mut self,
         handler: impl Fn(MouseScrollWheel, &mut EventContext) + 'static,
@@ -289,6 +297,23 @@ impl HandlerSet {
         self
     }
 
+    pub fn on_move_out(
+        mut self,
+        handler: impl Fn(MouseMoveOut, &mut EventContext) + 'static,
+    ) -> Self {
+        self.insert(MouseEvent::move_out_disc(), None,
+            Rc::new(move |region_event, cx| {
+                if let MouseEvent::MoveOut(e) = region_event {
+                    handler(e, cx);
+                } else {
+                    panic!(
+                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::MoveOut, found {:?}", 
+                        region_event);
+                }
+            }));
+        self
+    }
+
     pub fn on_down(
         mut self,
         button: MouseButton,