use std::rc::Rc;
use gpui::{App, IntoElement, RenderOnce, SharedString, Window};
use crate::data::grid::{DataGrid, GridRow, HierarchyRow};
use crate::data::{Cell, GridColumn, GridLines, SelectionChange, SelectionMode};
use crate::display::empty::{EmptyKind, EmptyState};
use crate::foundation::{Disableable, Ident};
type RenderRow = Rc<dyn Fn(usize, &mut Window, &mut App) -> TreeGridRow>;
type SelectHandler = Rc<dyn Fn(SharedString, &mut Window, &mut App)>;
type ExpandHandler = Rc<dyn Fn(SharedString, bool, &mut Window, &mut App)>;
#[derive(Debug)]
pub struct TreeGridRow {
row: GridRow,
level: u32,
has_children: bool,
expanded: bool,
parent: Option<SharedString>,
}
impl TreeGridRow {
pub fn new(id: impl Into<SharedString>, level: u32) -> Self {
Self {
row: GridRow::new(id),
level: level.max(1),
has_children: false,
expanded: false,
parent: None,
}
}
pub fn text(mut self, text: impl Into<SharedString>) -> Self {
self.row = self.row.text(text);
self
}
pub fn cell(mut self, key: impl Into<SharedString>, cell: impl Into<Cell>) -> Self {
self.row = self.row.cell(key, cell);
self
}
pub fn branch(mut self, expanded: bool) -> Self {
self.has_children = true;
self.expanded = expanded;
self
}
pub fn parent(mut self, id: impl Into<SharedString>) -> Self {
self.parent = Some(id.into());
self
}
pub fn disabled(mut self, disabled: bool) -> Self {
self.row = self.row.disabled(disabled);
self
}
fn into_grid_row(self) -> GridRow {
self.row.hierarchy(HierarchyRow {
level: self.level,
has_children: self.has_children,
expanded: self.expanded,
parent: self.parent,
})
}
}
#[derive(IntoElement)]
pub struct TreeGrid {
ident: Ident,
count: usize,
render_row: RenderRow,
columns: Vec<GridColumn>,
selected: Option<SharedString>,
visible_rows: Option<usize>,
row_height: Option<f32>,
lines: GridLines,
loading: bool,
failure: Option<SharedString>,
vacancy: Option<EmptyState>,
disabled: bool,
on_select: Option<SelectHandler>,
on_expand: Option<ExpandHandler>,
}
impl std::fmt::Debug for TreeGrid {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TreeGrid")
.field("ident", &self.ident)
.field("count", &self.count)
.field("columns", &self.columns.len())
.field("disabled", &self.disabled)
.finish()
}
}
impl TreeGrid {
pub fn new(
ident: impl Into<Ident>,
visible_row_count: usize,
render_row: impl Fn(usize, &mut Window, &mut App) -> TreeGridRow + 'static,
) -> Self {
Self {
ident: ident.into(),
count: visible_row_count,
render_row: Rc::new(render_row),
columns: vec![],
selected: None,
visible_rows: None,
row_height: None,
lines: GridLines::None,
loading: false,
failure: None,
vacancy: None,
disabled: false,
on_select: None,
on_expand: None,
}
}
pub fn column(mut self, column: GridColumn) -> Self {
self.columns.push(column);
self
}
pub fn columns(mut self, columns: impl IntoIterator<Item = GridColumn>) -> Self {
self.columns.extend(columns);
self
}
pub fn selected(mut self, id: impl Into<SharedString>) -> Self {
self.selected = Some(id.into());
self
}
pub fn visible_rows(mut self, rows: usize) -> Self {
self.visible_rows = Some(rows);
self
}
pub fn row_height(mut self, height: f32) -> Self {
self.row_height = Some(height);
self
}
pub fn lines(mut self, lines: GridLines) -> Self {
self.lines = lines;
self
}
pub fn loading(mut self, loading: bool) -> Self {
self.loading = loading;
self
}
pub fn failure(mut self, detail: impl Into<SharedString>) -> Self {
self.failure = Some(detail.into());
self
}
pub fn empty(mut self, state: EmptyState) -> Self {
self.vacancy = Some(state);
self
}
pub fn unavailable(mut self, title: impl Into<SharedString>) -> Self {
self.vacancy = Some(
EmptyState::new(self.ident.child("unavailable"), title).kind(EmptyKind::Unavailable),
);
self
}
pub fn on_select(
mut self,
handler: impl Fn(SharedString, &mut Window, &mut App) + 'static,
) -> Self {
self.on_select = Some(Rc::new(handler));
self
}
pub fn on_expand(
mut self,
handler: impl Fn(SharedString, bool, &mut Window, &mut App) + 'static,
) -> Self {
self.on_expand = Some(Rc::new(handler));
self
}
}
impl Disableable for TreeGrid {
fn disabled(mut self, disabled: bool) -> Self {
self.disabled = disabled;
self
}
}
impl RenderOnce for TreeGrid {
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
let render = self.render_row;
let mut grid = DataGrid::new(self.ident, self.count, move |index, window, cx| {
render(index, window, cx).into_grid_row()
})
.columns(self.columns)
.lines(self.lines)
.selection_mode(SelectionMode::Single)
.selected(self.selected)
.loading(self.loading)
.hierarchy_mode()
.disabled(self.disabled);
if let Some(rows) = self.visible_rows {
grid = grid.visible_rows(rows);
}
if let Some(height) = self.row_height {
grid = grid.row_height(height);
}
if let Some(failure) = self.failure {
grid = grid.failure(failure);
}
if let Some(empty) = self.vacancy {
grid = grid.empty(empty);
}
if let Some(handler) = self.on_select {
grid = grid.on_select(move |change, window, cx| {
if let SelectionChange::Replace(id) = change {
handler(id.clone(), window, cx);
}
});
}
if let Some(handler) = self.on_expand {
grid = grid.on_expand(move |id, open, window, cx| handler(id, open, window, cx));
}
grid
}
}