gpui_component/table/delegate.rs
1use std::ops::Range;
2
3use gpui::{
4 App, Context, Div, InteractiveElement as _, IntoElement, ParentElement as _, Pixels,
5 SharedString, Stateful, Styled as _, Window, div,
6};
7
8use crate::{
9 ActiveTheme as _, Icon, IconName, Size, h_flex,
10 menu::PopupMenu,
11 table::{Column, ColumnGroup, ColumnSort, TableState, loading::Loading},
12};
13
14/// A delegate trait for providing data and rendering for a table.
15#[allow(unused)]
16pub trait TableDelegate: Sized + 'static {
17 /// Return the number of columns in the table.
18 fn columns_count(&self, cx: &App) -> usize;
19
20 /// Return the number of rows in the table.
21 fn rows_count(&self, cx: &App) -> usize;
22
23 /// Returns the table column at the given index.
24 ///
25 /// This only call on Table prepare or refresh.
26 fn column(&self, col_ix: usize, cx: &App) -> Column;
27
28 /// Perform sort on the column at the given index.
29 fn perform_sort(
30 &mut self,
31 col_ix: usize,
32 sort: ColumnSort,
33 window: &mut Window,
34 cx: &mut Context<TableState<Self>>,
35 ) {
36 }
37
38 /// Render the table head row.
39 fn render_header(
40 &mut self,
41 window: &mut Window,
42 cx: &mut Context<TableState<Self>>,
43 ) -> Stateful<Div> {
44 div().id("header")
45 }
46
47 /// Return the group headers definitions (can be multi-level).
48 ///
49 /// By default, it returns None, meaning no group headers.
50 fn group_headers(&self, cx: &App) -> Option<Vec<Vec<ColumnGroup>>> {
51 None
52 }
53
54 /// Custom render for a group header cell.
55 /// Receives the group label, the logical col_span, and the pixel width.
56 fn render_group_th(
57 &mut self,
58 label: &SharedString,
59 _col_span: usize,
60 width: Pixels,
61 _window: &mut Window,
62 cx: &mut Context<TableState<Self>>,
63 ) -> impl IntoElement {
64 div()
65 .w(width)
66 .h_full()
67 .flex_shrink_0()
68 .flex()
69 .items_center()
70 .justify_center()
71 .border_r_1()
72 .border_color(cx.theme().border)
73 .child(label.clone())
74 }
75
76 /// Render the header cell at the given column index, default to the column name.
77 fn render_th(
78 &mut self,
79 col_ix: usize,
80 window: &mut Window,
81 cx: &mut Context<TableState<Self>>,
82 ) -> impl IntoElement {
83 div()
84 .size_full()
85 .child(self.column(col_ix, cx).name.clone())
86 }
87
88 /// Render the row at the given row and column.
89 ///
90 /// Not include the table head row.
91 fn render_tr(
92 &mut self,
93 row_ix: usize,
94 window: &mut Window,
95 cx: &mut Context<TableState<Self>>,
96 ) -> Stateful<Div> {
97 div().id(("row", row_ix))
98 }
99
100 /// Render the context menu for the row at the given row index.
101 fn context_menu(
102 &mut self,
103 row_ix: usize,
104 menu: PopupMenu,
105 window: &mut Window,
106 cx: &mut Context<TableState<Self>>,
107 ) -> PopupMenu {
108 menu
109 }
110
111 /// Render cell at the given row and column.
112 fn render_td(
113 &mut self,
114 row_ix: usize,
115 col_ix: usize,
116 window: &mut Window,
117 cx: &mut Context<TableState<Self>>,
118 ) -> impl IntoElement;
119
120 /// Move the column at the given `col_ix` so that it ends up at the index `to_ix`.
121 ///
122 /// e.g.: `let col = self.columns.remove(col_ix); self.columns.insert(to_ix, col);`
123 fn move_column(
124 &mut self,
125 col_ix: usize,
126 to_ix: usize,
127 window: &mut Window,
128 cx: &mut Context<TableState<Self>>,
129 ) {
130 }
131
132 /// Return a Element to show when table is empty.
133 fn render_empty(
134 &mut self,
135 window: &mut Window,
136 cx: &mut Context<TableState<Self>>,
137 ) -> impl IntoElement {
138 h_flex()
139 .size_full()
140 .justify_center()
141 .text_color(cx.theme().muted_foreground.opacity(0.6))
142 .child(Icon::new(IconName::Inbox).size_12())
143 .into_any_element()
144 }
145
146 /// Return true to show the loading view.
147 fn loading(&self, cx: &App) -> bool {
148 false
149 }
150
151 /// Return a Element to show when table is loading, default is built-in Skeleton loading view.
152 ///
153 /// The size is the size of the Table.
154 fn render_loading(
155 &mut self,
156 size: Size,
157 window: &mut Window,
158 cx: &mut Context<TableState<Self>>,
159 ) -> impl IntoElement {
160 Loading::new().size(size)
161 }
162
163 /// Return true to enable load more data when scrolling to the bottom.
164 ///
165 /// Default: false
166 fn has_more(&self, cx: &App) -> bool {
167 false
168 }
169
170 /// Returns a threshold value (n rows), of course, when scrolling to the bottom,
171 /// the remaining number of rows triggers `load_more`.
172 /// This should smaller than the total number of first load rows.
173 ///
174 /// Default: 20 rows
175 fn load_more_threshold(&self) -> usize {
176 20
177 }
178
179 /// Load more data when the table is scrolled to the bottom.
180 ///
181 /// This will performed in a background task.
182 ///
183 /// This is always called when the table is near the bottom,
184 /// so you must check if there is more data to load or lock the loading state.
185 fn load_more(&mut self, window: &mut Window, cx: &mut Context<TableState<Self>>) {}
186
187 /// Render the last empty column, default to empty.
188 fn render_last_empty_col(
189 &mut self,
190 window: &mut Window,
191 cx: &mut Context<TableState<Self>>,
192 ) -> impl IntoElement {
193 h_flex().w_3().h_full().flex_shrink_0()
194 }
195
196 /// Called when the visible range of the rows changed.
197 ///
198 /// NOTE: Make sure this method is fast, because it will be called frequently.
199 ///
200 /// This can used to handle some data update, to only update the visible rows.
201 /// Please ensure that the data is updated in the background task.
202 fn visible_rows_changed(
203 &mut self,
204 visible_range: Range<usize>,
205 window: &mut Window,
206 cx: &mut Context<TableState<Self>>,
207 ) {
208 }
209
210 /// Called when the visible range of the columns changed.
211 ///
212 /// NOTE: Make sure this method is fast, because it will be called frequently.
213 ///
214 /// This can used to handle some data update, to only update the visible rows.
215 /// Please ensure that the data is updated in the background task.
216 fn visible_columns_changed(
217 &mut self,
218 visible_range: Range<usize>,
219 window: &mut Window,
220 cx: &mut Context<TableState<Self>>,
221 ) {
222 }
223
224 /// Get the text representation of a cell for export purposes (e.g., CSV export).
225 ///
226 /// Returns an empty string by default. Implement this method to support export.
227 /// The text should be formatted as it should appear in the exported data.
228 fn cell_text(&self, row_ix: usize, col_ix: usize, cx: &App) -> String {
229 String::new()
230 }
231}