Remove on_click_out handler from context menu

Mikayla Maki created

Add 'delay_cancel()' method and on_down handler to relevant buttons

Change summary

crates/collab_ui/src/collab_titlebar_item.rs |  5 +
crates/context_menu/src/context_menu.rs      | 58 ++++++++++++++++++---
crates/copilot_button/src/copilot_button.rs  |  7 +
crates/terminal_view/src/terminal_element.rs | 21 ++++---
crates/terminal_view/src/terminal_panel.rs   |  2 
crates/workspace/src/pane.rs                 | 13 +++-
6 files changed, 79 insertions(+), 27 deletions(-)

Detailed changes

crates/collab_ui/src/collab_titlebar_item.rs 🔗

@@ -317,7 +317,7 @@ impl CollabTitlebarItem {
                     ),
                 ]
             };
-            user_menu.show(Default::default(), AnchorCorner::TopRight, items, cx);
+            user_menu.toggle(Default::default(), AnchorCorner::TopRight, items, cx);
         });
     }
 
@@ -683,6 +683,9 @@ impl CollabTitlebarItem {
                         .into_any()
                 })
                 .with_cursor_style(CursorStyle::PointingHand)
+                .on_down(MouseButton::Left, move |_, this, cx| {
+                    this.user_menu.update(cx, |menu, _| menu.delay_cancel());
+                })
                 .on_click(MouseButton::Left, move |_, this, cx| {
                     this.toggle_user_menu(&Default::default(), cx)
                 })

crates/context_menu/src/context_menu.rs 🔗

