DreamGUI
Reference

UDreamTreeView

A tree whose hierarchy is code, not an asset: a list whose rows carry an indent and a twisty.

Inherits from UDreamListViewBase.

Declared in Public/Controls/DreamTreeView.h.

A tree whose hierarchy is code, not an asset: a list whose rows carry an indent and a twisty.

A tree IS a list that indents, and this class is written to be exactly that much more than UDreamListView -- both derive from UDreamListViewBase, which owns the viewport, the scrolled column, the row template and the rows; this one adds a depth per item, a per-row indent, and a twisty that expands and collapses. FDreamTreeViewStyle is built the same way round: it carries a whole FDreamListStyle rather than restating its fields, so styling a project's lists styles its trees' rows too.

THE SOURCE IS FLAT, AND ON PURPOSE

Items (or ItemObjects) plus ItemDepths: the pre-order walk of the tree, with each item's depth beside it. That is the shape UUITreeView flattens ITS source into before it can lay a row out (Items + ItemDepths, rebuilt whenever expansion moves), and it is the only shape a control can take from a designer -- a nested source needs an interface on the item class, which is a contract a .dui author cannot sign and a details panel cannot draw.

What the flat form buys, beyond being authorable: the subtree of a row is exactly the run of rows that follow it at a greater depth, so collapsing is a skip rather than a graph walk, and no item ever needs to be asked who its children are.

Everything is expanded to begin with -- the authored list IS what you see -- and CollapsedItems is the set of exceptions. Selection stays an index into the SOURCE, so it survives a collapse.

OnGetItemChildren BUILDS THE FLAT SOURCE; IT DOES NOT REPLACE IT

UMG's TreeView asks each item for its children and walks the answer, and so does this one -- SetRootItems plus OnGetItemChildren (or IUITreeViewItem::GetTreeChildren, which this plugin's behaviour-side tree already speaks) flattens the hierarchy in pre-order into exactly the Items + ItemDepths pair above.

Flattening rather than walking lazily is the whole design, and it is what keeps every index in this control's API meaning something: SelectedIndex, ItemDepths, GetRowWidget, ScrollItemIntoView and CollapsedItems are all indices into the SOURCE, and a source that only materialises what is currently expanded would renumber itself every time a twisty moved. The walk therefore takes the WHOLE tree, including the children of collapsed nodes, and collapsing stays what it has always been here: a skip over a run of deeper rows at display time. A collapsed parent keeps its twisty because its children are still in the source to be counted.

The cost of that decision is stated rather than hidden: an unbounded or lazily-loaded hierarchy cannot be expressed this way, because the walk visits every node once. A tree that large wants the recycling stack (UUITreeView) instead, which is why that class stays.

Cycles are survivable: an item already visited is not visited again, so a graph produces a tree rather than a hang.

LEFT AND RIGHT ARE THE TREE'S

Up and down step through the rows that show, as a list's do. Left and right open and close, as STreeView::OnKeyDown has them: right on a folded parent unfolds it, right on an open one moves to its first child; left on an open parent folds it, left anywhere else moves to the parent. Where the key has nothing to do -- right on a leaf, left on a root that is already folded -- it still belongs to the tree and focus stays put, which is what STreeView does with the arrow keys. This library has one navigation road for the keyboard and the gamepad, so a D-pad gets the same answer; in UMG a D-pad goes round OnKeyDown and would leave the tree sideways instead. The twisty is not a navigation stop (UMG's expander arrow is not focusable either), so a press that follows a click on it starts from the row.

See UDreamListViewBase for the shape of the tree it builds, why it hosts the plain scroll view rather than the recycling one, and how these controls sit beside the each language feature.

Properties

