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:
parent
fd09229541
commit
2198134832
3 changed files with 128 additions and 35 deletions
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue