list, table: Add scroll_to_item to List, scroll_to_row to Table. (#535)

This commit is contained in:
Jason Lee 2025-01-09 14:23:46 +08:00 committed by GitHub
parent 8aac2f75e4
commit bf82e3db13
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 142 additions and 73 deletions

View file

@ -3,17 +3,18 @@ use std::time::Duration;
use fake::Fake;
use gpui::{
actions, div, px, relative, AnyElement, AppContext, ElementId, FocusHandle, FocusableView,
InteractiveElement, IntoElement, ParentElement, Render, RenderOnce, Styled, Task, Timer, View,
ViewContext, VisualContext, WindowContext,
actions, div, px, AppContext, ElementId, FocusHandle, FocusableView, InteractiveElement,
IntoElement, ParentElement, Render, RenderOnce, Styled, Task, Timer, View, ViewContext,
VisualContext, WindowContext,
};
use ui::{
button::Button,
h_flex,
label::Label,
list::{List, ListDelegate, ListItem},
theme::{hsl, ActiveTheme},
v_flex,
v_flex, Sizable,
};
actions!(list_story, [SelectedCompany]);
@ -171,39 +172,6 @@ impl ListDelegate for CompanyListDelegate {
}
}
fn render_initial(&self, cx: &mut ViewContext<List<Self>>) -> Option<AnyElement> {
let histories = ["BABA", "BIDU", "GOOGL", "LB", "LP", "LBW"];
let input_history = histories
.into_iter()
.map(|name| {
div()
.rounded_xl()
.min_w(px(30.))
.border_1()
.rounded_md()
.border_color(cx.theme().muted_foreground.opacity(0.3))
.line_height(relative(1.))
.p_1()
.child(div().whitespace_nowrap().child(name).text_xs())
})
.collect::<Vec<_>>();
let element = v_flex()
.p_4()
.child(
v_flex().gap_y_2().child("History").child(
h_flex()
.gap_x_4()
.gap_y_2()
.flex_wrap()
.children(input_history),
),
)
.into_any_element();
Some(element)
}
fn set_selected_index(&mut self, ix: Option<usize>, cx: &mut ViewContext<List<Self>>) {
if let Some(ix) = ix {
self.selected_index = ix;
@ -357,14 +325,43 @@ impl FocusableView for ListStory {
impl Render for ListStory {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
div()
v_flex()
.track_focus(&self.focus_handle)
.on_action(cx.listener(Self::selected_company))
.size_full()
.gap_4()
.border_1()
.border_color(cx.theme().border)
.rounded_md()
.child(self.company_list.clone())
.child(
h_flex()
.gap_2()
.child(
Button::new("scroll-top")
.child("Scroll to Top")
.small()
.on_click(cx.listener(|this, _, cx| {
this.company_list.update(cx, |list, cx| {
list.scroll_to_item(0, cx);
})
})),
)
.child(
Button::new("scroll-bottom")
.child("Scroll to Bottom")
.small()
.on_click(cx.listener(|this, _, cx| {
this.company_list.update(cx, |list, cx| {
list.scroll_to_item(list.delegate().items_count(cx) - 1, cx);
})
})),
),
)
.child(
div()
.flex_1()
.w_full()
.border_1()
.border_color(cx.theme().border)
.rounded_md()
.child(self.company_list.clone()),
)
}
}

View file

@ -8,7 +8,7 @@ use gpui::{
};
use serde::Deserialize;
use ui::{
button::{Button, ButtonVariants},
button::Button,
checkbox::Checkbox,
h_flex,
indicator::Indicator,
@ -18,7 +18,7 @@ use ui::{
prelude::FluentBuilder as _,
table::{ColFixed, ColSort, Table, TableDelegate, TableEvent},
theme::ActiveTheme as _,
v_flex, Selectable, Size, StyleSized as _,
v_flex, Selectable, Sizable as _, Size, StyleSized as _,
};
#[derive(Clone, PartialEq, Eq, Deserialize)]
@ -707,34 +707,6 @@ impl Render for TableStory {
.items_center()
.gap_3()
.flex_wrap()
.child(
Button::new("size")
.compact()
.outline()
.label(format!("size: {:?}", self.size))
.popup_menu(move |menu, _| {
menu.menu_with_check(
"Large",
size == Size::Large,
Box::new(ChangeSize(Size::Large)),
)
.menu_with_check(
"Medium",
size == Size::Medium,
Box::new(ChangeSize(Size::Medium)),
)
.menu_with_check(
"Small",
size == Size::Small,
Box::new(ChangeSize(Size::Small)),
)
.menu_with_check(
"XSmall",
size == Size::XSmall,
Box::new(ChangeSize(Size::XSmall)),
)
}),
)
.child(
Checkbox::new("loop-selection")
.label("Loop Selection")
@ -784,6 +756,76 @@ impl Render for TableStory {
.on_click(cx.listener(Self::toggle_refresh_data)),
),
)
.child(
h_flex()
.gap_2()
.child(
Button::new("size")
.small()
.label(format!("size: {:?}", self.size))
.popup_menu(move |menu, _| {
menu.menu_with_check(
"Large",
size == Size::Large,
Box::new(ChangeSize(Size::Large)),
)
.menu_with_check(
"Medium",
size == Size::Medium,
Box::new(ChangeSize(Size::Medium)),
)
.menu_with_check(
"Small",
size == Size::Small,
Box::new(ChangeSize(Size::Small)),
)
.menu_with_check(
"XSmall",
size == Size::XSmall,
Box::new(ChangeSize(Size::XSmall)),
)
}),
)
.child(
Button::new("scroll-top")
.child("Scroll to Top")
.small()
.on_click(cx.listener(|this, _, cx| {
this.table.update(cx, |table, cx| {
table.scroll_to_row(0, cx);
})
})),
)
.child(
Button::new("scroll-bottom")
.child("Scroll to Bottom")
.small()
.on_click(cx.listener(|this, _, cx| {
this.table.update(cx, |table, cx| {
table.scroll_to_row(table.delegate().rows_count(cx) - 1, cx);
})
})),
), // .child(
// Button::new("scroll-first-col")
// .child("Scroll to First Column")
// .small()
// .on_click(cx.listener(|this, _, cx| {
// this.table.update(cx, |table, cx| {
// table.scroll_to_col(0, cx);
// })
// })),
// )
// .child(
// Button::new("scroll-last-col")
// .child("Scroll to Last Column")
// .small()
// .on_click(cx.listener(|this, _, cx| {
// this.table.update(cx, |table, cx| {
// table.scroll_to_col(table.delegate().cols_count(cx), cx);
// })
// })),
// ),
)
.child(
h_flex().items_center().gap_2().child(
h_flex()

View file

@ -231,6 +231,18 @@ where
))
}
/// Scroll to the item at the given index.
pub fn scroll_to_item(&mut self, ix: usize, cx: &mut ViewContext<Self>) {
self.vertical_scroll_handle
.scroll_to_item(ix, ScrollStrategy::Top);
cx.notify();
}
/// Get scroll handle
pub fn scroll_handle(&self) -> &UniformListScrollHandle {
&self.vertical_scroll_handle
}
fn scroll_to_selected_item(&mut self, _cx: &mut ViewContext<Self>) {
if let Some(ix) = self.selected_index {
self.vertical_scroll_handle

View file

@ -367,12 +367,30 @@ where
cx.notify();
}
fn scroll_to_row(&mut self, row_ix: usize, cx: &mut ViewContext<Self>) {
/// Scroll to the row at the given index.
pub fn scroll_to_row(&mut self, row_ix: usize, cx: &mut ViewContext<Self>) {
self.vertical_scroll_handle
.scroll_to_item(row_ix, ScrollStrategy::Top);
cx.notify();
}
// Scroll to the column at the given index.
// TODO: Fix scroll to selected col, this was not working after fixed col.
// pub fn scroll_to_col(&mut self, col_ix: usize, cx: &mut ViewContext<Self>) {
// self.horizontal_scroll_handle.scroll_to_item(col_ix);
// cx.notify();
// }
/// Get scroll handle
pub fn scroll_handle(&self) -> &UniformListScrollHandle {
&self.vertical_scroll_handle
}
/// Get horizontal scroll handle
pub fn horizontal_scroll_handle(&self) -> &ScrollHandle {
&self.horizontal_scroll_handle
}
/// Returns the selected row index.
pub fn selected_row(&self) -> Option<usize> {
self.selected_row