Tree
See the TreeDemo.cs.
using Gridrand.Contracts;
using Gridrand.Contracts.InputSystem;
using Gridrand.RimGui.Extensions;
using Gridrand.RimGui.Manual.Utility;
using System.Collections.Generic;
namespace Gridrand.RimGui.Manual
{
/// <summary>
/// This is a demo of <see cref="Gui.Tree{TNode}(IEnumerable{TNode}, TreeDrawingBundle{TNode}, Rect?, int)"/> and
/// <see cref="Gui.FixedScrollTree{TNode}(float, IEnumerable{TNode}, TreeDrawingBundle{TNode}, int)"/>.
/// </summary>
class TreeDemo : ManualBase, IManual
{
// Scrollable tree structure data.
readonly List<Node> scrollRoots = new();
readonly ItemSelection<Node> scrollSelection = new();
// Fixed-size scrollable tree structure data.
readonly List<Node> fixedScrollRoots = new();
readonly ItemSelection<Node> fixedScrollSelection = new();
// Handlers for node interactions and rendering.
readonly NodeHandler nodeHandler;
readonly NodeHandler fixedScrollNodeHandler;
readonly NodeDrawer nodeDrawer;
public TreeDemo(ManualBaseResource p) : base(p)
{
nodeDrawer = new NodeDrawer(Gui);
nodeHandler = new NodeHandler(Input);
fixedScrollNodeHandler = new NodeHandler(Input);
BuildTree(scrollRoots, scrollSelection);
BuildTree(fixedScrollRoots, fixedScrollSelection);
foreach (var n in scrollRoots)
nodeHandler.SetOpenRecursively(n, true);
foreach (var n in fixedScrollRoots)
fixedScrollNodeHandler.SetOpenRecursively(n, true);
static void BuildTree(List<Node> roots, ItemSelection<Node> selection)
{
var n = 0;
roots.Add(new Node() { Name = ProcessName(ref n) }
.AddChildren(
new Node() { Name = ProcessName(ref n) }
.AddChildren(
new Node() { Name = ProcessName(ref n) },
new Node() { Name = ProcessName(ref n) }),
new Node() { Name = ProcessName(ref n) }
.AddChildren(new Node() { Name = ProcessName(ref n) })));
roots.Add(new Node() { Name = ProcessName(ref n) }
.AddChildren(
new Node() { Name = ProcessName(ref n) }
.AddChildren(
new Node() { Name = ProcessName(ref n) })));
roots.Add(new Node() { Name = ProcessName(ref n) });
roots.Add(new Node() { Name = ProcessName(ref n) });
roots.Add(new Node() { Name = ProcessName(ref n) });
roots.Add(new Node() { Name = ProcessName(ref n) });
selection.Select(roots[0]);
selection.Select(roots[1]);
}
static string ProcessName(ref int number)
{
var result = number;
number++;
return result.ToString();
}
}
public void Draw()
{
Gui.ToolTip("By holding down the Alt key while clicking triangle icon, you can open / close all child elements.");
Gui.Heading("Scroll");
{
// Set SpacingY to 0 within this scope.
using var s = Style.SpacingYs.Begin(0f);
Gui.NextHeight(200f);
// Render a scrollable tree.
if (Gui.BeginScroll())
{
Gui.Tree(scrollRoots, new(nodeDrawer, scrollSelection, nodeHandler), Ctx.GetWidgetRect());
Gui.EndScroll();
}
}
Gui.HeadingTooltip(
"FixedScrollTree",
"It only processes the displayed nodes, making it fast even when there are many.");
{
using var s = Style.SpacingYs.Begin(0f);
// Render a fixed-size scrollable tree.
Gui.FixedScrollTree(200f, fixedScrollRoots, new(nodeDrawer, fixedScrollSelection, fixedScrollNodeHandler));
}
}
/// <summary>
/// Represents a node in the tree structure.
/// </summary>
class Node
{
public bool IsCheck { get; set; }
public string Name { get; set; }
public List<Node> Children { get; private set; } = new();
public bool HasChild => 0 < Children.Count;
public Node AddChildren(params Node[] children)
{
Children.AddRange(children);
return this;
}
}
/// <summary>
/// Handles rendering of tree nodes.
/// </summary>
class NodeDrawer : ITreeNodeDrawer<Node>
{
readonly Gui ui;
public NodeDrawer(Gui ui)
{
this.ui = ui;
}
/// <summary>
/// Draws a tree node.
/// </summary>
/// <param name="node">The node to draw.</param>
/// <param name="rect">The rectangle area allocated for the node.</param>
public void Draw(Node node, Rect rect)
{
// note:Unscaled because the scale has already been taken into account.
using var rects = ui.LayoutBuilder.FixedUnscaled(rect.height).Fit(1).BuildHorizontal(rect);
var isCheck = node.IsCheck;
ui.NextRect(rects.R0).CheckBox(ref isCheck);
node.IsCheck = isCheck;
ui.NextRect(rects.R1).Text(node.Name);
}
}
/// <summary>
/// Handles tree node interactions, such as expanding and selecting nodes.
/// </summary>
class NodeHandler : TreeNodeHandlerBase<Node>
{
public NodeHandler(IInputContext input) : base(input)
{
}
public override IEnumerable<Node> GetChildren(Node node) => node.Children;
}
}
}