diff --git a/examples/Console/Trees/Program.cs b/examples/Console/Trees/Program.cs new file mode 100644 index 0000000..07cc974 --- /dev/null +++ b/examples/Console/Trees/Program.cs @@ -0,0 +1,47 @@ +using Spectre.Console; + +namespace TableExample +{ + public static class Program + { + public static void Main() + { + var tree = new Tree(); + + tree.AddNode(new FigletText("Dec 2020")); + tree.AddNode(new Markup("[link]Click to go to summary[/]")); + + // Add the calendar nodes + tree.AddNode(new Markup("[blue]Calendar[/]"), + node => node.AddNode( + new Calendar(2020, 12) + .AddCalendarEvent(2020, 12, 12) + .HideHeader())); + + // Add video games node + tree.AddNode(new Markup("[red]Played video games[/]"), + node => node.AddNode( + new Table() + .RoundedBorder() + .AddColumn("Title") + .AddColumn("Console") + .AddRow("The Witcher 3", "XBox One X") + .AddRow("Cyberpunk 2077", "PC") + .AddRow("Animal Crossing", "Nintendo Switch"))); + + + // Add the fruit nodes + tree.AddNode(new Markup("[green]Fruits[/]"), fruits => + fruits.AddNode(new Markup("Eaten"), + node => node.AddNode( + new BarChart().Width(40) + .AddItem("Apple", 12, Color.Red) + .AddItem("Kiwi", 3, Color.Green) + .AddItem("Banana", 21, Color.Yellow)))); + + AnsiConsole.WriteLine(); + AnsiConsole.MarkupLine("[yellow]Monthly summary[/]"); + AnsiConsole.Render(tree); + } + } +} diff --git a/examples/Console/Trees/Trees.csproj b/examples/Console/Trees/Trees.csproj new file mode 100644 index 0000000..9291334 --- /dev/null +++ b/examples/Console/Trees/Trees.csproj @@ -0,0 +1,15 @@ + + + + Exe + net5.0 + Trees + Demonstrates how to render trees in a console. + Widgets + + + + + + + diff --git a/src/Spectre.Console.Tests/Unit/TreeTests.cs b/src/Spectre.Console.Tests/Unit/TreeTests.cs index c677119..19cf646 100644 --- a/src/Spectre.Console.Tests/Unit/TreeTests.cs +++ b/src/Spectre.Console.Tests/Unit/TreeTests.cs @@ -20,15 +20,15 @@ namespace Spectre.Console.Tests.Unit .Select(x => new TreeNode(new Text($"multiple \n line {x}"))); var child2 = new TreeNode(new Text("child2")); var child2Child = new TreeNode(new Text("child2Child")); - child2.AddChild(child2Child); - child2Child.AddChild(new TreeNode(new Text("Child 2 child\n child"))); + child2.AddNode(child2Child); + child2Child.AddNode(new TreeNode(new Text("Child 2 child\n child"))); var child3 = new TreeNode(new Text("child3")); var child3Child = new TreeNode(new Text("single leaf\n multiline")); - child3Child.AddChild(new TreeNode(new Calendar(2020, 01))); - child3.AddChild(child3Child); + child3Child.AddNode(new TreeNode(new Calendar(2020, 01))); + child3.AddNode(child3Child); var children = new List { new(new Text("child1"), nestedChildren), child2, child3 }; var root = new TreeNode(new Text("Root node"), children); - var tree = new Tree().AddChild(root); + var tree = new Tree().AddNode(root); // When console.Render(tree); @@ -47,15 +47,15 @@ namespace Spectre.Console.Tests.Unit .Select(x => new TreeNode(new Text($"multiple \n line {x}"))); var child2 = new TreeNode(new Text("child2")); var child2Child = new TreeNode(new Text("child2Child")); - child2.AddChild(child2Child); - child2Child.AddChild(new TreeNode(new Text("Child 2 child\n child"))); + child2.AddNode(child2Child); + child2Child.AddNode(new TreeNode(new Text("Child 2 child\n child"))); var child3 = new TreeNode(new Text("child3")); var child3Child = new TreeNode(new Text("single leaf\n multiline")); - child3Child.AddChild(new TreeNode(new Calendar(2020, 01))); - child3.AddChild(child3Child); + child3Child.AddNode(new TreeNode(new Calendar(2020, 01))); + child3.AddNode(child3Child); var children = new List { new(new Text("child1"), nestedChildren), child2, child3 }; var root = new TreeNode(new Text("Root node"), children); - var tree = new Tree().AddChild(root).AddChild(child2Child); + var tree = new Tree().AddNode(root).AddNode(child2Child); // When console.Render(tree); @@ -70,7 +70,7 @@ namespace Spectre.Console.Tests.Unit // Given var console = new FakeConsole(width: 80); var root = new TreeNode(new Text("Root node"), Enumerable.Empty()); - var tree = new Tree().AddChild(root); + var tree = new Tree().AddNode(root); // When console.Render(tree); diff --git a/src/Spectre.Console.sln b/src/Spectre.Console.sln index c0cde8b..4dac018 100644 --- a/src/Spectre.Console.sln +++ b/src/Spectre.Console.sln @@ -78,6 +78,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spectre.Console.Testing", " EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{E0E45070-123C-4A4D-AA98-2A780308876C}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Trees", "..\examples\Console\Trees\Trees.csproj", "{CA7AF967-3FA5-4CB1-9564-740CF4527895}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -412,6 +414,18 @@ Global {7D5F6704-8249-46DD-906C-9E66419F215F}.Release|x64.Build.0 = Release|Any CPU {7D5F6704-8249-46DD-906C-9E66419F215F}.Release|x86.ActiveCfg = Release|Any CPU {7D5F6704-8249-46DD-906C-9E66419F215F}.Release|x86.Build.0 = Release|Any CPU + {CA7AF967-3FA5-4CB1-9564-740CF4527895}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CA7AF967-3FA5-4CB1-9564-740CF4527895}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CA7AF967-3FA5-4CB1-9564-740CF4527895}.Debug|x64.ActiveCfg = Debug|Any CPU + {CA7AF967-3FA5-4CB1-9564-740CF4527895}.Debug|x64.Build.0 = Debug|Any CPU + {CA7AF967-3FA5-4CB1-9564-740CF4527895}.Debug|x86.ActiveCfg = Debug|Any CPU + {CA7AF967-3FA5-4CB1-9564-740CF4527895}.Debug|x86.Build.0 = Debug|Any CPU + {CA7AF967-3FA5-4CB1-9564-740CF4527895}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CA7AF967-3FA5-4CB1-9564-740CF4527895}.Release|Any CPU.Build.0 = Release|Any CPU + {CA7AF967-3FA5-4CB1-9564-740CF4527895}.Release|x64.ActiveCfg = Release|Any CPU + {CA7AF967-3FA5-4CB1-9564-740CF4527895}.Release|x64.Build.0 = Release|Any CPU + {CA7AF967-3FA5-4CB1-9564-740CF4527895}.Release|x86.ActiveCfg = Release|Any CPU + {CA7AF967-3FA5-4CB1-9564-740CF4527895}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -443,6 +457,7 @@ Global {5734CB0C-CF2A-44E1-B017-AEFA34A4C39C} = {42792D7F-0BB6-4EE1-A314-8889305A4C48} {E9C02C5A-710C-4A57-A008-E3EAC89305CC} = {42792D7F-0BB6-4EE1-A314-8889305A4C48} {F83CB4F1-95B8-45A4-A415-6DB5F8CA1E12} = {42792D7F-0BB6-4EE1-A314-8889305A4C48} + {CA7AF967-3FA5-4CB1-9564-740CF4527895} = {F0575243-121F-4DEE-9F6B-246E26DC0844} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5729B071-67A0-48FB-8B1B-275E6822086C} diff --git a/src/Spectre.Console/Extensions/BarGraphExtensions.cs b/src/Spectre.Console/Extensions/BarGraphExtensions.cs index 76cbff2..97f5091 100644 --- a/src/Spectre.Console/Extensions/BarGraphExtensions.cs +++ b/src/Spectre.Console/Extensions/BarGraphExtensions.cs @@ -72,7 +72,7 @@ namespace Spectre.Console foreach (var item in items) { - AddItem(chart, item); + AddItem(chart, item); } return chart; diff --git a/src/Spectre.Console/Extensions/HasTreeNodeExtensions.cs b/src/Spectre.Console/Extensions/HasTreeNodeExtensions.cs index 945a7f8..f8b2575 100644 --- a/src/Spectre.Console/Extensions/HasTreeNodeExtensions.cs +++ b/src/Spectre.Console/Extensions/HasTreeNodeExtensions.cs @@ -1,3 +1,6 @@ +using System; +using Spectre.Console.Rendering; + namespace Spectre.Console { /// @@ -6,21 +9,68 @@ namespace Spectre.Console public static class HasTreeNodeExtensions { /// - /// Adds a child to the end of the node's list of children. + /// Adds a child tree node. /// /// An object type with tree nodes. /// The object that has tree nodes. - /// Child to be added. + /// The renderable to add. /// The same instance so that multiple calls can be chained. - public static T AddChild(this T obj, TreeNode child) + public static T AddNode(this T obj, IRenderable renderable) where T : class, IHasTreeNodes { if (obj is null) { - throw new System.ArgumentNullException(nameof(obj)); + throw new ArgumentNullException(nameof(obj)); } - obj.Children.Add(child); + obj.Children.Add(new TreeNode(renderable)); + return obj; + } + + /// + /// Adds a child tree node. + /// + /// An object type with tree nodes. + /// The object that has tree nodes. + /// The renderable to add. + /// An action that can be used to configure the created node further. + /// The same instance so that multiple calls can be chained. + public static T AddNode(this T obj, IRenderable renderable, Action config) + where T : class, IHasTreeNodes + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (config is null) + { + throw new ArgumentNullException(nameof(config)); + } + + var node = new TreeNode(renderable); + config(node); + + obj.Children.Add(node); + return obj; + } + + /// + /// Adds a child tree node. + /// + /// An object type with tree nodes. + /// The object that has tree nodes. + /// The tree node to add. + /// The same instance so that multiple calls can be chained. + public static T AddNode(this T obj, TreeNode node) + where T : class, IHasTreeNodes + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.Children.Add(node); return obj; } } diff --git a/src/Spectre.Console/Extensions/Obsolete/ObsoleteAlignableExtensions.cs b/src/Spectre.Console/Extensions/Obsolete/ObsoleteAlignableExtensions.cs index cfadf8f..e15a6ed 100644 --- a/src/Spectre.Console/Extensions/Obsolete/ObsoleteAlignableExtensions.cs +++ b/src/Spectre.Console/Extensions/Obsolete/ObsoleteAlignableExtensions.cs @@ -22,7 +22,7 @@ namespace Spectre.Console { if (obj is null) { - throw new System.ArgumentNullException(nameof(obj)); + throw new ArgumentNullException(nameof(obj)); } obj.Alignment = alignment; diff --git a/src/Spectre.Console/Internal/StackFrameInfo.cs b/src/Spectre.Console/Internal/StackFrameInfo.cs index 34deacf..de03011 100644 --- a/src/Spectre.Console/Internal/StackFrameInfo.cs +++ b/src/Spectre.Console/Internal/StackFrameInfo.cs @@ -16,8 +16,8 @@ namespace Spectre.Console.Internal string method, List<(string Type, string Name)> parameters, string? path, int? lineNumber) { - Method = method ?? throw new System.ArgumentNullException(nameof(method)); - Parameters = parameters ?? throw new System.ArgumentNullException(nameof(parameters)); + Method = method ?? throw new ArgumentNullException(nameof(method)); + Parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); Path = path; LineNumber = lineNumber; } diff --git a/src/Spectre.Console/Widgets/Panel.cs b/src/Spectre.Console/Widgets/Panel.cs index 547aa30..d737592 100644 --- a/src/Spectre.Console/Widgets/Panel.cs +++ b/src/Spectre.Console/Widgets/Panel.cs @@ -55,7 +55,7 @@ namespace Spectre.Console /// The panel content. public Panel(IRenderable content) { - _child = content ?? throw new System.ArgumentNullException(nameof(content)); + _child = content ?? throw new ArgumentNullException(nameof(content)); } /// diff --git a/src/Spectre.Console/Widgets/Tree.cs b/src/Spectre.Console/Widgets/Tree.cs index 898cd01..dd9a5c5 100644 --- a/src/Spectre.Console/Widgets/Tree.cs +++ b/src/Spectre.Console/Widgets/Tree.cs @@ -73,7 +73,7 @@ namespace Spectre.Console var root = new TreeNode(Text.Empty); foreach (var node in Nodes) { - root.AddChild(node); + root.AddNode(node); } return MeasureAtDepth(context, maxWidth, root, depth: 0); @@ -97,7 +97,7 @@ namespace Spectre.Console var root = new TreeNode(Text.Empty); foreach (var node in Nodes) { - root.AddChild(node); + root.AddNode(node); } return Enumerable.Empty()