more event wip

K Simmons created

Change summary

crates/gpui/src/elements/mouse_event_handler.rs |  27 +++
crates/gpui/src/presenter.rs                    | 147 ++++++++----------
crates/gpui/src/scene/mouse_region.rs           |  92 ++++++++++-
crates/workspace/src/pane.rs                    |   6 
4 files changed, 175 insertions(+), 97 deletions(-)

Detailed changes

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

@@ -51,6 +51,15 @@ impl MouseEventHandler {
         self
     }
 
+    pub fn on_up(
+        mut self,
+        button: MouseButton,
+        handler: impl Fn(MouseButtonEvent, &mut EventContext) + 'static,
+    ) -> Self {
+        self.handlers = self.handlers.on_up(button, handler);
+        self
+    }
+
     pub fn on_click(
         mut self,
         button: MouseButton,
@@ -69,6 +78,15 @@ impl MouseEventHandler {
         self
     }
 
+    pub fn on_up_out(
+        mut self,
+        button: MouseButton,
+        handler: impl Fn(MouseButtonEvent, &mut EventContext) + 'static,
+    ) -> Self {
+        self.handlers = self.handlers.on_up(button, handler);
+        self
+    }
+
     pub fn on_drag(
         mut self,
         button: MouseButton,
@@ -78,6 +96,15 @@ impl MouseEventHandler {
         self
     }
 
+    pub fn on_drag_over(
+        mut self,
+        button: MouseButton,
+        handler: impl Fn(bool, MouseMovedEvent, &mut EventContext) + 'static,
+    ) -> Self {
+        self.handlers = self.handlers.on_drag_over(button, handler);
+        self
+    }
+
     pub fn on_hover(
         mut self,
         handler: impl Fn(bool, MouseMovedEvent, &mut EventContext) + 'static,

crates/gpui/src/presenter.rs 🔗

@@ -234,10 +234,7 @@ impl Presenter {
     pub fn dispatch_event(&mut self, event: Event, cx: &mut MutableAppContext) -> bool {
         if let Some(root_view_id) = cx.root_view_id(self.window_id) {
             let mut invalidated_views = Vec::new();
-            let mut mouse_down_out_handlers = Vec::new();
-            let mut mouse_down_region = None;
-            let mut clicked_region = None;
-            let mut dragged_region = None;
+            let mut events_to_send = Vec::new();
 
             match &event {
                 Event::MouseDown(
@@ -248,32 +245,42 @@ impl Presenter {
                     let mut hit = false;
                     for (region, _) in self.mouse_regions.iter().rev() {
                         if region.bounds.contains_point(*position) {
-                            if !hit {
-                                hit = true;
+                            if !std::mem::replace(&mut hit, true) {
                                 invalidated_views.push(region.view_id);
-                                mouse_down_region =
-                                    Some((region.clone(), MouseRegionEvent::Down(e.clone())));
+                                events_to_send
+                                    .push((region.clone(), MouseRegionEvent::Down(e.clone())));
                                 self.clicked_region = Some(region.clone());
                                 self.prev_drag_position = Some(*position);
                             }
-                        } else if let Some(handler) = region
-                            .handlers
-                            .get(&(MouseRegionEvent::down_out_disc(), Some(*button)))
-                        {
-                            mouse_down_out_handlers.push((
-                                handler,
-                                region.view_id,
-                                MouseRegionEvent::DownOut(e.clone()),
-                            ));
+                        } else {
+                            events_to_send
+                                .push((region.clone(), MouseRegionEvent::DownOut(e.clone())));
                         }
                     }
                 }
-                Event::MouseUp(e @ MouseButtonEvent { position, .. }) => {
+                Event::MouseUp(
+                    e @ MouseButtonEvent {
+                        position, button, ..
+                    },
+                ) => {
+                    let mut hit = false;
+                    for (region, _) in self.mouse_regions.iter().rev() {
+                        if region.bounds.contains_point(*position) {
+                            if !std::mem::replace(&mut hit, true) {
+                                invalidated_views.push(region.view_id);
+                                events_to_send
+                                    .push((region.clone(), MouseRegionEvent::Up(e.clone())));
+                            }
+                        } else {
+                            events_to_send
+                                .push((region.clone(), MouseRegionEvent::UpOut(e.clone())));
+                        }
+                    }
                     self.prev_drag_position.take();
                     if let Some(region) = self.clicked_region.take() {
                         invalidated_views.push(region.view_id);
                         if region.bounds.contains_point(*position) {
-                            clicked_region = Some((region, MouseRegionEvent::Click(e.clone())));
+                            events_to_send.push((region, MouseRegionEvent::Click(e.clone())));
                         }
                     }
                 }
@@ -283,7 +290,7 @@ impl Presenter {
                         .as_ref()
                         .zip(self.prev_drag_position.as_mut())
                     {
-                        dragged_region = Some((
+                        events_to_send.push((
                             clicked_region.clone(),
                             MouseRegionEvent::Drag(*prev_drag_position, *e),
                         ));
@@ -298,39 +305,11 @@ impl Presenter {
             let (mut handled, mut event_cx) =
                 self.handle_hover_events(&event, &mut invalidated_views, cx);
 
-            for (handler, view_id, region_event) in mouse_down_out_handlers {
-                event_cx.with_current_view(view_id, |event_cx| handler(region_event, event_cx))
-            }
-
-            if let Some((mouse_down_region, region_event)) = mouse_down_region {
+            for (region, event) in events_to_send {
                 handled = true;
-                if let Some(mouse_down_callback) =
-                    mouse_down_region.handlers.get(&region_event.handler_key())
-                {
-                    event_cx.with_current_view(mouse_down_region.view_id, |event_cx| {
-                        mouse_down_callback(region_event, event_cx);
-                    })
-                }
-            }
-
-            if let Some((clicked_region, region_event)) = clicked_region {
-                handled = true;
-                if let Some(click_callback) =
-                    clicked_region.handlers.get(&region_event.handler_key())
-                {
-                    event_cx.with_current_view(clicked_region.view_id, |event_cx| {
-                        click_callback(region_event, event_cx);
-                    })
-                }
-            }
-
-            if let Some((dragged_region, region_event)) = dragged_region {
-                handled = true;
-                if let Some(drag_callback) =
-                    dragged_region.handlers.get(&region_event.handler_key())
-                {
-                    event_cx.with_current_view(dragged_region.view_id, |event_cx| {
-                        drag_callback(region_event, event_cx);
+                if let Some(callback) = region.handlers.get(&event.handler_key()) {
+                    event_cx.with_current_view(region.view_id, |event_cx| {
+                        callback(event, event_cx);
                     })
                 }
             }
@@ -366,38 +345,44 @@ impl Presenter {
             },
         ) = event
         {
-            if pressed_button.is_none() {
-                let mut style_to_assign = CursorStyle::Arrow;
-                for region in self.cursor_regions.iter().rev() {
-                    if region.bounds.contains_point(*position) {
-                        style_to_assign = region.style;
-                        break;
-                    }
+            let mut style_to_assign = CursorStyle::Arrow;
+            for region in self.cursor_regions.iter().rev() {
+                if region.bounds.contains_point(*position) {
+                    style_to_assign = region.style;
+                    break;
                 }
-                cx.platform().set_cursor_style(style_to_assign);
+            }
+            cx.platform().set_cursor_style(style_to_assign);
 
-                let mut hover_depth = None;
-                for (region, depth) in self.mouse_regions.iter().rev() {
-                    if region.bounds.contains_point(*position)
-                        && hover_depth.map_or(true, |hover_depth| hover_depth == *depth)
-                    {
-                        hover_depth = Some(*depth);
-                        if let Some(region_id) = region.id() {
-                            if !self.hovered_region_ids.contains(&region_id) {
-                                invalidated_views.push(region.view_id);
-                                hover_regions
-                                    .push((region.clone(), MouseRegionEvent::Hover(true, *e)));
-                                self.hovered_region_ids.insert(region_id);
-                            }
-                        }
-                    } else if let Some(region_id) = region.id() {
-                        if self.hovered_region_ids.contains(&region_id) {
+            let mut hover_depth = None;
+            for (region, depth) in self.mouse_regions.iter().rev() {
+                if region.bounds.contains_point(*position)
+                    && hover_depth.map_or(true, |hover_depth| hover_depth == *depth)
+                {
+                    hover_depth = Some(*depth);
+                    if let Some(region_id) = region.id() {
+                        if !self.hovered_region_ids.contains(&region_id) {
                             invalidated_views.push(region.view_id);
-                            hover_regions
-                                .push((region.clone(), MouseRegionEvent::Hover(false, *e)));
-                            self.hovered_region_ids.remove(&region_id);
+                            let region_event = if let Some(pressed_button) = pressed_button {
+                                MouseRegionEvent::DragOver(true, e.clone())
+                            } else {
+                                MouseRegionEvent::Hover(true, e.clone())
+                            };
+                            hover_regions.push((region.clone(), region_event));
+                            self.hovered_region_ids.insert(region_id);
                         }
                     }
+                } else if let Some(region_id) = region.id() {
+                    if self.hovered_region_ids.contains(&region_id) {
+                        invalidated_views.push(region.view_id);
+                        let region_event = if let Some(pressed_button) = pressed_button {
+                            MouseRegionEvent::DragOver(false, e.clone())
+                        } else {
+                            MouseRegionEvent::Hover(false, e.clone())
+                        };
+                        hover_regions.push((region.clone(), region_event));
+                        self.hovered_region_ids.remove(&region_id);
+                    }
                 }
             }
         }
@@ -407,9 +392,9 @@ impl Presenter {
 
         for (hover_region, region_event) in hover_regions {
             handled = true;
-            if let Some(hover_callback) = hover_region.handlers.get(&region_event.handler_key()) {
+            if let Some(callback) = hover_region.handlers.get(&region_event.handler_key()) {
                 event_cx.with_current_view(hover_region.view_id, |event_cx| {
-                    hover_callback(region_event, event_cx);
+                    callback(region_event, event_cx);
                 })
             }
         }

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

@@ -1,4 +1,8 @@
-use std::{any::TypeId, mem::Discriminant, rc::Rc};
+use std::{
+    any::TypeId,
+    mem::{discriminant, Discriminant},
+    rc::Rc,
+};
 
 use collections::HashMap;
 use pathfinder_geometry::{rect::RectF, vector::Vector2F};
@@ -81,6 +85,15 @@ impl MouseRegion {
         self
     }
 
+    pub fn on_up_out(
+        mut self,
+        button: MouseButton,
+        handler: impl Fn(MouseButtonEvent, &mut EventContext) + 'static,
+    ) -> Self {
+        self.handlers = self.handlers.on_up_out(button, handler);
+        self
+    }
+
     pub fn on_drag(
         mut self,
         button: MouseButton,
@@ -90,6 +103,15 @@ impl MouseRegion {
         self
     }
 
+    pub fn on_drag_over(
+        mut self,
+        button: MouseButton,
+        handler: impl Fn(Vector2F, MouseMovedEvent, &mut EventContext) + 'static,
+    ) -> Self {
+        self.handlers = self.handlers.on_drag_over(button, handler);
+        self
+    }
+
     pub fn on_hover(
         mut self,
         handler: impl Fn(bool, MouseMovedEvent, &mut EventContext) + 'static,
@@ -129,6 +151,10 @@ impl HandlerSet {
                 (MouseRegionEvent::drag_disc(), Some(button)),
                 Rc::new(|_, _| {}),
             );
+            set.insert(
+                (MouseRegionEvent::drag_over_disc(), Some(button)),
+                Rc::new(|_, _| {}),
+            );
             set.insert(
                 (MouseRegionEvent::down_disc(), Some(button)),
                 Rc::new(|_, _| {}),
@@ -145,6 +171,10 @@ impl HandlerSet {
                 (MouseRegionEvent::down_out_disc(), Some(button)),
                 Rc::new(|_, _| {}),
             );
+            set.insert(
+                (MouseRegionEvent::up_out_disc(), Some(button)),
+                Rc::new(|_, _| {}),
+            );
         }
         set.insert(
             (MouseRegionEvent::scroll_wheel_disc(), None),
@@ -233,6 +263,24 @@ impl HandlerSet {
         self
     }
 
+    pub fn on_up_out(
+        mut self,
+        button: MouseButton,
+        handler: impl Fn(MouseButtonEvent, &mut EventContext) + 'static,
+    ) -> Self {
+        self.set.insert((MouseRegionEvent::up_out_disc(), Some(button)),
+            Rc::new(move |region_event, cx| {
+                if let MouseRegionEvent::UpOut(mouse_button_event) = region_event {
+                    handler(mouse_button_event, cx);
+                } else {
+                    panic!(
+                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::UpOut, found {:?}", 
+                        region_event);
+                }
+            }));
+        self
+    }
+
     pub fn on_drag(
         mut self,
         button: MouseButton,
@@ -251,14 +299,32 @@ impl HandlerSet {
         self
     }
 
+    pub fn on_drag_over(
+        mut self,
+        button: MouseButton,
+        handler: impl Fn(bool, MouseMovedEvent, &mut EventContext) + 'static,
+    ) -> Self {
+        self.set.insert((MouseRegionEvent::drag_over_disc(), Some(button)),
+            Rc::new(move |region_event, cx| {
+                if let MouseRegionEvent::DragOver(started, mouse_moved_event) = region_event {
+                    handler(started, mouse_moved_event, cx);
+                } else {
+                    panic!(
+                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::DragOver, found {:?}", 
+                        region_event);
+                }
+            }));
+        self
+    }
+
     pub fn on_hover(
         mut self,
         handler: impl Fn(bool, MouseMovedEvent, &mut EventContext) + 'static,
     ) -> Self {
         self.set.insert((MouseRegionEvent::hover_disc(), None),
             Rc::new(move |region_event, cx| {
-                if let MouseRegionEvent::Hover(hover, mouse_moved_event) = region_event {
-                    handler(hover, mouse_moved_event, cx);
+                if let MouseRegionEvent::Hover(started, mouse_moved_event) = region_event {
+                    handler(started, mouse_moved_event, cx);
                 } else {
                     panic!(
                         "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Hover, found {:?}", 
@@ -273,7 +339,7 @@ impl HandlerSet {
 pub enum MouseRegionEvent {
     Move(MouseMovedEvent),
     Drag(Vector2F, MouseMovedEvent),
-    DragOver(Vector2F, MouseMovedEvent),
+    DragOver(bool, MouseMovedEvent),
     Hover(bool, MouseMovedEvent),
     Down(MouseButtonEvent),
     Up(MouseButtonEvent),
@@ -285,40 +351,40 @@ pub enum MouseRegionEvent {
 
 impl MouseRegionEvent {
     pub fn move_disc() -> Discriminant<MouseRegionEvent> {
-        std::mem::discriminant(&MouseRegionEvent::Move(Default::default()))
+        discriminant(&MouseRegionEvent::Move(Default::default()))
     }
     pub fn drag_disc() -> Discriminant<MouseRegionEvent> {
-        std::mem::discriminant(&MouseRegionEvent::Drag(
+        discriminant(&MouseRegionEvent::Drag(
             Default::default(),
             Default::default(),
         ))
     }
     pub fn drag_over_disc() -> Discriminant<MouseRegionEvent> {
-        std::mem::discriminant(&MouseRegionEvent::DragOver(
+        discriminant(&MouseRegionEvent::DragOver(
             Default::default(),
             Default::default(),
         ))
     }
     pub fn hover_disc() -> Discriminant<MouseRegionEvent> {
-        std::mem::discriminant(&MouseRegionEvent::Hover(
+        discriminant(&MouseRegionEvent::Hover(
             Default::default(),
             Default::default(),
         ))
     }
     pub fn down_disc() -> Discriminant<MouseRegionEvent> {
-        std::mem::discriminant(&MouseRegionEvent::Down(Default::default()))
+        discriminant(&MouseRegionEvent::Down(Default::default()))
     }
     pub fn up_disc() -> Discriminant<MouseRegionEvent> {
-        std::mem::discriminant(&MouseRegionEvent::Up(Default::default()))
+        discriminant(&MouseRegionEvent::Up(Default::default()))
     }
     pub fn up_out_disc() -> Discriminant<MouseRegionEvent> {
-        std::mem::discriminant(&MouseRegionEvent::UpOut(Default::default()))
+        discriminant(&MouseRegionEvent::UpOut(Default::default()))
     }
     pub fn click_disc() -> Discriminant<MouseRegionEvent> {
-        std::mem::discriminant(&MouseRegionEvent::Click(Default::default()))
+        discriminant(&MouseRegionEvent::Click(Default::default()))
     }
     pub fn down_out_disc() -> Discriminant<MouseRegionEvent> {
-        std::mem::discriminant(&MouseRegionEvent::DownOut(Default::default()))
+        discriminant(&MouseRegionEvent::DownOut(Default::default()))
     }
     pub fn scroll_wheel_disc() -> Discriminant<MouseRegionEvent> {
         std::mem::discriminant(&MouseRegionEvent::ScrollWheel(Default::default()))

crates/workspace/src/pane.rs 🔗

@@ -1025,13 +1025,13 @@ impl Pane {
                     .on_drag(MouseButton::Left, |_, cx| {
                         cx.global::<DragAndDrop>().dragging(some view handle)
                     })
-                    .on_mouse_up_out(MouseButton::Left, |_, cx| {
+                    .on_up_out(MouseButton::Left, |_, cx| {
                         cx.global::<DragAndDrop>().stopped_dragging(some view handle)
                     })
-                    .on_drag_over(MouseButton::Left, |started, _, cx| {
+                    .on_drag_over(MouseButton::Left, |started, _, _, cx| {
                         if started {
                             if let Some(tab) = cx.global::<DragAndDrop>().current_dragged::<Tab>() {
-                                cx.dispatch_action(ReceivingTab)
+                                cx.dispatch_action(ReceivingTab);
                             }
                         }
                     })