1use std::rc::Rc;
12
13use gpui::{App, IntoElement, RenderOnce, SharedString, Window};
14
15use crate::data::grid::{DataGrid, GridRow, HierarchyRow};
16use crate::data::{Cell, GridColumn, GridLines, SelectionChange, SelectionMode};
17use crate::display::empty::{EmptyKind, EmptyState};
18use crate::foundation::{Disableable, Ident};
19
20type RenderRow = Rc<dyn Fn(usize, &mut Window, &mut App) -> TreeGridRow>;
21type SelectHandler = Rc<dyn Fn(SharedString, &mut Window, &mut App)>;
22type ExpandHandler = Rc<dyn Fn(SharedString, bool, &mut Window, &mut App)>;
23
24#[derive(Debug)]
26pub struct TreeGridRow {
27 row: GridRow,
28 level: u32,
29 has_children: bool,
30 expanded: bool,
31 parent: Option<SharedString>,
32}
33
34impl TreeGridRow {
35 pub fn new(id: impl Into<SharedString>, level: u32) -> Self {
36 Self {
37 row: GridRow::new(id),
38 level: level.max(1),
39 has_children: false,
40 expanded: false,
41 parent: None,
42 }
43 }
44
45 pub fn text(mut self, text: impl Into<SharedString>) -> Self {
46 self.row = self.row.text(text);
47 self
48 }
49
50 pub fn cell(mut self, key: impl Into<SharedString>, cell: impl Into<Cell>) -> Self {
51 self.row = self.row.cell(key, cell);
52 self
53 }
54
55 pub fn branch(mut self, expanded: bool) -> Self {
56 self.has_children = true;
57 self.expanded = expanded;
58 self
59 }
60
61 pub fn parent(mut self, id: impl Into<SharedString>) -> Self {
63 self.parent = Some(id.into());
64 self
65 }
66
67 pub fn disabled(mut self, disabled: bool) -> Self {
68 self.row = self.row.disabled(disabled);
69 self
70 }
71
72 fn into_grid_row(self) -> GridRow {
73 self.row.hierarchy(HierarchyRow {
74 level: self.level,
75 has_children: self.has_children,
76 expanded: self.expanded,
77 parent: self.parent,
78 })
79 }
80}
81
82#[derive(IntoElement)]
84pub struct TreeGrid {
85 ident: Ident,
86 count: usize,
87 render_row: RenderRow,
88 columns: Vec<GridColumn>,
89 selected: Option<SharedString>,
90 visible_rows: Option<usize>,
91 row_height: Option<f32>,
92 lines: GridLines,
93 loading: bool,
94 failure: Option<SharedString>,
95 vacancy: Option<EmptyState>,
96 disabled: bool,
97 on_select: Option<SelectHandler>,
98 on_expand: Option<ExpandHandler>,
99}
100
101impl std::fmt::Debug for TreeGrid {
102 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103 f.debug_struct("TreeGrid")
104 .field("ident", &self.ident)
105 .field("count", &self.count)
106 .field("columns", &self.columns.len())
107 .field("disabled", &self.disabled)
108 .finish()
109 }
110}
111
112impl TreeGrid {
113 pub fn new(
114 ident: impl Into<Ident>,
115 visible_row_count: usize,
116 render_row: impl Fn(usize, &mut Window, &mut App) -> TreeGridRow + 'static,
117 ) -> Self {
118 Self {
119 ident: ident.into(),
120 count: visible_row_count,
121 render_row: Rc::new(render_row),
122 columns: vec![],
123 selected: None,
124 visible_rows: None,
125 row_height: None,
126 lines: GridLines::None,
127 loading: false,
128 failure: None,
129 vacancy: None,
130 disabled: false,
131 on_select: None,
132 on_expand: None,
133 }
134 }
135
136 pub fn column(mut self, column: GridColumn) -> Self {
137 self.columns.push(column);
138 self
139 }
140 pub fn columns(mut self, columns: impl IntoIterator<Item = GridColumn>) -> Self {
141 self.columns.extend(columns);
142 self
143 }
144 pub fn selected(mut self, id: impl Into<SharedString>) -> Self {
145 self.selected = Some(id.into());
146 self
147 }
148 pub fn visible_rows(mut self, rows: usize) -> Self {
149 self.visible_rows = Some(rows);
150 self
151 }
152 pub fn row_height(mut self, height: f32) -> Self {
153 self.row_height = Some(height);
154 self
155 }
156 pub fn lines(mut self, lines: GridLines) -> Self {
157 self.lines = lines;
158 self
159 }
160 pub fn loading(mut self, loading: bool) -> Self {
161 self.loading = loading;
162 self
163 }
164 pub fn failure(mut self, detail: impl Into<SharedString>) -> Self {
165 self.failure = Some(detail.into());
166 self
167 }
168 pub fn empty(mut self, state: EmptyState) -> Self {
169 self.vacancy = Some(state);
170 self
171 }
172 pub fn unavailable(mut self, title: impl Into<SharedString>) -> Self {
173 self.vacancy = Some(
174 EmptyState::new(self.ident.child("unavailable"), title).kind(EmptyKind::Unavailable),
175 );
176 self
177 }
178 pub fn on_select(
179 mut self,
180 handler: impl Fn(SharedString, &mut Window, &mut App) + 'static,
181 ) -> Self {
182 self.on_select = Some(Rc::new(handler));
183 self
184 }
185 pub fn on_expand(
186 mut self,
187 handler: impl Fn(SharedString, bool, &mut Window, &mut App) + 'static,
188 ) -> Self {
189 self.on_expand = Some(Rc::new(handler));
190 self
191 }
192}
193
194impl Disableable for TreeGrid {
195 fn disabled(mut self, disabled: bool) -> Self {
196 self.disabled = disabled;
197 self
198 }
199}
200
201impl RenderOnce for TreeGrid {
202 fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
203 let render = self.render_row;
204 let mut grid = DataGrid::new(self.ident, self.count, move |index, window, cx| {
205 render(index, window, cx).into_grid_row()
206 })
207 .columns(self.columns)
208 .lines(self.lines)
209 .selection_mode(SelectionMode::Single)
210 .selected(self.selected)
211 .loading(self.loading)
212 .hierarchy_mode()
213 .disabled(self.disabled);
214 if let Some(rows) = self.visible_rows {
215 grid = grid.visible_rows(rows);
216 }
217 if let Some(height) = self.row_height {
218 grid = grid.row_height(height);
219 }
220 if let Some(failure) = self.failure {
221 grid = grid.failure(failure);
222 }
223 if let Some(empty) = self.vacancy {
224 grid = grid.empty(empty);
225 }
226 if let Some(handler) = self.on_select {
227 grid = grid.on_select(move |change, window, cx| {
228 if let SelectionChange::Replace(id) = change {
229 handler(id.clone(), window, cx);
230 }
231 });
232 }
233 if let Some(handler) = self.on_expand {
234 grid = grid.on_expand(move |id, open, window, cx| handler(id, open, window, cx));
235 }
236 grid
237 }
238}