gpui_component/table/
mod.rs

1use crate::{
2    actions::{Cancel, SelectDown, SelectUp},
3    ActiveTheme, Sizable, Size,
4};
5use gpui::{
6    actions, div, prelude::FluentBuilder, App, Edges, Entity, Focusable, InteractiveElement,
7    IntoElement, KeyBinding, ParentElement, RenderOnce, Styled, Window,
8};
9
10mod column;
11mod delegate;
12mod loading;
13mod state;
14
15pub use column::*;
16pub use delegate::*;
17pub use state::*;
18
19actions!(table, [SelectPrevColumn, SelectNextColumn]);
20
21const CONTEXT: &'static str = "Table";
22pub(crate) fn init(cx: &mut App) {
23    cx.bind_keys([
24        KeyBinding::new("escape", Cancel, Some(CONTEXT)),
25        KeyBinding::new("up", SelectUp, Some(CONTEXT)),
26        KeyBinding::new("down", SelectDown, Some(CONTEXT)),
27        KeyBinding::new("left", SelectPrevColumn, Some(CONTEXT)),
28        KeyBinding::new("right", SelectNextColumn, Some(CONTEXT)),
29    ]);
30}
31
32struct TableOptions {
33    scrollbar_visible: Edges<bool>,
34    /// Set stripe style of the table.
35    stripe: bool,
36    /// Set to use border style of the table.
37    bordered: bool,
38    /// The cell size of the table.
39    size: Size,
40}
41
42impl Default for TableOptions {
43    fn default() -> Self {
44        Self {
45            scrollbar_visible: Edges::all(true),
46            stripe: false,
47            bordered: true,
48            size: Size::default(),
49        }
50    }
51}
52
53/// A table element.
54#[derive(IntoElement)]
55pub struct Table<D: TableDelegate> {
56    state: Entity<TableState<D>>,
57    options: TableOptions,
58}
59
60impl<D> Table<D>
61where
62    D: TableDelegate,
63{
64    /// Create a new Table element with the given [`TableState`].
65    pub fn new(state: &Entity<TableState<D>>) -> Self {
66        Self {
67            state: state.clone(),
68            options: TableOptions::default(),
69        }
70    }
71
72    /// Set to use stripe style of the table, default to false.
73    pub fn stripe(mut self, stripe: bool) -> Self {
74        self.options.stripe = stripe;
75        self
76    }
77
78    /// Set to use border style of the table, default to true.
79    pub fn bordered(mut self, bordered: bool) -> Self {
80        self.options.bordered = bordered;
81        self
82    }
83
84    /// Set scrollbar visibility.
85    pub fn scrollbar_visible(mut self, vertical: bool, horizontal: bool) -> Self {
86        self.options.scrollbar_visible = Edges {
87            right: vertical,
88            bottom: horizontal,
89            ..Default::default()
90        };
91        self
92    }
93}
94
95impl<D> Sizable for Table<D>
96where
97    D: TableDelegate,
98{
99    fn with_size(mut self, size: impl Into<Size>) -> Self {
100        self.options.size = size.into();
101        self
102    }
103}
104
105impl<D> RenderOnce for Table<D>
106where
107    D: TableDelegate,
108{
109    fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
110        let bordered = self.options.bordered;
111        let focus_handle = self.state.focus_handle(cx);
112        self.state.update(cx, |state, _| {
113            state.options = self.options;
114        });
115
116        div()
117            .id("table")
118            .size_full()
119            .key_context(CONTEXT)
120            .track_focus(&focus_handle)
121            .on_action(window.listener_for(&self.state, TableState::action_cancel))
122            .on_action(window.listener_for(&self.state, TableState::action_select_next))
123            .on_action(window.listener_for(&self.state, TableState::action_select_prev))
124            .on_action(window.listener_for(&self.state, TableState::action_select_next_col))
125            .on_action(window.listener_for(&self.state, TableState::action_select_prev_col))
126            .bg(cx.theme().table)
127            .when(bordered, |this| {
128                this.rounded(cx.theme().radius)
129                    .border_1()
130                    .border_color(cx.theme().border)
131            })
132            .child(self.state)
133    }
134}