diff --git a/crates/story/src/list_story.rs b/crates/story/src/list_story.rs index 253fad9f..dd37142f 100644 --- a/crates/story/src/list_story.rs +++ b/crates/story/src/list_story.rs @@ -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>) -> Option { - 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::>(); - - 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, cx: &mut ViewContext>) { 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) -> 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()), + ) } } diff --git a/crates/story/src/table_story.rs b/crates/story/src/table_story.rs index 5e71240b..23ba09db 100644 --- a/crates/story/src/table_story.rs +++ b/crates/story/src/table_story.rs @@ -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() diff --git a/crates/ui/src/list/list.rs b/crates/ui/src/list/list.rs index 0d0e2527..5114b7b4 100644 --- a/crates/ui/src/list/list.rs +++ b/crates/ui/src/list/list.rs @@ -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.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) { if let Some(ix) = self.selected_index { self.vertical_scroll_handle diff --git a/crates/ui/src/table.rs b/crates/ui/src/table.rs index 2205f011..c36cec4b 100644 --- a/crates/ui/src/table.rs +++ b/crates/ui/src/table.rs @@ -367,12 +367,30 @@ where cx.notify(); } - fn scroll_to_row(&mut self, row_ix: usize, cx: &mut ViewContext) { + /// Scroll to the row at the given index. + pub fn scroll_to_row(&mut self, row_ix: usize, cx: &mut ViewContext) { 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.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 { self.selected_row