@@ -124,6 +124,7 @@ pub struct ContextMenu {
     items: Vec<ContextMenuItem>,
     selected_index: Option<usize>,
     visible: bool,
+    delay_cancel: bool,
     previously_focused_view_id: Option<usize>,
     parent_view_id: usize,
     _actions_observation: Subscription,
@@ -178,6 +179,7 @@ impl ContextMenu {
     pub fn new(parent_view_id: usize, cx: &mut ViewContext<Self>) -> Self {
         Self {
             show_count: 0,
+            delay_cancel: false,
             anchor_position: Default::default(),
             anchor_corner: AnchorCorner::TopLeft,
             position_mode: OverlayPositionMode::Window,
@@ -232,15 +234,23 @@ impl ContextMenu {
         }
     }
 
+    pub fn delay_cancel(&mut self) {
+        self.delay_cancel = true;
+    }
+
     fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
-        self.reset(cx);
-        let show_count = self.show_count;
-        cx.defer(move |this, cx| {
-            if cx.handle().is_focused(cx) && this.show_count == show_count {
-                let window_id = cx.window_id();
-                (**cx).focus(window_id, this.previously_focused_view_id.take());
-            }
-        });
+        if !self.delay_cancel {
+            self.reset(cx);
+            let show_count = self.show_count;
+            cx.defer(move |this, cx| {
+                if cx.handle().is_focused(cx) && this.show_count == show_count {
+                    let window_id = cx.window_id();
+                    (**cx).focus(window_id, this.previously_focused_view_id.take());
+                }
+            });
+        } else {
+            self.delay_cancel = false;
+        }
     }
 
     fn reset(&mut self, cx: &mut ViewContext<Self>) {
@@ -293,6 +303,34 @@ impl ContextMenu {
         }
     }
 
+    pub fn toggle(
+        &mut self,
+        anchor_position: Vector2F,
+        anchor_corner: AnchorCorner,
+        items: Vec<ContextMenuItem>,
+        cx: &mut ViewContext<Self>,
+    ) {
+        if self.visible() {
+            self.cancel(&Cancel, cx);
+        } else {
+            let mut items = items.into_iter().peekable();
+            if items.peek().is_some() {
+                self.items = items.collect();
+                self.anchor_position = anchor_position;
+                self.anchor_corner = anchor_corner;
+                self.visible = true;
+                self.show_count += 1;
+                if !cx.is_self_focused() {
+                    self.previously_focused_view_id = cx.focused_view_id();
+                }
+                cx.focus_self();
+            } else {
+                self.visible = false;
+            }
+        }
+        cx.notify();
+    }
+
     pub fn show(
         &mut self,
         anchor_position: Vector2F,
@@ -477,10 +515,10 @@ impl ContextMenu {
                 .contained()
                 .with_style(style.container)
         })
-        .on_click_out(MouseButton::Left, |_, this, cx| {
+        .on_down_out(MouseButton::Left, |_, this, cx| {
             this.cancel(&Default::default(), cx);
         })
-        .on_click_out(MouseButton::Right, |_, this, cx| {
+        .on_down_out(MouseButton::Right, |_, this, cx| {
             this.cancel(&Default::default(), cx);
         })
     }

crates/copilot_button/src/copilot_button.rs 🔗

@@ -102,6 +102,9 @@ impl View for CopilotButton {
                     }
                 })
                 .with_cursor_style(CursorStyle::PointingHand)
+                .on_down(MouseButton::Left, |_, this, cx| {
+                    this.popup_menu.update(cx, |menu, _| menu.delay_cancel());
+                })
                 .on_click(MouseButton::Left, {
                     let status = status.clone();
                     move |_, this, cx| match status {
@@ -186,7 +189,7 @@ impl CopilotButton {
         }));
 
         self.popup_menu.update(cx, |menu, cx| {
-            menu.show(
+            menu.toggle(
                 Default::default(),
                 AnchorCorner::BottomRight,
                 menu_options,
@@ -266,7 +269,7 @@ impl CopilotButton {
         menu_options.push(ContextMenuItem::action("Sign Out", SignOut));
 
         self.popup_menu.update(cx, |menu, cx| {
-            menu.show(
+            menu.toggle(
                 Default::default(),
                 AnchorCorner::BottomRight,
                 menu_options,

crates/terminal_view/src/terminal_element.rs 🔗

@@ -395,16 +395,17 @@ impl TerminalElement {
         // Terminal Emulator controlled behavior:
         region = region
             // Start selections
-            .on_down(
-                MouseButton::Left,
-                TerminalElement::generic_button_handler(
-                    connection,
-                    origin,
-                    move |terminal, origin, e, _cx| {
-                        terminal.mouse_down(&e, origin);
-                    },
-                ),
-            )
+            .on_down(MouseButton::Left, move |event, v: &mut TerminalView, cx| {
+                cx.focus_parent();
+                v.context_menu.update(cx, |menu, _cx| menu.delay_cancel());
+                if let Some(conn_handle) = connection.upgrade(cx) {
+                    conn_handle.update(cx, |terminal, cx| {
+                        terminal.mouse_down(&event, origin);
+
+                        cx.notify();
+                    })
+                }
+            })
             // Update drag selections
             .on_drag(MouseButton::Left, move |event, _: &mut TerminalView, cx| {
                 if cx.is_self_focused() {

crates/terminal_view/src/terminal_panel.rs 🔗

@@ -87,6 +87,7 @@ impl TerminalPanel {
                                 }
                             })
                         },
+                        |_, _| {},
                         None,
                     ))
                     .with_child(Pane::render_tab_bar_button(
@@ -100,6 +101,7 @@ impl TerminalPanel {
                         Some(("Toggle Zoom".into(), Some(Box::new(workspace::ToggleZoom)))),
                         cx,
                         move |pane, cx| pane.toggle_zoom(&Default::default(), cx),
+                        |_, _| {},
                         None,
                     ))
                     .into_any()

crates/workspace/src/pane.rs 🔗

@@ -273,6 +273,7 @@ impl Pane {
                         Some(("New...".into(), None)),
                         cx,
                         |pane, cx| pane.deploy_new_menu(cx),
+                        |pane, cx| pane.tab_bar_context_menu.handle.update(cx, |menu, _| menu.delay_cancel()),
                         pane.tab_bar_context_menu
                             .handle_if_kind(TabBarContextMenuKind::New),
                     ))
@@ -283,6 +284,7 @@ impl Pane {
                         Some(("Split Pane".into(), None)),
                         cx,
                         |pane, cx| pane.deploy_split_menu(cx),
+                        |pane, cx| pane.tab_bar_context_menu.handle.update(cx, |menu, _| menu.delay_cancel()),
                         pane.tab_bar_context_menu
                             .handle_if_kind(TabBarContextMenuKind::Split),
                     ))
@@ -304,6 +306,7 @@ impl Pane {
                             Some((tooltip_label, Some(Box::new(ToggleZoom)))),
                             cx,
                             move |pane, cx| pane.toggle_zoom(&Default::default(), cx),
+                            move |_, _| {},
                             None,
                         )
                     })
@@ -988,7 +991,7 @@ impl Pane {
 
     fn deploy_split_menu(&mut self, cx: &mut ViewContext<Self>) {
         self.tab_bar_context_menu.handle.update(cx, |menu, cx| {
-            menu.show(
+            menu.toggle(
                 Default::default(),
                 AnchorCorner::TopRight,
                 vec![
@@ -1006,7 +1009,7 @@ impl Pane {
 
     fn deploy_new_menu(&mut self, cx: &mut ViewContext<Self>) {
         self.tab_bar_context_menu.handle.update(cx, |menu, cx| {
-            menu.show(
+            menu.toggle(
                 Default::default(),
                 AnchorCorner::TopRight,
                 vec![
@@ -1416,13 +1419,14 @@ impl Pane {
             .into_any()
     }
 
-    pub fn render_tab_bar_button<F: 'static + Fn(&mut Pane, &mut EventContext<Pane>)>(
+    pub fn render_tab_bar_button<F1: 'static + Fn(&mut Pane, &mut EventContext<Pane>), F2: 'static + Fn(&mut Pane, &mut EventContext<Pane>)>(
         index: usize,
         icon: &'static str,
         is_active: bool,
         tooltip: Option<(String, Option<Box<dyn Action>>)>,
         cx: &mut ViewContext<Pane>,
-        on_click: F,
+        on_click: F1,
+        on_down: F2,
         context_menu: Option<ViewHandle<ContextMenu>>,
     ) -> AnyElement<Pane> {
         enum TabBarButton {}
@@ -1440,6 +1444,7 @@ impl Pane {
                 .with_height(style.button_width)
         })
         .with_cursor_style(CursorStyle::PointingHand)
+        .on_down(MouseButton::Left, move |_, pane, cx| on_down(pane, cx))
         .on_click(MouseButton::Left, move |_, pane, cx| on_click(pane, cx))
         .into_any();
         if let Some((tooltip, action)) = tooltip {