input: Disable context menu item for disabled input. (#1280)
This commit is contained in:
parent
16105da122
commit
a6a14fd57b
6 changed files with 70 additions and 67 deletions
|
|
@ -17,24 +17,25 @@ struct Info(usize);
|
||||||
|
|
||||||
actions!(menu_story, [Copy, Paste, Cut, SearchAll, ToggleCheck]);
|
actions!(menu_story, [Copy, Paste, Cut, SearchAll, ToggleCheck]);
|
||||||
|
|
||||||
|
const CONTEXT: &str = "menu_story";
|
||||||
pub fn init(cx: &mut App) {
|
pub fn init(cx: &mut App) {
|
||||||
cx.bind_keys([
|
cx.bind_keys([
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
KeyBinding::new("cmd-c", Copy, None),
|
KeyBinding::new("cmd-c", Copy, Some(CONTEXT)),
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
KeyBinding::new("ctrl-c", Copy, None),
|
KeyBinding::new("ctrl-c", Copy, Some(CONTEXT)),
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
KeyBinding::new("cmd-v", Paste, None),
|
KeyBinding::new("cmd-v", Paste, Some(CONTEXT)),
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
KeyBinding::new("ctrl-v", Paste, None),
|
KeyBinding::new("ctrl-v", Paste, Some(CONTEXT)),
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
KeyBinding::new("cmd-x", Cut, None),
|
KeyBinding::new("cmd-x", Cut, Some(CONTEXT)),
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
KeyBinding::new("ctrl-x", Cut, None),
|
KeyBinding::new("ctrl-x", Cut, Some(CONTEXT)),
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
KeyBinding::new("cmd-shift-f", SearchAll, None),
|
KeyBinding::new("cmd-shift-f", SearchAll, Some(CONTEXT)),
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
KeyBinding::new("ctrl-shift-f", SearchAll, None),
|
KeyBinding::new("ctrl-shift-f", SearchAll, Some(CONTEXT)),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,6 +117,7 @@ impl Render for MenuStory {
|
||||||
let checked = self.checked;
|
let checked = self.checked;
|
||||||
|
|
||||||
v_flex()
|
v_flex()
|
||||||
|
.key_context(CONTEXT)
|
||||||
.track_focus(&self.focus_handle)
|
.track_focus(&self.focus_handle)
|
||||||
.on_action(cx.listener(Self::on_copy))
|
.on_action(cx.listener(Self::on_copy))
|
||||||
.on_action(cx.listener(Self::on_cut))
|
.on_action(cx.listener(Self::on_cut))
|
||||||
|
|
|
||||||
|
|
@ -18,25 +18,25 @@ use serde::Deserialize;
|
||||||
struct Info(usize);
|
struct Info(usize);
|
||||||
|
|
||||||
actions!(popover_story, [Copy, Paste, Cut, SearchAll, ToggleCheck]);
|
actions!(popover_story, [Copy, Paste, Cut, SearchAll, ToggleCheck]);
|
||||||
|
const CONTEXT: &str = "popover-story";
|
||||||
pub fn init(cx: &mut App) {
|
pub fn init(cx: &mut App) {
|
||||||
cx.bind_keys([
|
cx.bind_keys([
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
KeyBinding::new("cmd-c", Copy, None),
|
KeyBinding::new("cmd-c", Copy, Some(CONTEXT)),
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
KeyBinding::new("ctrl-c", Copy, None),
|
KeyBinding::new("ctrl-c", Copy, Some(CONTEXT)),
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
KeyBinding::new("cmd-v", Paste, None),
|
KeyBinding::new("cmd-v", Paste, Some(CONTEXT)),
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
KeyBinding::new("ctrl-v", Paste, None),
|
KeyBinding::new("ctrl-v", Paste, Some(CONTEXT)),
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
KeyBinding::new("cmd-x", Cut, None),
|
KeyBinding::new("cmd-x", Cut, Some(CONTEXT)),
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
KeyBinding::new("ctrl-x", Cut, None),
|
KeyBinding::new("ctrl-x", Cut, Some(CONTEXT)),
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
KeyBinding::new("cmd-shift-f", SearchAll, None),
|
KeyBinding::new("cmd-shift-f", SearchAll, Some(CONTEXT)),
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
KeyBinding::new("ctrl-shift-f", SearchAll, None),
|
KeyBinding::new("ctrl-shift-f", SearchAll, Some(CONTEXT)),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -159,6 +159,7 @@ impl Render for PopoverStory {
|
||||||
let form = self.form.clone();
|
let form = self.form.clone();
|
||||||
|
|
||||||
v_flex()
|
v_flex()
|
||||||
|
.key_context(CONTEXT)
|
||||||
.track_focus(&self.focus_handle)
|
.track_focus(&self.focus_handle)
|
||||||
.on_action(cx.listener(Self::on_copy))
|
.on_action(cx.listener(Self::on_copy))
|
||||||
.on_action(cx.listener(Self::on_cut))
|
.on_action(cx.listener(Self::on_cut))
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use gpui::{
|
use gpui::{
|
||||||
anchored, deferred, div, prelude::FluentBuilder as _, px, App, AppContext as _, Context,
|
anchored, deferred, div, prelude::FluentBuilder as _, px, App, AppContext as _, Context,
|
||||||
DismissEvent, Entity, IntoElement, MouseDownEvent, ParentElement as _, Pixels, Point, Render,
|
Corner, DismissEvent, Entity, IntoElement, MouseDownEvent, ParentElement as _, Pixels, Point,
|
||||||
Styled, Subscription, Window,
|
Render, Styled, Subscription, Window,
|
||||||
};
|
};
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
|
|
||||||
|
|
@ -40,11 +40,13 @@ impl InputState {
|
||||||
self.handle_hover_definition(offset, window, cx);
|
self.handle_hover_definition(offset, window, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
let has_goto_definition = self.lsp.definition_provider.is_some();
|
let is_enable = !self.disabled;
|
||||||
let has_code_action = !self.lsp.code_action_providers.is_empty();
|
let has_goto_definition = is_enable && self.lsp.definition_provider.is_some();
|
||||||
let is_selected = !self.selected_range.is_empty();
|
let has_code_action = is_enable && !self.lsp.code_action_providers.is_empty();
|
||||||
let has_paste = cx.read_from_clipboard().is_some();
|
let is_selected = is_enable && !self.selected_range.is_empty();
|
||||||
|
let has_paste = is_enable && cx.read_from_clipboard().is_some();
|
||||||
|
|
||||||
|
let action_context = self.focus_handle.clone();
|
||||||
self.mouse_context_menu.update(cx, |this, cx| {
|
self.mouse_context_menu.update(cx, |this, cx| {
|
||||||
this.mouse_position = event.position;
|
this.mouse_position = event.position;
|
||||||
this.menu.update(cx, |menu, cx| {
|
this.menu.update(cx, |menu, cx| {
|
||||||
|
|
@ -62,13 +64,18 @@ impl InputState {
|
||||||
)
|
)
|
||||||
.separator()
|
.separator()
|
||||||
})
|
})
|
||||||
.menu_with_enable(t!("Input.Cut"), Box::new(input::Cut), is_selected)
|
.menu_with_enable(
|
||||||
|
t!("Input.Cut"),
|
||||||
|
Box::new(input::Cut),
|
||||||
|
is_enable && is_selected,
|
||||||
|
)
|
||||||
.menu_with_enable(t!("Input.Copy"), Box::new(input::Copy), is_selected)
|
.menu_with_enable(t!("Input.Copy"), Box::new(input::Copy), is_selected)
|
||||||
.menu_with_enable(t!("Input.Paste"), Box::new(input::Paste), has_paste)
|
.menu_with_enable(t!("Input.Paste"), Box::new(input::Paste), has_paste)
|
||||||
.separator()
|
.separator()
|
||||||
.menu(t!("Input.Select All"), Box::new(input::SelectAll));
|
.menu(t!("Input.Select All"), Box::new(input::SelectAll));
|
||||||
|
|
||||||
menu.menu_items = new_menu.menu_items;
|
menu.menu_items = new_menu.menu_items;
|
||||||
|
menu.action_context = Some(action_context);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
});
|
});
|
||||||
this.open = true;
|
this.open = true;
|
||||||
|
|
@ -123,13 +130,11 @@ impl Render for MouseContextMenu {
|
||||||
return div().into_any_element();
|
return div().into_any_element();
|
||||||
}
|
}
|
||||||
|
|
||||||
let pos = self.mouse_position;
|
|
||||||
|
|
||||||
deferred(
|
deferred(
|
||||||
anchored()
|
anchored()
|
||||||
.snap_to_window_with_margin(px(8.))
|
.snap_to_window_with_margin(px(8.))
|
||||||
.anchor(gpui::Corner::TopLeft)
|
.anchor(Corner::TopLeft)
|
||||||
.position(pos)
|
.position(self.mouse_position)
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
.font_family(".SystemUIFont")
|
.font_family(".SystemUIFont")
|
||||||
|
|
|
||||||
|
|
@ -45,18 +45,18 @@ impl Kbd {
|
||||||
window: &Window,
|
window: &Window,
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
let key_context = context.and_then(|context| KeyContext::parse(context).ok());
|
let key_context = context.and_then(|context| KeyContext::parse(context).ok());
|
||||||
let bindings = match key_context {
|
let binding = match key_context {
|
||||||
Some(context) => window.bindings_for_action_in_context(action, context),
|
Some(context) => {
|
||||||
None => window.bindings_for_action(action),
|
window.highest_precedence_binding_for_action_in_context(action, context)
|
||||||
};
|
|
||||||
|
|
||||||
bindings.first().and_then(|binding| {
|
|
||||||
if let Some(key) = binding.keystrokes().first() {
|
|
||||||
Some(Self::new(key.as_keystroke().clone()))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
})
|
None => window.highest_precedence_binding_for_action(action),
|
||||||
|
}?;
|
||||||
|
|
||||||
|
if let Some(key) = binding.keystrokes().first() {
|
||||||
|
Some(Self::new(key.as_keystroke().clone()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the Platform specific keybinding string by KeyStroke
|
/// Return the Platform specific keybinding string by KeyStroke
|
||||||
|
|
@ -208,6 +208,8 @@ impl RenderOnce for Kbd {
|
||||||
.rounded_sm()
|
.rounded_sm()
|
||||||
.line_height(relative(1.))
|
.line_height(relative(1.))
|
||||||
.text_xs()
|
.text_xs()
|
||||||
|
.whitespace_normal()
|
||||||
|
.flex_shrink_0()
|
||||||
.refine_style(&self.style)
|
.refine_style(&self.style)
|
||||||
.child(Self::format(&self.stroke))
|
.child(Self::format(&self.stroke))
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,7 @@ use gpui::{
|
||||||
InteractiveElement, IntoElement, KeyBinding, ParentElement, Pixels, Render, ScrollHandle,
|
InteractiveElement, IntoElement, KeyBinding, ParentElement, Pixels, Render, ScrollHandle,
|
||||||
SharedString, StatefulInteractiveElement, Styled, WeakEntity, Window,
|
SharedString, StatefulInteractiveElement, Styled, WeakEntity, Window,
|
||||||
};
|
};
|
||||||
use gpui::{AsKeystroke, Half, MouseDownEvent, Subscription};
|
use gpui::{Half, MouseDownEvent, Subscription};
|
||||||
use std::ops::Deref;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
const CONTEXT: &str = "PopupMenu";
|
const CONTEXT: &str = "PopupMenu";
|
||||||
|
|
@ -109,10 +108,10 @@ impl PopupMenuItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PopupMenu {
|
pub struct PopupMenu {
|
||||||
/// The parent menu of this menu, if this is a submenu
|
|
||||||
parent_menu: Option<WeakEntity<Self>>,
|
|
||||||
focus_handle: FocusHandle,
|
focus_handle: FocusHandle,
|
||||||
pub(crate) menu_items: Vec<PopupMenuItem>,
|
pub(crate) menu_items: Vec<PopupMenuItem>,
|
||||||
|
/// The focus handle of Entity to handle actions.
|
||||||
|
pub(crate) action_context: Option<FocusHandle>,
|
||||||
has_icon: bool,
|
has_icon: bool,
|
||||||
selected_index: Option<usize>,
|
selected_index: Option<usize>,
|
||||||
min_width: Option<Pixels>,
|
min_width: Option<Pixels>,
|
||||||
|
|
@ -121,12 +120,13 @@ pub struct PopupMenu {
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
size: Size,
|
size: Size,
|
||||||
|
|
||||||
|
/// The parent menu of this menu, if this is a submenu
|
||||||
|
parent_menu: Option<WeakEntity<Self>>,
|
||||||
scrollable: bool,
|
scrollable: bool,
|
||||||
external_link_icon: bool,
|
external_link_icon: bool,
|
||||||
scroll_handle: ScrollHandle,
|
scroll_handle: ScrollHandle,
|
||||||
scroll_state: ScrollbarState,
|
scroll_state: ScrollbarState,
|
||||||
|
|
||||||
previous_focus_handle: Option<FocusHandle>,
|
|
||||||
_subscriptions: Vec<Subscription>,
|
_subscriptions: Vec<Subscription>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -134,7 +134,7 @@ impl PopupMenu {
|
||||||
pub(crate) fn new(cx: &mut App) -> Self {
|
pub(crate) fn new(cx: &mut App) -> Self {
|
||||||
Self {
|
Self {
|
||||||
focus_handle: cx.focus_handle(),
|
focus_handle: cx.focus_handle(),
|
||||||
previous_focus_handle: None,
|
action_context: None,
|
||||||
parent_menu: None,
|
parent_menu: None,
|
||||||
menu_items: Vec::new(),
|
menu_items: Vec::new(),
|
||||||
selected_index: None,
|
selected_index: None,
|
||||||
|
|
@ -159,7 +159,7 @@ impl PopupMenu {
|
||||||
) -> Entity<Self> {
|
) -> Entity<Self> {
|
||||||
cx.new(|cx| {
|
cx.new(|cx| {
|
||||||
let mut menu = Self::new(cx);
|
let mut menu = Self::new(cx);
|
||||||
menu.previous_focus_handle = window.focused(cx);
|
menu.action_context = window.focused(cx);
|
||||||
f(menu, window, cx)
|
f(menu, window, cx)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -725,8 +725,8 @@ impl PopupMenu {
|
||||||
cx.emit(DismissEvent);
|
cx.emit(DismissEvent);
|
||||||
|
|
||||||
// Focus back to the previous focused handle.
|
// Focus back to the previous focused handle.
|
||||||
if let Some(previous_focus_handle) = self.previous_focus_handle.as_ref() {
|
if let Some(action_context) = self.action_context.as_ref() {
|
||||||
window.focus(previous_focus_handle);
|
window.focus(action_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(parent_menu) = self.parent_menu.clone() else {
|
let Some(parent_menu) = self.parent_menu.clone() else {
|
||||||
|
|
@ -743,22 +743,15 @@ impl PopupMenu {
|
||||||
fn render_key_binding(
|
fn render_key_binding(
|
||||||
action: Option<Box<dyn Action>>,
|
action: Option<Box<dyn Action>>,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
_: &mut Context<Self>,
|
||||||
) -> Option<impl IntoElement> {
|
) -> Option<impl IntoElement> {
|
||||||
if let Some(action) = action {
|
let action = action?;
|
||||||
if let Some(key_binding) = window.bindings_for_action(action.deref()).first() {
|
Kbd::binding_for_action(action.as_ref(), None, window).map(|this| {
|
||||||
let el = div().text_color(cx.theme().muted_foreground).children(
|
this.p_0()
|
||||||
key_binding
|
.flex_nowrap()
|
||||||
.keystrokes()
|
.border_0()
|
||||||
.into_iter()
|
.bg(gpui::transparent_white())
|
||||||
.map(|key| Kbd::format(key.as_keystroke())),
|
})
|
||||||
);
|
|
||||||
|
|
||||||
return Some(el);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_icon(
|
fn render_icon(
|
||||||
|
|
|
||||||
|
|
@ -253,7 +253,7 @@
|
||||||
"list.active.border": "#36A3D9",
|
"list.active.border": "#36A3D9",
|
||||||
"list.even.background": "#191F2A99",
|
"list.even.background": "#191F2A99",
|
||||||
"muted.background": "#1F2430",
|
"muted.background": "#1F2430",
|
||||||
"muted.foreground": "#8a8986ff",
|
"muted.foreground": "#6a6967",
|
||||||
"panel.background": "#1F2126",
|
"panel.background": "#1F2126",
|
||||||
"popover.background": "#1F2127",
|
"popover.background": "#1F2127",
|
||||||
"popover.foreground": "#B3B1AD",
|
"popover.foreground": "#B3B1AD",
|
||||||
|
|
@ -263,10 +263,10 @@
|
||||||
"primary.hover.background": "#3DAEE9",
|
"primary.hover.background": "#3DAEE9",
|
||||||
"scrollbar.background": "#0A0E1400",
|
"scrollbar.background": "#0A0E1400",
|
||||||
"scrollbar.thumb.background": "#bfbdb64c",
|
"scrollbar.thumb.background": "#bfbdb64c",
|
||||||
"secondary.active.background": "#191d24",
|
"secondary.active.background": "#2D2F34",
|
||||||
"secondary.background": "#1f2127",
|
"secondary.background": "#2D2F34",
|
||||||
"secondary.foreground": "#B3B1AD",
|
"secondary.foreground": "#B3B1AD",
|
||||||
"secondary.hover.background": "#191d2499",
|
"secondary.hover.background": "#2D2F3499",
|
||||||
"tab.active.foreground": "#B3B1AD",
|
"tab.active.foreground": "#B3B1AD",
|
||||||
"tab.background": "#1F2127",
|
"tab.background": "#1F2127",
|
||||||
"tab.foreground": "#82807d",
|
"tab.foreground": "#82807d",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue