Add refinements to the keymap UI (#33816)
This includes mostly polishing up the keystroke editing modal, and some other bits like making the keystroke rendering function more composable. Release Notes: - Added refinements to the keymap UI design. --------- Co-authored-by: Ben Kunkle <ben@zed.dev> Co-authored-by: Ben Kunkle <Ben.kunkle@gmail.com>
This commit is contained in:
parent
fbc4256732
commit
77c4530e12
4 changed files with 233 additions and 163 deletions
|
@ -13,7 +13,7 @@ pub struct KeyBinding {
|
|||
/// More than one keystroke produces a chord.
|
||||
///
|
||||
/// This should always contain at least one keystroke.
|
||||
pub key_binding: gpui::KeyBinding,
|
||||
pub keystrokes: Vec<Keystroke>,
|
||||
|
||||
/// The [`PlatformStyle`] to use when displaying this keybinding.
|
||||
platform_style: PlatformStyle,
|
||||
|
@ -37,7 +37,7 @@ impl KeyBinding {
|
|||
return Self::for_action_in(action, &focused, window, cx);
|
||||
}
|
||||
let key_binding = window.highest_precedence_binding_for_action(action)?;
|
||||
Some(Self::new(key_binding, cx))
|
||||
Some(Self::new_from_gpui(key_binding, cx))
|
||||
}
|
||||
|
||||
/// Like `for_action`, but lets you specify the context from which keybindings are matched.
|
||||
|
@ -48,7 +48,7 @@ impl KeyBinding {
|
|||
cx: &App,
|
||||
) -> Option<Self> {
|
||||
let key_binding = window.highest_precedence_binding_for_action_in(action, focus)?;
|
||||
Some(Self::new(key_binding, cx))
|
||||
Some(Self::new_from_gpui(key_binding, cx))
|
||||
}
|
||||
|
||||
pub fn set_vim_mode(cx: &mut App, enabled: bool) {
|
||||
|
@ -59,9 +59,9 @@ impl KeyBinding {
|
|||
cx.try_global::<VimStyle>().is_some_and(|g| g.0)
|
||||
}
|
||||
|
||||
pub fn new(key_binding: gpui::KeyBinding, cx: &App) -> Self {
|
||||
pub fn new(keystrokes: Vec<Keystroke>, cx: &App) -> Self {
|
||||
Self {
|
||||
key_binding,
|
||||
keystrokes,
|
||||
platform_style: PlatformStyle::platform(),
|
||||
size: None,
|
||||
vim_mode: KeyBinding::is_vim_mode(cx),
|
||||
|
@ -69,6 +69,10 @@ impl KeyBinding {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new_from_gpui(key_binding: gpui::KeyBinding, cx: &App) -> Self {
|
||||
Self::new(key_binding.keystrokes().to_vec(), cx)
|
||||
}
|
||||
|
||||
/// Sets the [`PlatformStyle`] for this [`KeyBinding`].
|
||||
pub fn platform_style(mut self, platform_style: PlatformStyle) -> Self {
|
||||
self.platform_style = platform_style;
|
||||
|
@ -92,15 +96,20 @@ impl KeyBinding {
|
|||
self.vim_mode = enabled;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
fn render_key(&self, keystroke: &Keystroke, color: Option<Color>) -> AnyElement {
|
||||
let key_icon = icon_for_key(keystroke, self.platform_style);
|
||||
match key_icon {
|
||||
Some(icon) => KeyIcon::new(icon, color).size(self.size).into_any_element(),
|
||||
None => {
|
||||
let key = util::capitalize(&keystroke.key);
|
||||
Key::new(&key, color).size(self.size).into_any_element()
|
||||
}
|
||||
fn render_key(
|
||||
keystroke: &Keystroke,
|
||||
color: Option<Color>,
|
||||
platform_style: PlatformStyle,
|
||||
size: impl Into<Option<AbsoluteLength>>,
|
||||
) -> AnyElement {
|
||||
let key_icon = icon_for_key(keystroke, platform_style);
|
||||
match key_icon {
|
||||
Some(icon) => KeyIcon::new(icon, color).size(size).into_any_element(),
|
||||
None => {
|
||||
let key = util::capitalize(&keystroke.key);
|
||||
Key::new(&key, color).size(size).into_any_element()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -108,17 +117,12 @@ impl KeyBinding {
|
|||
impl RenderOnce for KeyBinding {
|
||||
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let color = self.disabled.then_some(Color::Disabled);
|
||||
let use_text = self.vim_mode
|
||||
|| matches!(
|
||||
self.platform_style,
|
||||
PlatformStyle::Linux | PlatformStyle::Windows
|
||||
);
|
||||
|
||||
h_flex()
|
||||
.debug_selector(|| {
|
||||
format!(
|
||||
"KEY_BINDING-{}",
|
||||
self.key_binding
|
||||
.keystrokes()
|
||||
self.keystrokes
|
||||
.iter()
|
||||
.map(|k| k.key.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
|
@ -127,35 +131,56 @@ impl RenderOnce for KeyBinding {
|
|||
})
|
||||
.gap(DynamicSpacing::Base04.rems(cx))
|
||||
.flex_none()
|
||||
.children(self.key_binding.keystrokes().iter().map(|keystroke| {
|
||||
.children(self.keystrokes.iter().map(|keystroke| {
|
||||
h_flex()
|
||||
.flex_none()
|
||||
.py_0p5()
|
||||
.rounded_xs()
|
||||
.text_color(cx.theme().colors().text_muted)
|
||||
.when(use_text, |el| {
|
||||
el.child(
|
||||
Key::new(
|
||||
keystroke_text(&keystroke, self.platform_style, self.vim_mode),
|
||||
color,
|
||||
)
|
||||
.size(self.size),
|
||||
)
|
||||
})
|
||||
.when(!use_text, |el| {
|
||||
el.children(render_modifiers(
|
||||
&keystroke.modifiers,
|
||||
self.platform_style,
|
||||
color,
|
||||
self.size,
|
||||
true,
|
||||
))
|
||||
.map(|el| el.child(self.render_key(&keystroke, color)))
|
||||
})
|
||||
.children(render_keystroke(
|
||||
keystroke,
|
||||
color,
|
||||
self.size,
|
||||
self.platform_style,
|
||||
self.vim_mode,
|
||||
))
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_keystroke(
|
||||
keystroke: &Keystroke,
|
||||
color: Option<Color>,
|
||||
size: impl Into<Option<AbsoluteLength>>,
|
||||
platform_style: PlatformStyle,
|
||||
vim_mode: bool,
|
||||
) -> Vec<AnyElement> {
|
||||
let use_text = vim_mode
|
||||
|| matches!(
|
||||
platform_style,
|
||||
PlatformStyle::Linux | PlatformStyle::Windows
|
||||
);
|
||||
let size = size.into();
|
||||
|
||||
if use_text {
|
||||
let element = Key::new(keystroke_text(&keystroke, platform_style, vim_mode), color)
|
||||
.size(size)
|
||||
.into_any_element();
|
||||
vec![element]
|
||||
} else {
|
||||
let mut elements = Vec::new();
|
||||
elements.extend(render_modifiers(
|
||||
&keystroke.modifiers,
|
||||
platform_style,
|
||||
color,
|
||||
size,
|
||||
true,
|
||||
));
|
||||
elements.push(render_key(&keystroke, color, platform_style, size));
|
||||
elements
|
||||
}
|
||||
}
|
||||
|
||||
fn icon_for_key(keystroke: &Keystroke, platform_style: PlatformStyle) -> Option<IconName> {
|
||||
match keystroke.key.as_str() {
|
||||
"left" => Some(IconName::ArrowLeft),
|
||||
|
@ -466,7 +491,7 @@ impl Component for KeyBinding {
|
|||
vec![
|
||||
single_example(
|
||||
"Default",
|
||||
KeyBinding::new(
|
||||
KeyBinding::new_from_gpui(
|
||||
gpui::KeyBinding::new("ctrl-s", gpui::NoAction, None),
|
||||
cx,
|
||||
)
|
||||
|
@ -474,7 +499,7 @@ impl Component for KeyBinding {
|
|||
),
|
||||
single_example(
|
||||
"Mac Style",
|
||||
KeyBinding::new(
|
||||
KeyBinding::new_from_gpui(
|
||||
gpui::KeyBinding::new("cmd-s", gpui::NoAction, None),
|
||||
cx,
|
||||
)
|
||||
|
@ -483,7 +508,7 @@ impl Component for KeyBinding {
|
|||
),
|
||||
single_example(
|
||||
"Windows Style",
|
||||
KeyBinding::new(
|
||||
KeyBinding::new_from_gpui(
|
||||
gpui::KeyBinding::new("ctrl-s", gpui::NoAction, None),
|
||||
cx,
|
||||
)
|
||||
|
@ -496,9 +521,12 @@ impl Component for KeyBinding {
|
|||
"Vim Mode",
|
||||
vec![single_example(
|
||||
"Vim Mode Enabled",
|
||||
KeyBinding::new(gpui::KeyBinding::new("dd", gpui::NoAction, None), cx)
|
||||
.vim_mode(true)
|
||||
.into_any_element(),
|
||||
KeyBinding::new_from_gpui(
|
||||
gpui::KeyBinding::new("dd", gpui::NoAction, None),
|
||||
cx,
|
||||
)
|
||||
.vim_mode(true)
|
||||
.into_any_element(),
|
||||
)],
|
||||
),
|
||||
example_group_with_title(
|
||||
|
@ -506,7 +534,7 @@ impl Component for KeyBinding {
|
|||
vec![
|
||||
single_example(
|
||||
"Multiple Keys",
|
||||
KeyBinding::new(
|
||||
KeyBinding::new_from_gpui(
|
||||
gpui::KeyBinding::new("ctrl-k ctrl-b", gpui::NoAction, None),
|
||||
cx,
|
||||
)
|
||||
|
@ -514,7 +542,7 @@ impl Component for KeyBinding {
|
|||
),
|
||||
single_example(
|
||||
"With Shift",
|
||||
KeyBinding::new(
|
||||
KeyBinding::new_from_gpui(
|
||||
gpui::KeyBinding::new("shift-cmd-p", gpui::NoAction, None),
|
||||
cx,
|
||||
)
|
||||
|
|
|
@ -216,7 +216,7 @@ impl Component for KeybindingHint {
|
|||
fn preview(window: &mut Window, cx: &mut App) -> Option<AnyElement> {
|
||||
let enter_fallback = gpui::KeyBinding::new("enter", menu::Confirm, None);
|
||||
let enter = KeyBinding::for_action(&menu::Confirm, window, cx)
|
||||
.unwrap_or(KeyBinding::new(enter_fallback, cx));
|
||||
.unwrap_or(KeyBinding::new_from_gpui(enter_fallback, cx));
|
||||
|
||||
let bg_color = cx.theme().colors().surface_background;
|
||||
|
||||
|
|
|
@ -18,16 +18,16 @@ impl Render for KeybindingStory {
|
|||
Story::container(cx)
|
||||
.child(Story::title_for::<KeyBinding>(cx))
|
||||
.child(Story::label("Single Key", cx))
|
||||
.child(KeyBinding::new(binding("Z"), cx))
|
||||
.child(KeyBinding::new_from_gpui(binding("Z"), cx))
|
||||
.child(Story::label("Single Key with Modifier", cx))
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.gap_3()
|
||||
.child(KeyBinding::new(binding("ctrl-c"), cx))
|
||||
.child(KeyBinding::new(binding("alt-c"), cx))
|
||||
.child(KeyBinding::new(binding("cmd-c"), cx))
|
||||
.child(KeyBinding::new(binding("shift-c"), cx)),
|
||||
.child(KeyBinding::new_from_gpui(binding("ctrl-c"), cx))
|
||||
.child(KeyBinding::new_from_gpui(binding("alt-c"), cx))
|
||||
.child(KeyBinding::new_from_gpui(binding("cmd-c"), cx))
|
||||
.child(KeyBinding::new_from_gpui(binding("shift-c"), cx)),
|
||||
)
|
||||
.child(Story::label("Single Key with Modifier (Permuted)", cx))
|
||||
.child(
|
||||
|
@ -41,42 +41,59 @@ impl Render for KeybindingStory {
|
|||
.gap_4()
|
||||
.py_3()
|
||||
.children(chunk.map(|permutation| {
|
||||
KeyBinding::new(binding(&(permutation.join("-") + "-x")), cx)
|
||||
KeyBinding::new_from_gpui(
|
||||
binding(&(permutation.join("-") + "-x")),
|
||||
cx,
|
||||
)
|
||||
}))
|
||||
}),
|
||||
),
|
||||
)
|
||||
.child(Story::label("Single Key with All Modifiers", cx))
|
||||
.child(KeyBinding::new(binding("ctrl-alt-cmd-shift-z"), cx))
|
||||
.child(KeyBinding::new_from_gpui(
|
||||
binding("ctrl-alt-cmd-shift-z"),
|
||||
cx,
|
||||
))
|
||||
.child(Story::label("Chord", cx))
|
||||
.child(KeyBinding::new(binding("a z"), cx))
|
||||
.child(KeyBinding::new_from_gpui(binding("a z"), cx))
|
||||
.child(Story::label("Chord with Modifier", cx))
|
||||
.child(KeyBinding::new(binding("ctrl-a shift-z"), cx))
|
||||
.child(KeyBinding::new(binding("fn-s"), cx))
|
||||
.child(KeyBinding::new_from_gpui(binding("ctrl-a shift-z"), cx))
|
||||
.child(KeyBinding::new_from_gpui(binding("fn-s"), cx))
|
||||
.child(Story::label("Single Key with All Modifiers (Linux)", cx))
|
||||
.child(
|
||||
KeyBinding::new(binding("ctrl-alt-cmd-shift-z"), cx)
|
||||
KeyBinding::new_from_gpui(binding("ctrl-alt-cmd-shift-z"), cx)
|
||||
.platform_style(PlatformStyle::Linux),
|
||||
)
|
||||
.child(Story::label("Chord (Linux)", cx))
|
||||
.child(KeyBinding::new(binding("a z"), cx).platform_style(PlatformStyle::Linux))
|
||||
.child(
|
||||
KeyBinding::new_from_gpui(binding("a z"), cx).platform_style(PlatformStyle::Linux),
|
||||
)
|
||||
.child(Story::label("Chord with Modifier (Linux)", cx))
|
||||
.child(
|
||||
KeyBinding::new(binding("ctrl-a shift-z"), cx).platform_style(PlatformStyle::Linux),
|
||||
KeyBinding::new_from_gpui(binding("ctrl-a shift-z"), cx)
|
||||
.platform_style(PlatformStyle::Linux),
|
||||
)
|
||||
.child(
|
||||
KeyBinding::new_from_gpui(binding("fn-s"), cx).platform_style(PlatformStyle::Linux),
|
||||
)
|
||||
.child(KeyBinding::new(binding("fn-s"), cx).platform_style(PlatformStyle::Linux))
|
||||
.child(Story::label("Single Key with All Modifiers (Windows)", cx))
|
||||
.child(
|
||||
KeyBinding::new(binding("ctrl-alt-cmd-shift-z"), cx)
|
||||
KeyBinding::new_from_gpui(binding("ctrl-alt-cmd-shift-z"), cx)
|
||||
.platform_style(PlatformStyle::Windows),
|
||||
)
|
||||
.child(Story::label("Chord (Windows)", cx))
|
||||
.child(KeyBinding::new(binding("a z"), cx).platform_style(PlatformStyle::Windows))
|
||||
.child(Story::label("Chord with Modifier (Windows)", cx))
|
||||
.child(
|
||||
KeyBinding::new(binding("ctrl-a shift-z"), cx)
|
||||
KeyBinding::new_from_gpui(binding("a z"), cx)
|
||||
.platform_style(PlatformStyle::Windows),
|
||||
)
|
||||
.child(Story::label("Chord with Modifier (Windows)", cx))
|
||||
.child(
|
||||
KeyBinding::new_from_gpui(binding("ctrl-a shift-z"), cx)
|
||||
.platform_style(PlatformStyle::Windows),
|
||||
)
|
||||
.child(
|
||||
KeyBinding::new_from_gpui(binding("fn-s"), cx)
|
||||
.platform_style(PlatformStyle::Windows),
|
||||
)
|
||||
.child(KeyBinding::new(binding("fn-s"), cx).platform_style(PlatformStyle::Windows))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue