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 gpui::{
div, impl_actions, AnyElement, InteractiveElement, IntoElement, ParentElement, Pixels, Render,
SharedString, Styled, Timer, View, ViewContext, VisualContext as _, WindowContext,
div, impl_actions, px, AnyElement, Edges, InteractiveElement, IntoElement, ParentElement,
Pixels, Render, SharedString, Styled, Timer, View, ViewContext, VisualContext as _,
WindowContext,
};
use serde::Deserialize;
use ui::{
@ -16,7 +17,7 @@ use ui::{
popup_menu::PopupMenuExt,
prelude::FluentBuilder as _,
table::{ColFixed, ColSort, Table, TableDelegate, TableEvent},
v_flex, Selectable, Size,
v_flex, Selectable, Size, StyleSized as _,
};
#[derive(Clone, PartialEq, Eq, Deserialize)]
@ -167,6 +168,7 @@ impl Column {
struct StockTableDelegate {
stocks: Vec<Stock>,
columns: Vec<Column>,
size: Size,
loop_selection: bool,
col_resize: bool,
col_order: bool,
@ -180,6 +182,7 @@ struct StockTableDelegate {
impl StockTableDelegate {
fn new(size: usize) -> Self {
Self {
size: Size::default(),
stocks: random_stocks(size),
columns: vec![
Column::new("id", "ID", None),
@ -253,7 +256,10 @@ impl StockTableDelegate {
}
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
// 30% to red, 30% to green, others to default
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> {
if !self.fixed_cols {
return None;
@ -316,6 +330,16 @@ impl TableDelegate for StockTableDelegate {
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(
&self,
row_ix: usize,
@ -617,6 +641,7 @@ impl TableStory {
self.size = a.0;
self.table.update(cx, |table, cx| {
table.set_size(a.0, cx);
table.delegate_mut().size = a.0;
});
}

View file

@ -5,7 +5,8 @@ use crate::{
theme::ActiveTheme,
};
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};
@ -146,6 +147,47 @@ pub enum Size {
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 {
fn from(size: Pixels) -> Self {
Size::Size(size)
@ -203,6 +245,8 @@ pub trait StyleSized<T: Styled> {
fn list_py(self, size: Size) -> Self;
/// Apply size with the given `Size`.
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 {
@ -290,6 +334,19 @@ impl<T: Styled> StyleSized<T> for T {
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 {

View file

@ -4,14 +4,14 @@ use crate::{
h_flex,
scroll::{ScrollableAxis, ScrollableMask, Scrollbar, ScrollbarState},
theme::ActiveTheme,
v_flex, Icon, IconName, Sizable, Size,
v_flex, Icon, IconName, Sizable, Size, StyleSized as _,
};
use gpui::{
actions, canvas, div, prelude::FluentBuilder, px, uniform_list, AppContext, Bounds, Div,
DragMoveEvent, Entity, EntityId, EventEmitter, FocusHandle, FocusableView, InteractiveElement,
IntoElement, KeyBinding, MouseButton, ParentElement, Pixels, Point, Render, ScrollHandle,
SharedString, StatefulInteractiveElement as _, Styled, UniformListScrollHandle, ViewContext,
VisualContext as _, WindowContext,
DragMoveEvent, Edges, Entity, EntityId, EventEmitter, FocusHandle, FocusableView,
InteractiveElement, IntoElement, KeyBinding, MouseButton, ParentElement, Pixels, Point, Render,
ScrollHandle, SharedString, StatefulInteractiveElement as _, Styled, UniformListScrollHandle,
ViewContext, VisualContext as _, WindowContext,
};
actions!(
@ -47,6 +47,7 @@ struct ColGroup {
bounds: Bounds<Pixels>,
sort: Option<ColSort>,
fixed: Option<ColFixed>,
padding: Option<Edges<Pixels>>,
}
#[derive(Clone)]
@ -169,6 +170,13 @@ pub trait TableDelegate: Sized + 'static {
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.
fn perform_sort(&mut self, col_ix: usize, sort: ColSort, cx: &mut ViewContext<Table<Self>>) {}
@ -302,16 +310,6 @@ where
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.
pub fn refresh(&mut self, cx: &mut ViewContext<Self>) {
self.prepare_col_groups(cx);
@ -321,6 +319,7 @@ where
self.col_groups = (0..self.delegate.cols_count())
.map(|col_ix| ColGroup {
width: self.delegate.col_width(col_ix),
padding: self.delegate.col_padding(col_ix),
bounds: Bounds::default(),
sort: self.delegate.col_sort(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 {
let col_width = self.col_groups[col_ix].width;
let col_padding = self.col_groups[col_ix].padding;
div()
.when_some(col_width, |this, width| this.w(width))
.h_full()
.flex_shrink_0()
.overflow_hidden()
.whitespace_nowrap()
.map(|this| match self.size {
Size::XSmall => this.text_sm().py_0p5().px_1(),
Size::Small => this.text_sm().py(px(3.)).px_1p5(),
Size::Large => this.py_2().px_3(),
_ => this.py_1().px_2(),
.table_cell_size(self.size)
.map(|this| match col_padding {
Some(padding) => this
.pl(padding.left)
.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.
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)
&& self.selected_col == Some(col_ix)
&& self.selection_state == SelectionState::Column
{
h_flex().bg(cx.theme().table_active)
el.bg(cx.theme().table_active)
} else {
h_flex()
el
}
}
@ -592,7 +598,7 @@ where
Some(
div()
.absolute()
.top(self.table_head_height())
.top(self.size.table_row_height())
.left_0()
.right_0()
.bottom_0()
@ -765,6 +771,13 @@ where
.justify_between()
.items_center()
.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)),
)
.when(self.delegate.can_move_col(col_ix), |this| {
@ -827,7 +840,7 @@ where
h_flex()
.w_full()
.h(self.table_head_height())
.h(self.size.table_row_height())
.flex_shrink_0()
.border_b_1()
.border_color(cx.theme().border)
@ -908,12 +921,7 @@ where
.map(|this| vec![this])
}
})
.map(|this| match self.size {
Size::Large => this.h_10(),
Size::Small => this.h(px(30.)),
Size::XSmall => this.h(px(26.)),
_ => this.h_8(),
})
.h(self.size.table_row_height())
.h_full()
.flex_1(),
)
@ -936,6 +944,7 @@ where
.render_tr(row_ix, cx)
.id(("table-row", row_ix))
.w_full()
.h(self.size.table_row_height())
.when(row_ix > 0, |this| {
this.border_t_1().border_color(cx.theme().table_row_border)
})
@ -951,6 +960,7 @@ where
// Left fixed columns
Some(
h_flex()
.h_full()
.border_r_1()
.border_color(cx.theme().table_row_border)
.children((0..left_cols_count).map(|col_ix| {
@ -966,6 +976,7 @@ where
.child(
h_flex()
.flex_1()
.h_full()
.overflow_hidden()
.children((left_cols_count..cols_count).map(|col_ix| {
self