Allow clicking on commands in the command palette
This commit is contained in:
parent
4ef95f05e8
commit
ad017a5df5
5 changed files with 104 additions and 25 deletions
|
@ -71,6 +71,40 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||
self
|
||||
}
|
||||
|
||||
fn on_any_mouse_down(
|
||||
mut self,
|
||||
handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interactivity()
|
||||
.mouse_down_listeners
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
||||
handler(view, event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_any_mouse_up(
|
||||
mut self,
|
||||
handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interactivity()
|
||||
.mouse_up_listeners
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
||||
handler(view, event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_mouse_up(
|
||||
mut self,
|
||||
button: MouseButton,
|
||||
|
@ -111,7 +145,6 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||
|
||||
fn on_mouse_up_out(
|
||||
mut self,
|
||||
button: MouseButton,
|
||||
handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
|
@ -120,10 +153,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||
self.stateless_interactivity()
|
||||
.mouse_up_listeners
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Capture
|
||||
&& event.button == button
|
||||
&& !bounds.contains_point(&event.position)
|
||||
{
|
||||
if phase == DispatchPhase::Capture && !bounds.contains_point(&event.position) {
|
||||
handler(view, event, cx);
|
||||
}
|
||||
}));
|
||||
|
|
|
@ -101,6 +101,12 @@ pub struct FocusHandle {
|
|||
handles: Arc<RwLock<SlotMap<FocusId, AtomicUsize>>>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for FocusHandle {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_fmt(format_args!("FocusHandle({:?})", self.id))
|
||||
}
|
||||
}
|
||||
|
||||
impl FocusHandle {
|
||||
pub(crate) fn new(handles: &Arc<RwLock<SlotMap<FocusId, AtomicUsize>>>) -> Self {
|
||||
let id = handles.write().insert(AtomicUsize::new(1));
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use editor::Editor;
|
||||
use gpui::{
|
||||
div, uniform_list, Component, Div, ParentElement, Render, StatelessInteractive, Styled, Task,
|
||||
UniformListScrollHandle, View, ViewContext, VisualContext, WindowContext,
|
||||
div, uniform_list, Component, Div, MouseButton, ParentElement, Render, StatelessInteractive,
|
||||
Styled, Task, UniformListScrollHandle, View, ViewContext, VisualContext, WindowContext,
|
||||
};
|
||||
use std::{cmp, sync::Arc};
|
||||
use ui::{prelude::*, v_stack, Divider, Label, LabelColor};
|
||||
|
@ -11,6 +11,7 @@ pub struct Picker<D: PickerDelegate> {
|
|||
scroll_handle: UniformListScrollHandle,
|
||||
editor: View<Editor>,
|
||||
pending_update_matches: Option<Task<()>>,
|
||||
confirm_on_update: Option<bool>,
|
||||
}
|
||||
|
||||
pub trait PickerDelegate: Sized + 'static {
|
||||
|
@ -44,9 +45,10 @@ impl<D: PickerDelegate> Picker<D> {
|
|||
cx.subscribe(&editor, Self::on_input_editor_event).detach();
|
||||
let mut this = Self {
|
||||
delegate,
|
||||
editor,
|
||||
scroll_handle: UniformListScrollHandle::new(),
|
||||
pending_update_matches: None,
|
||||
editor,
|
||||
confirm_on_update: None,
|
||||
};
|
||||
this.update_matches("".to_string(), cx);
|
||||
this
|
||||
|
@ -101,12 +103,27 @@ impl<D: PickerDelegate> Picker<D> {
|
|||
}
|
||||
|
||||
fn confirm(&mut self, _: &menu::Confirm, cx: &mut ViewContext<Self>) {
|
||||
if self.pending_update_matches.is_some() {
|
||||
self.confirm_on_update = Some(false)
|
||||
} else {
|
||||
self.delegate.confirm(false, cx);
|
||||
}
|
||||
}
|
||||
|
||||
fn secondary_confirm(&mut self, _: &menu::SecondaryConfirm, cx: &mut ViewContext<Self>) {
|
||||
if self.pending_update_matches.is_some() {
|
||||
self.confirm_on_update = Some(true)
|
||||
} else {
|
||||
self.delegate.confirm(true, cx);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_click(&mut self, ix: usize, secondary: bool, cx: &mut ViewContext<Self>) {
|
||||
cx.stop_propagation();
|
||||
cx.prevent_default();
|
||||
self.delegate.set_selected_index(ix, cx);
|
||||
self.delegate.confirm(secondary, cx);
|
||||
}
|
||||
|
||||
fn on_input_editor_event(
|
||||
&mut self,
|
||||
|
@ -136,6 +153,9 @@ impl<D: PickerDelegate> Picker<D> {
|
|||
let index = self.delegate.selected_index();
|
||||
self.scroll_handle.scroll_to_item(index);
|
||||
self.pending_update_matches = None;
|
||||
if let Some(secondary) = self.confirm_on_update.take() {
|
||||
self.delegate.confirm(secondary, cx);
|
||||
}
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
@ -173,7 +193,22 @@ impl<D: PickerDelegate> Render for Picker<D> {
|
|||
let selected_ix = this.delegate.selected_index();
|
||||
visible_range
|
||||
.map(|ix| {
|
||||
this.delegate.render_match(ix, ix == selected_ix, cx)
|
||||
div()
|
||||
.on_mouse_down(
|
||||
MouseButton::Left,
|
||||
move |this: &mut Self, event, cx| {
|
||||
this.handle_click(
|
||||
ix,
|
||||
event.modifiers.command,
|
||||
cx,
|
||||
)
|
||||
},
|
||||
)
|
||||
.child(this.delegate.render_match(
|
||||
ix,
|
||||
ix == selected_ix,
|
||||
cx,
|
||||
))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
@ -186,10 +221,11 @@ impl<D: PickerDelegate> Render for Picker<D> {
|
|||
})
|
||||
.when(self.delegate.match_count() == 0, |el| {
|
||||
el.child(
|
||||
v_stack()
|
||||
.p_1()
|
||||
.grow()
|
||||
v_stack().p_1().grow().child(
|
||||
div()
|
||||
.px_1()
|
||||
.child(Label::new("No matches").color(LabelColor::Muted)),
|
||||
),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ impl KeyBinding {
|
|||
div()
|
||||
.flex()
|
||||
.gap_1()
|
||||
.when(keystroke.modifiers.function, |el| el.child(Key::new("fn")))
|
||||
.when(keystroke.modifiers.control, |el| el.child(Key::new("^")))
|
||||
.when(keystroke.modifiers.alt, |el| el.child(Key::new("⌥")))
|
||||
.when(keystroke.modifiers.command, |el| el.child(Key::new("⌘")))
|
||||
|
@ -136,6 +137,7 @@ mod stories {
|
|||
.child(KeyBinding::new(binding("a z")))
|
||||
.child(Story::label(cx, "Chord with Modifier"))
|
||||
.child(KeyBinding::new(binding("ctrl-a shift-z")))
|
||||
.child(KeyBinding::new(binding("fn-s")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use gpui::{
|
|||
div, px, AnyView, Div, EventEmitter, FocusHandle, ParentElement, Render, StatelessInteractive,
|
||||
Styled, Subscription, View, ViewContext, VisualContext, WindowContext,
|
||||
};
|
||||
use ui::v_stack;
|
||||
use ui::{h_stack, v_stack};
|
||||
|
||||
pub struct ActiveModal {
|
||||
modal: AnyView,
|
||||
|
@ -33,8 +33,6 @@ impl ModalLayer {
|
|||
V: Modal,
|
||||
B: FnOnce(&mut ViewContext<V>) -> V,
|
||||
{
|
||||
let previous_focus = cx.focused();
|
||||
|
||||
if let Some(active_modal) = &self.active_modal {
|
||||
let is_close = active_modal.modal.clone().downcast::<V>().is_ok();
|
||||
self.hide_modal(cx);
|
||||
|
@ -85,9 +83,6 @@ impl Render for ModalLayer {
|
|||
|
||||
div()
|
||||
.absolute()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.items_center()
|
||||
.size_full()
|
||||
.top_0()
|
||||
.left_0()
|
||||
|
@ -96,11 +91,21 @@ impl Render for ModalLayer {
|
|||
v_stack()
|
||||
.h(px(0.0))
|
||||
.top_20()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.items_center()
|
||||
.track_focus(&active_modal.focus_handle)
|
||||
.child(
|
||||
h_stack()
|
||||
// needed to prevent mouse events leaking to the
|
||||
// UI below. // todo! for gpui3.
|
||||
.on_any_mouse_down(|_, _, cx| cx.stop_propagation())
|
||||
.on_any_mouse_up(|_, _, cx| cx.stop_propagation())
|
||||
.on_mouse_down_out(|this: &mut Self, event, cx| {
|
||||
this.hide_modal(cx);
|
||||
})
|
||||
.child(active_modal.modal.clone()),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue