Capture hover events on tabs

Nathan Sobo and Antonio Scandurra created

Co-Authored-By: Antonio Scandurra <me@as-cii.com>

Change summary

gpui/src/elements/mod.rs                 |  1 
gpui/src/elements/mouse_event_handler.rs | 14 ++++-------
gpui/src/platform/mac/window.rs          |  4 +++
zed/src/editor/buffer_element.rs         |  1 
zed/src/workspace/pane.rs                | 31 +++++++++++++++----------
5 files changed, 29 insertions(+), 22 deletions(-)

Detailed changes

gpui/src/elements/mod.rs 🔗

@@ -23,6 +23,7 @@ pub use event_handler::*;
 pub use flex::*;
 pub use label::*;
 pub use line_box::*;
+pub use mouse_event_handler::*;
 pub use new::*;
 pub use stack::*;
 pub use svg::*;

gpui/src/elements/mouse_event_handler.rs 🔗

@@ -17,11 +17,11 @@ pub struct MouseState {
 }
 
 impl MouseEventHandler {
-    pub fn new<Tag: 'static>(
-        id: usize,
-        ctx: &AppContext,
-        render_child: impl FnOnce(MouseState) -> ElementBox,
-    ) -> Self {
+    pub fn new<Tag, F>(id: usize, ctx: &AppContext, render_child: F) -> Self
+    where
+        Tag: 'static,
+        F: FnOnce(MouseState) -> ElementBox,
+    {
         let state = ctx.value::<Tag, _>(id);
         let child = state.map(ctx, |state| render_child(*state));
         Self { state, child }
@@ -30,7 +30,6 @@ impl MouseEventHandler {
 
 impl Element for MouseEventHandler {
     type LayoutState = ();
-
     type PaintState = ();
 
     fn layout(
@@ -72,7 +71,6 @@ impl Element for MouseEventHandler {
                 let mouse_in = bounds.contains_point(*position);
                 if state.hovered != mouse_in {
                     state.hovered = mouse_in;
-                    log::info!("hovered {}", state.hovered);
                     // ctx.notify();
                     true
                 } else {
@@ -81,7 +79,6 @@ impl Element for MouseEventHandler {
             }
             Event::LeftMouseDown { position, .. } => {
                 if bounds.contains_point(*position) {
-                    log::info!("clicked");
                     state.clicked = true;
                     // ctx.notify();
                     true
@@ -91,7 +88,6 @@ impl Element for MouseEventHandler {
             }
             Event::LeftMouseUp { .. } => {
                 if state.clicked {
-                    log::info!("unclicked");
                     state.clicked = false;
                     // ctx.notify();
                     true

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

@@ -82,6 +82,10 @@ unsafe fn build_classes() {
             sel!(mouseUp:),
             handle_view_event as extern "C" fn(&Object, Sel, id),
         );
+        decl.add_method(
+            sel!(mouseMoved:),
+            handle_view_event as extern "C" fn(&Object, Sel, id),
+        );
         decl.add_method(
             sel!(mouseDragged:),
             handle_view_event as extern "C" fn(&Object, Sel, id),

zed/src/editor/buffer_element.rs 🔗

@@ -474,6 +474,7 @@ impl Element for BufferElement {
                     precise,
                 } => self.scroll(*position, *delta, *precise, layout, paint, ctx),
                 Event::KeyDown { chars, .. } => self.key_down(chars, ctx),
+                _ => false,
             }
         } else {
             false

zed/src/workspace/pane.rs 🔗

@@ -176,14 +176,14 @@ impl Pane {
         ctx.emit(Event::Split(direction));
     }
 
-    fn render_tabs(&self, app: &AppContext) -> ElementBox {
+    fn render_tabs(&self, ctx: &AppContext) -> ElementBox {
         let settings = smol::block_on(self.settings.read());
         let border_color = ColorU::from_u32(0xdbdbdcff);
 
         let mut row = Flex::row();
         let last_item_ix = self.items.len() - 1;
         for (ix, item) in self.items.iter().enumerate() {
-            let title = item.title(app);
+            let title = item.title(ctx);
 
             let mut border = Border::new(1.0, border_color);
             border.left = ix > 0;
@@ -204,7 +204,7 @@ impl Pane {
                         LineBox::new(
                             settings.ui_font_family,
                             settings.ui_font_size,
-                            Align::new(Self::render_modified_icon(item.is_dirty(app)))
+                            Align::new(Self::render_modified_icon(item.is_dirty(ctx)))
                                 .right()
                                 .boxed(),
                         )
@@ -224,19 +224,24 @@ impl Pane {
                 container = container.with_background_color(ColorU::from_u32(0xeaeaebff));
             }
 
+            enum Tab {}
+
             row.add_child(
                 Expanded::new(
                     1.0,
-                    ConstrainedBox::new(
-                        EventHandler::new(container.boxed())
-                            .on_mouse_down(move |ctx| {
-                                ctx.dispatch_action("pane:activate_item", ix);
-                                true
-                            })
-                            .boxed(),
-                    )
-                    .with_min_width(80.0)
-                    .with_max_width(264.0)
+                    MouseEventHandler::new::<Tab, _>(0, ctx, |mouse_state| {
+                        ConstrainedBox::new(
+                            EventHandler::new(container.boxed())
+                                .on_mouse_down(move |ctx| {
+                                    ctx.dispatch_action("pane:activate_item", ix);
+                                    true
+                                })
+                                .boxed(),
+                        )
+                        .with_min_width(80.0)
+                        .with_max_width(264.0)
+                        .boxed()
+                    })
                     .boxed(),
                 )
                 .named("tab"),