gpui_component/table/
mod.rs1use 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 stripe: bool,
36 bordered: bool,
38 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#[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 pub fn new(state: &Entity<TableState<D>>) -> Self {
66 Self {
67 state: state.clone(),
68 options: TableOptions::default(),
69 }
70 }
71
72 pub fn stripe(mut self, stripe: bool) -> Self {
74 self.options.stripe = stripe;
75 self
76 }
77
78 pub fn bordered(mut self, bordered: bool) -> Self {
80 self.options.bordered = bordered;
81 self
82 }
83
84 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}