Expand description
TreeView — a virtualized, expandable/collapsible hierarchical list widget.
Displays a TreeModel<T> as an indented tree.
Internally each view owns a TreeSlice for independent
expand state, so two TreeViews on the same model can be open at different
depths simultaneously. Only rows in the visible viewport + a small buffer have
live widgets — rows outside the buffer are dormant, matching ListView’s
virtualization model. An external TreeDataSource
is also accepted via TreeView::from_source when the data lives outside a
TreeModel.
Row heights come in three modes: uniform (item_height, default fast path),
exact per-flat-index callback (item_height_fn), and auto-measured
(auto_item_height — height-for-width per row, scroll-anchored).
§Scrolling to a row
handle returns a TreeViewHandle, a cheap Clone
taken before the view is added and usable from any handler afterwards. Its
scroll_to_index and
ensure_index_visible take a flat
visible row index and are applied at the next layout pass, after row
measurement and scroll anchoring, so they may follow an expansion in the
same turn, or be called before mount:
let tree = TreeView::new(model, |item, _entry, _selected| {
Box::new(TextWidget::new(lit!(item)))
});
let handle = tree.handle();
// … `ctx.add(tree)`; then, from a handler, after expanding the row's
// ancestors in the same turn:
handle.ensure_index_visible(42);§The keyboard cursor
The tree has one current row, its keyboard cursor: the row the arrow keys
step from and the one it names to assistive technology as its active
descendant while it holds keyboard focus. The same TreeViewHandle
reads and moves it, in flat visible indices:
cursor,
set_cursor (clamped to the last visible
row; keyboard focus, the selection and the scroll offset are left alone)
and cursor_signal, for an application
to observe. The cursor follows its row through an expansion or a collapse
above it, whoever set it. A cursor set before mount is there at the first
build.
In a single selection the cursor follows the selection. In a multiple
selection the two are separate: Ctrl+↓ moves the cursor and leaves
the selection, and a selection written from outside leaves the cursor
where it was. Read the cursor, not the first selected row, for “the row
the user is on”.
§Pan to scroll
The view installs common::scrollable::ScrollableBehavior,
which gives it the shared wheel arithmetic, a finger’s pan and the
PanClaim that puts it on a pan’s claimant chain. A pan scrolls it, the
release coasts, and a pan it cannot absorb hands the whole event to the
container outside. Vertical only: this view owns no horizontal offset, so a
horizontal pan is declined and chains outward. A pan that starts on a row
scrolls rather than activating it, toggling its chevron, or collapsing a
multi-selection onto it — the three things a release on that row commits.
Activation is a gesture, so the arbitration cancels it; the chevron and the
deferred collapse are raw PointerUp arms the arbitration cannot reach, so
each asks data_views::release_completes_the_press whether the release still
belongs to the row.
§Keyboard
Arrows move the cursor; Home / End reach the first and last visible
row and PageUp / PageDown a viewport of them, each moving the selection
unless the accelerator is held, which moves the cursor alone — in a
multiple selection only: a single selection always moves with the cursor,
a selection the application sets moves the cursor onto it, and a
structural change carries the selection along with its row. Shift
extends a range from the anchor and Ctrl+Shift extends it additively.
→ opens a closed node and, on one already open, moves into its first
child; ← closes an open node and, on a leaf or a closed one, ascends to
the parent. Both mirror under RTL. * expands the whole subtree, + and
- one level. Space selects or toggles, Enter activates, Ctrl+A and
Ctrl+Shift+A select and deselect everything, and Ctrl+Arrow with
Ctrl+Space build a disjoint selection. On macOS ⌘↓ opens a row, ⌘↑
ascends, and ⌥→/⌥← expand or collapse a subtree.
The full table, and why some of it is platform-specific, is in docs/data-view-keyboard.md.
§Example
let _w = TreeView::new(tree_model, |item, entry, _selected| {
let indent = entry.depth as f32 * 20.0;
Box::new(HStack::new()
.child(Padding::new(0.0, 0.0, 0.0, indent))
.child(TextWidget::new(lit!(&item.title))))
})
.item_height(28.0);Structs§
- Tree
RowContext - Per-row context passed to a 4-arg TreeView delegate. Carries a
reference to the slice handle and the row’s
NodeIdso the delegate can wire chevron toggles and other tree-aware behavior without manually cloning state outside the closure. - Tree
View - Tree
View Handle - A handle on a mounted
TreeView, to scroll it to a row from outside the widget — a view-model revealing the node a search found, say.