Tree
A row with a parent key sits under its parent. The tree is built from the live rows in the background, in a few O(n) passes, so rows can arrive, leave and change parents while the grid is on screen. The portfolio example is a live tree of funds, desks, books and positions.
Parents
Section titled “Parents”GridRow::parent_key returns the parent’s key, or None for a root:
fn parent_key(&self) -> Option<&u64> { self.parent.as_ref()}- A row whose parent is missing (an orphan), and rows in a parent cycle, become roots;
GridStats::tree_cyclescounts the latter. - A row that gets another parent moves with its subtree.
The tree view
Section titled “The tree view”ViewSpec::with_tree(TreeSpec) builds the view as a tree; set_tree(Some(spec), cx) switches a live grid to one and set_tree(None, cx) back. A tree and grouping replace each other. portfolio’s grid:
let grid = cx.new(|cx| { let grid = LiveGridState::new_standalone( model::schema(), Portfolio, StoreOptions::default(), cx, ) .with_view( ViewSpec::new() .with_sort([(NodeColumn::Name, SortDirection::Ascending)]) .with_tree(TreeSpec::new().with_column(NodeColumn::Name)) // The totals add up the positions, the leaves // (`TreeTotals::Leaves`): the books' sums do not count // twice. The totals row and the status bar show them. .with_aggregates([ (NodeColumn::Pnl, Aggregate::Sum), (NodeColumn::Delta, Aggregate::Sum), ]), ) .with_totals(PinnedEdge::Bottom) // Funds and desks expanded, books collapsed. .with_expand_depth(ExpandDepth::Levels(2)) // Rows at a time, as in `blotter`: a drag or Cmd/Ctrl+A takes // books and desks too, or with `FocusBranches` the positions // shown. .with_selection_mode(SelectionMode::RowSet); if focus_branches { grid.with_selection_policy(FocusBranches) } else { grid }});TreeSpec::with_columnnames the tree column, which shows the indent and the chevron.- Siblings sort by the view’s sort.
Filters
Section titled “Filters”A filter or the quick filter keeps the ancestors of matching rows, so a match is always shown where it lives (TreeFilter::KeepAncestors, the default). TreeSpec::with_filter(TreeFilter::HideSubtree) hides a non-matching row with everything under it, and TreeFilter::Custom takes your own TreeFilterRule.
Totals
Section titled “Totals”The totals add up the leaves (TreeTotals::Leaves): a parent that already holds its children’s sum does not count twice. TreeSpec::with_totals(TreeTotals::Custom(…)) takes your own rule. The grid does not roll children up into their parents’ cells; portfolio’s producer writes the sums into the book and desk rows itself.
Selection
Section titled “Selection”Tree rows are data rows and are selected like any row, as in AG Grid’s tree data. With with_selection_policy(FocusBranches), rows with children take the focus but not the selection, and a command on one acts on its leaves (PORTFOLIO_SELECT=branches in the example).
- The chevron toggles a row; with Alt/Option, its whole subtree.
+expands and-collapses the focused row;-on a leaf goes to its parent.- ← and → move between cells, as everywhere else in the grid.
ExpandDepth::Levels(n)sets the default depth, and the user’s toggles are kept by key across live updates.
Apache-2.0, built on gpui-kit. Repository Sponsor More from GigLabo Privacy Licenses