Add col_padding to Table delegate to control the column padding. (#326)

<img width="775" alt="image"
src="https://github.com/user-attachments/assets/a7189c06-9945-4508-86fb-e71fd819cc41">
This commit is contained in:
Jason Lee 2024-10-10 13:58:49 +08:00 committed by GitHub
parent fd09229541
commit 2198134832
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 128 additions and 35 deletions

View file

@ -2,8 +2,9 @@ use std::time::{self, Duration};
use fake::{Fake, Faker}; use fake::{Fake, Faker};
use gpui::{ use gpui::{
div, impl_actions, AnyElement, InteractiveElement, IntoElement, ParentElement, Pixels, Render, div, impl_actions, px, AnyElement, Edges, InteractiveElement, IntoElement, ParentElement,
SharedString, Styled, Timer, View, ViewContext, VisualContext as _, WindowContext, Pixels, Render, SharedString, Styled, Timer, View, ViewContext, VisualContext as _,
WindowContext,
}; };
use serde::Deserialize; use serde::Deserialize;
use ui::{ use ui::{
@ -16,7 +17,7 @@ use ui::{
popup_menu::PopupMenuExt, popup_menu::PopupMenuExt,
prelude::FluentBuilder as _, prelude::FluentBuilder as _,
table::{ColFixed, ColSort, Table, TableDelegate, TableEvent}, table::{ColFixed, ColSort, Table, TableDelegate, TableEvent},
v_flex, Selectable, Size, v_flex, Selectable, Size, StyleSized as _,
}; };
#[derive(Clone, PartialEq, Eq, Deserialize)] #[derive(Clone, PartialEq, Eq, Deserialize)]
@ -167,6 +168,7 @@ impl Column {
struct StockTableDelegate { struct StockTableDelegate {
stocks: Vec<Stock>, stocks: Vec<Stock>,
columns: Vec<Column>, columns: Vec<Column>,
size: Size,
loop_selection: bool, loop_selection: bool,
col_resize: bool, col_resize: bool,
col_order: bool, col_order: bool,
@ -180,6 +182,7 @@ struct StockTableDelegate {
impl StockTableDelegate { impl StockTableDelegate {
fn new(size: usize) -> Self { fn new(size: usize) -> Self {
Self { Self {
size: Size::default(),
stocks: random_stocks(size), stocks: random_stocks(size),
columns: vec![ columns: vec![
Column::new("id", "ID", None), Column::new("id", "ID", None),
@ -253,7 +256,10 @@ impl StockTableDelegate {
} }
fn render_value_cell(&self, val: f64) -> AnyElement { fn render_value_cell(&self, val: f64) -> AnyElement {
let this = div().child(format!("{:.3}", val)); let this = div()
.h_full()
.table_cell_size(self.size)
.child(format!("{:.3}", val));
// Val is a 0.0 .. n.0 // Val is a 0.0 .. n.0
// 30% to red, 30% to green, others to default // 30% to red, 30% to green, others to default
let right_num = ((val - val.floor()) * 1000.).floor() as i32; let right_num = ((val - val.floor()) * 1000.).floor() as i32;
@ -296,6 +302,14 @@ impl TableDelegate for StockTableDelegate {
} }
} }
fn col_padding(&self, col_ix: usize) -> Option<Edges<Pixels>> {
if col_ix >= 3 && col_ix <= 10 {
Some(Edges::all(px(0.)))
} else {
None
}
}
fn col_fixed(&self, col_ix: usize) -> Option<ui::table::ColFixed> { fn col_fixed(&self, col_ix: usize) -> Option<ui::table::ColFixed> {
if !self.fixed_cols { if !self.fixed_cols {
return None; return None;
@ -316,6 +330,16 @@ impl TableDelegate for StockTableDelegate {
return self.col_selection; return self.col_selection;
} }
fn render_th(&self, col_ix: usize, _cx: &mut ViewContext<Table<Self>>) -> impl IntoElement {
let th = div().child(self.col_name(col_ix));
if col_ix >= 3 && col_ix <= 10 {
th.table_cell_size(self.size)
} else {
th
}
}
fn render_td( fn render_td(
&self, &self,
row_ix: usize, row_ix: usize,
@ -617,6 +641,7 @@ impl TableStory {
self.size = a.0; self.size = a.0;
self.table.update(cx, |table, cx| { self.table.update(cx, |table, cx| {
table.set_size(a.0, cx); table.set_size(a.0, cx);
table.delegate_mut().size = a.0;
}); });
} }

View file

@ -5,7 +5,8 @@ use crate::{
theme::ActiveTheme, theme::ActiveTheme,
}; };
use gpui::{ use gpui::{
div, px, Axis, Div, Element, ElementId, EntityId, FocusHandle, Pixels, Styled, WindowContext, div, px, Axis, Div, Edges, Element, ElementId, EntityId, FocusHandle, Pixels, Styled,
WindowContext,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -146,6 +147,47 @@ pub enum Size {
Large, Large,
} }
impl Size {
/// Returns the height for table row.
pub fn table_row_height(&self) -> Pixels {
match self {
Size::XSmall => px(26.),
Size::Small => px(30.),
Size::Large => px(40.),
_ => px(32.),
}
}
/// Returns the padding for a table cell.
pub fn table_cell_padding(&self) -> Edges<Pixels> {
match self {
Size::XSmall => Edges {
top: px(2.),
bottom: px(2.),
left: px(4.),
right: px(4.),
},
Size::Small => Edges {
top: px(3.),
bottom: px(3.),
left: px(6.),
right: px(6.),
},
Size::Large => Edges {
top: px(8.),
bottom: px(8.),
left: px(12.),
right: px(12.),
},
_ => Edges {
top: px(4.),
bottom: px(4.),
left: px(8.),
right: px(8.),
},
}
}
}
impl From<Pixels> for Size { impl From<Pixels> for Size {
fn from(size: Pixels) -> Self { fn from(size: Pixels) -> Self {
Size::Size(size) Size::Size(size)
@ -203,6 +245,8 @@ pub trait StyleSized<T: Styled> {
fn list_py(self, size: Size) -> Self; fn list_py(self, size: Size) -> Self;
/// Apply size with the given `Size`. /// Apply size with the given `Size`.
fn size_with(self, size: Size) -> Self; fn size_with(self, size: Size) -> Self;
/// Apply the table cell size (Font size, padding) with the given `Size`.
fn table_cell_size(self, size: Size) -> Self;
} }
impl<T: Styled> StyleSized<T> for T { impl<T: Styled> StyleSized<T> for T {
@ -290,6 +334,19 @@ impl<T: Styled> StyleSized<T> for T {
Size::Size(size) => self.size(size), Size::Size(size) => self.size(size),
} }
} }
fn table_cell_size(self, size: Size) -> Self {
let padding = size.table_cell_padding();
match size {
Size::XSmall => self.text_sm(),
Size::Small => self.text_sm(),
_ => self,
}
.pl(padding.left)
.pr(padding.right)
.pt(padding.top)
.pb(padding.bottom)
}
} }
pub trait AxisExt { pub trait AxisExt {

View file

@ -4,14 +4,14 @@ use crate::{
h_flex, h_flex,
scroll::{ScrollableAxis, ScrollableMask, Scrollbar, ScrollbarState}, scroll::{ScrollableAxis, ScrollableMask, Scrollbar, ScrollbarState},
theme::ActiveTheme, theme::ActiveTheme,
v_flex, Icon, IconName, Sizable, Size, v_flex, Icon, IconName, Sizable, Size, StyleSized as _,
}; };
use gpui::{ use gpui::{
actions, canvas, div, prelude::FluentBuilder, px, uniform_list, AppContext, Bounds, Div, actions, canvas, div, prelude::FluentBuilder, px, uniform_list, AppContext, Bounds, Div,
DragMoveEvent, Entity, EntityId, EventEmitter, FocusHandle, FocusableView, InteractiveElement, DragMoveEvent, Edges, Entity, EntityId, EventEmitter, FocusHandle, FocusableView,
IntoElement, KeyBinding, MouseButton, ParentElement, Pixels, Point, Render, ScrollHandle, InteractiveElement, IntoElement, KeyBinding, MouseButton, ParentElement, Pixels, Point, Render,
SharedString, StatefulInteractiveElement as _, Styled, UniformListScrollHandle, ViewContext, ScrollHandle, SharedString, StatefulInteractiveElement as _, Styled, UniformListScrollHandle,
VisualContext as _, WindowContext, ViewContext, VisualContext as _, WindowContext,
}; };
actions!( actions!(
@ -47,6 +47,7 @@ struct ColGroup {
bounds: Bounds<Pixels>, bounds: Bounds<Pixels>,
sort: Option<ColSort>, sort: Option<ColSort>,
fixed: Option<ColFixed>, fixed: Option<ColFixed>,
padding: Option<Edges<Pixels>>,
} }
#[derive(Clone)] #[derive(Clone)]
@ -169,6 +170,13 @@ pub trait TableDelegate: Sized + 'static {
None None
} }
/// 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) -> Option<Edges<Pixels>> {
None
}
/// Perform sort on the column at the given index. /// Perform sort on the column at the given index.
fn perform_sort(&mut self, col_ix: usize, sort: ColSort, cx: &mut ViewContext<Table<Self>>) {} fn perform_sort(&mut self, col_ix: usize, sort: ColSort, cx: &mut ViewContext<Table<Self>>) {}
@ -302,16 +310,6 @@ where
cx.notify(); cx.notify();
} }
/// Return the height of the table head.
fn table_head_height(&self) -> Pixels {
match self.size {
Size::Large => px(48.),
Size::Small => px(30.),
Size::XSmall => px(26.),
_ => px(32.),
}
}
/// When we update columns or rows, we need to refresh the table. /// When we update columns or rows, we need to refresh the table.
pub fn refresh(&mut self, cx: &mut ViewContext<Self>) { pub fn refresh(&mut self, cx: &mut ViewContext<Self>) {
self.prepare_col_groups(cx); self.prepare_col_groups(cx);
@ -321,6 +319,7 @@ where
self.col_groups = (0..self.delegate.cols_count()) self.col_groups = (0..self.delegate.cols_count())
.map(|col_ix| ColGroup { .map(|col_ix| ColGroup {
width: self.delegate.col_width(col_ix), width: self.delegate.col_width(col_ix),
padding: self.delegate.col_padding(col_ix),
bounds: Bounds::default(), bounds: Bounds::default(),
sort: self.delegate.col_sort(col_ix), sort: self.delegate.col_sort(col_ix),
fixed: self.delegate.col_fixed(col_ix), fixed: self.delegate.col_fixed(col_ix),
@ -560,29 +559,36 @@ where
fn render_cell(&self, col_ix: usize, _cx: &mut ViewContext<Self>) -> Div { fn render_cell(&self, col_ix: usize, _cx: &mut ViewContext<Self>) -> Div {
let col_width = self.col_groups[col_ix].width; let col_width = self.col_groups[col_ix].width;
let col_padding = self.col_groups[col_ix].padding;
div() div()
.when_some(col_width, |this, width| this.w(width)) .when_some(col_width, |this, width| this.w(width))
.h_full()
.flex_shrink_0() .flex_shrink_0()
.overflow_hidden() .overflow_hidden()
.whitespace_nowrap() .whitespace_nowrap()
.map(|this| match self.size { .table_cell_size(self.size)
Size::XSmall => this.text_sm().py_0p5().px_1(), .map(|this| match col_padding {
Size::Small => this.text_sm().py(px(3.)).px_1p5(), Some(padding) => this
Size::Large => this.py_2().px_3(), .pl(padding.left)
_ => this.py_1().px_2(), .pr(padding.right)
.pt(padding.top)
.pb(padding.bottom),
None => this,
}) })
} }
/// Show Column selection style, when the column is selected and the selection state is Column. /// Show Column selection style, when the column is selected and the selection state is Column.
fn render_col_wrap(&self, col_ix: usize, cx: &mut ViewContext<Self>) -> Div { fn render_col_wrap(&self, col_ix: usize, cx: &mut ViewContext<Self>) -> Div {
let el = h_flex().h_full();
if self.delegate().can_select_col(col_ix) if self.delegate().can_select_col(col_ix)
&& self.selected_col == Some(col_ix) && self.selected_col == Some(col_ix)
&& self.selection_state == SelectionState::Column && self.selection_state == SelectionState::Column
{ {
h_flex().bg(cx.theme().table_active) el.bg(cx.theme().table_active)
} else { } else {
h_flex() el
} }
} }
@ -592,7 +598,7 @@ where
Some( Some(
div() div()
.absolute() .absolute()
.top(self.table_head_height()) .top(self.size.table_row_height())
.left_0() .left_0()
.right_0() .right_0()
.bottom_0() .bottom_0()
@ -765,6 +771,13 @@ where
.justify_between() .justify_between()
.items_center() .items_center()
.child(self.delegate.render_th(col_ix, cx)) .child(self.delegate.render_th(col_ix, cx))
.when_some(self.delegate().col_padding(col_ix), |this, padding| {
// Leave right space for the sort icon, if this column have custom padding
let offset_pr =
self.size.table_cell_padding().right - padding.right;
this.pr(offset_pr.max(px(0.)))
})
.children(self.render_sort_icon(col_ix, cx)), .children(self.render_sort_icon(col_ix, cx)),
) )
.when(self.delegate.can_move_col(col_ix), |this| { .when(self.delegate.can_move_col(col_ix), |this| {
@ -827,7 +840,7 @@ where
h_flex() h_flex()
.w_full() .w_full()
.h(self.table_head_height()) .h(self.size.table_row_height())
.flex_shrink_0() .flex_shrink_0()
.border_b_1() .border_b_1()
.border_color(cx.theme().border) .border_color(cx.theme().border)
@ -908,12 +921,7 @@ where
.map(|this| vec![this]) .map(|this| vec![this])
} }
}) })
.map(|this| match self.size { .h(self.size.table_row_height())
Size::Large => this.h_10(),
Size::Small => this.h(px(30.)),
Size::XSmall => this.h(px(26.)),
_ => this.h_8(),
})
.h_full() .h_full()
.flex_1(), .flex_1(),
) )
@ -936,6 +944,7 @@ where
.render_tr(row_ix, cx) .render_tr(row_ix, cx)
.id(("table-row", row_ix)) .id(("table-row", row_ix))
.w_full() .w_full()
.h(self.size.table_row_height())
.when(row_ix > 0, |this| { .when(row_ix > 0, |this| {
this.border_t_1().border_color(cx.theme().table_row_border) this.border_t_1().border_color(cx.theme().table_row_border)
}) })
@ -951,6 +960,7 @@ where
// Left fixed columns // Left fixed columns
Some( Some(
h_flex() h_flex()
.h_full()
.border_r_1() .border_r_1()
.border_color(cx.theme().table_row_border) .border_color(cx.theme().table_row_border)
.children((0..left_cols_count).map(|col_ix| { .children((0..left_cols_count).map(|col_ix| {
@ -966,6 +976,7 @@ where
.child( .child(
h_flex() h_flex()
.flex_1() .flex_1()
.h_full()
.overflow_hidden() .overflow_hidden()
.children((left_cols_count..cols_count).map(|col_ix| { .children((left_cols_count..cols_count).map(|col_ix| {
self self