Dismiss context menu when one of its action is dispatched

This commit is contained in:
Antonio Scandurra 2022-05-30 10:01:49 +02:00
parent 2b9015c096
commit 63900612b0
2 changed files with 47 additions and 8 deletions

View file

@ -1,6 +1,9 @@
use std::{any::TypeId, time::Duration};
use gpui::{
elements::*, geometry::vector::Vector2F, keymap, platform::CursorStyle, Action, AppContext,
Axis, Entity, MutableAppContext, RenderContext, SizeConstraint, View, ViewContext,
Axis, Entity, MutableAppContext, RenderContext, SizeConstraint, Subscription, View,
ViewContext,
};
use menu::*;
use settings::Settings;
@ -37,15 +40,22 @@ impl ContextMenuItem {
fn is_separator(&self) -> bool {
matches!(self, Self::Separator)
}
fn action_id(&self) -> Option<TypeId> {
match self {
ContextMenuItem::Item { action, .. } => Some(action.id()),
ContextMenuItem::Separator => None,
}
}
}
#[derive(Default)]
pub struct ContextMenu {
position: Vector2F,
items: Vec<ContextMenuItem>,
selected_index: Option<usize>,
visible: bool,
previously_focused_view_id: Option<usize>,
_actions_observation: Subscription,
}
impl Entity for ContextMenu {
@ -87,15 +97,36 @@ impl View for ContextMenu {
}
fn on_blur(&mut self, cx: &mut ViewContext<Self>) {
self.visible = false;
self.selected_index.take();
cx.notify();
self.reset(cx);
}
}
impl ContextMenu {
pub fn new() -> Self {
Default::default()
pub fn new(cx: &mut ViewContext<Self>) -> Self {
Self {
position: Default::default(),
items: Default::default(),
selected_index: Default::default(),
visible: Default::default(),
previously_focused_view_id: Default::default(),
_actions_observation: cx.observe_actions(Self::action_dispatched),
}
}
fn action_dispatched(&mut self, action_id: TypeId, cx: &mut ViewContext<Self>) {
if let Some(ix) = self
.items
.iter()
.position(|item| item.action_id() == Some(action_id))
{
self.selected_index = Some(ix);
cx.notify();
cx.spawn(|this, mut cx| async move {
cx.background().timer(Duration::from_millis(100)).await;
this.update(&mut cx, |this, cx| this.cancel(&Default::default(), cx));
})
.detach();
}
}
fn confirm(&mut self, _: &Confirm, cx: &mut ViewContext<Self>) {
@ -109,12 +140,20 @@ impl ContextMenu {
}
fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
self.reset(cx);
if cx.handle().is_focused(cx) {
let window_id = cx.window_id();
(**cx).focus(window_id, self.previously_focused_view_id.take());
}
}
fn reset(&mut self, cx: &mut ViewContext<Self>) {
self.items.clear();
self.visible = false;
self.selected_index.take();
cx.notify();
}
fn select_first(&mut self, _: &SelectFirst, cx: &mut ViewContext<Self>) {
self.selected_index = self.items.iter().position(|item| !item.is_separator());
cx.notify();

View file

@ -172,7 +172,7 @@ impl ProjectPanel {
selection: None,
edit_state: None,
filename_editor,
context_menu: cx.add_view(|_| ContextMenu::new()),
context_menu: cx.add_view(|cx| ContextMenu::new(cx)),
};
this.update_visible_entries(None, cx);
this