From ed75659765ee4e44ef60673833b659aa21409023 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Wed, 16 Jul 2025 17:11:49 +0800 Subject: [PATCH] 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`. --- crates/story/src/button_story.rs | 72 ++++---- crates/story/src/table_story.rs | 288 +++++++++++++++++++------------ crates/ui/src/table.rs | 65 +++---- 3 files changed, 245 insertions(+), 180 deletions(-) diff --git a/crates/story/src/button_story.rs b/crates/story/src/button_story.rs index 4363d94f..6f4a581c 100644 --- a/crates/story/src/button_story.rs +++ b/crates/story/src/button_story.rs @@ -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), + ), + ) } } diff --git a/crates/story/src/table_story.rs b/crates/story/src/table_story.rs index 1a9d13dc..5d209a05 100644 --- a/crates/story/src/table_story.rs +++ b/crates/story/src/table_story.rs @@ -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 { struct Column { id: SharedString, name: SharedString, + align: TextAlign, sort: Option, + paddings: Option>, + width: Pixels, + fixed: bool, + resizable: bool, } impl Column { - fn new( - id: impl Into, - name: impl Into, - sort: Option, - ) -> Self { + fn new(id: impl Into, name: impl Into) -> 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) -> 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, columns: Vec, 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>) -> AnyElement { + fn render_value_cell( + &self, + col: &Column, + val: f64, + cx: &mut Context>, + ) -> 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> { - if col_ix >= 3 && col_ix <= 10 { - Some(Edges::all(px(0.))) - } else { - None - } + fn col_paddings(&self, col_ix: usize, _: &App) -> Option> { + let Some(col) = self.columns.get(col_ix) else { + return None; + }; + + col.paddings } fn col_fixed(&self, col_ix: usize, _: &App) -> Option { @@ -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>, + _: &mut Context>, ) -> 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::() { + if let Ok(total_count) = text.parse::() { + 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.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) -> 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( diff --git a/crates/ui/src/table.rs b/crates/ui/src/table.rs index 91722a7d..34a4a756 100644 --- a/crates/ui/src/table.rs +++ b/crates/ui/src/table.rs @@ -43,7 +43,7 @@ pub(crate) struct ColGroup { pub(crate) bounds: Bounds, pub(crate) sort: Option, pub(crate) fixed: Option, - pub(crate) padding: Option>, + pub(crate) paddings: Option>, } #[derive(Clone)] @@ -144,6 +144,11 @@ pub struct Table { col_groups: Vec, 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> { + fn col_paddings(&self, col_ix: usize, cx: &App) -> Option> { 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>, ) -> 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.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) { - 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) -> 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,