Rework presenter and MouseRegion to use Handler hashmap rather than individual fields

K Simmons created

Change summary

crates/activity_indicator/src/activity_indicator.rs |   6 
crates/auto_update/src/update_notification.rs       |   8 
crates/chat_panel/src/chat_panel.rs                 |   6 
crates/contacts_panel/src/contacts_panel.rs         |  29 +
crates/contacts_panel/src/notifications.rs          |  10 
crates/context_menu/src/context_menu.rs             |  10 
crates/diagnostics/src/items.rs                     |  10 
crates/editor/src/editor.rs                         |  10 
crates/editor/src/element.rs                        |  12 
crates/gpui/src/app.rs                              |   4 
crates/gpui/src/elements/event_handler.rs           |  28 -
crates/gpui/src/elements/mouse_event_handler.rs     |  93 +----
crates/gpui/src/elements/tooltip.rs                 |   6 
crates/gpui/src/platform/event.rs                   |  40 +
crates/gpui/src/platform/mac/event.rs               |   8 
crates/gpui/src/platform/mac/window.rs              |   4 
crates/gpui/src/presenter.rs                        | 211 ++++--------
crates/gpui/src/scene.rs                            | 250 ++++++++++++++
crates/gpui/src/views/select.rs                     |  10 
crates/picker/src/picker.rs                         |   8 
crates/project_panel/src/project_panel.rs           |  54 +-
crates/search/src/buffer_search.rs                  |  12 
crates/search/src/project_search.rs                 |  12 
crates/terminal/src/terminal_element.rs             | 123 ++++---
crates/workspace/src/pane.rs                        |  20 
crates/workspace/src/sidebar.rs                     |  38 +
crates/workspace/src/toolbar.rs                     |   6 
crates/workspace/src/workspace.rs                   |  10 
crates/zed/src/feedback.rs                          |   4 
styles/package-lock.json                            |   1 
30 files changed, 619 insertions(+), 424 deletions(-)

Detailed changes

crates/activity_indicator/src/activity_indicator.rs 🔗

@@ -3,7 +3,7 @@ use editor::Editor;
 use futures::StreamExt;
 use gpui::{
     actions, elements::*, platform::CursorStyle, Action, AppContext, Entity, ModelHandle,
-    MutableAppContext, RenderContext, View, ViewContext, ViewHandle,
+    MouseButton, MutableAppContext, RenderContext, View, ViewContext, ViewHandle,
 };
 use language::{LanguageRegistry, LanguageServerBinaryStatus};
 use project::{LanguageServerProgress, Project};
@@ -317,7 +317,9 @@ impl View for ActivityIndicator {
         if let Some(action) = action {
             element = element
                 .with_cursor_style(CursorStyle::PointingHand)
-                .on_click(move |_, _, cx| cx.dispatch_any_action(action.boxed_clone()));
+                .on_click(MouseButton::Left, move |_, cx| {
+                    cx.dispatch_any_action(action.boxed_clone())
+                });
         }
 
         element.boxed()

crates/auto_update/src/update_notification.rs 🔗

@@ -2,7 +2,7 @@ use crate::ViewReleaseNotes;
 use gpui::{
     elements::{Flex, MouseEventHandler, Padding, ParentElement, Svg, Text},
     platform::{AppVersion, CursorStyle},
-    Element, Entity, View, ViewContext,
+    Element, Entity, MouseButton, View, ViewContext,
 };
 use menu::Cancel;
 use settings::Settings;
@@ -62,7 +62,7 @@ impl View for UpdateNotification {
                                     .boxed()
                             })
                             .with_padding(Padding::uniform(5.))
-                            .on_click(move |_, _, cx| cx.dispatch_action(Cancel))
+                            .on_click(MouseButton::Left, move |_, cx| cx.dispatch_action(Cancel))
                             .aligned()
                             .constrained()
                             .with_height(cx.font_cache().line_height(theme.message.text.font_size))
@@ -84,7 +84,9 @@ impl View for UpdateNotification {
                 .boxed()
         })
         .with_cursor_style(CursorStyle::PointingHand)
-        .on_click(|_, _, cx| cx.dispatch_action(ViewReleaseNotes))
+        .on_click(MouseButton::Left, |_, cx| {
+            cx.dispatch_action(ViewReleaseNotes)
+        })
         .boxed()
     }
 }

crates/chat_panel/src/chat_panel.rs 🔗

@@ -8,8 +8,8 @@ use gpui::{
     elements::*,
     platform::CursorStyle,
     views::{ItemType, Select, SelectStyle},
-    AppContext, Entity, ModelHandle, MutableAppContext, RenderContext, Subscription, Task, View,
-    ViewContext, ViewHandle,
+    AppContext, Entity, ModelHandle, MouseButton, MutableAppContext, RenderContext, Subscription,
+    Task, View, ViewContext, ViewHandle,
 };
 use menu::Confirm;
 use postage::prelude::Stream;
@@ -320,7 +320,7 @@ impl ChatPanel {
                 .boxed()
             })
             .with_cursor_style(CursorStyle::PointingHand)
