Skip to main content

Tree

private readonly Tree<VltNode> _nodes;
private readonly VltFile _vlt;

_nodes = new Tree<VltNode>(options.Keymap)
{
Render = node => node.Name,
OnExpanding = node => node.Children = _vlt.LoadChildren(node.Value),
OnActivate = node => ViewKind.Node,
Roots = roots,
};

Widgets are built in the view's constructor, so options is the ArlecchinoOptions the container hands it, and region is the region the view draws the widget into.

Nodes

TreeNode<T> carries the value, its children and whether it is open:

var roots = projects
.Select(project => new TreeNode<Project>(project))
.ToList();

A node with no children is a leaf and gets no marker. Rows are indented two columns per level and prefixed with / .

Keys and clicks

InputDoes
Expands the node under the cursor, then steps into it
Collapses it, then walks up to the parent
ConfirmToggles a branch, or activates a leaf through OnActivate
Click on the markerToggles that node without activating it
Click elsewhereSelects the row; a second click activates it

Movement, paging and the wheel come from the ListBox inside.

Filling children in late

OnExpanding fires just before a node opens, which is where children are filled in for a tree that loads level by level:

OnExpanding = node => node.Children = _vlt.LoadChildren(node.Value),

That keeps a large hierarchy cheap: nothing below a closed node is ever read. Work that has to leave the thread goes through an async atom and posts the children back rather than blocking the frame.

ExpandAll() and CollapseAll() walk the whole thing.

A worked example

samples/Arlecchino.Sample shows a tree beside the rest of its gallery, with the branches folded in until they are opened:

dotnet run --project samples/Arlecchino.Sample -- --frame widgets 100x24