table: Update to standardization the TableDelegate API. (#1067)
## Break Changes - Renamed some method name of the TableDelegate. ```diff - fn can_select_col + fn col_selectable - fn can_resize_col + fn col_resizable - fn col_padding + fn col_paddings - fn can_move_col + fn col_movable ``` - Removed `fn can_loop_select` remove TableDelegate, instead of to use `loop_selection` option on `Table`.
This commit is contained in:
parent
ea1f5331c8
commit
ed75659765
3 changed files with 245 additions and 180 deletions
|
|
@ -587,42 +587,6 @@ impl Render for ButtonStory {
|
|||
.on_click(Self::on_click),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
section("Custom Button")
|
||||
.child(
|
||||
Button::new("button-6-custom")
|
||||
.custom(custom_variant)
|
||||
.label("Custom Button")
|
||||
.disabled(disabled)
|
||||
.selected(selected)
|
||||
.loading(loading)
|
||||
.when(compact, |this| this.compact())
|
||||
.on_click(Self::on_click),
|
||||
)
|
||||
.child(
|
||||
Button::new("button-outline-6-custom")
|
||||
.outline()
|
||||
.custom(custom_variant)
|
||||
.label("Outline Button")
|
||||
.disabled(disabled)
|
||||
.selected(selected)
|
||||
.loading(loading)
|
||||
.when(compact, |this| this.compact())
|
||||
.on_click(Self::on_click),
|
||||
)
|
||||
.child(
|
||||
Button::new("button-outline-6-custom-1")
|
||||
.outline()
|
||||
.icon(IconName::Bell)
|
||||
.custom(custom_variant)
|
||||
.label("Icon Button")
|
||||
.disabled(disabled)
|
||||
.selected(selected)
|
||||
.loading(loading)
|
||||
.when(compact, |this| this.compact())
|
||||
.on_click(Self::on_click),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
section("Button Group").child(
|
||||
ButtonGroup::new("button-group")
|
||||
|
|
@ -936,5 +900,41 @@ impl Render for ButtonStory {
|
|||
.when(compact, |this| this.compact()),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
section("Custom Button")
|
||||
.child(
|
||||
Button::new("button-6-custom")
|
||||
.custom(custom_variant)
|
||||
.label("Custom Button")
|
||||
.disabled(disabled)
|
||||
.selected(selected)
|
||||
.loading(loading)
|
||||
.when(compact, |this| this.compact())
|
||||
.on_click(Self::on_click),
|
||||
)
|
||||
.child(
|
||||
Button::new("button-outline-6-custom")
|
||||
.outline()
|
||||
.custom(custom_variant)
|
||||
.label("Outline Button")
|
||||
.disabled(disabled)
|
||||
.selected(selected)
|
||||
.loading(loading)
|
||||
.when(compact, |this| this.compact())
|
||||
.on_click(Self::on_click),
|
||||
)
|
||||
.child(
|
||||
Button::new("button-outline-6-custom-1")
|
||||
.outline()
|
||||
.icon(IconName::Bell)
|
||||
.custom(custom_variant)
|
||||
.label("Icon Button")
|
||||
.disabled(disabled)
|
||||
.selected(selected)
|
||||
.loading(loading)
|
||||
.when(compact, |this| this.compact())
|
||||
.on_click(Self::on_click),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use fake::Fake;
|
|||
use gpui::{
|
||||
div, prelude::FluentBuilder as _, px, Action, AnyElement, App, AppContext, ClickEvent, Context,
|
||||
Edges, Entity, Focusable, InteractiveElement, IntoElement, ParentElement, Pixels, Render,
|
||||
SharedString, StatefulInteractiveElement, Styled, Timer, Window,
|
||||
SharedString, StatefulInteractiveElement, Styled, TextAlign, Timer, Window,
|
||||
};
|
||||
use gpui_component::{
|
||||
button::Button,
|
||||
|
|
@ -19,7 +19,7 @@ use gpui_component::{
|
|||
label::Label,
|
||||
popup_menu::{PopupMenu, PopupMenuExt},
|
||||
table::{self, ColFixed, ColSort, Table, TableDelegate, TableEvent},
|
||||
v_flex, ActiveTheme as _, Selectable, Sizable as _, Size, StyleSized as _,
|
||||
v_flex, ActiveTheme as _, Selectable, Sizable as _, Size, StyleSized as _, StyledExt,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -174,28 +174,63 @@ fn random_stocks(size: usize) -> Vec<Stock> {
|
|||
struct Column {
|
||||
id: SharedString,
|
||||
name: SharedString,
|
||||
align: TextAlign,
|
||||
sort: Option<ColSort>,
|
||||
paddings: Option<Edges<Pixels>>,
|
||||
width: Pixels,
|
||||
fixed: bool,
|
||||
resizable: bool,
|
||||
}
|
||||
|
||||
impl Column {
|
||||
fn new(
|
||||
id: impl Into<SharedString>,
|
||||
name: impl Into<SharedString>,
|
||||
sort: Option<ColSort>,
|
||||
) -> Self {
|
||||
fn new(id: impl Into<SharedString>, name: impl Into<SharedString>) -> Self {
|
||||
Self {
|
||||
id: id.into(),
|
||||
name: name.into(),
|
||||
sort,
|
||||
align: TextAlign::Left,
|
||||
sort: None,
|
||||
paddings: None,
|
||||
width: px(100.),
|
||||
fixed: false,
|
||||
resizable: true,
|
||||
}
|
||||
}
|
||||
|
||||
fn sortable(mut self) -> Self {
|
||||
self.sort = Some(ColSort::Default);
|
||||
self
|
||||
}
|
||||
|
||||
fn text_right(mut self) -> Self {
|
||||
self.align = TextAlign::Right;
|
||||
self
|
||||
}
|
||||
|
||||
fn p_0(mut self) -> Self {
|
||||
self.paddings = Some(Edges::all(px(0.)));
|
||||
self
|
||||
}
|
||||
|
||||
fn w(mut self, width: impl Into<Pixels>) -> Self {
|
||||
self.width = width.into();
|
||||
self
|
||||
}
|
||||
|
||||
fn fixed(mut self) -> Self {
|
||||
self.fixed = true;
|
||||
self
|
||||
}
|
||||
|
||||
fn resizable(mut self, resizable: bool) -> Self {
|
||||
self.resizable = resizable;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
struct StockTableDelegate {
|
||||
stocks: Vec<Stock>,
|
||||
columns: Vec<Column>,
|
||||
size: Size,
|
||||
loop_selection: bool,
|
||||
col_resize: bool,
|
||||
col_order: bool,
|
||||
col_sort: bool,
|
||||
|
|
@ -214,53 +249,64 @@ impl StockTableDelegate {
|
|||
size: Size::default(),
|
||||
stocks: random_stocks(size),
|
||||
columns: vec![
|
||||
Column::new("id", "ID", None),
|
||||
Column::new("market", "Market", None),
|
||||
Column::new("symbol", "Symbol", Some(ColSort::Default)),
|
||||
Column::new("name", "Name", None),
|
||||
Column::new("price", "Price", Some(ColSort::Default)),
|
||||
Column::new("change", "Chg", Some(ColSort::Default)),
|
||||
Column::new("change_percent", "Chg%", Some(ColSort::Default)),
|
||||
Column::new("volume", "Volume", None),
|
||||
Column::new("turnover", "Turnover", None),
|
||||
Column::new("market_cap", "Market Cap", None),
|
||||
Column::new("ttm", "TTM", None),
|
||||
Column::new("five_mins_ranking", "5m Ranking", None),
|
||||
Column::new("th60_days_ranking", "60d Ranking", None),
|
||||
Column::new("year_change_percent", "Year Chg%", None),
|
||||
Column::new("bid", "Bid", None),
|
||||
Column::new("bid_volume", "Bid Vol", None),
|
||||
Column::new("ask", "Ask", None),
|
||||
Column::new("ask_volume", "Ask Vol", None),
|
||||
Column::new("open", "Open", None),
|
||||
Column::new("prev_close", "Prev Close", None),
|
||||
Column::new("high", "High", None),
|
||||
Column::new("low", "Low", None),
|
||||
Column::new("turnover_rate", "Turnover Rate", None),
|
||||
Column::new("rise_rate", "Rise Rate", None),
|
||||
Column::new("amplitude", "Amplitude", None),
|
||||
Column::new("pe_status", "P/E", None),
|
||||
Column::new("pb_status", "P/B", None),
|
||||
Column::new("volume_ratio", "Volume Ratio", None),
|
||||
Column::new("bid_ask_ratio", "Bid Ask Ratio", None),
|
||||
Column::new("latest_pre_close", "Latest Pre Close", None),
|
||||
Column::new("latest_post_close", "Latest Post Close", None),
|
||||
Column::new("pre_market_cap", "Pre Mkt Cap", None),
|
||||
Column::new("pre_market_percent", "Pre Mkt%", None),
|
||||
Column::new("pre_market_change", "Pre Mkt Chg", None),
|
||||
Column::new("post_market_cap", "Post Mkt Cap", None),
|
||||
Column::new("post_market_percent", "Post Mkt%", None),
|
||||
Column::new("post_market_change", "Post Mkt Chg", None),
|
||||
Column::new("float_cap", "Float Cap", None),
|
||||
Column::new("shares", "Shares", None),
|
||||
Column::new("shares_float", "Float Shares", None),
|
||||
Column::new("day_5_ranking", "5d Ranking", None),
|
||||
Column::new("day_10_ranking", "10d Ranking", None),
|
||||
Column::new("day_30_ranking", "30d Ranking", None),
|
||||
Column::new("day_120_ranking", "120d Ranking", None),
|
||||
Column::new("day_250_ranking", "250d Ranking", None),
|
||||
Column::new("id", "ID").w(60.).fixed().resizable(false),
|
||||
Column::new("market", "Market")
|
||||
.w(60.)
|
||||
.fixed()
|
||||
.resizable(false),
|
||||
Column::new("symbol", "Symbol").w(100.).fixed().sortable(),
|
||||
Column::new("name", "Name").w(180.).fixed(),
|
||||
Column::new("price", "Price").sortable().text_right().p_0(),
|
||||
Column::new("change", "Chg").sortable().text_right().p_0(),
|
||||
Column::new("change_percent", "Chg%")
|
||||
.sortable()
|
||||
.text_right()
|
||||
.p_0(),
|
||||
Column::new("volume", "Volume").p_0(),
|
||||
Column::new("turnover", "Turnover").p_0(),
|
||||
Column::new("market_cap", "Market Cap").p_0(),
|
||||
Column::new("ttm", "TTM").p_0(),
|
||||
Column::new("five_mins_ranking", "5m Ranking")
|
||||
.text_right()
|
||||
.p_0(),
|
||||
Column::new("th60_days_ranking", "60d Ranking"),
|
||||
Column::new("year_change_percent", "Year Chg%"),
|
||||
Column::new("bid", "Bid").text_right().p_0(),
|
||||
Column::new("bid_volume", "Bid Vol").text_right().p_0(),
|
||||
Column::new("ask", "Ask").text_right().p_0(),
|
||||
Column::new("ask_volume", "Ask Vol").text_right().p_0(),
|
||||
Column::new("open", "Open").text_right().p_0(),
|
||||
Column::new("prev_close", "Prev Close").text_right().p_0(),
|
||||
Column::new("high", "High").text_right().p_0(),
|
||||
Column::new("low", "Low").text_right().p_0(),
|
||||
Column::new("turnover_rate", "Turnover Rate"),
|
||||
Column::new("rise_rate", "Rise Rate"),
|
||||
Column::new("amplitude", "Amplitude"),
|
||||
Column::new("pe_status", "P/E"),
|
||||
Column::new("pb_status", "P/B"),
|
||||
Column::new("volume_ratio", "Volume Ratio")
|
||||
.text_right()
|
||||
.p_0(),
|
||||
Column::new("bid_ask_ratio", "Bid Ask Ratio")
|
||||
.text_right()
|
||||
.p_0(),
|
||||
Column::new("latest_pre_close", "Latest Pre Close"),
|
||||
Column::new("latest_post_close", "Latest Post Close"),
|
||||
Column::new("pre_market_cap", "Pre Mkt Cap"),
|
||||
Column::new("pre_market_percent", "Pre Mkt%"),
|
||||
Column::new("pre_market_change", "Pre Mkt Chg"),
|
||||
Column::new("post_market_cap", "Post Mkt Cap"),
|
||||
Column::new("post_market_percent", "Post Mkt%"),
|
||||
Column::new("post_market_change", "Post Mkt Chg"),
|
||||
Column::new("float_cap", "Float Cap"),
|
||||
Column::new("shares", "Shares"),
|
||||
Column::new("shares_float", "Float Shares"),
|
||||
Column::new("day_5_ranking", "5d Ranking"),
|
||||
Column::new("day_10_ranking", "10d Ranking"),
|
||||
Column::new("day_30_ranking", "30d Ranking"),
|
||||
Column::new("day_120_ranking", "120d Ranking"),
|
||||
Column::new("day_250_ranking", "250d Ranking"),
|
||||
],
|
||||
loop_selection: true,
|
||||
col_resize: true,
|
||||
col_order: true,
|
||||
col_sort: true,
|
||||
|
|
@ -281,7 +327,12 @@ impl StockTableDelegate {
|
|||
self.full_loading = false;
|
||||
}
|
||||
|
||||
fn render_value_cell(&self, val: f64, cx: &mut Context<Table<Self>>) -> AnyElement {
|
||||
fn render_value_cell(
|
||||
&self,
|
||||
col: &Column,
|
||||
val: f64,
|
||||
cx: &mut Context<Table<Self>>,
|
||||
) -> AnyElement {
|
||||
let this = div()
|
||||
.h_full()
|
||||
.table_cell_size(self.size)
|
||||
|
|
@ -300,7 +351,10 @@ impl StockTableDelegate {
|
|||
this
|
||||
};
|
||||
|
||||
this.into_any_element()
|
||||
this.when(col.align == TextAlign::Right, |this| {
|
||||
this.h_flex().justify_end()
|
||||
})
|
||||
.into_any_element()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -314,29 +368,25 @@ impl TableDelegate for StockTableDelegate {
|
|||
}
|
||||
|
||||
fn col_name(&self, col_ix: usize, _: &App) -> SharedString {
|
||||
if let Some(col) = self.columns.get(col_ix) {
|
||||
col.name.clone()
|
||||
} else {
|
||||
"--".into()
|
||||
}
|
||||
self.columns
|
||||
.get(col_ix)
|
||||
.map(|col| col.name.clone())
|
||||
.unwrap_or("--".into())
|
||||
}
|
||||
|
||||
fn col_width(&self, col_ix: usize, _: &App) -> Pixels {
|
||||
px(match col_ix {
|
||||
0 => 60.,
|
||||
1 => 60.,
|
||||
2 => 100.,
|
||||
3 => 180.,
|
||||
_ => 100.,
|
||||
})
|
||||
self.columns
|
||||
.get(col_ix)
|
||||
.map(|col| col.width)
|
||||
.unwrap_or(px(100.))
|
||||
}
|
||||
|
||||
fn col_padding(&self, col_ix: usize, _: &App) -> Option<Edges<Pixels>> {
|
||||
if col_ix >= 3 && col_ix <= 10 {
|
||||
Some(Edges::all(px(0.)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
fn col_paddings(&self, col_ix: usize, _: &App) -> Option<Edges<Pixels>> {
|
||||
let Some(col) = self.columns.get(col_ix) else {
|
||||
return None;
|
||||
};
|
||||
|
||||
col.paddings
|
||||
}
|
||||
|
||||
fn col_fixed(&self, col_ix: usize, _: &App) -> Option<table::ColFixed> {
|
||||
|
|
@ -344,18 +394,26 @@ impl TableDelegate for StockTableDelegate {
|
|||
return None;
|
||||
}
|
||||
|
||||
if col_ix < 4 {
|
||||
let Some(col) = self.columns.get(col_ix) else {
|
||||
return None;
|
||||
};
|
||||
|
||||
if col.fixed {
|
||||
Some(ColFixed::Left)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn can_resize_col(&self, col_ix: usize, _: &App) -> bool {
|
||||
return self.col_resize && col_ix > 1;
|
||||
fn col_resizable(&self, col_ix: usize, _: &App) -> bool {
|
||||
let Some(col) = self.columns.get(col_ix) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
col.resizable
|
||||
}
|
||||
|
||||
fn can_select_col(&self, _: usize, _: &App) -> bool {
|
||||
fn col_selectable(&self, _: usize, _: &App) -> bool {
|
||||
return self.col_selection;
|
||||
}
|
||||
|
||||
|
|
@ -363,15 +421,18 @@ impl TableDelegate for StockTableDelegate {
|
|||
&self,
|
||||
col_ix: usize,
|
||||
_: &mut Window,
|
||||
cx: &mut Context<Table<Self>>,
|
||||
_: &mut Context<Table<Self>>,
|
||||
) -> impl IntoElement {
|
||||
let th = div().child(self.col_name(col_ix, cx));
|
||||
let col = self.columns.get(col_ix).unwrap();
|
||||
|
||||
if col_ix >= 3 && col_ix <= 10 {
|
||||
th.table_cell_size(self.size)
|
||||
} else {
|
||||
th
|
||||
}
|
||||
div()
|
||||
.child(col.name.clone())
|
||||
.when(col_ix >= 3 && col_ix <= 10, |this| {
|
||||
this.table_cell_size(self.size)
|
||||
})
|
||||
.when(col.align == TextAlign::Right, |this| {
|
||||
this.h_flex().w_full().justify_end()
|
||||
})
|
||||
}
|
||||
|
||||
fn context_menu(
|
||||
|
|
@ -440,14 +501,14 @@ impl TableDelegate for StockTableDelegate {
|
|||
.into_any_element(),
|
||||
"symbol" => stock.counter.symbol_code().into_any_element(),
|
||||
"name" => stock.counter.name.clone().into_any_element(),
|
||||
"price" => self.render_value_cell(stock.price, cx),
|
||||
"change" => self.render_value_cell(stock.change, cx),
|
||||
"change_percent" => self.render_value_cell(stock.change_percent, cx),
|
||||
"volume" => self.render_value_cell(stock.volume, cx),
|
||||
"turnover" => self.render_value_cell(stock.turnover, cx),
|
||||
"market_cap" => self.render_value_cell(stock.market_cap, cx),
|
||||
"ttm" => self.render_value_cell(stock.ttm, cx),
|
||||
"five_mins_ranking" => self.render_value_cell(stock.five_mins_ranking, cx),
|
||||
"price" => self.render_value_cell(&col, stock.price, cx),
|
||||
"change" => self.render_value_cell(&col, stock.change, cx),
|
||||
"change_percent" => self.render_value_cell(&col, stock.change_percent, cx),
|
||||
"volume" => self.render_value_cell(&col, stock.volume, cx),
|
||||
"turnover" => self.render_value_cell(&col, stock.turnover, cx),
|
||||
"market_cap" => self.render_value_cell(&col, stock.market_cap, cx),
|
||||
"ttm" => self.render_value_cell(&col, stock.ttm, cx),
|
||||
"five_mins_ranking" => self.render_value_cell(&col, stock.five_mins_ranking, cx),
|
||||
"th60_days_ranking" => stock
|
||||
.th60_days_ranking
|
||||
.floor()
|
||||
|
|
@ -457,14 +518,14 @@ impl TableDelegate for StockTableDelegate {
|
|||
.floor()
|
||||
.to_string()
|
||||
.into_any_element(),
|
||||
"bid" => self.render_value_cell(stock.bid, cx),
|
||||
"bid_volume" => self.render_value_cell(stock.bid_volume, cx),
|
||||
"ask" => self.render_value_cell(stock.ask, cx),
|
||||
"ask_volume" => self.render_value_cell(stock.ask_volume, cx),
|
||||
"open" => stock.open.floor().to_string().into_any_element(),
|
||||
"prev_close" => stock.prev_close.floor().to_string().into_any_element(),
|
||||
"high" => self.render_value_cell(stock.high, cx),
|
||||
"low" => self.render_value_cell(stock.low, cx),
|
||||
"bid" => self.render_value_cell(&col, stock.bid, cx),
|
||||
"bid_volume" => self.render_value_cell(&col, stock.bid_volume, cx),
|
||||
"ask" => self.render_value_cell(&col, stock.ask, cx),
|
||||
"ask_volume" => self.render_value_cell(&col, stock.ask_volume, cx),
|
||||
"open" => self.render_value_cell(&col, stock.open, cx),
|
||||
"prev_close" => self.render_value_cell(&col, stock.prev_close, cx),
|
||||
"high" => self.render_value_cell(&col, stock.high, cx),
|
||||
"low" => self.render_value_cell(&col, stock.low, cx),
|
||||
"turnover_rate" => (stock.turnover_rate * 100.0)
|
||||
.floor()
|
||||
.to_string()
|
||||
|
|
@ -479,8 +540,8 @@ impl TableDelegate for StockTableDelegate {
|
|||
.into_any_element(),
|
||||
"pe_status" => stock.pe_status.floor().to_string().into_any_element(),
|
||||
"pb_status" => stock.pb_status.floor().to_string().into_any_element(),
|
||||
"volume_ratio" => self.render_value_cell(stock.volume_ratio, cx),
|
||||
"bid_ask_ratio" => self.render_value_cell(stock.bid_ask_ratio, cx),
|
||||
"volume_ratio" => self.render_value_cell(&col, stock.volume_ratio, cx),
|
||||
"bid_ask_ratio" => self.render_value_cell(&col, stock.bid_ask_ratio, cx),
|
||||
"latest_pre_close" => stock
|
||||
.latest_pre_close
|
||||
.floor()
|
||||
|
|
@ -523,11 +584,7 @@ impl TableDelegate for StockTableDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
fn can_loop_select(&self, _: &App) -> bool {
|
||||
self.loop_selection
|
||||
}
|
||||
|
||||
fn can_move_col(&self, _: usize, _: &App) -> bool {
|
||||
fn col_movable(&self, _: usize, _: &App) -> bool {
|
||||
self.col_order
|
||||
}
|
||||
|
||||
|
|
@ -736,9 +793,13 @@ impl TableStory {
|
|||
// Update when the user presses Enter or the input loses focus
|
||||
InputEvent::PressEnter { .. } | InputEvent::Blur => {
|
||||
let text = self.num_stocks_input.read(cx).value().to_string();
|
||||
if let Ok(num) = text.parse::<usize>() {
|
||||
if let Ok(total_count) = text.parse::<usize>() {
|
||||
if total_count == self.table.read(cx).delegate().stocks.len() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.table.update(cx, |table, _| {
|
||||
table.delegate_mut().update_stocks(num);
|
||||
table.delegate_mut().update_stocks(total_count);
|
||||
});
|
||||
cx.notify();
|
||||
}
|
||||
|
|
@ -749,7 +810,7 @@ impl TableStory {
|
|||
|
||||
fn toggle_loop_selection(&mut self, checked: &bool, _: &mut Window, cx: &mut Context<Self>) {
|
||||
self.table.update(cx, |table, cx| {
|
||||
table.delegate_mut().loop_selection = *checked;
|
||||
table.loop_selection = *checked;
|
||||
cx.notify();
|
||||
});
|
||||
}
|
||||
|
|
@ -840,6 +901,7 @@ impl TableStory {
|
|||
impl Render for TableStory {
|
||||
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl gpui::IntoElement {
|
||||
let delegate = self.table.read(cx).delegate();
|
||||
let loop_selection = self.table.read(cx).loop_selection;
|
||||
let rows_count = delegate.rows_count(cx);
|
||||
let size = self.size;
|
||||
|
||||
|
|
@ -856,7 +918,7 @@ impl Render for TableStory {
|
|||
.child(
|
||||
Checkbox::new("loop-selection")
|
||||
.label("Loop Selection")
|
||||
.selected(delegate.loop_selection)
|
||||
.selected(loop_selection)
|
||||
.on_click(cx.listener(Self::toggle_loop_selection)),
|
||||
)
|
||||
.child(
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ pub(crate) struct ColGroup {
|
|||
pub(crate) bounds: Bounds<Pixels>,
|
||||
pub(crate) sort: Option<ColSort>,
|
||||
pub(crate) fixed: Option<ColFixed>,
|
||||
pub(crate) padding: Option<Edges<Pixels>>,
|
||||
pub(crate) paddings: Option<Edges<Pixels>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -144,6 +144,11 @@ pub struct Table<D: TableDelegate> {
|
|||
col_groups: Vec<ColGroup>,
|
||||
fixed_cols: FixedCols,
|
||||
|
||||
/// Whether the table can loop selection, default is true.
|
||||
///
|
||||
/// When the prev/next selection is out of the table bounds, the selection will loop to the other side.
|
||||
pub loop_selection: bool,
|
||||
|
||||
pub vertical_scroll_handle: UniformListScrollHandle,
|
||||
pub vertical_scroll_state: ScrollbarState,
|
||||
pub horizontal_scroll_handle: ScrollHandle,
|
||||
|
|
@ -182,12 +187,12 @@ pub trait TableDelegate: Sized + 'static {
|
|||
fn col_name(&self, col_ix: usize, cx: &App) -> SharedString;
|
||||
|
||||
/// Returns whether the column at the given index can be resized. Default: true
|
||||
fn can_resize_col(&self, col_ix: usize, cx: &App) -> bool {
|
||||
fn col_resizable(&self, col_ix: usize, cx: &App) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Returns whether the column at the given index can be selected. Default: false
|
||||
fn can_select_col(&self, col_ix: usize, cx: &App) -> bool {
|
||||
fn col_selectable(&self, col_ix: usize, cx: &App) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
|
|
@ -216,10 +221,15 @@ pub trait TableDelegate: Sized + 'static {
|
|||
/// Return the padding of the column at the given index to override the default padding.
|
||||
///
|
||||
/// Return None, use the default padding.
|
||||
fn col_padding(&self, col_ix: usize, cx: &App) -> Option<Edges<Pixels>> {
|
||||
fn col_paddings(&self, col_ix: usize, cx: &App) -> Option<Edges<Pixels>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Return true to enable column order change.
|
||||
fn col_movable(&self, col_ix: usize, cx: &App) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Perform sort on the column at the given index.
|
||||
fn perform_sort(
|
||||
&mut self,
|
||||
|
|
@ -264,20 +274,6 @@ pub trait TableDelegate: Sized + 'static {
|
|||
cx: &mut Context<Table<Self>>,
|
||||
) -> impl IntoElement;
|
||||
|
||||
/// Return true to enable loop selection on the table.
|
||||
///
|
||||
/// When the prev/next selection is out of the table bounds, the selection will loop to the other side.
|
||||
///
|
||||
/// Default: true
|
||||
fn can_loop_select(&self, _: &App) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Return true to enable column order change.
|
||||
fn can_move_col(&self, col_ix: usize, cx: &App) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Move the column at the given `col_ix` to insert before the column at the given `to_ix`.
|
||||
fn move_col(
|
||||
&mut self,
|
||||
|
|
@ -403,6 +399,7 @@ where
|
|||
size: Size::default(),
|
||||
scrollbar_visible: Edges::all(true),
|
||||
visible_range: VisibleRangeState::default(),
|
||||
loop_selection: true,
|
||||
_load_more_task: Task::ready(()),
|
||||
_measure: Vec::new(),
|
||||
};
|
||||
|
|
@ -436,6 +433,12 @@ where
|
|||
self
|
||||
}
|
||||
|
||||
/// Set to loop selection, default to true.
|
||||
pub fn loop_selection(mut self, loop_selection: bool) -> Self {
|
||||
self.loop_selection = loop_selection;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the size to the table.
|
||||
pub fn set_size(&mut self, size: Size, cx: &mut Context<Self>) {
|
||||
self.size = size;
|
||||
|
|
@ -466,7 +469,7 @@ where
|
|||
self.col_groups = (0..self.delegate.cols_count(cx))
|
||||
.map(|col_ix| ColGroup {
|
||||
width: self.delegate.col_width(col_ix, cx),
|
||||
padding: self.delegate.col_padding(col_ix, cx),
|
||||
paddings: self.delegate.col_paddings(col_ix, cx),
|
||||
bounds: Bounds::default(),
|
||||
sort: self.delegate.col_sort(col_ix, cx),
|
||||
fixed: self.delegate.col_fixed(col_ix, cx),
|
||||
|
|
@ -563,7 +566,7 @@ where
|
|||
}
|
||||
|
||||
fn on_col_head_click(&mut self, col_ix: usize, _: &mut Window, cx: &mut Context<Self>) {
|
||||
if !self.delegate.can_select_col(col_ix, cx) {
|
||||
if !self.delegate.col_selectable(col_ix, cx) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -584,7 +587,7 @@ where
|
|||
if selected_row > 0 {
|
||||
selected_row = selected_row.saturating_sub(1);
|
||||
} else {
|
||||
if self.delegate.can_loop_select(cx) {
|
||||
if self.loop_selection {
|
||||
selected_row = rows_count.saturating_sub(1);
|
||||
}
|
||||
}
|
||||
|
|
@ -601,7 +604,7 @@ where
|
|||
let selected_row = match self.selected_row {
|
||||
Some(selected_row) if selected_row < rows_count.saturating_sub(1) => selected_row + 1,
|
||||
Some(selected_row) => {
|
||||
if self.delegate.can_loop_select(cx) {
|
||||
if self.loop_selection {
|
||||
0
|
||||
} else {
|
||||
selected_row
|
||||
|
|
@ -624,7 +627,7 @@ where
|
|||
if selected_col > 0 {
|
||||
selected_col = selected_col.saturating_sub(1);
|
||||
} else {
|
||||
if self.delegate.can_loop_select(cx) {
|
||||
if self.loop_selection {
|
||||
selected_col = cols_count.saturating_sub(1);
|
||||
}
|
||||
}
|
||||
|
|
@ -641,7 +644,7 @@ where
|
|||
if selected_col < self.delegate.cols_count(cx).saturating_sub(1) {
|
||||
selected_col += 1;
|
||||
} else {
|
||||
if self.delegate.can_loop_select(cx) {
|
||||
if self.loop_selection {
|
||||
selected_col = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -678,7 +681,7 @@ where
|
|||
const MIN_WIDTH: Pixels = px(10.0);
|
||||
const MAX_WIDTH: Pixels = px(1200.0);
|
||||
|
||||
if !self.delegate.can_resize_col(ix, cx) {
|
||||
if !self.delegate.col_resizable(ix, cx) {
|
||||
return;
|
||||
}
|
||||
let size = size.floor();
|
||||
|
|
@ -810,7 +813,7 @@ where
|
|||
};
|
||||
|
||||
let col_width = col_group.width;
|
||||
let col_padding = col_group.padding;
|
||||
let col_padding = col_group.paddings;
|
||||
|
||||
div()
|
||||
.w(col_width)
|
||||
|
|
@ -833,7 +836,7 @@ where
|
|||
fn render_col_wrap(&self, col_ix: usize, _: &mut Window, cx: &mut Context<Self>) -> Div {
|
||||
let el = h_flex().h_full();
|
||||
|
||||
if self.delegate().can_select_col(col_ix, cx)
|
||||
if self.delegate().col_selectable(col_ix, cx)
|
||||
&& self.selected_col == Some(col_ix)
|
||||
&& self.selection_state == SelectionState::Column
|
||||
{
|
||||
|
|
@ -896,7 +899,7 @@ where
|
|||
) -> impl IntoElement {
|
||||
const HANDLE_SIZE: Pixels = px(2.);
|
||||
|
||||
if !self.delegate.can_resize_col(ix, cx) {
|
||||
if !self.delegate.col_resizable(ix, cx) {
|
||||
return div().into_any_element();
|
||||
}
|
||||
|
||||
|
|
@ -1024,8 +1027,8 @@ where
|
|||
) -> impl IntoElement {
|
||||
let entity_id = cx.entity_id();
|
||||
let col_group = self.col_groups.get(col_ix).expect("BUG: invalid col index");
|
||||
let moveable = self.delegate.can_move_col(col_ix, cx);
|
||||
let paddings = self.delegate.col_padding(col_ix, cx);
|
||||
let movable = self.delegate.col_movable(col_ix, cx);
|
||||
let paddings = self.delegate.col_paddings(col_ix, cx);
|
||||
let name = self.delegate.col_name(col_ix, cx);
|
||||
|
||||
h_flex()
|
||||
|
|
@ -1052,7 +1055,7 @@ where
|
|||
})
|
||||
.children(self.render_sort_icon(col_ix, &col_group, window, cx)),
|
||||
)
|
||||
.when(moveable, |this| {
|
||||
.when(movable, |this| {
|
||||
this.on_drag(
|
||||
DragCol {
|
||||
entity_id,
|
||||
|
|
|
|||
Loading…
Reference in a new issue