Restore focus when closing context menu

This commit is contained in:
Antonio Scandurra 2022-05-26 15:21:02 +02:00
parent a5044ccbba
commit 82ddac8e7e
5 changed files with 41 additions and 15 deletions

1
Cargo.lock generated
View file

@ -6088,6 +6088,7 @@ dependencies = [
"collections", "collections",
"command_palette", "command_palette",
"contacts_panel", "contacts_panel",
"context_menu",
"ctor", "ctor",
"diagnostics", "diagnostics",
"dirs 3.0.1", "dirs 3.0.1",

View file

@ -1,9 +1,18 @@
use gpui::{ use gpui::{
elements::*, geometry::vector::Vector2F, platform::CursorStyle, Action, Axis, Entity, elements::*, geometry::vector::Vector2F, impl_internal_actions, platform::CursorStyle, Action,
RenderContext, SizeConstraint, View, ViewContext, Axis, Entity, MutableAppContext, RenderContext, SizeConstraint, View, ViewContext,
}; };
use settings::Settings; use settings::Settings;
pub fn init(cx: &mut MutableAppContext) {
cx.add_action(ContextMenu::dismiss);
}
#[derive(Clone)]
struct Dismiss;
impl_internal_actions!(context_menu, [Dismiss]);
pub enum ContextMenuItem { pub enum ContextMenuItem {
Item { Item {
label: String, label: String,
@ -25,11 +34,13 @@ impl ContextMenuItem {
} }
} }
#[derive(Default)]
pub struct ContextMenu { pub struct ContextMenu {
position: Vector2F, position: Vector2F,
items: Vec<ContextMenuItem>, items: Vec<ContextMenuItem>,
selected_index: Option<usize>, selected_index: Option<usize>,
visible: bool, visible: bool,
previously_focused_view_id: Option<usize>,
} }
impl Entity for ContextMenu { impl Entity for ContextMenu {
@ -72,11 +83,13 @@ impl View for ContextMenu {
impl ContextMenu { impl ContextMenu {
pub fn new() -> Self { pub fn new() -> Self {
Self { Default::default()
position: Default::default(), }
items: Default::default(),
selected_index: Default::default(), fn dismiss(&mut self, _: &Dismiss, cx: &mut ViewContext<Self>) {
visible: false, if cx.handle().is_focused(cx) {
let window_id = cx.window_id();
(**cx).focus(window_id, self.previously_focused_view_id.take());
} }
} }
@ -87,11 +100,15 @@ impl ContextMenu {
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) { ) {
let mut items = items.into_iter().peekable(); let mut items = items.into_iter().peekable();
assert!(items.peek().is_some(), "must have at least one item"); if items.peek().is_some() {
self.items = items.collect(); self.items = items.collect();
self.position = position; self.position = position;
self.visible = true; self.visible = true;
cx.focus_self(); self.previously_focused_view_id = cx.focused_view_id(cx.window_id());
cx.focus_self();
} else {
self.visible = false;
}
cx.notify(); cx.notify();
} }
@ -107,7 +124,10 @@ impl ContextMenu {
&Default::default(), &Default::default(),
Some(ix) == self.selected_index, Some(ix) == self.selected_index,
); );
Label::new(label.to_string(), style.label.clone()).boxed() Label::new(label.to_string(), style.label.clone())
.contained()
.with_style(style.container)
.boxed()
} }
ContextMenuItem::Separator => Empty::new() ContextMenuItem::Separator => Empty::new()
.collapsed() .collapsed()
@ -180,7 +200,10 @@ impl ContextMenu {
.boxed() .boxed()
}) })
.with_cursor_style(CursorStyle::PointingHand) .with_cursor_style(CursorStyle::PointingHand)
.on_click(move |_, _, cx| cx.dispatch_any_action(action.boxed_clone())) .on_click(move |_, _, cx| {
cx.dispatch_any_action(action.boxed_clone());
cx.dispatch_action(Dismiss);
})
.boxed() .boxed()
} }
ContextMenuItem::Separator => Empty::new() ContextMenuItem::Separator => Empty::new()

View file

@ -2407,7 +2407,7 @@ impl MutableAppContext {
}) })
} }
fn focus(&mut self, window_id: usize, view_id: Option<usize>) { pub fn focus(&mut self, window_id: usize, view_id: Option<usize>) {
if let Some(pending_focus_index) = self.pending_focus_index { if let Some(pending_focus_index) = self.pending_focus_index {
self.pending_effects.remove(pending_focus_index); self.pending_effects.remove(pending_focus_index);
} }

View file

@ -22,6 +22,7 @@ chat_panel = { path = "../chat_panel" }
cli = { path = "../cli" } cli = { path = "../cli" }
collections = { path = "../collections" } collections = { path = "../collections" }
command_palette = { path = "../command_palette" } command_palette = { path = "../command_palette" }
context_menu = { path = "../context_menu" }
client = { path = "../client" } client = { path = "../client" }
clock = { path = "../clock" } clock = { path = "../clock" }
contacts_panel = { path = "../contacts_panel" } contacts_panel = { path = "../contacts_panel" }

View file

@ -134,6 +134,7 @@ fn main() {
let mut languages = languages::build_language_registry(login_shell_env_loaded); let mut languages = languages::build_language_registry(login_shell_env_loaded);
let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http.clone(), cx)); let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http.clone(), cx));
context_menu::init(cx);
auto_update::init(http, client::ZED_SERVER_URL.clone(), cx); auto_update::init(http, client::ZED_SERVER_URL.clone(), cx);
project::Project::init(&client); project::Project::init(&client);
client::Channel::init(&client); client::Channel::init(&client);