Clear last-mouse-moved pressed button when that button gets a mouse-up

ForLoveOfCats created

This fixes an annoying issue where if the last mouse moved event was
during a drag it would never trigger mouse cursor changes until next
mouse move reset it. It makes sense to continue to not change the cursor
while the button is pressed so instead this tracks when the mouse button
is released in order to update the mouse move event

Change summary

crates/gpui/src/platform/event.rs |  2 
crates/gpui/src/presenter.rs      | 94 ++++++++++++++++++--------------
2 files changed, 53 insertions(+), 43 deletions(-)

Detailed changes

crates/gpui/src/platform/event.rs 🔗

@@ -64,7 +64,7 @@ impl Default for MouseButton {
     }
 }
 
-#[derive(Clone, Debug, Default)]
+#[derive(Clone, Copy, Debug, Default)]
 pub struct MouseButtonEvent {
     pub button: MouseButton,
     pub position: Vector2F,

crates/gpui/src/presenter.rs 🔗

@@ -31,7 +31,7 @@ pub struct Presenter {
     font_cache: Arc<FontCache>,
     text_layout_cache: TextLayoutCache,
     asset_cache: Arc<AssetCache>,
-    last_mouse_moved_event: Option<Event>,
+    last_mouse_moved_event: Option<MouseMovedEvent>,
     hovered_region_ids: HashSet<MouseRegionId>,
     clicked_region: Option<MouseRegion>,
     right_clicked_region: Option<MouseRegion>,
@@ -268,15 +268,27 @@ impl Presenter {
                         }
                     }
                 }
-                Event::MouseUp(e @ MouseButtonEvent { position, .. }) => {
+
+                &Event::MouseUp(
+                    e @ MouseButtonEvent {
+                        position, button, ..
+                    },
+                ) => {
                     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) {
+                        if region.bounds.contains_point(position) {
                             clicked_region = Some((region, MouseRegionEvent::Click(e.clone())));
                         }
                     }
+
+                    if let Some(moved) = &mut self.last_mouse_moved_event {
+                        if moved.pressed_button == Some(button) {
+                            moved.pressed_button = None;
+                        }
+                    }
                 }
+
                 Event::MouseMoved(e @ MouseMovedEvent { position, .. }) => {
                     if let Some((clicked_region, prev_drag_position)) = self
                         .clicked_region
@@ -290,13 +302,17 @@ impl Presenter {
                         *prev_drag_position = *position;
                     }
 
-                    self.last_mouse_moved_event = Some(event.clone());
+                    self.last_mouse_moved_event = Some(e.clone());
                 }
+
                 _ => {}
             }
 
-            let (mut handled, mut event_cx) =
-                self.handle_hover_events(&event, &mut invalidated_views, cx);
+            let (mut handled, mut event_cx) = if let Event::MouseMoved(e) = &event {
+                self.handle_hover_events(e, &mut invalidated_views, cx)
+            } else {
+                (false, self.build_event_context(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))
@@ -353,51 +369,45 @@ impl Presenter {
 
     fn handle_hover_events<'a>(
         &'a mut self,
-        event: &Event,
+        e @ MouseMovedEvent {
+            position,
+            pressed_button,
+            ..
+        }: &MouseMovedEvent,
         invalidated_views: &mut Vec<usize>,
         cx: &'a mut MutableAppContext,
     ) -> (bool, EventContext<'a>) {
         let mut hover_regions = Vec::new();
-        if let Event::MouseMoved(
-            e @ MouseMovedEvent {
-                position,
-                pressed_button,
-                ..
-            },
-        ) = 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;
-                    }
+
+        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;
                 }
-                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);
+                            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) {
+                        invalidated_views.push(region.view_id);
+                        hover_regions.push((region.clone(), MouseRegionEvent::Hover(false, *e)));
+                        self.hovered_region_ids.remove(&region_id);
+                    }
                 }
             }
         }