Fix list next to select first item, cancel to deselect item. (#110)

- Add confirmed to ListItem to show check style.
This commit is contained in:
Jason Lee 2024-08-06 11:31:35 +08:00 committed by GitHub
parent e7a0d13b69
commit f3fdfae002
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 49 additions and 27 deletions

20
Cargo.lock generated
View file

@ -925,7 +925,7 @@ dependencies = [
[[package]] [[package]]
name = "collections" name = "collections"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/huacnlee/zed.git?branch=export-platform-window#d18b49a95309fdc8b46b64cb57dae96d4be0e49b" source = "git+https://github.com/huacnlee/zed.git?branch=export-platform-window#371a680215f5a1e91fdfd6a00afbbf362f71eade"
dependencies = [ dependencies = [
"rustc-hash", "rustc-hash",
] ]
@ -1238,7 +1238,7 @@ dependencies = [
[[package]] [[package]]
name = "derive_refineable" name = "derive_refineable"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/huacnlee/zed.git?branch=export-platform-window#d18b49a95309fdc8b46b64cb57dae96d4be0e49b" source = "git+https://github.com/huacnlee/zed.git?branch=export-platform-window#371a680215f5a1e91fdfd6a00afbbf362f71eade"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2178,7 +2178,7 @@ dependencies = [
[[package]] [[package]]
name = "gpui" name = "gpui"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/huacnlee/zed.git?branch=export-platform-window#d18b49a95309fdc8b46b64cb57dae96d4be0e49b" source = "git+https://github.com/huacnlee/zed.git?branch=export-platform-window#371a680215f5a1e91fdfd6a00afbbf362f71eade"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"as-raw-xcb-connection", "as-raw-xcb-connection",
@ -2278,7 +2278,7 @@ dependencies = [
[[package]] [[package]]
name = "gpui_macros" name = "gpui_macros"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/huacnlee/zed.git?branch=export-platform-window#d18b49a95309fdc8b46b64cb57dae96d4be0e49b" source = "git+https://github.com/huacnlee/zed.git?branch=export-platform-window#371a680215f5a1e91fdfd6a00afbbf362f71eade"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2482,7 +2482,7 @@ dependencies = [
[[package]] [[package]]
name = "http_client" name = "http_client"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/huacnlee/zed.git?branch=export-platform-window#d18b49a95309fdc8b46b64cb57dae96d4be0e49b" source = "git+https://github.com/huacnlee/zed.git?branch=export-platform-window#371a680215f5a1e91fdfd6a00afbbf362f71eade"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"derive_more", "derive_more",
@ -2997,7 +2997,7 @@ dependencies = [
[[package]] [[package]]
name = "media" name = "media"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/huacnlee/zed.git?branch=export-platform-window#d18b49a95309fdc8b46b64cb57dae96d4be0e49b" source = "git+https://github.com/huacnlee/zed.git?branch=export-platform-window#371a680215f5a1e91fdfd6a00afbbf362f71eade"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bindgen", "bindgen",
@ -4107,7 +4107,7 @@ dependencies = [
[[package]] [[package]]
name = "refineable" name = "refineable"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/huacnlee/zed.git?branch=export-platform-window#d18b49a95309fdc8b46b64cb57dae96d4be0e49b" source = "git+https://github.com/huacnlee/zed.git?branch=export-platform-window#371a680215f5a1e91fdfd6a00afbbf362f71eade"
dependencies = [ dependencies = [
"derive_refineable", "derive_refineable",
] ]
@ -4382,7 +4382,7 @@ checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a"
[[package]] [[package]]
name = "semantic_version" name = "semantic_version"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/huacnlee/zed.git?branch=export-platform-window#d18b49a95309fdc8b46b64cb57dae96d4be0e49b" source = "git+https://github.com/huacnlee/zed.git?branch=export-platform-window#371a680215f5a1e91fdfd6a00afbbf362f71eade"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"serde", "serde",
@ -4791,7 +4791,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]] [[package]]
name = "sum_tree" name = "sum_tree"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/huacnlee/zed.git?branch=export-platform-window#d18b49a95309fdc8b46b64cb57dae96d4be0e49b" source = "git+https://github.com/huacnlee/zed.git?branch=export-platform-window#371a680215f5a1e91fdfd6a00afbbf362f71eade"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"log", "log",
@ -5427,7 +5427,7 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]] [[package]]
name = "util" name = "util"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/huacnlee/zed.git?branch=export-platform-window#d18b49a95309fdc8b46b64cb57dae96d4be0e49b" source = "git+https://github.com/huacnlee/zed.git?branch=export-platform-window#371a680215f5a1e91fdfd6a00afbbf362f71eade"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-fs 1.6.0", "async-fs 1.6.0",

View file

@ -17,7 +17,8 @@ use ui::{
pub struct ListItemDeletegate { pub struct ListItemDeletegate {
story: WeakView<PickerStory>, story: WeakView<PickerStory>,
selected_index: usize, confirmed_index: Option<usize>,
selected_index: Option<usize>,
items: Vec<Arc<String>>, items: Vec<Arc<String>>,
matches: Vec<Arc<String>>, matches: Vec<Arc<String>>,
} }
@ -30,7 +31,7 @@ impl ListDelegate for ListItemDeletegate {
} }
fn confirmed_index(&self) -> Option<usize> { fn confirmed_index(&self) -> Option<usize> {
Some(self.selected_index) self.confirmed_index
} }
fn perform_search(&mut self, query: &str, cx: &mut ViewContext<List<Self>>) -> Task<()> { fn perform_search(&mut self, query: &str, cx: &mut ViewContext<List<Self>>) -> Task<()> {
@ -55,10 +56,13 @@ impl ListDelegate for ListItemDeletegate {
} }
fn render_item(&self, ix: usize, _: &mut ViewContext<List<Self>>) -> Option<Self::Item> { fn render_item(&self, ix: usize, _: &mut ViewContext<List<Self>>) -> Option<Self::Item> {
let selected = ix == self.selected_index; let confirmed = Some(ix) == self.confirmed_index;
let selected = Some(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(("item", ix)) let list_item = ListItem::new(("item", ix))
.check_icon(ui::IconName::Check) .check_icon(ui::IconName::Check)
.confirmed(confirmed)
.selected(selected) .selected(selected)
.py_1() .py_1()
.px_3() .px_3()
@ -115,7 +119,7 @@ impl ListDelegate for ListItemDeletegate {
if let Some(story) = self.story.upgrade() { if let Some(story) = self.story.upgrade() {
cx.update_view(&story, |story, cx| { cx.update_view(&story, |story, cx| {
if let Some(ix) = ix { if let Some(ix) = ix {
self.selected_index = ix; self.confirmed_index = Some(ix);
if let Some(item) = self.matches.get(ix) { if let Some(item) = self.matches.get(ix) {
story.selected_value = Some(item.clone()); story.selected_value = Some(item.clone());
} }
@ -127,8 +131,9 @@ impl ListDelegate for ListItemDeletegate {
} }
fn set_selected_index(&mut self, ix: Option<usize>, cx: &mut ViewContext<List<Self>>) { fn set_selected_index(&mut self, ix: Option<usize>, cx: &mut ViewContext<List<Self>>) {
if let Some(ix) = ix { self.selected_index = ix;
self.selected_index = ix;
if let Some(_) = ix {
cx.notify(); cx.notify();
} }
} }
@ -204,7 +209,8 @@ impl PickerStory {
let story = cx.view().downgrade(); let story = cx.view().downgrade();
let delegate = ListItemDeletegate { let delegate = ListItemDeletegate {
story, story,
selected_index: 0, selected_index: None,
confirmed_index: None,
items: items.clone(), items: items.clone(),
matches: items.clone(), matches: items.clone(),
}; };

View file

@ -225,6 +225,7 @@ where
} }
fn action_cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) { fn action_cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
self.set_selected_index(None, cx);
self.delegate.cancel(cx); self.delegate.cancel(cx);
cx.notify(); cx.notify();
} }
@ -259,9 +260,12 @@ where
return; return;
} }
let selected_index = self.selected_index.unwrap_or(0); if let Some(selected_index) = self.selected_index {
if selected_index < self.delegate.items_count() - 1 { if selected_index < self.delegate.items_count() - 1 {
self.selected_index = Some(selected_index + 1); self.selected_index = Some(selected_index + 1);
} else {
self.selected_index = Some(0);
}
} else { } else {
self.selected_index = Some(0); self.selected_index = Some(0);
} }

View file

@ -12,6 +12,7 @@ pub struct ListItem {
base: Stateful<Div>, base: Stateful<Div>,
disabled: bool, disabled: bool,
selected: bool, selected: bool,
confirmed: bool,
check_icon: Option<Icon>, check_icon: Option<Icon>,
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>>,
@ -25,6 +26,7 @@ impl ListItem {
base: h_flex().id(id.into()).gap_x_1().py_1().px_2().text_base(), base: h_flex().id(id.into()).gap_x_1().py_1().px_2().text_base(),
disabled: false, disabled: false,
selected: false, selected: false,
confirmed: false,
on_click: None, on_click: None,
on_secondary_mouse_down: None, on_secondary_mouse_down: None,
check_icon: None, check_icon: None,
@ -33,16 +35,24 @@ impl ListItem {
} }
} }
/// Set to show check icon, default is None.
pub fn check_icon(mut self, icon: IconName) -> Self { pub fn check_icon(mut self, icon: IconName) -> Self {
self.check_icon = Some(Icon::new(icon)); self.check_icon = Some(Icon::new(icon));
self self
} }
/// Set ListItem as the selected item style.
pub fn selected(mut self, selected: bool) -> Self { pub fn selected(mut self, selected: bool) -> Self {
self.selected = selected; self.selected = selected;
self self
} }
/// Set ListItem as the confirmed item style, it will show a check icon.
pub fn confirmed(mut self, confirmed: bool) -> Self {
self.confirmed = confirmed;
self
}
pub fn disabled(mut self, disabled: bool) -> Self { pub fn disabled(mut self, disabled: bool) -> Self {
self.disabled = disabled; self.disabled = disabled;
self self
@ -100,6 +110,8 @@ 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 {
let is_active = self.selected || self.confirmed;
self.base self.base
.text_color(cx.theme().foreground) .text_color(cx.theme().foreground)
.relative() .relative()
@ -112,8 +124,8 @@ impl RenderOnce for ListItem {
this this
} }
}) })
.when(self.selected, |this| this.bg(cx.theme().list_active)) .when(is_active, |this| this.bg(cx.theme().list_active))
.when(!self.selected && !self.disabled, |this| { .when(!is_active && !self.disabled, |this| {
this.hover(|this| this.bg(cx.theme().list_hover)) this.hover(|this| this.bg(cx.theme().list_hover))
}) })
// Right click // Right click
@ -133,7 +145,7 @@ impl RenderOnce for ListItem {
.child(div().w_full().overflow_hidden().children(self.children)) .child(div().w_full().overflow_hidden().children(self.children))
.when_some(self.check_icon, |this, icon| { .when_some(self.check_icon, |this, icon| {
this.child(div().w_5().items_center().justify_center().when( this.child(div().w_5().items_center().justify_center().when(
self.selected, self.confirmed,
|this| { |this| {
this.child( this.child(
icon.size(Size::Small) icon.size(Size::Small)

View file

@ -84,8 +84,8 @@ impl Asset for Image {
return Err(usvg::Error::InvalidSize.into()); return Err(usvg::Error::InvalidSize.into());
} }
let size = Size { let size = Size {
width: size.width * scale, width: (size.width * scale).ceil(),
height: size.height * scale, height: (size.height * scale).ceil(),
}; };
let bytes = match source.source { let bytes = match source.source {
@ -258,8 +258,8 @@ impl Element for SvgImg {
}; };
let img_bounds = Bounds { let img_bounds = Bounds {
size: new_size, origin: new_origin.map(|origin| origin.floor()),
origin: new_origin, size: new_size.map(|size| size.ceil()),
}; };
match cx.paint_image(img_bounds, px(0.).into(), data, 0, false) { match cx.paint_image(img_bounds, px(0.).into(), data, 0, false) {