diff --git a/crates/ui/src/components/context_menu.rs b/crates/ui/src/components/context_menu.rs index ec35412feec73dcbf1dfa7c66bac68f3622bdb0e..6586bf66e26ea9461158613de6ba3e4eaeaffaa2 100644 --- a/crates/ui/src/components/context_menu.rs +++ b/crates/ui/src/components/context_menu.rs @@ -4,8 +4,8 @@ use crate::{ }; use gpui::{ Action, AnyElement, App, Bounds, Corner, DismissEvent, Entity, EventEmitter, FocusHandle, - Focusable, MouseDownEvent, MouseMoveEvent, Pixels, Point, Size, Subscription, anchored, canvas, - prelude::*, px, + Focusable, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, Point, Size, + Subscription, anchored, canvas, prelude::*, px, }; use menu::{SelectChild, SelectFirst, SelectLast, SelectNext, SelectParent, SelectPrevious}; use settings::Settings; @@ -252,6 +252,7 @@ pub struct ContextMenu { submenu_trigger_observed_bounds_by_item: Rc>>>, is_submenu: bool, submenu_hovered: bool, + submenu_trigger_mouse_down: bool, submenu_generation: u64, ignore_blur_cancel_until: Option, parent_menu: Option>, @@ -352,6 +353,7 @@ impl ContextMenu { submenu_trigger_observed_bounds_by_item: Rc::new(RefCell::new(HashMap::new())), is_submenu: false, submenu_hovered: false, + submenu_trigger_mouse_down: false, submenu_generation: 0, ignore_blur_cancel_until: None, parent_menu: None, @@ -430,6 +432,7 @@ impl ContextMenu { submenu_trigger_observed_bounds_by_item: Rc::new(RefCell::new(HashMap::new())), is_submenu: false, submenu_hovered: false, + submenu_trigger_mouse_down: false, submenu_generation: 0, ignore_blur_cancel_until: None, parent_menu: None, @@ -500,6 +503,7 @@ impl ContextMenu { submenu_trigger_observed_bounds_by_item: Rc::new(RefCell::new(HashMap::new())), is_submenu: false, submenu_hovered: false, + submenu_trigger_mouse_down: false, submenu_generation: 0, ignore_blur_cancel_until: None, parent_menu: None, @@ -1135,6 +1139,7 @@ impl ContextMenu { submenu_trigger_observed_bounds_by_item: Rc::new(RefCell::new(HashMap::new())), is_submenu: true, submenu_hovered: false, + submenu_trigger_mouse_down: false, submenu_generation: 0, ignore_blur_cancel_until: None, parent_menu: Some(parent_entity), @@ -1386,6 +1391,17 @@ impl ContextMenu { div() .id(("context-menu-submenu-trigger", ix)) + .capture_any_mouse_down(cx.listener(move |this, event: &MouseDownEvent, _, _| { + // This prevents on_hover(false) from closing the submenu during a click. + if event.button == MouseButton::Left { + this.submenu_trigger_mouse_down = true; + } + })) + .capture_any_mouse_up(cx.listener(move |this, event: &MouseUpEvent, _, _| { + if event.button == MouseButton::Left { + this.submenu_trigger_mouse_down = false; + } + })) .on_mouse_move(cx.listener(move |this, event: &MouseMoveEvent, _, cx| { this.update_last_mouse_position(event.position); @@ -1445,6 +1461,10 @@ impl ContextMenu { cx.notify(); } else { + if this.submenu_trigger_mouse_down { + return; + } + let is_open_for_this_item = matches!( &this.submenu_state, SubmenuState::Open(open_submenu) if open_submenu.item_index == ix @@ -2003,6 +2023,20 @@ impl Render for ContextMenu { } } + if this.is_submenu { + if let Some(parent) = &this.parent_menu { + let overriden_by_parent_trigger = parent + .read(cx) + .submenu_trigger_observed_bounds_by_item + .borrow() + .values() + .any(|bounds| bounds.contains(&event.position)); + if overriden_by_parent_trigger { + return; + } + } + } + this.cancel(&menu::Cancel, window, cx) }, ))