gpui_component/table/
column.rs

1use gpui::{
2    div, prelude::FluentBuilder, px, Bounds, Context, Edges, Empty, EntityId, IntoElement,
3    ParentElement as _, Pixels, Render, SharedString, Styled as _, TextAlign, Window,
4};
5
6use crate::ActiveTheme as _;
7
8/// Represents a column in a table, used for initializing table columns.
9#[derive(Debug, Clone)]
10pub struct Column {
11    /// The unique key of the column.
12    ///
13    /// This is used to identify the column in the table and your data source.
14    ///
15    /// In most cases, it should match the field name in your data source.
16    pub key: SharedString,
17    /// The display name of the column.
18    pub name: SharedString,
19    /// The text alignment of the column.
20    pub align: TextAlign,
21    /// The sorting behavior of the column, if any.
22    ///
23    /// If `None`, the column is not sortable.
24    pub sort: Option<ColumnSort>,
25    /// The padding of the column.
26    pub paddings: Option<Edges<Pixels>>,
27    /// The width of the column.
28    pub width: Pixels,
29    /// Whether the column is fixed, the fixed column will pin at the left side when scrolling horizontally.
30    pub fixed: Option<ColumnFixed>,
31    /// Whether the column is resizable.
32    pub resizable: bool,
33    /// Whether the column is movable.
34    pub movable: bool,
35    /// Whether the column is selectable, if true this column's cells can be selected in column selection mode.
36    pub selectable: bool,
37}
38
39impl Default for Column {
40    fn default() -> Self {
41        Self {
42            key: SharedString::new(""),
43            name: SharedString::new(""),
44            align: TextAlign::Left,
45            sort: None,
46            paddings: None,
47            width: px(100.),
48            fixed: None,
49            resizable: true,
50            movable: true,
51            selectable: true,
52        }
53    }
54}
55
56impl Column {
57    /// Create a new column with the given key and name.
58    pub fn new(key: impl Into<SharedString>, name: impl Into<SharedString>) -> Self {
59        Self {
60            key: key.into(),
61            name: name.into(),
62            ..Default::default()
63        }
64    }
65
66    /// Set the column to be sortable with custom sort function, default is None (not sortable).
67    ///
68    /// See also [`Column::sortable`] to enable sorting with default.
69    pub fn sort(mut self, sort: ColumnSort) -> Self {
70        self.sort = Some(sort);
71        self
72    }
73
74    /// Set whether the column is sortable, default is true.
75    ///
76    /// See also [`Column::sort`].
77    pub fn sortable(mut self) -> Self {
78        self.sort = Some(ColumnSort::Default);
79        self
80    }
81
82    /// Set whether the column is sort with ascending order.
83    pub fn ascending(mut self) -> Self {
84        self.sort = Some(ColumnSort::Ascending);
85        self
86    }
87
88    /// Set whether the column is sort with descending order.
89    pub fn descending(mut self) -> Self {
90        self.sort = Some(ColumnSort::Descending);
91        self
92    }
93
94    /// Set the alignment of the column text, default is left.
95    ///
96    /// Only `text_left`, `text_right` is supported.
97    pub fn text_right(mut self) -> Self {
98        self.align = TextAlign::Right;
99        self
100    }
101
102    /// Set the padding of the column, default is None.
103    pub fn paddings(mut self, paddings: impl Into<Edges<Pixels>>) -> Self {
104        self.paddings = Some(paddings.into());
105        self
106    }
107
108    /// Set the padding of the column to 0px.
109    pub fn p_0(mut self) -> Self {
110        self.paddings = Some(Edges::all(px(0.)));
111        self
112    }
113
114    /// Set the width of the column, default is 100px.
115    pub fn width(mut self, width: impl Into<Pixels>) -> Self {
116        self.width = width.into();
117        self
118    }
119
120    /// Set whether the column is fixed, default is false.
121    pub fn fixed(mut self, fixed: impl Into<ColumnFixed>) -> Self {
122        self.fixed = Some(fixed.into());
123        self
124    }
125
126    /// Set whether the column is fixed on left side, default is false.
127    pub fn fixed_left(mut self) -> Self {
128        self.fixed = Some(ColumnFixed::Left);
129        self
130    }
131
132    /// Set whether the column is resizable, default is true.
133    pub fn resizable(mut self, resizable: bool) -> Self {
134        self.resizable = resizable;
135        self
136    }
137
138    /// Set whether the column is movable, default is true.
139    pub fn movable(mut self, movable: bool) -> Self {
140        self.movable = movable;
141        self
142    }
143
144    /// Set whether the column is selectable, default is true.
145    pub fn selectable(mut self, selectable: bool) -> Self {
146        self.selectable = selectable;
147        self
148    }
149}
150
151impl FluentBuilder for Column {}
152
153#[derive(Debug, Clone, Copy, PartialEq, Eq)]
154pub enum ColumnFixed {
155    Left,
156}
157
158/// Used to sort the column runtime info in Table internal.
159#[derive(Debug, Clone)]
160pub(crate) struct ColGroup {
161    pub(crate) column: Column,
162    /// This is the runtime width of the column, we may update it when the column is resized.
163    ///
164    /// Including the width with next columns by col_span.
165    pub(crate) width: Pixels,
166    /// The bounds of the column in the table after it renders.
167    pub(crate) bounds: Bounds<Pixels>,
168}
169
170impl ColGroup {
171    pub(crate) fn is_resizable(&self) -> bool {
172        self.column.resizable
173    }
174}
175
176#[derive(Clone)]
177pub(crate) struct DragColumn {
178    pub(crate) entity_id: EntityId,
179    pub(crate) name: SharedString,
180    pub(crate) width: Pixels,
181    pub(crate) col_ix: usize,
182}
183
184/// The sorting behavior of a column.
185#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
186pub enum ColumnSort {
187    /// No sorting.
188    #[default]
189    Default,
190    /// Sort in ascending order.
191    Ascending,
192    /// Sort in descending order.
193    Descending,
194}
195
196impl Render for DragColumn {
197    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
198        div()
199            .px_4()
200            .py_1()
201            .bg(cx.theme().table_head)
202            .text_color(cx.theme().muted_foreground)
203            .opacity(0.9)
204            .border_1()
205            .border_color(cx.theme().border)
206            .shadow_md()
207            .w(self.width)
208            .min_w(px(100.))
209            .max_w(px(450.))
210            .child(self.name.clone())
211    }
212}
213
214#[derive(Clone)]
215pub(crate) struct ResizeColumn(pub (EntityId, usize));
216impl Render for ResizeColumn {
217    fn render(&mut self, _window: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
218        Empty
219    }
220}