NameTypeCategoryIn the details panelFrom BlueprintDescription
StyleFDreamTreeViewStyleTree ViewyesGetStyle / SetStyleThis instance's own look. The project sheet wins while StyleSource says so AND a sheet actually exists; with no sheet in the project this IS the look in effect -- which is why it stays editable instead of being gated on the enum.
ItemDepthsTArray<int32>Tree ViewyesGetItemDepths / SetItemDepthsOne depth per item, parallel to Items / ItemObjects: 0 is a root, 1 is a child of the nearest preceding 0, and so on. Missing entries read as 0, so a tree given no depths at all is simply a flat list -- which is the right thing for it to be.
CollapsedItemsTSet<int32>Tree ViewyesGetCollapsedItems / SetCollapsedItemsThe collapsed items, by source index. An exception set rather than an expanded set because a tree that opens showing nothing is a tree nobody can see they authored.
CollapsedItemObjectsTSet<TObjectPtr<UObject> >Tree View-read onlyThe same exceptions, by IDENTITY, for a source that has ItemObjects.
TwistyTemplateNodeTObjectPtr<UDreamWidget>Tree View-read onlyThe template's twisty. Every row has a copy of it, found by display name.
TwistyGlyphTemplateNodeTObjectPtr<UDreamWidget>Tree View-read onlyThe glyph inside it -- the stand-in for a state whose brush holds no image.
RootItemsTArray<TObjectPtr<UObject> >Tree Viewyesread / writeThe top of the hierarchy, for a tree that is authored as a GRAPH rather than as a flat array.
OnGetItemChildrenFDreamTreeGetItemChildrenTree View-read / writeWho an item's children are. UMG's OnGetItemChildren, with its signature and its job.

Functions

FunctionKindDescription
void CollapseAll()callableCollapse All
void ExpandAll()callableExpand All
TSet<int32> GetCollapsedItems()pureGet Collapsed Items
TArray<int32> GetItemDepths()pureGet Item Depths
float GetRowIndent(int32 InItemIndex)pureHow far in this item's row starts, in pixels: its depth times the style's IndentPerLevel.
FDreamTreeViewStyle GetStyle()pureBy value, not by reference: a UFUNCTION return has to be a value, and a style is a small struct.
bool IsItemExpanded(int32 InItemIndex)pureIs Item Expanded
bool ItemHasChildren(int32 InItemIndex)pureTrue when the next item is deeper -- which, in a pre-order flat list, is what a parent is.
void RefreshTree()callableWalk the roots again and rebuild the flat source from what the children provider says now.
void SetCollapsedItems(TSet<int32> InCollapsed)callableReplace the whole fold state at once and re-derive the visible rows.
void SetItemDepths(TArray<int32> InDepths)callableReplace the depths alone, for a source that did not move.
void SetItemExpanded(int32 InItemIndex, bool bInExpanded)callableMoves the twisty, rebuilds the visible rows, then says so. A no-op if it was already there.
void SetItemExpansion(int32 InItemIndex, bool bInExpanded)callableUMG's name for SetItemExpanded, which is the one this control was written with.
void SetItemsWithDepths(TArray<FText> InItems, TArray<int32> InDepths)callableReplace the source and its depths together, which is the only way they are ever coherent.
void SetRootItems(TArray<UObject*> InRootItems)callableReplace the roots and re-walk. The hierarchical counterpart of SetItemsWithDepths.
void SetStyle(FDreamTreeViewStyle InStyle)callableReplace the whole look and re-push it. The indent and the twisty are style, so rows rebuild.
void ToggleItemExpansion(int32 InItemIndex)callableToggle Item Expansion

Events

EventSignatureDescription
OnItemExpansionChangedvoid DreamTreeExpansionChangedEvent__DelegateSignature(int32 ItemIndex, bool bExpanded)Per depth level, in whichever direction the twisty was clicked.

Compared with UMG

Every Blueprint-facing member of the UMG class, and where it went. adopt: same name, same meaning. map: here under another name or on another type. reject: deliberately absent, with the reason.

UMGMemberStatusHereNote
UTreeViewSetItemExpansionadoptSetItemExpansionA one-line forward to SetItemExpanded, which is the name this control was written with and which every existing caller uses. By source index, so it survives a collapse above it. The player reaches it too: Left and Right on a row open, close and walk to parent or first child as STreeView::OnKeyDown does with the arrow keys -- and, this library having one navigation road, a D-pad does the same, where in UMG it would leave the tree sideways.
UTreeViewExpandAlladoptExpandAll
UTreeViewCollapseAlladoptCollapseAll
UTreeViewBP_OnGetItemChildrenmapOnGetItemChildrenFDreamTreeGetItemChildren, with UMG's signature. Single-cast like UMG's: this one is a QUESTION, and two answers to a question is an ambiguity nothing can resolve. Unbound, the walk falls back to IUITreeViewItem::GetTreeChildren.
UTreeViewBP_OnItemExpansionChangedmapOnItemExpansionChangedCarries the source index and the new state. Fired after the visible rows have been rebuilt, so a handler counting rows sees the tree the user just made.

On this page