editor: Hide mouse context menu when modal is opened (#29127)
Closes #28787 The context menu appears before the modal because it is a Deferred element, which is always displayed above normal elements. Release Notes: Previously, the editor context menu appeared before the Command Palette. This commit ensures the editor context menu is hidden when a modal, including the Command Palette, is opened.
This commit is contained in:
parent
9a3434efb4
commit
6d2bdc3bac
4 changed files with 84 additions and 5 deletions
|
@ -12,8 +12,8 @@ use crate::{
|
||||||
use buffer_diff::{BufferDiff, DiffHunkSecondaryStatus, DiffHunkStatus, DiffHunkStatusKind};
|
use buffer_diff::{BufferDiff, DiffHunkSecondaryStatus, DiffHunkStatus, DiffHunkStatusKind};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
BackgroundExecutor, SemanticVersion, TestAppContext, UpdateGlobal, VisualTestContext,
|
BackgroundExecutor, DismissEvent, SemanticVersion, TestAppContext, UpdateGlobal,
|
||||||
WindowBounds, WindowOptions, div,
|
VisualTestContext, WindowBounds, WindowOptions, div,
|
||||||
};
|
};
|
||||||
use indoc::indoc;
|
use indoc::indoc;
|
||||||
use language::{
|
use language::{
|
||||||
|
@ -19549,6 +19549,64 @@ println!("5");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_hide_mouse_context_menu_on_modal_opened(cx: &mut TestAppContext) {
|
||||||
|
struct EmptyModalView {
|
||||||
|
focus_handle: gpui::FocusHandle,
|
||||||
|
}
|
||||||
|
impl EventEmitter<DismissEvent> for EmptyModalView {}
|
||||||
|
impl Render for EmptyModalView {
|
||||||
|
fn render(&mut self, _: &mut Window, _: &mut Context<'_, Self>) -> impl IntoElement {
|
||||||
|
div()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Focusable for EmptyModalView {
|
||||||
|
fn focus_handle(&self, _cx: &App) -> gpui::FocusHandle {
|
||||||
|
self.focus_handle.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl workspace::ModalView for EmptyModalView {}
|
||||||
|
fn new_empty_modal_view(cx: &App) -> EmptyModalView {
|
||||||
|
EmptyModalView {
|
||||||
|
focus_handle: cx.focus_handle(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init_test(cx, |_| {});
|
||||||
|
|
||||||
|
let fs = FakeFs::new(cx.executor());
|
||||||
|
let project = Project::test(fs, [], cx).await;
|
||||||
|
let workspace = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx));
|
||||||
|
let buffer = cx.update(|cx| MultiBuffer::build_simple("hello world!", cx));
|
||||||
|
let cx = &mut VisualTestContext::from_window(*workspace.deref(), cx);
|
||||||
|
let editor = cx.new_window_entity(|window, cx| {
|
||||||
|
Editor::new(
|
||||||
|
EditorMode::full(),
|
||||||
|
buffer,
|
||||||
|
Some(project.clone()),
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
workspace
|
||||||
|
.update(cx, |workspace, window, cx| {
|
||||||
|
workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
editor.update_in(cx, |editor, window, cx| {
|
||||||
|
editor.open_context_menu(&OpenContextMenu, window, cx);
|
||||||
|
assert!(editor.mouse_context_menu.is_some());
|
||||||
|
});
|
||||||
|
workspace
|
||||||
|
.update(cx, |workspace, window, cx| {
|
||||||
|
workspace.toggle_modal(window, cx, |_, cx| new_empty_modal_view(cx));
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
cx.read(|cx| {
|
||||||
|
assert!(editor.read(cx).mouse_context_menu.is_none());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn empty_range(row: usize, column: usize) -> Range<DisplayPoint> {
|
fn empty_range(row: usize, column: usize) -> Range<DisplayPoint> {
|
||||||
let point = DisplayPoint::new(DisplayRow(row as u32), column as u32);
|
let point = DisplayPoint::new(DisplayRow(row as u32), column as u32);
|
||||||
point..point
|
point..point
|
||||||
|
|
|
@ -928,9 +928,17 @@ impl Item for Editor {
|
||||||
&mut self,
|
&mut self,
|
||||||
workspace: &mut Workspace,
|
workspace: &mut Workspace,
|
||||||
_window: &mut Window,
|
_window: &mut Window,
|
||||||
_: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) {
|
||||||
self.workspace = Some((workspace.weak_handle(), workspace.database_id()));
|
self.workspace = Some((workspace.weak_handle(), workspace.database_id()));
|
||||||
|
if let Some(workspace) = &workspace.weak_handle().upgrade() {
|
||||||
|
cx.subscribe(&workspace, |editor, _, event: &workspace::Event, _cx| {
|
||||||
|
if matches!(event, workspace::Event::ModalOpened) {
|
||||||
|
editor.mouse_context_menu.take();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_item_events(event: &EditorEvent, mut f: impl FnMut(ItemEvent)) {
|
fn to_item_events(event: &EditorEvent, mut f: impl FnMut(ItemEvent)) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use gpui::{
|
use gpui::{
|
||||||
AnyView, DismissEvent, Entity, FocusHandle, Focusable as _, ManagedView, MouseButton,
|
AnyView, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable as _, ManagedView,
|
||||||
Subscription,
|
MouseButton, Subscription,
|
||||||
};
|
};
|
||||||
use ui::prelude::*;
|
use ui::prelude::*;
|
||||||
|
|
||||||
|
@ -56,6 +56,10 @@ pub struct ModalLayer {
|
||||||
dismiss_on_focus_lost: bool,
|
dismiss_on_focus_lost: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) struct ModalOpenedEvent;
|
||||||
|
|
||||||
|
impl EventEmitter<ModalOpenedEvent> for ModalLayer {}
|
||||||
|
|
||||||
impl Default for ModalLayer {
|
impl Default for ModalLayer {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
|
@ -84,6 +88,7 @@ impl ModalLayer {
|
||||||
}
|
}
|
||||||
let new_modal = cx.new(|cx| build_view(window, cx));
|
let new_modal = cx.new(|cx| build_view(window, cx));
|
||||||
self.show_modal(new_modal, window, cx);
|
self.show_modal(new_modal, window, cx);
|
||||||
|
cx.emit(ModalOpenedEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_modal<V>(&mut self, new_modal: Entity<V>, window: &mut Window, cx: &mut Context<Self>)
|
fn show_modal<V>(&mut self, new_modal: Entity<V>, window: &mut Window, cx: &mut Context<Self>)
|
||||||
|
|
|
@ -781,6 +781,7 @@ pub enum Event {
|
||||||
language: &'static str,
|
language: &'static str,
|
||||||
},
|
},
|
||||||
ZoomChanged,
|
ZoomChanged,
|
||||||
|
ModalOpened,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -1051,6 +1052,13 @@ impl Workspace {
|
||||||
cx.emit(Event::WorkspaceCreated(weak_handle.clone()));
|
cx.emit(Event::WorkspaceCreated(weak_handle.clone()));
|
||||||
let modal_layer = cx.new(|_| ModalLayer::new());
|
let modal_layer = cx.new(|_| ModalLayer::new());
|
||||||
let toast_layer = cx.new(|_| ToastLayer::new());
|
let toast_layer = cx.new(|_| ToastLayer::new());
|
||||||
|
cx.subscribe(
|
||||||
|
&modal_layer,
|
||||||
|
|_, _, _: &modal_layer::ModalOpenedEvent, cx| {
|
||||||
|
cx.emit(Event::ModalOpened);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.detach();
|
||||||
|
|
||||||
let bottom_dock_layout = WorkspaceSettings::get_global(cx).bottom_dock_layout;
|
let bottom_dock_layout = WorkspaceSettings::get_global(cx).bottom_dock_layout;
|
||||||
let left_dock = Dock::new(DockPosition::Left, modal_layer.clone(), window, cx);
|
let left_dock = Dock::new(DockPosition::Left, modal_layer.clone(), window, cx);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue