Improve Picker details.
This commit is contained in:
parent
3288270b49
commit
ddadcda140
3 changed files with 52 additions and 51 deletions
|
|
@ -37,7 +37,7 @@ impl PickerDelegate for ListItemDeletegate {
|
||||||
self.selected_index = index
|
self.selected_index = index
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_match(
|
fn render_item(
|
||||||
&self,
|
&self,
|
||||||
ix: usize,
|
ix: usize,
|
||||||
selected: bool,
|
selected: bool,
|
||||||
|
|
@ -198,23 +198,27 @@ impl Render for PickerStory {
|
||||||
.style(ButtonStyle::Primary)
|
.style(ButtonStyle::Primary)
|
||||||
.on_click(cx.listener(|this, _, cx| {
|
.on_click(cx.listener(|this, _, cx| {
|
||||||
this.open = !this.open;
|
this.open = !this.open;
|
||||||
|
this.picker.focus_handle(cx).focus(cx);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
})),
|
})),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.when_some(self.selected_value.clone(), |this, selected_value| {
|
.when_some(self.selected_value.clone(), |this, selected_value| {
|
||||||
this.child("Selected: ").child(Label::new(selected_value))
|
this.child(
|
||||||
|
h_flex()
|
||||||
|
.gap_1()
|
||||||
|
.child("You have selected:")
|
||||||
|
.child(selected_value),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.when(self.open, |this| {
|
.when(self.open, |this| {
|
||||||
this.child(
|
this.child(
|
||||||
div().absolute().size_full().top_0().left_0().child(
|
div().absolute().size_full().top_0().left_0().child(
|
||||||
v_flex()
|
v_flex()
|
||||||
// .h(px(0.0))
|
|
||||||
.top_10()
|
.top_10()
|
||||||
.flex()
|
.flex()
|
||||||
.flex_col()
|
.flex_col()
|
||||||
.items_center()
|
.items_center()
|
||||||
.track_focus(&self.picker.focus_handle(cx))
|
|
||||||
.child(h_flex().w(px(450.)).occlude().child(self.picker.clone())),
|
.child(h_flex().w(px(450.)).occlude().child(self.picker.clone())),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ where
|
||||||
self.selected_index = index;
|
self.selected_index = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_match(
|
fn render_item(
|
||||||
&self,
|
&self,
|
||||||
ix: usize,
|
ix: usize,
|
||||||
selected: bool,
|
selected: bool,
|
||||||
|
|
@ -135,7 +135,7 @@ where
|
||||||
selected_index: 0,
|
selected_index: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
let picker = cx.new_view(|cx| Picker::uniform_list(picker_delegate, cx));
|
let picker = cx.new_view(|cx| Picker::uniform_list(picker_delegate, cx).no_query());
|
||||||
Self {
|
Self {
|
||||||
id: id.into(),
|
id: id.into(),
|
||||||
focus_handle: cx.focus_handle(),
|
focus_handle: cx.focus_handle(),
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, div, list, prelude::FluentBuilder as _, px, rems, uniform_list, AppContext,
|
actions, div, list, prelude::FluentBuilder as _, px, rems, uniform_list, AppContext,
|
||||||
|
|
@ -12,7 +10,6 @@ use gpui::{
|
||||||
actions!(
|
actions!(
|
||||||
picker,
|
picker,
|
||||||
[
|
[
|
||||||
UseSelectedQuery,
|
|
||||||
Cancel,
|
Cancel,
|
||||||
Confirm,
|
Confirm,
|
||||||
SecondaryConfirm,
|
SecondaryConfirm,
|
||||||
|
|
@ -57,8 +54,13 @@ pub trait PickerDelegate: Sized + 'static {
|
||||||
type ListItem: IntoElement;
|
type ListItem: IntoElement;
|
||||||
|
|
||||||
fn match_count(&self) -> usize;
|
fn match_count(&self) -> usize;
|
||||||
|
|
||||||
|
/// Return the index of the selected item.
|
||||||
fn selected_index(&self) -> usize;
|
fn selected_index(&self) -> usize;
|
||||||
fn set_selected_index(&mut self, index: usize, cx: &mut ViewContext<Picker<Self>>);
|
|
||||||
|
/// Update the selected index.
|
||||||
|
fn set_selected_index(&mut self, ix: usize, cx: &mut ViewContext<Picker<Self>>);
|
||||||
|
|
||||||
fn selected_index_changed(
|
fn selected_index_changed(
|
||||||
&self,
|
&self,
|
||||||
_ix: usize,
|
_ix: usize,
|
||||||
|
|
@ -67,11 +69,18 @@ pub trait PickerDelegate: Sized + 'static {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Callback when the picker is confirmed.
|
||||||
fn confirm(&mut self, _secondary: bool, _cx: &mut ViewContext<Picker<Self>>) {}
|
fn confirm(&mut self, _secondary: bool, _cx: &mut ViewContext<Picker<Self>>) {}
|
||||||
|
|
||||||
|
/// Callback when the picker is dismissed.
|
||||||
fn dismissed(&mut self, _cx: &mut ViewContext<Picker<Self>>) {}
|
fn dismissed(&mut self, _cx: &mut ViewContext<Picker<Self>>) {}
|
||||||
|
|
||||||
|
/// Determine if the picker should be dismissed, return true by default. Return false will abort the dismiss action.
|
||||||
fn should_dismiss(&self) -> bool {
|
fn should_dismiss(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Override this method to customize the query input header container.
|
||||||
fn render_query(&self, input: &View<TextInput>, _cx: &mut ViewContext<Picker<Self>>) -> Div {
|
fn render_query(&self, input: &View<TextInput>, _cx: &mut ViewContext<Picker<Self>>) -> Div {
|
||||||
v_flex()
|
v_flex()
|
||||||
.child(
|
.child(
|
||||||
|
|
@ -84,7 +93,9 @@ pub trait PickerDelegate: Sized + 'static {
|
||||||
)
|
)
|
||||||
.child(Divider::horizontal())
|
.child(Divider::horizontal())
|
||||||
}
|
}
|
||||||
fn render_match(
|
|
||||||
|
/// Render the list item at the given index.
|
||||||
|
fn render_item(
|
||||||
&self,
|
&self,
|
||||||
ix: usize,
|
ix: usize,
|
||||||
selected: bool,
|
selected: bool,
|
||||||
|
|
@ -94,21 +105,19 @@ pub trait PickerDelegate: Sized + 'static {
|
||||||
fn separators_after_indices(&self) -> Vec<usize> {
|
fn separators_after_indices(&self) -> Vec<usize> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_matches(&mut self, _query: &str, _cx: &mut ViewContext<Picker<Self>>) -> Task<()> {
|
fn update_matches(&mut self, _query: &str, _cx: &mut ViewContext<Picker<Self>>) -> Task<()> {
|
||||||
Task::ready(())
|
Task::ready(())
|
||||||
}
|
}
|
||||||
fn confirm_update_query(&mut self, _cx: &mut ViewContext<Picker<Self>>) -> Option<String> {
|
|
||||||
|
fn confirm_update_query(
|
||||||
|
&mut self,
|
||||||
|
_cx: &mut ViewContext<Picker<Self>>,
|
||||||
|
) -> Option<SharedString> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
fn finalize_update_matches(
|
|
||||||
&mut self,
|
fn selected_as_query(&self) -> Option<SharedString> {
|
||||||
_query: SharedString,
|
|
||||||
_duration: Duration,
|
|
||||||
_cx: &mut ViewContext<Picker<Self>>,
|
|
||||||
) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
fn selected_as_query(&self) -> Option<String> {
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -137,9 +146,9 @@ pub struct Picker<D: PickerDelegate> {
|
||||||
width: Option<Length>,
|
width: Option<Length>,
|
||||||
max_height: Option<Length>,
|
max_height: Option<Length>,
|
||||||
is_modal: bool,
|
is_modal: bool,
|
||||||
|
/// Just a empty view for holding the focus
|
||||||
head: View<Empty>,
|
head: View<Empty>,
|
||||||
pending_update_matches: Option<PendingUpdateMatches>,
|
pending_update_matches: Option<PendingUpdateMatches>,
|
||||||
confirm_on_update: Option<bool>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: PickerDelegate> Picker<D> {
|
impl<D: PickerDelegate> Picker<D> {
|
||||||
|
|
@ -181,7 +190,6 @@ impl<D: PickerDelegate> Picker<D> {
|
||||||
max_height: Some(rems(20.).into()),
|
max_height: Some(rems(20.).into()),
|
||||||
element_container,
|
element_container,
|
||||||
pending_update_matches: None,
|
pending_update_matches: None,
|
||||||
confirm_on_update: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -227,6 +235,12 @@ impl<D: PickerDelegate> Picker<D> {
|
||||||
self.focus_handle(cx).focus(cx);
|
self.focus_handle(cx).focus(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Hide the query input.
|
||||||
|
pub fn no_query(mut self) -> Self {
|
||||||
|
self.query_input = None;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_query(&mut self, query: &str, cx: &mut ViewContext<Self>) {
|
pub fn set_query(&mut self, query: &str, cx: &mut ViewContext<Self>) {
|
||||||
if let Some(input) = &self.query_input {
|
if let Some(input) = &self.query_input {
|
||||||
input.update(cx, |this, cx| this.set_text(query.to_string(), cx));
|
input.update(cx, |this, cx| this.set_text(query.to_string(), cx));
|
||||||
|
|
@ -292,7 +306,7 @@ impl<D: PickerDelegate> Picker<D> {
|
||||||
)
|
)
|
||||||
.children(
|
.children(
|
||||||
self.delegate
|
self.delegate
|
||||||
.render_match(ix, ix == self.delegate.selected_index(), cx),
|
.render_item(ix, ix == self.delegate.selected_index(), cx),
|
||||||
)
|
)
|
||||||
.when(
|
.when(
|
||||||
self.delegate.separators_after_indices().contains(&ix),
|
self.delegate.separators_after_indices().contains(&ix),
|
||||||
|
|
@ -313,12 +327,12 @@ impl<D: PickerDelegate> Picker<D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_confirm(&mut self, secondary: bool, cx: &mut ViewContext<Self>) {
|
fn do_confirm(&mut self, secondary: bool, cx: &mut ViewContext<Self>) {
|
||||||
// if let Some(update_query) = self.delegate.confirm_update_query(cx) {
|
if let Some(update_query) = self.delegate.confirm_update_query(cx) {
|
||||||
// self.set_query(update_query, cx);
|
self.set_query(&update_query, cx);
|
||||||
// self.delegate.set_selected_index(0, cx);
|
self.delegate.set_selected_index(0, cx);
|
||||||
// } else {
|
} else {
|
||||||
self.delegate.confirm(secondary, cx)
|
self.delegate.confirm(secondary, cx)
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_selected_index(
|
pub fn set_selected_index(
|
||||||
|
|
@ -349,16 +363,7 @@ impl<D: PickerDelegate> Picker<D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn confirm(&mut self, _: &Confirm, cx: &mut ViewContext<Self>) {
|
fn confirm(&mut self, _: &Confirm, cx: &mut ViewContext<Self>) {
|
||||||
if self.pending_update_matches.is_some()
|
self.do_confirm(false, cx);
|
||||||
&& !self
|
|
||||||
.delegate
|
|
||||||
.finalize_update_matches(self.query(cx), Duration::from_millis(16), cx)
|
|
||||||
{
|
|
||||||
self.confirm_on_update = Some(false)
|
|
||||||
} else {
|
|
||||||
self.pending_update_matches.take();
|
|
||||||
self.do_confirm(false, cx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn select_next(&mut self, _: &SelectNext, cx: &mut ViewContext<Self>) {
|
pub fn select_next(&mut self, _: &SelectNext, cx: &mut ViewContext<Self>) {
|
||||||
|
|
@ -405,13 +410,6 @@ impl<D: PickerDelegate> Picker<D> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_selected_query(&mut self, _: &UseSelectedQuery, cx: &mut ViewContext<Self>) {
|
|
||||||
if let Some(new_query) = self.delegate.selected_as_query() {
|
|
||||||
self.set_query(&new_query, cx);
|
|
||||||
cx.stop_propagation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn refresh(&mut self, cx: &mut ViewContext<Self>) {
|
pub fn refresh(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
let query = self.query(cx);
|
let query = self.query(cx);
|
||||||
self.update_matches(&query, cx);
|
self.update_matches(&query, cx);
|
||||||
|
|
@ -478,9 +476,12 @@ impl<D: PickerDelegate> Picker<D> {
|
||||||
|
|
||||||
impl<D: PickerDelegate> Render for Picker<D> {
|
impl<D: PickerDelegate> Render for Picker<D> {
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
|
let focus_handle = self.focus_handle(cx);
|
||||||
|
|
||||||
v_flex()
|
v_flex()
|
||||||
.key_context("Picker")
|
.key_context("Picker")
|
||||||
.size_full()
|
.size_full()
|
||||||
|
.track_focus(&focus_handle)
|
||||||
.when_some(self.width, |el, width| el.w(width))
|
.when_some(self.width, |el, width| el.w(width))
|
||||||
.overflow_hidden()
|
.overflow_hidden()
|
||||||
.when(self.is_modal, |this| this.elevation_3(cx))
|
.when(self.is_modal, |this| this.elevation_3(cx))
|
||||||
|
|
@ -490,9 +491,6 @@ impl<D: PickerDelegate> Render for Picker<D> {
|
||||||
.on_action(cx.listener(Self::select_last))
|
.on_action(cx.listener(Self::select_last))
|
||||||
.on_action(cx.listener(Self::cancel))
|
.on_action(cx.listener(Self::cancel))
|
||||||
.on_action(cx.listener(Self::confirm))
|
.on_action(cx.listener(Self::confirm))
|
||||||
// .on_action(cx.listener(Self::secondary_confirm))
|
|
||||||
.on_action(cx.listener(Self::use_selected_query))
|
|
||||||
// .on_action(cx.listener(Self::confirm_input))
|
|
||||||
// Render Query Input header
|
// Render Query Input header
|
||||||
.child(match self.query_input {
|
.child(match self.query_input {
|
||||||
Some(ref input) => self.delegate.render_query(input, cx),
|
Some(ref input) => self.delegate.render_query(input, cx),
|
||||||
|
|
@ -504,7 +502,6 @@ impl<D: PickerDelegate> Render for Picker<D> {
|
||||||
.flex_grow()
|
.flex_grow()
|
||||||
.when_some(self.max_height, |div, max_h| div.max_h(max_h))
|
.when_some(self.max_height, |div, max_h| div.max_h(max_h))
|
||||||
.overflow_hidden()
|
.overflow_hidden()
|
||||||
// .children(self.delegate.render_header(cx))
|
|
||||||
.child(self.render_element_container(cx)),
|
.child(self.render_element_container(cx)),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue