diff --git a/src/Spectre.Console.Tests/Unit/RowsTests.cs b/src/Spectre.Console.Tests/Unit/RowsTests.cs new file mode 100644 index 0000000..3b57a12 --- /dev/null +++ b/src/Spectre.Console.Tests/Unit/RowsTests.cs @@ -0,0 +1,96 @@ +using Shouldly; +using Spectre.Console.Rendering; +using Xunit; + +namespace Spectre.Console.Tests.Unit +{ + public sealed class RowsTests + { + [Fact] + public void Should_Render_Rows() + { + // Given + var console = new PlainConsole(width: 60); + var rows = new Rows( + new IRenderable[] + { + new Markup("Hello"), + new Table() + .AddColumns("Foo", "Bar") + .AddRow("Baz", "Qux"), + new Markup("World"), + }); + + // When + console.Render(rows); + + // Then + console.Lines.Count.ShouldBe(7); + console.Lines[0].ShouldBe("Hello"); + console.Lines[1].ShouldBe("┌─────┬─────┐"); + console.Lines[2].ShouldBe("│ Foo │ Bar │"); + console.Lines[3].ShouldBe("├─────┼─────┤"); + console.Lines[4].ShouldBe("│ Baz │ Qux │"); + console.Lines[5].ShouldBe("└─────┴─────┘"); + console.Lines[6].ShouldBe("World"); + } + + [Fact] + public void Should_Render_Rows_Correctly_Inside_Other_Widget() + { + // Given + var console = new PlainConsole(width: 60); + var table = new Table() + .AddColumns("Foo", "Bar") + .AddRow("HELLO WORLD") + .AddRow( + new Rows(new IRenderable[] + { + new Markup("Hello"), + new Markup("World"), + }), new Text("Qux")); + + // When + console.Render(table); + + // Then + console.Lines.Count.ShouldBe(7); + console.Lines[0].ShouldBe("┌─────────────┬─────┐"); + console.Lines[1].ShouldBe("│ Foo │ Bar │"); + console.Lines[2].ShouldBe("├─────────────┼─────┤"); + console.Lines[3].ShouldBe("│ HELLO WORLD │ │"); + console.Lines[4].ShouldBe("│ Hello │ Qux │"); + console.Lines[5].ShouldBe("│ World │ │"); + console.Lines[6].ShouldBe("└─────────────┴─────┘"); + } + + [Fact] + public void Should_Render_Rows_Correctly_Inside_Other_Widget_When_Expanded() + { + // Given + var console = new PlainConsole(width: 60); + var table = new Table() + .AddColumns("Foo", "Bar") + .AddRow("HELLO WORLD") + .AddRow( + new Rows(new IRenderable[] + { + new Markup("Hello"), + new Markup("World"), + }).Expand(), new Text("Qux")); + + // When + console.Render(table); + + // Then + console.Lines.Count.ShouldBe(7); + console.Lines[0].ShouldBe("┌────────────────────────────────────────────────────┬─────┐"); + console.Lines[1].ShouldBe("│ Foo │ Bar │"); + console.Lines[2].ShouldBe("├────────────────────────────────────────────────────┼─────┤"); + console.Lines[3].ShouldBe("│ HELLO WORLD │ │"); + console.Lines[4].ShouldBe("│ Hello │ Qux │"); + console.Lines[5].ShouldBe("│ World │ │"); + console.Lines[6].ShouldBe("└────────────────────────────────────────────────────┴─────┘"); + } + } +} diff --git a/src/Spectre.Console/Widgets/Rows.cs b/src/Spectre.Console/Widgets/Rows.cs new file mode 100644 index 0000000..2a8455e --- /dev/null +++ b/src/Spectre.Console/Widgets/Rows.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Spectre.Console.Internal; +using Spectre.Console.Rendering; + +namespace Spectre.Console +{ + /// + /// Renders things in rows. + /// + public sealed class Rows : Renderable, IExpandable + { + private readonly List _children; + + /// + public bool Expand { get; set; } + + /// + /// Initializes a new instance of the class. + /// + /// The children to render. + public Rows(IEnumerable children) + { + _children = new List(children ?? throw new ArgumentNullException(nameof(children))); + } + + /// + protected override Measurement Measure(RenderContext context, int maxWidth) + { + if (Expand) + { + return new Measurement(maxWidth, maxWidth); + } + else + { + var measurements = _children.Select(c => c.Measure(context, maxWidth)); + return new Measurement( + measurements.Min(c => c.Min), + measurements.Min(c => c.Max)); + } + } + + /// + protected override IEnumerable Render(RenderContext context, int maxWidth) + { + foreach (var child in _children) + { + var segments = child.Render(context, maxWidth); + foreach (var (_, _, last, segment) in segments.Enumerate()) + { + yield return segment; + + if (last) + { + if (!segment.IsLineBreak) + { + yield return Segment.LineBreak; + } + } + } + } + } + } +}