1use crate::{
2 ActiveTheme, Sizable, Size,
3 actions::{
4 Cancel, SelectDown, SelectFirst, SelectLast, SelectNextColumn, SelectPageDown,
5 SelectPageUp, SelectPrevColumn, SelectUp,
6 },
7 table::{TableDelegate, TableState},
8};
9use gpui::{
10 App, Edges, Entity, Focusable, InteractiveElement, IntoElement, KeyBinding, ParentElement,
11 RenderOnce, Styled, Window, div, prelude::FluentBuilder,
12};
13
14const CONTEXT: &'static str = "DataTable";
15pub(super) fn init(cx: &mut App) {
16 cx.bind_keys([
17 KeyBinding::new("escape", Cancel, Some(CONTEXT)),
18 KeyBinding::new("up", SelectUp, Some(CONTEXT)),
19 KeyBinding::new("down", SelectDown, Some(CONTEXT)),
20 KeyBinding::new("left", SelectPrevColumn, Some(CONTEXT)),
21 KeyBinding::new("right", SelectNextColumn, Some(CONTEXT)),
22 KeyBinding::new("home", SelectFirst, Some(CONTEXT)),
23 KeyBinding::new("end", SelectLast, Some(CONTEXT)),
24 KeyBinding::new("pageup", SelectPageUp, Some(CONTEXT)),
25 KeyBinding::new("pagedown", SelectPageDown, Some(CONTEXT)),
26 KeyBinding::new("tab", SelectNextColumn, Some(CONTEXT)),
27 KeyBinding::new("shift-tab", SelectPrevColumn, Some(CONTEXT)),
28 ]);
29}
30
31pub(super) struct TableOptions {
32 pub(super) scrollbar_visible: Edges<bool>,
33 pub(super) stripe: bool,
35 pub(super) bordered: bool,
37 pub(super) size: Size,
39}
40
41impl Default for TableOptions {
42 fn default() -> Self {
43 Self {
44 scrollbar_visible: Edges::all(true),
45 stripe: false,
46 bordered: true,
47 size: Size::default(),
48 }
49 }
50}
51
52#[derive(IntoElement)]
90pub struct DataTable<D: TableDelegate> {
91 state: Entity<TableState<D>>,
92 options: TableOptions,
93}
94
95impl<D> DataTable<D>
96where
97 D: TableDelegate,
98{
99 pub fn new(state: &Entity<TableState<D>>) -> Self {
101 Self {
102 state: state.clone(),
103 options: TableOptions::default(),
104 }
105 }
106
107 pub fn stripe(mut self, stripe: bool) -> Self {
109 self.options.stripe = stripe;
110 self
111 }
112
113 pub fn bordered(mut self, bordered: bool) -> Self {
115 self.options.bordered = bordered;
116 self
117 }
118
119 pub fn scrollbar_visible(mut self, vertical: bool, horizontal: bool) -> Self {
121 self.options.scrollbar_visible = Edges {
122 right: vertical,
123 bottom: horizontal,
124 ..Default::default()
125 };
126 self
127 }
128}
129
130impl<D> Sizable for DataTable<D>
131where
132 D: TableDelegate,
133{
134 fn with_size(mut self, size: impl Into<Size>) -> Self {
135 self.options.size = size.into();
136 self
137 }
138}
139
140impl<D> RenderOnce for DataTable<D>
141where
142 D: TableDelegate,
143{
144 fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
145 let bordered = self.options.bordered;
146 let focus_handle = self.state.focus_handle(cx);
147 self.state.update(cx, |state, _| {
148 state.options = self.options;
149 });
150
151 div()
152 .id("table")
153 .size_full()
154 .key_context(CONTEXT)
155 .track_focus(&focus_handle)
156 .on_action(window.listener_for(&self.state, TableState::action_cancel))
157 .on_action(window.listener_for(&self.state, TableState::action_select_next))
158 .on_action(window.listener_for(&self.state, TableState::action_select_prev))
159 .on_action(window.listener_for(&self.state, TableState::action_select_next_col))
160 .on_action(window.listener_for(&self.state, TableState::action_select_prev_col))
161 .on_action(window.listener_for(&self.state, TableState::action_select_first_column))
162 .on_action(window.listener_for(&self.state, TableState::action_select_last_column))
163 .on_action(window.listener_for(&self.state, TableState::action_select_page_up))
164 .on_action(window.listener_for(&self.state, TableState::action_select_page_down))
165 .bg(cx.theme().tokens.table)
166 .when(bordered, |this| {
167 this.rounded(cx.theme().radius)
168 .border_1()
169 .border_color(cx.theme().border)
170 })
171 .child(self.state)
172 }
173}