using System; using System.Collections.Generic; using System.Text; using Terminal.Gui.Graphs; using Xunit; using Xunit.Abstractions; namespace Terminal.Gui.CoreTests { public class LineCanvasTests { readonly ITestOutputHelper output; public LineCanvasTests (ITestOutputHelper output) { this.output = output; } [Fact, AutoInitShutdown] public void TestLineCanvas_Dot () { var v = GetCanvas (out var canvas); canvas.AddLine (new Point (0, 0), 0, Orientation.Horizontal, BorderStyle.Single); v.Redraw (v.Bounds); string looksLike = @" ."; TestHelpers.AssertDriverContentsAre (looksLike, output); } [InlineData (BorderStyle.Single)] [InlineData (BorderStyle.Rounded)] [Theory, AutoInitShutdown] public void TestLineCanvas_Horizontal (BorderStyle style) { var v = GetCanvas (out var canvas); canvas.AddLine (new Point (0, 0), 1, Orientation.Horizontal, style); v.Redraw (v.Bounds); string looksLike = @" ──"; TestHelpers.AssertDriverContentsAre (looksLike, output); } [Fact, AutoInitShutdown] public void TestLineCanvas_Horizontal_Double () { var v = GetCanvas (out var canvas); canvas.AddLine (new Point (0, 0), 1, Orientation.Horizontal, BorderStyle.Double); v.Redraw (v.Bounds); string looksLike = @" ══"; TestHelpers.AssertDriverContentsAre (looksLike, output); } [InlineData (BorderStyle.Single)] [InlineData (BorderStyle.Rounded)] [Theory, AutoInitShutdown] public void TestLineCanvas_Vertical (BorderStyle style) { var v = GetCanvas (out var canvas); canvas.AddLine (new Point (0, 0), 1, Orientation.Vertical, style); v.Redraw (v.Bounds); string looksLike = @" │ │"; TestHelpers.AssertDriverContentsAre (looksLike, output); } [Fact, AutoInitShutdown] public void TestLineCanvas_Vertical_Double () { var v = GetCanvas (out var canvas); canvas.AddLine (new Point (0, 0), 1, Orientation.Vertical, BorderStyle.Double); v.Redraw (v.Bounds); string looksLike = @" ║ ║"; TestHelpers.AssertDriverContentsAre (looksLike, output); } /// /// This test demonstrates that corners are only drawn when lines overlap. /// Not when they terminate adjacent to one another. /// [Fact, AutoInitShutdown] public void TestLineCanvas_Corner_NoOverlap () { var v = GetCanvas (out var canvas); canvas.AddLine (new Point (0, 0), 1, Orientation.Horizontal, BorderStyle.Single); canvas.AddLine (new Point (0, 1), 1, Orientation.Vertical, BorderStyle.Single); v.Redraw (v.Bounds); string looksLike = @" ── │ │"; TestHelpers.AssertDriverContentsAre (looksLike, output); } /// /// This test demonstrates how to correctly trigger a corner. By /// overlapping the lines in the same cell /// [Fact, AutoInitShutdown] public void TestLineCanvas_Corner_Correct () { var v = GetCanvas (out var canvas); canvas.AddLine (new Point (0, 0), 1, Orientation.Horizontal, BorderStyle.Single); canvas.AddLine (new Point (0, 0), 2, Orientation.Vertical, BorderStyle.Single); v.Redraw (v.Bounds); string looksLike = @" ┌─ │ │"; TestHelpers.AssertDriverContentsAre (looksLike, output); } [Fact, AutoInitShutdown] public void TestLineCanvas_Window () { var v = GetCanvas (out var canvas); // outer box canvas.AddLine (new Point (0, 0), 9, Orientation.Horizontal, BorderStyle.Single); canvas.AddLine (new Point (9, 0), 4, Orientation.Vertical, BorderStyle.Single); canvas.AddLine (new Point (9, 4), -9, Orientation.Horizontal, BorderStyle.Single); canvas.AddLine (new Point (0, 4), -4, Orientation.Vertical, BorderStyle.Single); canvas.AddLine (new Point (5, 0), 4, Orientation.Vertical, BorderStyle.Single); canvas.AddLine (new Point (0, 2), 9, Orientation.Horizontal, BorderStyle.Single); v.Redraw (v.Bounds); string looksLike = @" ┌────┬───┐ │ │ │ ├────┼───┤ │ │ │ └────┴───┘"; TestHelpers.AssertDriverContentsAre (looksLike, output); } /// /// Demonstrates when corners are used. Notice how /// not all lines declare rounded. If there are 1+ lines intersecting and a corner is /// to be used then if any of them are rounded a rounded corner is used. /// [Fact, AutoInitShutdown] public void TestLineCanvas_Window_Rounded () { var v = GetCanvas (out var canvas); // outer box canvas.AddLine (new Point (0, 0), 9, Orientation.Horizontal, BorderStyle.Rounded); // BorderStyle.Single is ignored because corner overlaps with the above line which is Rounded // this results in a rounded corner being used. canvas.AddLine (new Point (9, 0), 4, Orientation.Vertical, BorderStyle.Single); canvas.AddLine (new Point (9, 4), -9, Orientation.Horizontal, BorderStyle.Rounded); canvas.AddLine (new Point (0, 4), -4, Orientation.Vertical, BorderStyle.Single); // These lines say rounded but they will result in the T sections which are never rounded. canvas.AddLine (new Point (5, 0), 4, Orientation.Vertical, BorderStyle.Rounded); canvas.AddLine (new Point (0, 2), 9, Orientation.Horizontal, BorderStyle.Rounded); v.Redraw (v.Bounds); string looksLike = @" ╭────┬───╮ │ │ │ ├────┼───┤ │ │ │ ╰────┴───╯"; TestHelpers.AssertDriverContentsAre (looksLike, output); } [Fact, AutoInitShutdown] public void TestLineCanvas_Window_Double () { var v = GetCanvas (out var canvas); // outer box canvas.AddLine (new Point (0, 0), 9, Orientation.Horizontal, BorderStyle.Double); canvas.AddLine (new Point (9, 0), 4, Orientation.Vertical, BorderStyle.Double); canvas.AddLine (new Point (9, 4), -9, Orientation.Horizontal, BorderStyle.Double); canvas.AddLine (new Point (0, 4), -4, Orientation.Vertical, BorderStyle.Double); canvas.AddLine (new Point (5, 0), 4, Orientation.Vertical, BorderStyle.Double); canvas.AddLine (new Point (0, 2), 9, Orientation.Horizontal, BorderStyle.Double); v.Redraw (v.Bounds); string looksLike = @" ╔════╦═══╗ ║ ║ ║ ╠════╬═══╣ ║ ║ ║ ╚════╩═══╝"; TestHelpers.AssertDriverContentsAre (looksLike, output); } [Theory, AutoInitShutdown] [InlineData (BorderStyle.Single)] [InlineData (BorderStyle.Rounded)] public void TestLineCanvas_Window_DoubleTop_SingleSides (BorderStyle thinStyle) { var v = GetCanvas (out var canvas); // outer box canvas.AddLine (new Point (0, 0), 9, Orientation.Horizontal, BorderStyle.Double); canvas.AddLine (new Point (9, 0), 4, Orientation.Vertical, thinStyle); canvas.AddLine (new Point (9, 4), -9, Orientation.Horizontal, BorderStyle.Double); canvas.AddLine (new Point (0, 4), -4, Orientation.Vertical, thinStyle); canvas.AddLine (new Point (5, 0), 4, Orientation.Vertical, thinStyle); canvas.AddLine (new Point (0, 2), 9, Orientation.Horizontal, BorderStyle.Double); v.Redraw (v.Bounds); string looksLike = @" ╒════╤═══╕ │ │ │ ╞════╪═══╡ │ │ │ ╘════╧═══╛ "; TestHelpers.AssertDriverContentsAre (looksLike, output); } [Theory, AutoInitShutdown] [InlineData (BorderStyle.Single)] [InlineData (BorderStyle.Rounded)] public void TestLineCanvas_Window_SingleTop_DoubleSides (BorderStyle thinStyle) { var v = GetCanvas (out var canvas); // outer box canvas.AddLine (new Point (0, 0), 9, Orientation.Horizontal, thinStyle); canvas.AddLine (new Point (9, 0), 4, Orientation.Vertical, BorderStyle.Double); canvas.AddLine (new Point (9, 4), -9, Orientation.Horizontal, thinStyle); canvas.AddLine (new Point (0, 4), -4, Orientation.Vertical, BorderStyle.Double); canvas.AddLine (new Point (5, 0), 4, Orientation.Vertical, BorderStyle.Double); canvas.AddLine (new Point (0, 2), 9, Orientation.Horizontal, thinStyle); v.Redraw (v.Bounds); string looksLike = @" ╓────╥───╖ ║ ║ ║ ╟────╫───╢ ║ ║ ║ ╙────╨───╜ "; TestHelpers.AssertDriverContentsAre (looksLike, output); } [Fact, AutoInitShutdown] public void TestLineCanvas_LeaveMargin_Top1_Left1 () { // Draw at 1,1 within client area of View (i.e. leave a top and left margin of 1) var v = GetCanvas (out var canvas, 1, 1); // outer box canvas.AddLine (new Point (0, 0), 8, Orientation.Horizontal, BorderStyle.Single); canvas.AddLine (new Point (8, 0), 3, Orientation.Vertical, BorderStyle.Single); canvas.AddLine (new Point (8, 3), -8, Orientation.Horizontal, BorderStyle.Single); canvas.AddLine (new Point (0, 3), -3, Orientation.Vertical, BorderStyle.Single); canvas.AddLine (new Point (5, 0), 3, Orientation.Vertical, BorderStyle.Single); canvas.AddLine (new Point (0, 2), 8, Orientation.Horizontal, BorderStyle.Single); v.Redraw (v.Bounds); string looksLike = @" ┌────┬──┐ │ │ │ ├────┼──┤ └────┴──┘ "; TestHelpers.AssertDriverContentsAre (looksLike, output); } /// /// Creates a new into which a is rendered /// at time. /// /// The you can draw into. /// How far to offset drawing in X /// How far to offset drawing in Y /// private View GetCanvas (out LineCanvas canvas, int offsetX = 0, int offsetY = 0) { var v = new View { Width = 10, Height = 5, Bounds = new Rect (0, 0, 10, 5) }; var canvasCopy = canvas = new LineCanvas (); v.DrawContentComplete += (r) => { foreach(var p in canvasCopy.GenerateImage(v.Bounds)) { v.AddRune( offsetX + p.Key.X, offsetY + p.Key.Y, p.Value); } }; return v; } } }