Merge pull request #2242 from zed-industries/mouse-event-handlers-yes

Julia created

Fix surprising mouse propagation & avoid focusing tab while closing

Change summary

crates/gpui/src/presenter.rs | 20 +++++----
crates/workspace/src/pane.rs | 71 ++++++++++++++++++++++---------------
2 files changed, 53 insertions(+), 38 deletions(-)

Detailed changes

crates/gpui/src/presenter.rs 🔗

@@ -507,15 +507,18 @@ impl Presenter {
                 }
                 // Handle Down events if the MouseRegion has a Click or Drag handler. This makes the api more intuitive as you would
                 // not expect a MouseRegion to be transparent to Down events if it also has a Click handler.
-                // This behavior can be overridden by adding a Down handler that calls cx.propogate_event
+                // This behavior can be overridden by adding a Down handler
                 if let MouseEvent::Down(e) = &mouse_event {
-                    if valid_region
+                    let has_click = valid_region
                         .handlers
-                        .contains(MouseEvent::click_disc(), Some(e.button))
-                        || valid_region
-                            .handlers
-                            .contains(MouseEvent::drag_disc(), Some(e.button))
-                    {
+                        .contains(MouseEvent::click_disc(), Some(e.button));
+                    let has_drag = valid_region
+                        .handlers
+                        .contains(MouseEvent::drag_disc(), Some(e.button));
+                    let has_down = valid_region
+                        .handlers
+                        .contains(MouseEvent::down_disc(), Some(e.button));
+                    if !has_down && (has_click || has_drag) {
                         event_cx.handled = true;
                     }
                 }
@@ -523,14 +526,13 @@ impl Presenter {
                 // `event_consumed` should only be true if there are any handlers for this event.
                 let mut event_consumed = event_cx.handled;
                 if let Some(callbacks) = valid_region.handlers.get(&mouse_event.handler_key()) {
-                    event_consumed = true;
                     for callback in callbacks {
                         event_cx.handled = true;
                         event_cx.with_current_view(valid_region.id().view_id(), {
                             let region_event = mouse_event.clone();
                             |cx| callback(region_event, cx)
                         });
-                        event_consumed &= event_cx.handled;
+                        event_consumed |= event_cx.handled;
                         any_event_handled |= event_cx.handled;
                     }
                 }

crates/workspace/src/pane.rs 🔗

@@ -1150,40 +1150,53 @@ impl Pane {
             let tab_active = ix == self.active_item_index;
 
             row.add_child({
-                enum Tab {}
-                let mut receiver = dragged_item_receiver::<Tab, _>(ix, ix, true, None, cx, {
-                    let item = item.clone();
-                    let pane = pane.clone();
-                    let detail = detail.clone();
-
-                    let theme = cx.global::<Settings>().theme.clone();
-
-                    move |mouse_state, cx| {
-                        let tab_style = theme.workspace.tab_bar.tab_style(pane_active, tab_active);
-                        let hovered = mouse_state.hovered();
-                        Self::render_tab(&item, pane, ix == 0, detail, hovered, tab_style, cx)
-                    }
-                });
+                enum TabDragReceiver {}
+                let mut receiver =
+                    dragged_item_receiver::<TabDragReceiver, _>(ix, ix, true, None, cx, {
+                        let item = item.clone();
+                        let pane = pane.clone();
+                        let detail = detail.clone();
+
+                        let theme = cx.global::<Settings>().theme.clone();
+
+                        move |mouse_state, cx| {
+                            let tab_style =
+                                theme.workspace.tab_bar.tab_style(pane_active, tab_active);
+                            let hovered = mouse_state.hovered();
+
+                            enum Tab {}
+                            MouseEventHandler::<Tab>::new(ix, cx, |_, cx| {
+                                Self::render_tab(
+                                    &item,
+                                    pane.clone(),
+                                    ix == 0,
+                                    detail,
+                                    hovered,
+                                    tab_style,
+                                    cx,
+                                )
+                            })
+                            .on_down(MouseButton::Left, move |_, cx| {
+                                cx.dispatch_action(ActivateItem(ix));
+                            })
+                            .on_click(MouseButton::Middle, {
+                                let item = item.clone();
+                                move |_, cx: &mut EventContext| {
+                                    cx.dispatch_action(CloseItem {
+                                        item_id: item.id(),
+                                        pane: pane.clone(),
+                                    })
+                                }
+                            })
+                            .boxed()
+                        }
+                    });
 
                 if !pane_active || !tab_active {
                     receiver = receiver.with_cursor_style(CursorStyle::PointingHand);
                 }
 
                 receiver
-                    .on_down(MouseButton::Left, move |_, cx| {
-                        cx.dispatch_action(ActivateItem(ix));
-                        cx.propagate_event();
-                    })
-                    .on_click(MouseButton::Middle, {
-                        let item = item.clone();
-                        let pane = pane.clone();
-                        move |_, cx: &mut EventContext| {
-                            cx.dispatch_action(CloseItem {
-                                item_id: item.id(),
-                                pane: pane.clone(),
-                            })
-                        }
-                    })
                     .as_draggable(
                         DraggedItem {
                             item,
@@ -1438,7 +1451,7 @@ impl View for Pane {
                                             .with_style(theme.workspace.tab_bar.container)
                                             .boxed()
                                     })
-                                    .on_click(MouseButton::Left, move |_, cx| {
+                                    .on_down(MouseButton::Left, move |_, cx| {
                                         cx.dispatch_action(ActivateItem(active_item_index));
                                     })
                                     .boxed(),