-            .on_click(move |_, _, cx| {
+            .on_click(MouseButton::Left, move |_, cx| {
                 let rpc = rpc.clone();
                 let this = this.clone();
                 cx.spawn(|mut cx| async move {

crates/contacts_panel/src/contacts_panel.rs 🔗

@@ -13,8 +13,9 @@ use gpui::{
     geometry::{rect::RectF, vector::vec2f},
     impl_actions, impl_internal_actions,
     platform::CursorStyle,
-    AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle, MutableAppContext,
-    RenderContext, Subscription, View, ViewContext, ViewHandle, WeakModelHandle, WeakViewHandle,
+    AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle, MouseButton,
+    MutableAppContext, RenderContext, Subscription, View, ViewContext, ViewHandle, WeakModelHandle,
+    WeakViewHandle,
 };
 use join_project_notification::JoinProjectNotification;
 use menu::{Confirm, SelectNext, SelectPrev};
@@ -310,7 +311,9 @@ impl ContactsPanel {
                 .boxed()
         })
         .with_cursor_style(CursorStyle::PointingHand)
-        .on_click(move |_, _, cx| cx.dispatch_action(ToggleExpanded(section)))
+        .on_click(MouseButton::Left, move |_, cx| {
+            cx.dispatch_action(ToggleExpanded(section))
+        })
         .boxed()
     }
 
@@ -445,7 +448,7 @@ impl ContactsPanel {
                                 Some(
                                     button
                                         .with_cursor_style(CursorStyle::PointingHand)
-                                        .on_click(move |_, _, cx| {
+                                        .on_click(MouseButton::Left, move |_, cx| {
                                             cx.dispatch_action(ToggleProjectOnline {
                                                 project: Some(open_project.clone()),
                                             })
@@ -499,7 +502,7 @@ impl ContactsPanel {
         } else {
             CursorStyle::Arrow
         })
-        .on_click(move |_, _, cx| {
+        .on_click(MouseButton::Left, move |_, cx| {
             if !is_host {
                 cx.dispatch_global_action(JoinProject {
                     contact: contact.clone(),
@@ -563,7 +566,7 @@ impl ContactsPanel {
                     } else {
                         button
                             .with_cursor_style(CursorStyle::PointingHand)
-                            .on_click(move |_, _, cx| {
+                            .on_click(MouseButton::Left, move |_, cx| {
                                 let project = project_handle.upgrade(cx.deref_mut());
                                 cx.dispatch_action(ToggleProjectOnline { project })
                             })
@@ -646,7 +649,7 @@ impl ContactsPanel {
                         .boxed()
                 })
                 .with_cursor_style(CursorStyle::PointingHand)
-                .on_click(move |_, _, cx| {
+                .on_click(MouseButton::Left, move |_, cx| {
                     cx.dispatch_action(RespondToContactRequest {
                         user_id,
                         accept: false,
@@ -668,7 +671,7 @@ impl ContactsPanel {
                         .boxed()
                 })
                 .with_cursor_style(CursorStyle::PointingHand)
-                .on_click(move |_, _, cx| {
+                .on_click(MouseButton::Left, move |_, cx| {
                     cx.dispatch_action(RespondToContactRequest {
                         user_id,
                         accept: true,
@@ -691,7 +694,9 @@ impl ContactsPanel {
                 })
                 .with_padding(Padding::uniform(2.))
                 .with_cursor_style(CursorStyle::PointingHand)
-                .on_click(move |_, _, cx| cx.dispatch_action(RemoveContact(user_id)))
+                .on_click(MouseButton::Left, move |_, cx| {
+                    cx.dispatch_action(RemoveContact(user_id))
+                })
                 .flex_float()
                 .boxed(),
             );
@@ -1078,7 +1083,9 @@ impl View for ContactsPanel {
                                     .boxed()
                             })
                             .with_cursor_style(CursorStyle::PointingHand)
-                            .on_click(|_, _, cx| cx.dispatch_action(contact_finder::Toggle))
+                            .on_click(MouseButton::Left, |_, cx| {
+                                cx.dispatch_action(contact_finder::Toggle)
+                            })
                             .boxed(),
                         )
                         .constrained()
@@ -1126,7 +1133,7 @@ impl View for ContactsPanel {
                                         },
                                     )
                                     .with_cursor_style(CursorStyle::PointingHand)
-                                    .on_click(move |_, _, cx| {
+                                    .on_click(MouseButton::Left, move |_, cx| {
                                         cx.write_to_clipboard(ClipboardItem::new(
                                             info.url.to_string(),
                                         ));

crates/contacts_panel/src/notifications.rs 🔗

@@ -3,7 +3,7 @@ use client::User;
 use gpui::{
     elements::{Flex, Image, Label, MouseEventHandler, Padding, ParentElement, Text},
     platform::CursorStyle,
-    Action, Element, ElementBox, RenderContext, View,
+    Action, Element, ElementBox, MouseButton, RenderContext, View,
 };
 use settings::Settings;
 use std::sync::Arc;
@@ -61,7 +61,9 @@ pub fn render_user_notification<V: View, A: Action + Clone>(
                     })
                     .with_cursor_style(CursorStyle::PointingHand)
                     .with_padding(Padding::uniform(5.))
-                    .on_click(move |_, _, cx| cx.dispatch_any_action(dismiss_action.boxed_clone()))
+                    .on_click(MouseButton::Left, move |_, cx| {
+                        cx.dispatch_any_action(dismiss_action.boxed_clone())
+                    })
                     .aligned()
                     .constrained()
                     .with_height(
@@ -96,7 +98,9 @@ pub fn render_user_notification<V: View, A: Action + Clone>(
                                     .boxed()
                             })
                             .with_cursor_style(CursorStyle::PointingHand)
-                            .on_click(move |_, _, cx| cx.dispatch_any_action(action.boxed_clone()))
+                            .on_click(MouseButton::Left, move |_, cx| {
+                                cx.dispatch_any_action(action.boxed_clone())
+                            })
                             .boxed()
                         },
                     ))

crates/context_menu/src/context_menu.rs 🔗

@@ -1,7 +1,7 @@
 use gpui::{
     elements::*, geometry::vector::Vector2F, impl_internal_actions, keymap, platform::CursorStyle,
-    Action, AppContext, Axis, Entity, MutableAppContext, RenderContext, SizeConstraint,
-    Subscription, View, ViewContext,
+    Action, AppContext, Axis, Entity, MouseButton, MutableAppContext, RenderContext,
+    SizeConstraint, Subscription, View, ViewContext,
 };
 use menu::*;
 use settings::Settings;
@@ -337,7 +337,7 @@ impl ContextMenu {
                                     .boxed()
                             })
                             .with_cursor_style(CursorStyle::PointingHand)
-                            .on_click(move |_, _, cx| {
+                            .on_click(MouseButton::Left, move |_, cx| {
                                 cx.dispatch_action(Clicked);
                                 cx.dispatch_any_action(action.boxed_clone());
                             })
@@ -355,7 +355,7 @@ impl ContextMenu {
                 .with_style(style.container)
                 .boxed()
         })
-        .on_mouse_down_out(|_, cx| cx.dispatch_action(Cancel))
-        .on_right_mouse_down_out(|_, cx| cx.dispatch_action(Cancel))
+        .on_mouse_down_out(MouseButton::Left, |_, cx| cx.dispatch_action(Cancel))
+        .on_mouse_down_out(MouseButton::Right, |_, cx| cx.dispatch_action(Cancel))
     }
 }

crates/diagnostics/src/items.rs 🔗

@@ -1,8 +1,8 @@
 use collections::HashSet;
 use editor::{Editor, GoToNextDiagnostic};
 use gpui::{
-    elements::*, platform::CursorStyle, serde_json, Entity, ModelHandle, MutableAppContext,
-    RenderContext, Subscription, View, ViewContext, ViewHandle, WeakViewHandle,
+    elements::*, platform::CursorStyle, serde_json, Entity, ModelHandle, MouseButton,
+    MutableAppContext, RenderContext, Subscription, View, ViewContext, ViewHandle, WeakViewHandle,
 };
 use language::Diagnostic;
 use project::Project;
@@ -161,7 +161,7 @@ impl View for DiagnosticIndicator {
                     .boxed()
             })
             .with_cursor_style(CursorStyle::PointingHand)
-            .on_click(|_, _, cx| cx.dispatch_action(crate::Deploy))
+            .on_click(MouseButton::Left, |_, cx| cx.dispatch_action(crate::Deploy))
             .with_tooltip::<Summary, _>(
                 0,
                 "Project Diagnostics".to_string(),
@@ -201,7 +201,9 @@ impl View for DiagnosticIndicator {
                     .boxed()
                 })
                 .with_cursor_style(CursorStyle::PointingHand)
-                .on_click(|_, _, cx| cx.dispatch_action(GoToNextDiagnostic))
+                .on_click(MouseButton::Left, |_, cx| {
+                    cx.dispatch_action(GoToNextDiagnostic)
+                })
                 .boxed(),
             );
         }

crates/editor/src/editor.rs 🔗

@@ -30,8 +30,8 @@ use gpui::{
     impl_actions, impl_internal_actions,
     platform::CursorStyle,
     text_layout, AppContext, AsyncAppContext, ClipboardItem, Element, ElementBox, Entity,
-    ModelHandle, MutableAppContext, RenderContext, Subscription, Task, View, ViewContext,
-    ViewHandle, WeakViewHandle,
+    ModelHandle, MouseButton, MutableAppContext, RenderContext, Subscription, Task, View,
+    ViewContext, ViewHandle, WeakViewHandle,
 };
 use highlight_matching_bracket::refresh_matching_bracket_highlights;
 use hover_popover::{hide_hover, HoverState};
@@ -707,7 +707,7 @@ impl CompletionsMenu {
                             },
                         )
                         .with_cursor_style(CursorStyle::PointingHand)
-                        .on_mouse_down(move |_, cx| {
+                        .on_mouse_down(MouseButton::Left, move |_, cx| {
                             cx.dispatch_action(ConfirmCompletion {
                                 item_ix: Some(item_ix),
                             });
@@ -840,7 +840,7 @@ impl CodeActionsMenu {
                                 .boxed()
                         })
                         .with_cursor_style(CursorStyle::PointingHand)
-                        .on_mouse_down(move |_, cx| {
+                        .on_mouse_down(MouseButton::Left, move |_, cx| {
                             cx.dispatch_action(ConfirmCodeAction {
                                 item_ix: Some(item_ix),
                             });
@@ -2674,7 +2674,7 @@ impl Editor {
                 })
                 .with_cursor_style(CursorStyle::PointingHand)
                 .with_padding(Padding::uniform(3.))
-                .on_mouse_down(|_, cx| {
+                .on_mouse_down(MouseButton::Left, |_, cx| {
                     cx.dispatch_action(ToggleCodeActions {
                         deployed_from_indicator: true,
                     });

crates/editor/src/element.rs 🔗

@@ -25,7 +25,7 @@ use gpui::{
     platform::CursorStyle,
     text_layout::{self, Line, RunStyle, TextLayoutCache},
     AppContext, Axis, Border, CursorRegion, Element, ElementBox, Event, EventContext, KeyDownEvent,
-    LayoutContext, ModifiersChangedEvent, MouseButton, MouseEvent, MouseMovedEvent,
+    LayoutContext, ModifiersChangedEvent, MouseButton, MouseButtonEvent, MouseMovedEvent,
     MutableAppContext, PaintContext, Quad, Scene, ScrollWheelEvent, SizeConstraint, ViewContext,
     WeakViewHandle,
 };
@@ -968,7 +968,9 @@ impl EditorElement {
                                     .boxed()
                             })
                             .with_cursor_style(CursorStyle::PointingHand)
-                            .on_click(move |_, _, cx| cx.dispatch_action(jump_action.clone()))
+                            .on_click(MouseButton::Left, move |_, cx| {
+                                cx.dispatch_action(jump_action.clone())
+                            })
                             .with_tooltip::<JumpIcon, _>(
                                 *key,
                                 "Jump to Buffer".to_string(),
@@ -1483,7 +1485,7 @@ impl Element for EditorElement {
         }
 
         match event {
-            Event::MouseDown(MouseEvent {
+            Event::MouseDown(MouseButtonEvent {
                 button: MouseButton::Left,
                 position,
                 cmd,
@@ -1501,12 +1503,12 @@ impl Element for EditorElement {
                 paint,
                 cx,
             ),
-            Event::MouseDown(MouseEvent {
+            Event::MouseDown(MouseButtonEvent {
                 button: MouseButton::Right,
                 position,
                 ..
             }) => self.mouse_right_down(*position, layout, paint, cx),
-            Event::MouseUp(MouseEvent {
+            Event::MouseUp(MouseButtonEvent {
                 button: MouseButton::Left,
                 position,
                 ..

crates/gpui/src/app.rs 🔗

@@ -5401,7 +5401,7 @@ impl RefCounts {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::{actions, elements::*, impl_actions, MouseButton, MouseEvent};
+    use crate::{actions, elements::*, impl_actions, MouseButton, MouseButtonEvent};
     use serde::Deserialize;
     use smol::future::poll_once;
     use std::{
@@ -5754,7 +5754,7 @@ mod tests {
         let presenter = cx.presenters_and_platform_windows[&window_id].0.clone();
         // Ensure window's root element is in a valid lifecycle state.
         presenter.borrow_mut().dispatch_event(
-            Event::MouseDown(MouseEvent {
+            Event::MouseDown(MouseButtonEvent {
                 position: Default::default(),
                 button: MouseButton::Left,
                 ctrl: false,

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

@@ -1,11 +1,11 @@
 use crate::{
     geometry::vector::Vector2F, CursorRegion, DebugContext, Element, ElementBox, Event,
-    EventContext, LayoutContext, MouseButton, MouseEvent, MouseRegion, NavigationDirection,
+    EventContext, LayoutContext, MouseButton, MouseButtonEvent, MouseRegion, NavigationDirection,
     PaintContext, SizeConstraint,
 };
 use pathfinder_geometry::rect::RectF;
 use serde_json::json;
-use std::{any::TypeId, rc::Rc};
+use std::any::TypeId;
 
 pub struct EventHandler {
     child: ElementBox,
@@ -82,19 +82,11 @@ impl Element for EventHandler {
                 bounds: visible_bounds,
                 style: Default::default(),
             });
-            cx.scene.push_mouse_region(MouseRegion {
-                view_id: cx.current_view_id(),
-                discriminant: Some(discriminant),
-                bounds: visible_bounds,
-                hover: Some(Rc::new(|_, _, _| {})),
-                mouse_down: Some(Rc::new(|_, _| {})),
-                click: Some(Rc::new(|_, _, _| {})),
-                right_mouse_down: Some(Rc::new(|_, _| {})),
-                right_click: Some(Rc::new(|_, _, _| {})),
-                drag: Some(Rc::new(|_, _, _| {})),
-                mouse_down_out: Some(Rc::new(|_, _| {})),
-                right_mouse_down_out: Some(Rc::new(|_, _| {})),
-            });
+            cx.scene.push_mouse_region(MouseRegion::handle_all(
+                cx.current_view_id(),
+                Some(discriminant),
+                visible_bounds,
+            ));
             cx.scene.pop_stacking_context();
         }
         self.child.paint(bounds.origin(), visible_bounds, cx);
@@ -117,7 +109,7 @@ impl Element for EventHandler {
             true
         } else {
             match event {
-                Event::MouseDown(MouseEvent {
+                Event::MouseDown(MouseButtonEvent {
                     button: MouseButton::Left,
                     position,
                     ..
@@ -129,7 +121,7 @@ impl Element for EventHandler {
                     }
                     false
                 }
-                Event::MouseDown(MouseEvent {
+                Event::MouseDown(MouseButtonEvent {
                     button: MouseButton::Right,
                     position,
                     ..
@@ -141,7 +133,7 @@ impl Element for EventHandler {
                     }
                     false
                 }
-                Event::MouseDown(MouseEvent {
+                Event::MouseDown(MouseButtonEvent {
                     button: MouseButton::Navigate(direction),
                     position,
                     ..

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

@@ -1,4 +1,4 @@
-use std::{any::TypeId, rc::Rc};
+use std::any::TypeId;
 
 use super::Padding;
 use crate::{
@@ -8,24 +8,16 @@ use crate::{
     },
     platform::CursorStyle,
     scene::CursorRegion,
-    DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, MouseRegion, MouseState,
-    PaintContext, RenderContext, SizeConstraint, View,
+    DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, MouseButton,
+    MouseButtonEvent, MouseMovedEvent, MouseRegion, MouseState, PaintContext, RenderContext,
+    SizeConstraint, View,
 };
 use serde_json::json;
 
 pub struct MouseEventHandler {
     child: ElementBox,
-    tag: TypeId,
-    id: usize,
     cursor_style: Option<CursorStyle>,
-    mouse_down: Option<Rc<dyn Fn(Vector2F, &mut EventContext)>>,
-    click: Option<Rc<dyn Fn(Vector2F, usize, &mut EventContext)>>,
-    right_mouse_down: Option<Rc<dyn Fn(Vector2F, &mut EventContext)>>,
-    right_click: Option<Rc<dyn Fn(Vector2F, usize, &mut EventContext)>>,
-    mouse_down_out: Option<Rc<dyn Fn(Vector2F, &mut EventContext)>>,
-    right_mouse_down_out: Option<Rc<dyn Fn(Vector2F, &mut EventContext)>>,
-    drag: Option<Rc<dyn Fn(Vector2F, Vector2F, &mut EventContext)>>,
-    hover: Option<Rc<dyn Fn(Vector2F, bool, &mut EventContext)>>,
+    region: MouseRegion,
     padding: Padding,
 }
 
@@ -37,18 +29,9 @@ impl MouseEventHandler {
         F: FnOnce(MouseState, &mut RenderContext<V>) -> ElementBox,
     {
         Self {
-            id,
-            tag: TypeId::of::<Tag>(),
             child: render_child(cx.mouse_state::<Tag>(id), cx),
             cursor_style: None,
-            mouse_down: None,
-            click: None,
-            right_mouse_down: None,
-            right_click: None,
-            mouse_down_out: None,
-            right_mouse_down_out: None,
-            drag: None,
-            hover: None,
+            region: MouseRegion::new(0, Some((TypeId::of::<Tag>(), id)), Default::default()),
             padding: Default::default(),
         }
     }
@@ -60,65 +43,45 @@ impl MouseEventHandler {
 
     pub fn on_mouse_down(
         mut self,
-        handler: impl Fn(Vector2F, &mut EventContext) + 'static,
+        button: MouseButton,
+        handler: impl Fn(MouseButtonEvent, &mut EventContext) + 'static,
     ) -> Self {
-        self.mouse_down = Some(Rc::new(handler));
+        self.region = self.region.on_down(button, handler);
         self
     }
 
     pub fn on_click(
         mut self,
-        handler: impl Fn(Vector2F, usize, &mut EventContext) + 'static,
+        button: MouseButton,
+        handler: impl Fn(MouseButtonEvent, &mut EventContext) + 'static,
     ) -> Self {
-        self.click = Some(Rc::new(handler));
-        self
-    }
-
-    pub fn on_right_mouse_down(
-        mut self,
-        handler: impl Fn(Vector2F, &mut EventContext) + 'static,
-    ) -> Self {
-        self.right_mouse_down = Some(Rc::new(handler));
-        self
-    }
-
-    pub fn on_right_click(
-        mut self,
-        handler: impl Fn(Vector2F, usize, &mut EventContext) + 'static,
-    ) -> Self {
-        self.right_click = Some(Rc::new(handler));
+        self.region = self.region.on_click(button, handler);
         self
     }
 
     pub fn on_mouse_down_out(
         mut self,
-        handler: impl Fn(Vector2F, &mut EventContext) + 'static,
-    ) -> Self {
-        self.mouse_down_out = Some(Rc::new(handler));
-        self
-    }
-
-    pub fn on_right_mouse_down_out(
-        mut self,
-        handler: impl Fn(Vector2F, &mut EventContext) + 'static,
+        button: MouseButton,
+        handler: impl Fn(MouseButtonEvent, &mut EventContext) + 'static,
     ) -> Self {
-        self.right_mouse_down_out = Some(Rc::new(handler));
+        self.region = self.region.on_down_out(button, handler);
         self
     }
 
     pub fn on_drag(
         mut self,
-        handler: impl Fn(Vector2F, Vector2F, &mut EventContext) + 'static,
+        button: MouseButton,
+        handler: impl Fn(Vector2F, MouseMovedEvent, &mut EventContext) + 'static,
     ) -> Self {
-        self.drag = Some(Rc::new(handler));
+        self.region = self.region.on_drag(button, handler);
         self
     }
 
     pub fn on_hover(
         mut self,
-        handler: impl Fn(Vector2F, bool, &mut EventContext) + 'static,
+        handler: impl Fn(bool, MouseMovedEvent, &mut EventContext) + 'static,
     ) -> Self {
-        self.hover = Some(Rc::new(handler));
+        self.region = self.region.on_hover(handler);
         self
     }
 
@@ -163,19 +126,9 @@ impl Element for MouseEventHandler {
             });
         }
 
-        cx.scene.push_mouse_region(MouseRegion {
-            view_id: cx.current_view_id(),
-            discriminant: Some((self.tag, self.id)),
-            bounds: hit_bounds,
-            hover: self.hover.clone(),
-            click: self.click.clone(),
-            mouse_down: self.mouse_down.clone(),
-            right_click: self.right_click.clone(),
-            right_mouse_down: self.right_mouse_down.clone(),
-            mouse_down_out: self.mouse_down_out.clone(),
-            right_mouse_down_out: self.right_mouse_down_out.clone(),
-            drag: self.drag.clone(),
-        });
+        self.region.view_id = cx.current_view_id();
+        self.region.bounds = hit_bounds;
+        cx.scene.push_mouse_region(self.region.clone());
 
         self.child.paint(bounds.origin(), visible_bounds, cx);
     }

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

@@ -6,8 +6,8 @@ use crate::{
     fonts::TextStyle,
     geometry::{rect::RectF, vector::Vector2F},
     json::json,
-    Action, Axis, ElementStateHandle, LayoutContext, PaintContext, RenderContext, SizeConstraint,
-    Task, View,
+    Action, Axis, ElementStateHandle, LayoutContext, MouseMovedEvent, PaintContext, RenderContext,
+    SizeConstraint, Task, View,
 };
 use serde::Deserialize;
 use std::{
@@ -91,7 +91,7 @@ impl Tooltip {
         };
         let child =
             MouseEventHandler::new::<MouseEventHandlerState<Tag>, _, _>(id, cx, |_, _| child)
-                .on_hover(move |position, hover, cx| {
+                .on_hover(move |hover, MouseMovedEvent { position, .. }, cx| {
                     let window_id = cx.window_id();
                     if let Some(view_id) = cx.view_id() {
                         if hover {

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

@@ -21,20 +21,26 @@ pub struct ModifiersChangedEvent {
     pub cmd: bool,
 }
 
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Default)]
 pub struct ScrollWheelEvent {
     pub position: Vector2F,
     pub delta: Vector2F,
     pub precise: bool,
 }
 
-#[derive(Copy, Clone, Debug)]
+#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
 pub enum NavigationDirection {
     Back,
     Forward,
 }
 
-#[derive(Copy, Clone, Debug)]
+impl Default for NavigationDirection {
+    fn default() -> Self {
+        Self::Back
+    }
+}
+
+#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
 pub enum MouseButton {
     Left,
     Right,
@@ -42,8 +48,26 @@ pub enum MouseButton {
     Navigate(NavigationDirection),
 }
 
-#[derive(Clone, Debug)]
-pub struct MouseEvent {
+impl MouseButton {
+    pub fn all() -> Vec<Self> {
+        vec![
+            MouseButton::Left,
+            MouseButton::Right,
+            MouseButton::Middle,
+            MouseButton::Navigate(NavigationDirection::Back),
+            MouseButton::Navigate(NavigationDirection::Forward),
+        ]
+    }
+}
+
+impl Default for MouseButton {
+    fn default() -> Self {
+        Self::Left
+    }
+}
+
+#[derive(Clone, Debug, Default)]
+pub struct MouseButtonEvent {
     pub button: MouseButton,
     pub position: Vector2F,
     pub ctrl: bool,
@@ -53,7 +77,7 @@ pub struct MouseEvent {
     pub click_count: usize,
 }
 
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, Default)]
 pub struct MouseMovedEvent {
     pub position: Vector2F,
     pub pressed_button: Option<MouseButton>,
@@ -68,8 +92,8 @@ pub enum Event {
     KeyDown(KeyDownEvent),
     KeyUp(KeyUpEvent),
     ModifiersChanged(ModifiersChangedEvent),
-    MouseDown(MouseEvent),
-    MouseUp(MouseEvent),
+    MouseDown(MouseButtonEvent),
+    MouseUp(MouseButtonEvent),
     MouseMoved(MouseMovedEvent),
     ScrollWheel(ScrollWheelEvent),
 }

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

@@ -2,8 +2,8 @@ use crate::{
     geometry::vector::vec2f,
     keymap::Keystroke,
     platform::{Event, NavigationDirection},
-    KeyDownEvent, KeyUpEvent, ModifiersChangedEvent, MouseButton, MouseEvent, MouseMovedEvent,
-    ScrollWheelEvent,
+    KeyDownEvent, KeyUpEvent, ModifiersChangedEvent, MouseButton, MouseButtonEvent,
+    MouseMovedEvent, ScrollWheelEvent,
 };
 use cocoa::{
     appkit::{NSEvent, NSEventModifierFlags, NSEventType},
@@ -126,7 +126,7 @@ impl Event {
                 let modifiers = native_event.modifierFlags();
 
                 window_height.map(|window_height| {
-                    Self::MouseDown(MouseEvent {
+                    Self::MouseDown(MouseButtonEvent {
                         button,
                         position: vec2f(
                             native_event.locationInWindow().x as f32,
@@ -155,7 +155,7 @@ impl Event {
 
                 window_height.map(|window_height| {
                     let modifiers = native_event.modifierFlags();
-                    Self::MouseUp(MouseEvent {
+                    Self::MouseUp(MouseButtonEvent {
                         button,
                         position: vec2f(
                             native_event.locationInWindow().x as f32,

crates/gpui/src/platform/mac/window.rs 🔗

@@ -6,7 +6,7 @@ use crate::{
     },
     keymap::Keystroke,
     platform::{self, Event, WindowBounds, WindowContext},
-    KeyDownEvent, ModifiersChangedEvent, MouseButton, MouseEvent, MouseMovedEvent, Scene,
+    KeyDownEvent, ModifiersChangedEvent, MouseButton, MouseButtonEvent, MouseMovedEvent, Scene,
 };
 use block::ConcreteBlock;
 use cocoa::{
@@ -635,7 +635,7 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
                     ))
                     .detach();
             }
-            Event::MouseUp(MouseEvent {
+            Event::MouseUp(MouseButtonEvent {
                 button: MouseButton::Left,
                 ..
             }) => {

crates/gpui/src/presenter.rs 🔗

@@ -6,10 +6,10 @@ use crate::{
     json::{self, ToJson},
     keymap::Keystroke,
     platform::{CursorStyle, Event},
-    scene::CursorRegion,
+    scene::{CursorRegion, MouseRegionEvent},
     text_layout::TextLayoutCache,
     Action, AnyModelHandle, AnyViewHandle, AnyWeakModelHandle, AssetCache, ElementBox, Entity,
-    FontSystem, ModelHandle, MouseButton, MouseEvent, MouseMovedEvent, MouseRegion, MouseRegionId,
+    FontSystem, ModelHandle, MouseButtonEvent, MouseMovedEvent, MouseRegion, MouseRegionId,
     ReadModel, ReadView, RenderContext, RenderParams, Scene, UpgradeModelHandle, UpgradeViewHandle,
     View, ViewHandle, WeakModelHandle, WeakViewHandle,
 };
@@ -230,105 +230,58 @@ impl Presenter {
             let mut mouse_down_out_handlers = Vec::new();
             let mut mouse_down_region = None;
             let mut clicked_region = None;
-            let mut right_mouse_down_region = None;
-            let mut right_clicked_region = None;
             let mut dragged_region = None;
 
-            match event {
-                Event::MouseDown(MouseEvent {
-                    position,
-                    button: MouseButton::Left,
-                    ..
-                }) => {
+            match &event {
+                Event::MouseDown(
+                    e @ MouseButtonEvent {
+                        position, button, ..
+                    },
+                ) => {
                     let mut hit = false;
                     for (region, _) in self.mouse_regions.iter().rev() {
-                        if region.bounds.contains_point(position) {
+                        if region.bounds.contains_point(*position) {
                             if !hit {
                                 hit = true;
                                 invalidated_views.push(region.view_id);
-                                mouse_down_region = Some((region.clone(), position));
+                                mouse_down_region =
+                                    Some((region.clone(), MouseRegionEvent::Down(e.clone())));
                                 self.clicked_region = Some(region.clone());
-                                self.prev_drag_position = Some(position);
+                                self.prev_drag_position = Some(*position);
                             }
-                        } else if let Some(handler) = region.mouse_down_out.clone() {
-                            mouse_down_out_handlers.push((handler, region.view_id, position));
+                        } else if let Some(handler) = region
+                            .handlers
+                            .get(&(MouseRegionEvent::down_out_disc(), Some(*button)))
+                            .cloned()
+                        {
+                            mouse_down_out_handlers.push((
+                                handler,
+                                region.view_id,
+                                MouseRegionEvent::DownOut(e.clone()),
+                            ));
                         }
                     }
                 }
-                Event::MouseUp(MouseEvent {
-                    position,
-                    click_count,
-                    button: MouseButton::Left,
-                    ..
-                }) => {
+                Event::MouseUp(e @ MouseButtonEvent { position, .. }) => {
                     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, position, click_count));
-                        }
-                    }
-                }
-                Event::MouseDown(MouseEvent {
-                    position,
-                    button: MouseButton::Right,
-                    ..
-                }) => {
-                    let mut hit = false;
-                    for (region, _) in self.mouse_regions.iter().rev() {
-                        if region.bounds.contains_point(position) {
-                            if !hit {
-                                hit = true;
-                                invalidated_views.push(region.view_id);
-                                right_mouse_down_region = Some((region.clone(), position));
-                                self.right_clicked_region = Some(region.clone());
-                            }
-                        } else if let Some(handler) = region.right_mouse_down_out.clone() {
-                            mouse_down_out_handlers.push((handler, region.view_id, position));
-                        }
-                    }
-                }
-                Event::MouseUp(MouseEvent {
-                    position,
-                    click_count,
-                    button: MouseButton::Right,
-                    ..
-                }) => {
-                    if let Some(region) = self.right_clicked_region.take() {
-                        invalidated_views.push(region.view_id);
-                        if region.bounds.contains_point(position) {
-                            right_clicked_region = Some((region, position, click_count));
+                        if region.bounds.contains_point(*position) {
+                            clicked_region = Some((region, MouseRegionEvent::Click(e.clone())));
                         }
                     }
                 }
-                Event::MouseMoved(MouseMovedEvent {
-                    pressed_button,
-                    position,
-                    shift,
-                    ctrl,
-                    alt,
-                    cmd,
-                    ..
-                }) => {
-                    if let Some(MouseButton::Left) = pressed_button {
-                        if let Some((clicked_region, prev_drag_position)) = self
-                            .clicked_region
-                            .as_ref()
-                            .zip(self.prev_drag_position.as_mut())
-                        {
-                            dragged_region =
-                                Some((clicked_region.clone(), *prev_drag_position, position));
-                            *prev_drag_position = position;
-                        }
-
-                        self.last_mouse_moved_event = Some(Event::MouseMoved(MouseMovedEvent {
-                            position,
-                            pressed_button: Some(MouseButton::Left),
-                            shift,
-                            ctrl,
-                            alt,
-                            cmd,
-                        }));
+                Event::MouseMoved(e @ MouseMovedEvent { position, .. }) => {
+                    if let Some((clicked_region, prev_drag_position)) = self
+                        .clicked_region
+                        .as_ref()
+                        .zip(self.prev_drag_position.as_mut())
+                    {
+                        dragged_region = Some((
+                            clicked_region.clone(),
+                            MouseRegionEvent::Drag(*prev_drag_position, e.clone()),
+                        ));
+                        *prev_drag_position = *position;
                     }
 
                     self.last_mouse_moved_event = Some(event.clone());
@@ -339,51 +292,39 @@ impl Presenter {
             let (mut handled, mut event_cx) =
                 self.handle_hover_events(&event, &mut invalidated_views, cx);
 
-            for (handler, view_id, position) in mouse_down_out_handlers {
-                event_cx.with_current_view(view_id, |event_cx| handler(position, event_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, position)) = mouse_down_region {
+            if let Some((mouse_down_region, region_event)) = mouse_down_region {
                 handled = true;
-                if let Some(mouse_down_callback) = mouse_down_region.mouse_down {
+                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(position, event_cx);
+                        mouse_down_callback(region_event, event_cx);
                     })
                 }
             }
 
-            if let Some((clicked_region, position, click_count)) = clicked_region {
+            if let Some((clicked_region, region_event)) = clicked_region {
                 handled = true;
-                if let Some(click_callback) = clicked_region.click {
+                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(position, click_count, event_cx);
-                    })
-                }
-            }
-
-            if let Some((right_mouse_down_region, position)) = right_mouse_down_region {
-                handled = true;
-                if let Some(right_mouse_down_callback) = right_mouse_down_region.right_mouse_down {
-                    event_cx.with_current_view(right_mouse_down_region.view_id, |event_cx| {
-                        right_mouse_down_callback(position, event_cx);
-                    })
-                }
-            }
-
-            if let Some((right_clicked_region, position, click_count)) = right_clicked_region {
-                handled = true;
-                if let Some(right_click_callback) = right_clicked_region.right_click {
-                    event_cx.with_current_view(right_clicked_region.view_id, |event_cx| {
-                        right_click_callback(position, click_count, event_cx);
+                        click_callback(region_event, event_cx);
                     })
                 }
             }
 
-            if let Some((dragged_region, prev_position, position)) = dragged_region {
+            if let Some((dragged_region, region_event)) = dragged_region {
                 handled = true;
-                if let Some(drag_callback) = dragged_region.drag {
+                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(prev_position, position, event_cx);
+                        drag_callback(region_event, event_cx);
                     })
                 }
             }
@@ -420,14 +361,17 @@ impl Presenter {
         invalidated_views: &mut Vec<usize>,
         cx: &'a mut MutableAppContext,
     ) -> (bool, EventContext<'a>) {
-        let mut unhovered_regions = Vec::new();
-        let mut hovered_regions = Vec::new();
-
-        if let Event::MouseMoved(MouseMovedEvent {
-            position,
-            pressed_button,
-            ..
-        }) = event
+        let mut hover_regions = Vec::new();
+        // let mut unhovered_regions = Vec::new();
+        // let mut hovered_regions = Vec::new();
+
+        if let Event::MouseMoved(
+            e @ MouseMovedEvent {
+                position,
+                pressed_button,
+                ..
+            },
+        ) = event
         {
             if let None = pressed_button {
                 let mut style_to_assign = CursorStyle::Arrow;
@@ -448,7 +392,10 @@ impl Presenter {
                         if let Some(region_id) = region.id() {
                             if !self.hovered_region_ids.contains(&region_id) {
                                 invalidated_views.push(region.view_id);
-                                hovered_regions.push((region.clone(), position));
+                                hover_regions.push((
+                                    region.clone(),
+                                    MouseRegionEvent::Hover(true, e.clone()),
+                                ));
                                 self.hovered_region_ids.insert(region_id);
                             }
                         }
@@ -456,7 +403,10 @@ impl Presenter {
                         if let Some(region_id) = region.id() {
                             if self.hovered_region_ids.contains(&region_id) {
                                 invalidated_views.push(region.view_id);
-                                unhovered_regions.push((region.clone(), position));
+                                hover_regions.push((
+                                    region.clone(),
+                                    MouseRegionEvent::Hover(false, e.clone()),
+                                ));
                                 self.hovered_region_ids.remove(&region_id);
                             }
                         }
@@ -468,20 +418,11 @@ impl Presenter {
         let mut event_cx = self.build_event_context(cx);
         let mut handled = false;
 
-        for (unhovered_region, position) in unhovered_regions {
-            handled = true;
-            if let Some(hover_callback) = unhovered_region.hover {
-                event_cx.with_current_view(unhovered_region.view_id, |event_cx| {
-                    hover_callback(*position, false, event_cx);
-                })
-            }
-        }
-
-        for (hovered_region, position) in hovered_regions {
+        for (hover_region, region_event) in hover_regions {
             handled = true;
-            if let Some(hover_callback) = hovered_region.hover {
-                event_cx.with_current_view(hovered_region.view_id, |event_cx| {
-                    hover_callback(*position, true, event_cx);
+            if let Some(hover_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);
                 })
             }
         }

crates/gpui/src/scene.rs 🔗

@@ -1,6 +1,7 @@
+use collections::HashMap;
 use serde::Deserialize;
 use serde_json::json;
-use std::{any::TypeId, borrow::Cow, rc::Rc, sync::Arc};
+use std::{any::TypeId, borrow::Cow, mem::Discriminant, rc::Rc, sync::Arc};
 
 use crate::{
     color::Color,
@@ -8,7 +9,7 @@ use crate::{
     geometry::{rect::RectF, vector::Vector2F},
     json::ToJson,
     platform::CursorStyle,
-    EventContext, ImageData, MouseEvent, MouseMovedEvent, ScrollWheelEvent,
+    EventContext, ImageData, MouseButton, MouseButtonEvent, MouseMovedEvent, ScrollWheelEvent,
 };
 
 pub struct Scene {
@@ -44,30 +45,247 @@ pub struct CursorRegion {
     pub style: CursorStyle,
 }
 
+#[derive(Debug)]
 pub enum MouseRegionEvent {
-    Moved(MouseMovedEvent),
-    Hover(MouseEvent),
-    Down(MouseEvent),
-    Up(MouseEvent),
-    Click(MouseEvent),
-    DownOut(MouseEvent),
+    Move(MouseMovedEvent),
+    Drag(Vector2F, MouseMovedEvent),
+    Hover(bool, MouseMovedEvent),
+    Down(MouseButtonEvent),
+    Up(MouseButtonEvent),
+    Click(MouseButtonEvent),
+    DownOut(MouseButtonEvent),
     ScrollWheel(ScrollWheelEvent),
 }
 
+impl MouseRegionEvent {
+    pub fn move_disc() -> Discriminant<MouseRegionEvent> {
+        std::mem::discriminant(&MouseRegionEvent::Move(Default::default()))
+    }
+    pub fn drag_disc() -> Discriminant<MouseRegionEvent> {
+        std::mem::discriminant(&MouseRegionEvent::Drag(
+            Default::default(),
+            Default::default(),
+        ))
+    }
+    pub fn hover_disc() -> Discriminant<MouseRegionEvent> {
+        std::mem::discriminant(&MouseRegionEvent::Hover(
+            Default::default(),
+            Default::default(),
+        ))
+    }
+    pub fn down_disc() -> Discriminant<MouseRegionEvent> {
+        std::mem::discriminant(&MouseRegionEvent::Down(Default::default()))
+    }
+    pub fn up_disc() -> Discriminant<MouseRegionEvent> {
+        std::mem::discriminant(&MouseRegionEvent::Up(Default::default()))
+    }
+    pub fn click_disc() -> Discriminant<MouseRegionEvent> {
+        std::mem::discriminant(&MouseRegionEvent::Click(Default::default()))
+    }
+    pub fn down_out_disc() -> Discriminant<MouseRegionEvent> {
+        std::mem::discriminant(&MouseRegionEvent::DownOut(Default::default()))
+    }
+    pub fn scroll_wheel_disc() -> Discriminant<MouseRegionEvent> {
+        std::mem::discriminant(&MouseRegionEvent::ScrollWheel(Default::default()))
+    }
+
+    pub fn handler_key(&self) -> (Discriminant<MouseRegionEvent>, Option<MouseButton>) {
+        match self {
+            MouseRegionEvent::Move(_) => (Self::move_disc(), None),
+            MouseRegionEvent::Drag(_, MouseMovedEvent { pressed_button, .. }) => {
+                (Self::drag_disc(), *pressed_button)
+            }
+            MouseRegionEvent::Hover(_, _) => (Self::hover_disc(), None),
+            MouseRegionEvent::Down(MouseButtonEvent { button, .. }) => {
+                (Self::down_disc(), Some(*button))
+            }
+            MouseRegionEvent::Up(MouseButtonEvent { button, .. }) => {
+                (Self::up_disc(), Some(*button))
+            }
+            MouseRegionEvent::Click(MouseButtonEvent { button, .. }) => {
+                (Self::click_disc(), Some(*button))
+            }
+            MouseRegionEvent::DownOut(MouseButtonEvent { button, .. }) => {
+                (Self::down_out_disc(), Some(*button))
+            }
+            MouseRegionEvent::ScrollWheel(_) => (Self::scroll_wheel_disc(), None),
+        }
+    }
+}
+
 #[derive(Clone, Default)]
 pub struct MouseRegion {
     pub view_id: usize,
     pub discriminant: Option<(TypeId, usize)>,
     pub bounds: RectF,
+    pub handlers: HashMap<
+        (Discriminant<MouseRegionEvent>, Option<MouseButton>),
+        Rc<dyn Fn(MouseRegionEvent, &mut EventContext)>,
+    >,
+}
+
+impl MouseRegion {
+    pub fn new(view_id: usize, discriminant: Option<(TypeId, usize)>, bounds: RectF) -> Self {
+        Self {
+            view_id,
+            discriminant,
+            bounds,
+            handlers: Default::default(),
+        }
+    }
+
+    pub fn handle_all(
+        view_id: usize,
+        discriminant: Option<(TypeId, usize)>,
+        bounds: RectF,
+    ) -> Self {
+        let mut handlers: HashMap<
+            (Discriminant<MouseRegionEvent>, Option<MouseButton>),
+            Rc<dyn Fn(MouseRegionEvent, &mut EventContext)>,
+        > = Default::default();
+        handlers.insert((MouseRegionEvent::move_disc(), None), Rc::new(|_, _| {}));
+        handlers.insert((MouseRegionEvent::hover_disc(), None), Rc::new(|_, _| {}));
+        for button in MouseButton::all() {
+            handlers.insert(
+                (MouseRegionEvent::drag_disc(), Some(button)),
+                Rc::new(|_, _| {}),
+            );
+            handlers.insert(
+                (MouseRegionEvent::down_disc(), Some(button)),
+                Rc::new(|_, _| {}),
+            );
+            handlers.insert(
+                (MouseRegionEvent::up_disc(), Some(button)),
+                Rc::new(|_, _| {}),
+            );
+            handlers.insert(
+                (MouseRegionEvent::click_disc(), Some(button)),
+                Rc::new(|_, _| {}),
+            );
+            handlers.insert(
+                (MouseRegionEvent::down_out_disc(), Some(button)),
+                Rc::new(|_, _| {}),
+            );
+        }
+        handlers.insert(
+            (MouseRegionEvent::scroll_wheel_disc(), None),
+            Rc::new(|_, _| {}),
+        );
 
-    pub hover: Option<Rc<dyn Fn(Vector2F, bool, &mut EventContext)>>,
-    pub mouse_down: Option<Rc<dyn Fn(Vector2F, &mut EventContext)>>,
-    pub click: Option<Rc<dyn Fn(Vector2F, usize, &mut EventContext)>>,
-    pub right_mouse_down: Option<Rc<dyn Fn(Vector2F, &mut EventContext)>>,
-    pub right_click: Option<Rc<dyn Fn(Vector2F, usize, &mut EventContext)>>,
-    pub drag: Option<Rc<dyn Fn(Vector2F, Vector2F, &mut EventContext)>>,
-    pub mouse_down_out: Option<Rc<dyn Fn(Vector2F, &mut EventContext)>>,
-    pub right_mouse_down_out: Option<Rc<dyn Fn(Vector2F, &mut EventContext)>>,
+        Self {
+            view_id,
+            discriminant,
+            bounds,
+            handlers,
+        }
+    }
+
+    pub fn on_down(
+        mut self,
+        button: MouseButton,
+        handler: impl Fn(MouseButtonEvent, &mut EventContext) + 'static,
+    ) -> Self {
+        self.handlers.insert((MouseRegionEvent::down_disc(), Some(button)),
+            Rc::new(move |region_event, cx| {
+                if let MouseRegionEvent::Down(mouse_button_event) = region_event {
+                    handler(mouse_button_event, cx);
+                } else {
+                    panic!(
+                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Down, found {:?}", 
+                        region_event);
+                }
+            }));
+        self
+    }
+
+    pub fn on_up(
+        mut self,
+        button: MouseButton,
+        handler: impl Fn(MouseButtonEvent, &mut EventContext) + 'static,
+    ) -> Self {
+        self.handlers.insert((MouseRegionEvent::up_disc(), Some(button)),
+            Rc::new(move |region_event, cx| {
+                if let MouseRegionEvent::Up(mouse_button_event) = region_event {
+                    handler(mouse_button_event, cx);
+                } else {
+                    panic!(
+                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Up, found {:?}", 
+                        region_event);
+                }
+            }));
+        self
+    }
+
+    pub fn on_click(
+        mut self,
+        button: MouseButton,
+        handler: impl Fn(MouseButtonEvent, &mut EventContext) + 'static,
+    ) -> Self {
+        self.handlers.insert((MouseRegionEvent::click_disc(), Some(button)),
+            Rc::new(move |region_event, cx| {
+                if let MouseRegionEvent::Click(mouse_button_event) = region_event {
+                    handler(mouse_button_event, cx);
+                } else {
+                    panic!(
+                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Click, found {:?}", 
+                        region_event);
+                }
+            }));
+        self
+    }
+
+    pub fn on_down_out(
+        mut self,
+        button: MouseButton,
+        handler: impl Fn(MouseButtonEvent, &mut EventContext) + 'static,
+    ) -> Self {
+        self.handlers.insert((MouseRegionEvent::down_out_disc(), Some(button)),
+            Rc::new(move |region_event, cx| {
+                if let MouseRegionEvent::DownOut(mouse_button_event) = region_event {
+                    handler(mouse_button_event, cx);
+                } else {
+                    panic!(
+                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::DownOut, found {:?}", 
+                        region_event);
+                }
+            }));
+        self
+    }
+
+    pub fn on_drag(
+        mut self,
+        button: MouseButton,
+        handler: impl Fn(Vector2F, MouseMovedEvent, &mut EventContext) + 'static,
+    ) -> Self {
+        self.handlers.insert((MouseRegionEvent::drag_disc(), Some(button)),
+            Rc::new(move |region_event, cx| {
+                if let MouseRegionEvent::Drag(prev_drag_position, mouse_moved_event) = region_event {
+                    handler(prev_drag_position, mouse_moved_event, cx);
+                } else {
+                    panic!(
+                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Drag, found {:?}", 
+                        region_event);
+                }
+            }));
+        self
+    }
+
+    pub fn on_hover(
+        mut self,
+        handler: impl Fn(bool, MouseMovedEvent, &mut EventContext) + 'static,
+    ) -> Self {
+        self.handlers.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);
+                } else {
+                    panic!(
+                        "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Hover, found {:?}", 
+                        region_event);
+                }
+            }));
+        self
+    }
 }
 
 #[derive(Copy, Clone, Eq, PartialEq, Hash)]

crates/gpui/src/views/select.rs 🔗

@@ -1,8 +1,8 @@
 use serde::Deserialize;
 
 use crate::{
-    actions, elements::*, impl_actions, AppContext, Entity, MutableAppContext, RenderContext, View,
-    ViewContext, WeakViewHandle,
+    actions, elements::*, impl_actions, AppContext, Entity, MouseButton, MutableAppContext,
+    RenderContext, View, ViewContext, WeakViewHandle,
 };
 
 pub struct Select {
@@ -119,7 +119,9 @@ impl View for Select {
                 .with_style(style.header)
                 .boxed()
             })
-            .on_click(move |_, _, cx| cx.dispatch_action(ToggleSelect))
+            .on_click(MouseButton::Left, move |_, cx| {
+                cx.dispatch_action(ToggleSelect)
+            })
             .boxed(),
         );
         if self.is_open {
@@ -151,7 +153,7 @@ impl View for Select {
                                                 )
                                             },
                                         )
-                                        .on_click(move |_, _, cx| {
+                                        .on_click(MouseButton::Left, move |_, cx| {
                                             cx.dispatch_action(SelectItem(ix))
                                         })
                                         .boxed()

crates/picker/src/picker.rs 🔗

@@ -7,8 +7,8 @@ use gpui::{
     geometry::vector::{vec2f, Vector2F},
     keymap,
     platform::CursorStyle,
-    AppContext, Axis, Element, ElementBox, Entity, MouseState, MutableAppContext, RenderContext,
-    Task, View, ViewContext, ViewHandle, WeakViewHandle,
+    AppContext, Axis, Element, ElementBox, Entity, MouseButton, MouseState, MutableAppContext,
+    RenderContext, Task, View, ViewContext, ViewHandle, WeakViewHandle,
 };
 use menu::{Cancel, Confirm, SelectFirst, SelectIndex, SelectLast, SelectNext, SelectPrev};
 use settings::Settings;
@@ -90,7 +90,9 @@ impl<D: PickerDelegate> View for Picker<D> {
                                         .read(cx)
                                         .render_match(ix, state, ix == selected_ix, cx)
                                 })
-                                .on_mouse_down(move |_, cx| cx.dispatch_action(SelectIndex(ix)))
+                                .on_mouse_down(MouseButton::Left, move |_, cx| {
+                                    cx.dispatch_action(SelectIndex(ix))
+                                })
                                 .with_cursor_style(CursorStyle::PointingHand)
                                 .boxed()
                             }));

crates/project_panel/src/project_panel.rs 🔗

@@ -11,8 +11,9 @@ use gpui::{
     geometry::vector::Vector2F,
     impl_internal_actions, keymap,
     platform::CursorStyle,
-    AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle, MutableAppContext,
-    PromptLevel, RenderContext, Task, View, ViewContext, ViewHandle,
+    AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle, MouseButton,
+    MouseButtonEvent, MutableAppContext, PromptLevel, RenderContext, Task, View, ViewContext,
+    ViewHandle,
 };
 use menu::{Confirm, SelectNext, SelectPrev};
 use project::{Entry, EntryKind, Project, ProjectEntryId, ProjectPath, Worktree, WorktreeId};
@@ -1054,19 +1055,25 @@ impl ProjectPanel {
                 .with_padding_left(padding)
                 .boxed()
         })
-        .on_click(move |_, click_count, cx| {
-            if kind == EntryKind::Dir {
-                cx.dispatch_action(ToggleExpanded(entry_id))
-            } else {
-                cx.dispatch_action(Open {
-                    entry_id,
-                    change_focus: click_count > 1,
-                })
-            }
-        })
-        .on_right_mouse_down(move |position, cx| {
-            cx.dispatch_action(DeployContextMenu { entry_id, position })
-        })
+        .on_click(
+            MouseButton::Left,
+            move |MouseButtonEvent { click_count, .. }, cx| {
+                if kind == EntryKind::Dir {
+                    cx.dispatch_action(ToggleExpanded(entry_id))
+                } else {
+                    cx.dispatch_action(Open {
+                        entry_id,
+                        change_focus: click_count > 1,
+                    })
+                }
+            },
+        )
+        .on_mouse_down(
+            MouseButton::Right,
+            move |MouseButtonEvent { position, .. }, cx| {
+                cx.dispatch_action(DeployContextMenu { entry_id, position })
+            },
+        )
         .with_cursor_style(CursorStyle::PointingHand)
         .boxed()
     }
@@ -1113,13 +1120,16 @@ impl View for ProjectPanel {
                     .expanded()
                     .boxed()
                 })
-                .on_right_mouse_down(move |position, cx| {
-                    // When deploying the context menu anywhere below the last project entry,
-                    // act as if the user clicked the root of the last worktree.
-                    if let Some(entry_id) = last_worktree_root_id {
-                        cx.dispatch_action(DeployContextMenu { entry_id, position })
-                    }
-                })
+                .on_mouse_down(
+                    MouseButton::Right,
+                    move |MouseButtonEvent { position, .. }, cx| {
+                        // When deploying the context menu anywhere below the last project entry,
+                        // act as if the user clicked the root of the last worktree.
+                        if let Some(entry_id) = last_worktree_root_id {
+                            cx.dispatch_action(DeployContextMenu { entry_id, position })
+                        }
+                    },
+                )
                 .boxed(),
             )
             .with_child(ChildView::new(&self.context_menu).boxed())

crates/search/src/buffer_search.rs 🔗

@@ -7,8 +7,8 @@ use collections::HashMap;
 use editor::{Anchor, Autoscroll, Editor};
 use gpui::{
     actions, elements::*, impl_actions, platform::CursorStyle, Action, AppContext, Entity,
-    MutableAppContext, RenderContext, Subscription, Task, View, ViewContext, ViewHandle,
-    WeakViewHandle,
+    MouseButton, MutableAppContext, RenderContext, Subscription, Task, View, ViewContext,
+    ViewHandle, WeakViewHandle,
 };
 use language::OffsetRangeExt;
 use project::search::SearchQuery;
@@ -285,7 +285,9 @@ impl BufferSearchBar {
                 .with_style(style.container)
                 .boxed()
         })
-        .on_click(move |_, _, cx| cx.dispatch_any_action(option.to_toggle_action()))
+        .on_click(MouseButton::Left, move |_, cx| {
+            cx.dispatch_any_action(option.to_toggle_action())
+        })
         .with_cursor_style(CursorStyle::PointingHand)
         .with_tooltip::<Self, _>(
             option as usize,
@@ -330,9 +332,9 @@ impl BufferSearchBar {
                 .with_style(style.container)
                 .boxed()
         })
-        .on_click({
+        .on_click(MouseButton::Left, {
             let action = action.boxed_clone();
-            move |_, _, cx| cx.dispatch_any_action(action.boxed_clone())
+            move |_, cx| cx.dispatch_any_action(action.boxed_clone())
         })
         .with_cursor_style(CursorStyle::PointingHand)
         .with_tooltip::<NavButton, _>(

crates/search/src/project_search.rs 🔗

@@ -7,8 +7,8 @@ use collections::HashMap;
 use editor::{Anchor, Autoscroll, Editor, MultiBuffer, SelectAll, MAX_TAB_TITLE_LEN};
 use gpui::{
     actions, elements::*, platform::CursorStyle, Action, AppContext, ElementBox, Entity,
-    ModelContext, ModelHandle, MutableAppContext, RenderContext, Subscription, Task, View,
-    ViewContext, ViewHandle, WeakModelHandle, WeakViewHandle,
+    ModelContext, ModelHandle, MouseButton, MutableAppContext, RenderContext, Subscription, Task,
+    View, ViewContext, ViewHandle, WeakModelHandle, WeakViewHandle,
 };
 use menu::Confirm;
 use project::{search::SearchQuery, Project};
@@ -735,9 +735,9 @@ impl ProjectSearchBar {
                 .with_style(style.container)
                 .boxed()
         })
-        .on_click({
+        .on_click(MouseButton::Left, {
             let action = action.boxed_clone();
-            move |_, _, cx| cx.dispatch_any_action(action.boxed_clone())
+            move |_, cx| cx.dispatch_any_action(action.boxed_clone())
         })
         .with_cursor_style(CursorStyle::PointingHand)
         .with_tooltip::<NavButton, _>(
@@ -770,7 +770,9 @@ impl ProjectSearchBar {
                 .with_style(style.container)
                 .boxed()
         })
-        .on_click(move |_, _, cx| cx.dispatch_any_action(option.to_toggle_action()))
+        .on_click(MouseButton::Left, move |_, cx| {
+            cx.dispatch_any_action(option.to_toggle_action())
+        })
         .with_cursor_style(CursorStyle::PointingHand)
         .with_tooltip::<Self, _>(
             option as usize,

crates/terminal/src/terminal_element.rs 🔗

@@ -20,8 +20,8 @@ use gpui::{
     },
     json::json,
     text_layout::{Line, RunStyle},
-    Event, FontCache, KeyDownEvent, MouseRegion, PaintContext, Quad, ScrollWheelEvent,
-    SizeConstraint, TextLayoutCache, WeakModelHandle,
+    Event, FontCache, KeyDownEvent, MouseButton, MouseButtonEvent, MouseMovedEvent, MouseRegion,
+    PaintContext, Quad, ScrollWheelEvent, SizeConstraint, TextLayoutCache, WeakModelHandle,
 };
 use itertools::Itertools;
 use ordered_float::OrderedFloat;
@@ -29,7 +29,7 @@ use settings::Settings;
 use theme::TerminalStyle;
 use util::ResultExt;
 
-use std::{cmp::min, ops::Range, rc::Rc, sync::Arc};
+use std::{cmp::min, ops::Range, sync::Arc};
 use std::{fmt::Debug, ops::Sub};
 
 use crate::{color_translation::convert_color, connection::TerminalConnection, ZedListener};
@@ -594,63 +594,76 @@ fn attach_mouse_handlers(
     let drag_mutex = terminal_mutex.clone();
     let mouse_down_mutex = terminal_mutex.clone();
 
-    cx.scene.push_mouse_region(MouseRegion {
-        view_id,
-        mouse_down: Some(Rc::new(move |pos, _| {
-            let mut term = mouse_down_mutex.lock();
-            let (point, side) = mouse_to_cell_data(
-                pos,
-                origin,
-                cur_size,
-                term.renderable_content().display_offset,
-            );
-            term.selection = Some(Selection::new(SelectionType::Simple, point, side))
-        })),
-        click: Some(Rc::new(move |pos, click_count, cx| {
-            let mut term = click_mutex.lock();
-
-            let (point, side) = mouse_to_cell_data(
-                pos,
-                origin,
-                cur_size,
-                term.renderable_content().display_offset,
-            );
-
-            let selection_type = match click_count {
-                0 => return, //This is a release
-                1 => Some(SelectionType::Simple),
-                2 => Some(SelectionType::Semantic),
-                3 => Some(SelectionType::Lines),
-                _ => None,
-            };
+    cx.scene.push_mouse_region(
+        MouseRegion::new(view_id, None, visible_bounds)
+            .on_down(
+                MouseButton::Left,
+                move |MouseButtonEvent { position, .. }, _| {
+                    let mut term = mouse_down_mutex.lock();
+
+                    let (point, side) = mouse_to_cell_data(
+                        position,
+                        origin,
+                        cur_size,
+                        term.renderable_content().display_offset,
+                    );
+                    term.selection = Some(Selection::new(SelectionType::Simple, point, side))
+                },
+            )
+            .on_click(
+                MouseButton::Left,
+                move |MouseButtonEvent {
+                          position,
+                          click_count,
+                          ..
+                      },
+                      cx| {
+                    let mut term = click_mutex.lock();
+
+                    let (point, side) = mouse_to_cell_data(
+                        position,
+                        origin,
+                        cur_size,
+                        term.renderable_content().display_offset,
+                    );
 
-            let selection =
-                selection_type.map(|selection_type| Selection::new(selection_type, point, side));
+                    let selection_type = match click_count {
+                        0 => return, //This is a release
+                        1 => Some(SelectionType::Simple),
+                        2 => Some(SelectionType::Semantic),
+                        3 => Some(SelectionType::Lines),
+                        _ => None,
+                    };
 
-            term.selection = selection;
-            cx.focus_parent_view();
-            cx.notify();
-        })),
-        bounds: visible_bounds,
-        drag: Some(Rc::new(move |_delta, pos, cx| {
-            let mut term = drag_mutex.lock();
+                    let selection = selection_type
+                        .map(|selection_type| Selection::new(selection_type, point, side));
 
-            let (point, side) = mouse_to_cell_data(
-                pos,
-                origin,
-                cur_size,
-                term.renderable_content().display_offset,
-            );
+                    term.selection = selection;
+                    cx.focus_parent_view();
+                    cx.notify();
+                },
+            )
+            .on_drag(
+                MouseButton::Left,
+                move |_, MouseMovedEvent { position, .. }, cx| {
+                    let mut term = drag_mutex.lock();
+
+                    let (point, side) = mouse_to_cell_data(
+                        position,
+                        origin,
+                        cur_size,
+                        term.renderable_content().display_offset,
+                    );
 
-            if let Some(mut selection) = term.selection.take() {
-                selection.update(point, side);
-                term.selection = Some(selection);
-            }
+                    if let Some(mut selection) = term.selection.take() {
+                        selection.update(point, side);
+                        term.selection = Some(selection);
+                    }
 
-            cx.notify();
-        })),
-        ..Default::default()
-    });
+                    cx.notify();
+                },
+            ),
+    );
 }
 
 ///Copied (with modifications) from alacritty/src/input.rs > Processor::cell_side()

crates/workspace/src/pane.rs 🔗

@@ -13,8 +13,9 @@ use gpui::{
     },
     impl_actions, impl_internal_actions,
     platform::{CursorStyle, NavigationDirection},
-    AppContext, AsyncAppContext, Entity, ModelHandle, MutableAppContext, PromptLevel, Quad,
-    RenderContext, Task, View, ViewContext, ViewHandle, WeakViewHandle,
+    AppContext, AsyncAppContext, Entity, ModelHandle, MouseButton, MouseButtonEvent,
+    MutableAppContext, PromptLevel, Quad, RenderContext, Task, View, ViewContext, ViewHandle,
+    WeakViewHandle,
 };
 use project::{Project, ProjectEntryId, ProjectPath};
 use serde::Deserialize;
@@ -955,9 +956,9 @@ impl Pane {
                                             )
                                             .with_padding(Padding::uniform(4.))
                                             .with_cursor_style(CursorStyle::PointingHand)
-                                            .on_click({
+                                            .on_click(MouseButton::Left, {
                                                 let pane = pane.clone();
-                                                move |_, _, cx| {
+                                                move |_, cx| {
                                                     cx.dispatch_action(CloseItem {
                                                         item_id,
                                                         pane: pane.clone(),
@@ -978,7 +979,7 @@ impl Pane {
                         .with_style(style.container)
                         .boxed()
                     })
-                    .on_mouse_down(move |_, cx| {
+                    .on_mouse_down(MouseButton::Left, move |_, cx| {
                         cx.dispatch_action(ActivateItem(ix));
                     })
                     .boxed()
@@ -1079,9 +1080,12 @@ impl View for Pane {
                                         },
                                     )
                                     .with_cursor_style(CursorStyle::PointingHand)
-                                    .on_mouse_down(|position, cx| {
-                                        cx.dispatch_action(DeploySplitMenu { position });
-                                    })
+                                    .on_mouse_down(
+                                        MouseButton::Left,
+                                        |MouseButtonEvent { position, .. }, cx| {
+                                            cx.dispatch_action(DeploySplitMenu { position });
+                                        },
+                                    )
                                     .boxed(),
                                 )
                                 .constrained()

crates/workspace/src/sidebar.rs 🔗

@@ -1,7 +1,7 @@
 use crate::StatusItemView;
 use gpui::{
     elements::*, impl_actions, platform::CursorStyle, AnyViewHandle, AppContext, Entity,
-    RenderContext, Subscription, View, ViewContext, ViewHandle,
+    MouseButton, MouseMovedEvent, RenderContext, Subscription, View, ViewContext, ViewHandle,
 };
 use serde::Deserialize;
 use settings::Settings;
@@ -187,19 +187,27 @@ impl Sidebar {
             ..Default::default()
         })
         .with_cursor_style(CursorStyle::ResizeLeftRight)
-        .on_mouse_down(|_, _| {}) // This prevents the mouse down event from being propagated elsewhere
-        .on_drag(move |old_position, new_position, cx| {
-            let delta = new_position.x() - old_position.x();
-            let prev_width = *actual_width.borrow();
-            *custom_width.borrow_mut() = 0f32
-                .max(match side {
-                    Side::Left => prev_width + delta,
-                    Side::Right => prev_width - delta,
-                })
-                .round();
+        .on_mouse_down(MouseButton::Left, |_, _| {}) // This prevents the mouse down event from being propagated elsewhere
+        .on_drag(
+            MouseButton::Left,
+            move |old_position,
+                  MouseMovedEvent {
+                      position: new_position,
+                      ..
+                  },
+                  cx| {
+                let delta = new_position.x() - old_position.x();
+                let prev_width = *actual_width.borrow();
+                *custom_width.borrow_mut() = 0f32
+                    .max(match side {
+                        Side::Left => prev_width + delta,
+                        Side::Right => prev_width - delta,
+                    })
+                    .round();
 
-            cx.notify();
-        })
+                cx.notify();
+            },
+        )
         .boxed()
     }
 }
@@ -314,9 +322,9 @@ impl View for SidebarButtons {
                             .boxed()
                     })
                     .with_cursor_style(CursorStyle::PointingHand)
-                    .on_click({
+                    .on_click(MouseButton::Left, {
                         let action = action.clone();
-                        move |_, _, cx| cx.dispatch_action(action.clone())
+                        move |_, cx| cx.dispatch_action(action.clone())
                     })
                     .with_tooltip::<Self, _>(
                         ix,

crates/workspace/src/toolbar.rs 🔗

@@ -1,7 +1,7 @@
 use crate::{ItemHandle, Pane};
 use gpui::{
     elements::*, platform::CursorStyle, Action, AnyViewHandle, AppContext, ElementBox, Entity,
-    MutableAppContext, RenderContext, View, ViewContext, ViewHandle, WeakViewHandle,
+    MouseButton, MutableAppContext, RenderContext, View, ViewContext, ViewHandle, WeakViewHandle,
 };
 use settings::Settings;
 
@@ -191,7 +191,9 @@ fn nav_button<A: Action + Clone>(
     } else {
         CursorStyle::default()
     })
-    .on_click(move |_, _, cx| cx.dispatch_action(action.clone()))
+    .on_click(MouseButton::Left, move |_, cx| {
+        cx.dispatch_action(action.clone())
+    })
     .with_tooltip::<A, _>(
         0,
         action_name.to_string(),

crates/workspace/src/workspace.rs 🔗

@@ -21,8 +21,8 @@ use gpui::{
     json::{self, ToJson},
     platform::{CursorStyle, WindowOptions},
     AnyModelHandle, AnyViewHandle, AppContext, AsyncAppContext, Border, Entity, ImageData,
-    ModelContext, ModelHandle, MutableAppContext, PathPromptOptions, PromptLevel, RenderContext,
-    Task, View, ViewContext, ViewHandle, WeakViewHandle,
+    ModelContext, ModelHandle, MouseButton, MutableAppContext, PathPromptOptions, PromptLevel,
+    RenderContext, Task, View, ViewContext, ViewHandle, WeakViewHandle,
 };
 use language::LanguageRegistry;
 use log::error;
@@ -1980,7 +1980,7 @@ impl Workspace {
                         .with_style(style.container)
                         .boxed()
                 })
-                .on_click(|_, _, cx| cx.dispatch_action(Authenticate))
+                .on_click(MouseButton::Left, |_, cx| cx.dispatch_action(Authenticate))
                 .with_cursor_style(CursorStyle::PointingHand)
                 .aligned()
                 .boxed(),
@@ -2031,7 +2031,9 @@ impl Workspace {
         if let Some((peer_id, peer_github_login)) = peer {
             MouseEventHandler::new::<ToggleFollow, _, _>(replica_id.into(), cx, move |_, _| content)
                 .with_cursor_style(CursorStyle::PointingHand)
-                .on_click(move |_, _, cx| cx.dispatch_action(ToggleFollow(peer_id)))
+                .on_click(MouseButton::Left, move |_, cx| {
+                    cx.dispatch_action(ToggleFollow(peer_id))
+                })
                 .with_tooltip::<ToggleFollow, _>(
                     peer_id.0 as usize,
                     if is_followed {

crates/zed/src/feedback.rs 🔗

@@ -2,7 +2,7 @@ use crate::OpenBrowser;
 use gpui::{
     elements::{MouseEventHandler, Text},
     platform::CursorStyle,
-    Element, Entity, RenderContext, View,
+    Element, Entity, MouseButton, RenderContext, View,
 };
 use settings::Settings;
 use workspace::StatusItemView;
@@ -32,7 +32,7 @@ impl View for FeedbackLink {
             .boxed()
         })
         .with_cursor_style(CursorStyle::PointingHand)
-        .on_click(|_, _, cx| {
+        .on_click(MouseButton::Left, |_, cx| {
             cx.dispatch_action(OpenBrowser {
                 url: NEW_ISSUE_URL.into(),
             })

styles/package-lock.json 🔗

@@ -5,6 +5,7 @@
     "requires": true,
     "packages": {
         "": {
+            "name": "styles",
             "version": "1.0.0",
             "license": "ISC",
             "dependencies": {