mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-06-19 13:28:16 +08:00
Streamline tree API a bit
This commit is contained in:

committed by
Patrik Svensson

parent
b136d0299b
commit
4bfb24bfcb
@ -19,9 +19,9 @@ namespace Spectre.Console
|
||||
public Style Style { get; set; } = Style.Plain;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the rendering type used for the tree.
|
||||
/// Gets or sets the appearance of the tree.
|
||||
/// </summary>
|
||||
public ITreeRendering Rendering { get; set; } = TreeRendering.Ascii;
|
||||
public TreeAppearance Appearance { get; set; } = TreeAppearance.Ascii;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Tree"/> class.
|
||||
@ -29,37 +29,37 @@ namespace Spectre.Console
|
||||
/// <param name="rootNode">Root node of the tree to be rendered.</param>
|
||||
public Tree(TreeNode rootNode)
|
||||
{
|
||||
_rootNode = rootNode;
|
||||
_rootNode = rootNode ?? throw new ArgumentNullException(nameof(rootNode));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Measurement Measure(RenderContext context, int maxWidth)
|
||||
{
|
||||
return MeasureAtDepth(context, maxWidth, _rootNode, depth: 0);
|
||||
}
|
||||
|
||||
private Measurement MeasureAtDepth(RenderContext context, int maxWidth, TreeNode node, int depth)
|
||||
{
|
||||
var rootMeasurement = node.Measure(context, maxWidth);
|
||||
var treeIndentation = depth * Rendering.PartSize;
|
||||
var currentMax = rootMeasurement.Max + treeIndentation;
|
||||
var currentMin = rootMeasurement.Min + treeIndentation;
|
||||
|
||||
foreach (var child in node.Children)
|
||||
Measurement MeasureAtDepth(RenderContext context, int maxWidth, TreeNode node, int depth)
|
||||
{
|
||||
var childMeasurement = MeasureAtDepth(context, maxWidth, child, depth + 1);
|
||||
if (childMeasurement.Min > currentMin)
|
||||
var rootMeasurement = node.Measure(context, maxWidth);
|
||||
var treeIndentation = depth * Appearance.PartSize;
|
||||
var currentMax = rootMeasurement.Max + treeIndentation;
|
||||
var currentMin = rootMeasurement.Min + treeIndentation;
|
||||
|
||||
foreach (var child in node.Children)
|
||||
{
|
||||
currentMin = childMeasurement.Min;
|
||||
var childMeasurement = MeasureAtDepth(context, maxWidth, child, depth + 1);
|
||||
if (childMeasurement.Min > currentMin)
|
||||
{
|
||||
currentMin = childMeasurement.Min;
|
||||
}
|
||||
|
||||
if (childMeasurement.Max > currentMax)
|
||||
{
|
||||
currentMax = childMeasurement.Max;
|
||||
}
|
||||
}
|
||||
|
||||
if (childMeasurement.Max > currentMax)
|
||||
{
|
||||
currentMax = childMeasurement.Max;
|
||||
}
|
||||
return new Measurement(currentMin, Math.Min(currentMax, maxWidth));
|
||||
}
|
||||
|
||||
return new Measurement(currentMin, Math.Min(currentMax, maxWidth));
|
||||
return MeasureAtDepth(context, maxWidth, _rootNode, depth: 0);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -68,27 +68,25 @@ namespace Spectre.Console
|
||||
return _rootNode
|
||||
.Render(context, maxWidth)
|
||||
.Concat(new List<Segment> { Segment.LineBreak })
|
||||
.Concat(RenderChildren(context, maxWidth - Rendering.PartSize, _rootNode, depth: 0));
|
||||
.Concat(RenderChildren(context, maxWidth - Appearance.PartSize, _rootNode, depth: 0));
|
||||
}
|
||||
|
||||
private IEnumerable<Segment> RenderChildren(RenderContext context, int maxWidth, TreeNode node, int depth,
|
||||
int? trailingStarted = null)
|
||||
{
|
||||
var result = new List<Segment>();
|
||||
|
||||
foreach (var (index, firstChild, lastChild, childNode) in node.Children.Enumerate())
|
||||
foreach (var (_, _, lastChild, childNode) in node.Children.Enumerate())
|
||||
{
|
||||
var lines = Segment.SplitLines(context, childNode.Render(context, maxWidth));
|
||||
|
||||
foreach (var (lineIndex, firstLine, lastLine, line) in lines.Enumerate())
|
||||
foreach (var (_, isFirstLine, _, line) in lines.Enumerate())
|
||||
{
|
||||
var siblingConnectorSegment =
|
||||
new Segment(Rendering.GetPart(TreePart.SiblingConnector), Style);
|
||||
new Segment(Appearance.GetPart(TreePart.SiblingConnector), Style);
|
||||
if (trailingStarted != null)
|
||||
{
|
||||
result.AddRange(Enumerable.Repeat(siblingConnectorSegment, trailingStarted.Value));
|
||||
result.AddRange(Enumerable.Repeat(
|
||||
Segment.Padding(Rendering.PartSize),
|
||||
Segment.Padding(Appearance.PartSize),
|
||||
depth - trailingStarted.Value));
|
||||
}
|
||||
else
|
||||
@ -96,15 +94,15 @@ namespace Spectre.Console
|
||||
result.AddRange(Enumerable.Repeat(siblingConnectorSegment, depth));
|
||||
}
|
||||
|
||||
if (firstLine)
|
||||
if (isFirstLine)
|
||||
{
|
||||
result.Add(lastChild
|
||||
? new Segment(Rendering.GetPart(TreePart.BottomChildBranch), Style)
|
||||
: new Segment(Rendering.GetPart(TreePart.ChildBranch), Style));
|
||||
? new Segment(Appearance.GetPart(TreePart.BottomChildBranch), Style)
|
||||
: new Segment(Appearance.GetPart(TreePart.ChildBranch), Style));
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Add(lastChild ? Segment.Padding(Rendering.PartSize) : siblingConnectorSegment);
|
||||
result.Add(lastChild ? Segment.Padding(Appearance.PartSize) : siblingConnectorSegment);
|
||||
}
|
||||
|
||||
result.AddRange(line);
|
||||
@ -112,8 +110,12 @@ namespace Spectre.Console
|
||||
}
|
||||
|
||||
var childTrailingStarted = trailingStarted ?? (lastChild ? depth : null);
|
||||
result.AddRange(RenderChildren(context, maxWidth - Rendering.PartSize, childNode, depth + 1,
|
||||
childTrailingStarted));
|
||||
|
||||
result.AddRange(
|
||||
RenderChildren(
|
||||
context, maxWidth - Appearance.PartSize,
|
||||
childNode, depth + 1,
|
||||
childTrailingStarted));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Spectre.Console.Rendering;
|
||||
@ -7,10 +8,12 @@ namespace Spectre.Console
|
||||
/// <summary>
|
||||
/// Node of a tree.
|
||||
/// </summary>
|
||||
public sealed class TreeNode : IRenderable
|
||||
public sealed class TreeNode : IHasTreeNodes, IRenderable
|
||||
{
|
||||
private readonly IRenderable _renderable;
|
||||
private List<TreeNode> _children;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public List<TreeNode> Children { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TreeNode"/> class.
|
||||
@ -19,25 +22,8 @@ namespace Spectre.Console
|
||||
/// <param name="children">Any children that the node is declared with.</param>
|
||||
public TreeNode(IRenderable renderable, IEnumerable<TreeNode>? children = null)
|
||||
{
|
||||
_renderable = renderable;
|
||||
_children = new List<TreeNode>(children ?? Enumerable.Empty<TreeNode>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the children of this node.
|
||||
/// </summary>
|
||||
public List<TreeNode> Children
|
||||
{
|
||||
get => _children;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a child to the end of the node's list of children.
|
||||
/// </summary>
|
||||
/// <param name="child">Child to be added.</param>
|
||||
public void AddChild(TreeNode child)
|
||||
{
|
||||
_children.Add(child);
|
||||
_renderable = renderable ?? throw new ArgumentNullException(nameof(renderable));
|
||||
Children = new List<TreeNode>(children ?? Enumerable.Empty<TreeNode>());
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
Reference in New Issue
Block a user