Dismiss context menu when one of its action is dispatched
This commit is contained in:
parent
2b9015c096
commit
63900612b0
2 changed files with 47 additions and 8 deletions
|
@ -1,6 +1,9 @@
|
||||||
|
use std::{any::TypeId, time::Duration};
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
elements::*, geometry::vector::Vector2F, keymap, platform::CursorStyle, Action, AppContext,
|
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 menu::*;
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
|
@ -37,15 +40,22 @@ impl ContextMenuItem {
|
||||||
fn is_separator(&self) -> bool {
|
fn is_separator(&self) -> bool {
|
||||||
matches!(self, Self::Separator)
|
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 {
|
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>,
|
previously_focused_view_id: Option<usize>,
|
||||||
|
_actions_observation: Subscription,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Entity for ContextMenu {
|
impl Entity for ContextMenu {
|
||||||
|
@ -87,15 +97,36 @@ impl View for ContextMenu {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_blur(&mut self, cx: &mut ViewContext<Self>) {
|
fn on_blur(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
self.visible = false;
|
self.reset(cx);
|
||||||
self.selected_index.take();
|
|
||||||
cx.notify();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContextMenu {
|
impl ContextMenu {
|
||||||
pub fn new() -> Self {
|
pub fn new(cx: &mut ViewContext<Self>) -> Self {
|
||||||
Default::default()
|
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>) {
|
fn confirm(&mut self, _: &Confirm, cx: &mut ViewContext<Self>) {
|
||||||
|
@ -109,12 +140,20 @@ impl ContextMenu {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
|
fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
|
||||||
|
self.reset(cx);
|
||||||
if cx.handle().is_focused(cx) {
|
if cx.handle().is_focused(cx) {
|
||||||
let window_id = cx.window_id();
|
let window_id = cx.window_id();
|
||||||
(**cx).focus(window_id, self.previously_focused_view_id.take());
|
(**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>) {
|
fn select_first(&mut self, _: &SelectFirst, cx: &mut ViewContext<Self>) {
|
||||||
self.selected_index = self.items.iter().position(|item| !item.is_separator());
|
self.selected_index = self.items.iter().position(|item| !item.is_separator());
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
|
|
@ -172,7 +172,7 @@ impl ProjectPanel {
|
||||||
selection: None,
|
selection: None,
|
||||||
edit_state: None,
|
edit_state: None,
|
||||||
filename_editor,
|
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.update_visible_entries(None, cx);
|
||||||
this
|
this
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue