Fix picker_story to display selected value.

This commit is contained in:
Jason Lee 2024-06-26 19:01:52 +08:00
parent 085b8e578b
commit 672240d750
3 changed files with 51 additions and 15 deletions

View file

@ -1,7 +1,7 @@
use gpui::{ use gpui::{
div, prelude::FluentBuilder as _, px, Div, Empty, Entity, InteractiveElement as _, IntoElement, actions, div, prelude::FluentBuilder as _, px, Div, Empty, Entity, InteractiveElement as _,
ParentElement, Render, SharedString, Styled, Task, View, ViewContext, VisualContext as _, IntoElement, ParentElement, Render, SharedString, Styled, Task, View, ViewContext,
WindowContext, VisualContext as _, WeakView, WindowContext,
}; };
use ui::{ use ui::{
@ -17,7 +17,10 @@ use ui::{
use super::story_case; use super::story_case;
actions!(picker_story, [DismissPicker]);
pub struct ListItemDeletegate { pub struct ListItemDeletegate {
story: WeakView<PickerStory>,
selected_index: usize, selected_index: usize,
items: Vec<String>, items: Vec<String>,
matches: Vec<String>, matches: Vec<String>,
@ -42,12 +45,12 @@ impl PickerDelegate for ListItemDeletegate {
&self, &self,
ix: usize, ix: usize,
selected: bool, selected: bool,
cx: &mut ViewContext<Picker<Self>>, _cx: &mut ViewContext<Picker<Self>>,
) -> Option<Self::ListItem> { ) -> Option<Self::ListItem> {
let is_selected = ix == self.selected_index;
if let Some(item) = self.matches.get(ix) { if let Some(item) = self.matches.get(ix) {
let list_item = ListItem::new(format!("item-{}", ix)) let list_item = ListItem::new(format!("item-{}", ix))
.selected(is_selected) .check_icon(ui::IconName::Check)
.selected(selected)
.py_1() .py_1()
.px_3() .px_3()
.child(item.clone()); .child(item.clone());
@ -73,6 +76,27 @@ impl PickerDelegate for ListItemDeletegate {
Task::ready(()) Task::ready(())
} }
fn dismissed(&mut self, cx: &mut ViewContext<Picker<Self>>) {
if let Some(story) = self.story.upgrade() {
cx.update_view(&story, |story, cx| {
story.open = false;
cx.notify();
});
}
}
fn confirm(&mut self, _secondary: bool, cx: &mut ViewContext<Picker<Self>>) {
if let Some(story) = self.story.upgrade() {
cx.update_view(&story, |story, cx| {
if let Some(item) = self.matches.get(self.selected_index) {
story.selected_value = Some(item.clone());
}
story.open = false;
cx.notify();
});
}
}
} }
pub struct PickerStory { pub struct PickerStory {
@ -82,7 +106,7 @@ pub struct PickerStory {
} }
impl PickerStory { impl PickerStory {
pub(crate) fn new(cx: &mut WindowContext) -> Self { pub(crate) fn new(cx: &mut ViewContext<Self>) -> Self {
let items = [ let items = [
"Baguette (France)", "Baguette (France)",
"Baklava (Turkey)", "Baklava (Turkey)",
@ -135,11 +159,13 @@ impl PickerStory {
"Wiener Schnitzel (Austria)", "Wiener Schnitzel (Austria)",
]; ];
let story = cx.view().downgrade();
let picker = cx.new_view(|cx| { let picker = cx.new_view(|cx| {
let items: Vec<String> = items.iter().map(|s| s.to_string()).collect(); let items: Vec<String> = items.iter().map(|s| s.to_string()).collect();
let mut picker = Picker::uniform_list( let mut picker = Picker::uniform_list(
ListItemDeletegate { ListItemDeletegate {
story,
selected_index: 0, selected_index: 0,
matches: items.clone(), matches: items.clone(),
items, items,

View file

@ -4,13 +4,14 @@ use gpui::{
StatefulInteractiveElement as _, Style, Styled, WindowContext, StatefulInteractiveElement as _, Style, Styled, WindowContext,
}; };
use crate::{h_flex, theme::ActiveTheme, Disableable, IconName, Selectable}; use crate::{h_flex, theme::ActiveTheme, Disableable, Icon, IconName, Selectable};
#[derive(IntoElement)] #[derive(IntoElement)]
pub struct ListItem { pub struct ListItem {
base: Stateful<Div>, base: Stateful<Div>,
disabled: bool, disabled: bool,
selected: bool, selected: bool,
check_icon: Option<IconName>,
on_click: Option<Box<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>>, on_click: Option<Box<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>>,
on_secondary_mouse_down: Option<Box<dyn Fn(&MouseDownEvent, &mut WindowContext) + 'static>>, on_secondary_mouse_down: Option<Box<dyn Fn(&MouseDownEvent, &mut WindowContext) + 'static>>,
} }
@ -23,9 +24,15 @@ impl ListItem {
selected: false, selected: false,
on_click: None, on_click: None,
on_secondary_mouse_down: None, on_secondary_mouse_down: None,
check_icon: None,
} }
} }
pub fn check_icon(mut self, icon: IconName) -> Self {
self.check_icon = Some(icon);
self
}
pub fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut WindowContext) + 'static) -> Self { pub fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut WindowContext) + 'static) -> Self {
self.on_click = Some(Box::new(handler)); self.on_click = Some(Box::new(handler));
self self
@ -68,7 +75,10 @@ impl ParentElement for ListItem {
impl RenderOnce for ListItem { impl RenderOnce for ListItem {
fn render(self, cx: &mut WindowContext) -> impl IntoElement { fn render(self, cx: &mut WindowContext) -> impl IntoElement {
self.base h_flex()
.id("item-group")
.items_center()
.gap_2()
.w_full() .w_full()
.relative() .relative()
.gap_x_2() .gap_x_2()
@ -85,12 +95,12 @@ impl RenderOnce for ListItem {
this.hover(|this| this.bg(cx.theme().accent)) this.hover(|this| this.bg(cx.theme().accent))
}) })
.when(self.selected, |this| this.bg(cx.theme().accent)) .when(self.selected, |this| this.bg(cx.theme().accent))
.map(|this| { .child(self.base.when(self.selected, |this| {
if self.selected { if let Some(icon) = self.check_icon {
this.child(IconName::Check) this.child(icon)
} else { } else {
this.child(div()) this
} }
}) }))
} }
} }

View file

@ -56,7 +56,7 @@ pub trait PickerDelegate: Sized + 'static {
fn confirm(&mut self, secondary: bool, cx: &mut ViewContext<Picker<Self>>) {} fn confirm(&mut self, secondary: bool, cx: &mut ViewContext<Picker<Self>>) {}
fn dismissed(&mut self, cx: &mut ViewContext<Picker<Self>>) {} fn dismissed(&mut self, cx: &mut ViewContext<Picker<Self>>) {}
fn should_dismiss(&self) -> bool { fn should_dismiss(&self) -> bool {
return true; true
} }
fn render_query(&self, input: &View<TextField>, _cx: &mut ViewContext<Picker<Self>>) -> Div { fn render_query(&self, input: &View<TextField>, _cx: &mut ViewContext<Picker<Self>>) -> Div {
v_flex() v_flex()