From 235114e60d2de41fc1d01b86b26df0a052cfd48b Mon Sep 17 00:00:00 2001 From: tznind Date: Mon, 13 Feb 2023 01:54:01 +0000 Subject: [PATCH 1/5] Fix LineCanvas not respecting X and Y of clip bounds --- Terminal.Gui/Core/Graphs/LineCanvas.cs | 2 +- UnitTests/Core/LineCanvasTests.cs | 52 +++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/Terminal.Gui/Core/Graphs/LineCanvas.cs b/Terminal.Gui/Core/Graphs/LineCanvas.cs index ab45c0264..abb17005c 100644 --- a/Terminal.Gui/Core/Graphs/LineCanvas.cs +++ b/Terminal.Gui/Core/Graphs/LineCanvas.cs @@ -65,7 +65,7 @@ namespace Terminal.Gui.Graphs { for (int x = 0; x < inArea.Width; x++) { var intersects = lines - .Select (l => l.Intersects (x, y)) + .Select (l => l.Intersects (inArea.X + x, inArea.Y + y)) .Where (i => i != null) .ToArray (); diff --git a/UnitTests/Core/LineCanvasTests.cs b/UnitTests/Core/LineCanvasTests.cs index 7e988b0de..a56738c72 100644 --- a/UnitTests/Core/LineCanvasTests.cs +++ b/UnitTests/Core/LineCanvasTests.cs @@ -1,4 +1,7 @@ -using Terminal.Gui.Graphs; +using System; +using System.Collections.Generic; +using System.Text; +using Terminal.Gui.Graphs; using Xunit; using Xunit.Abstractions; @@ -129,6 +132,7 @@ namespace Terminal.Gui.CoreTests { TestHelpers.AssertDriverContentsAre (looksLike, output); } + [Fact,AutoInitShutdown] public void TestLineCanvas_Window () { @@ -280,6 +284,52 @@ namespace Terminal.Gui.CoreTests { TestHelpers.AssertDriverContentsAre (looksLike, output); } + + [Theory, AutoInitShutdown] + [InlineData(0,0,@" +═══ +══ +═══")] + [InlineData (1, 0,@" +══ +═ +══")] + [InlineData (2, 0,@" +═ + +═")] + [InlineData (0, 1,@" +══ +═══")] + [InlineData (0, 2,@" +═══")] + public void TestLineCanvasRenderOffset_NoOffset (int xOffset,int yOffset, string expect) + { + var canvas = new LineCanvas (); + canvas.AddLine (new Point (0, 0), 2, Orientation.Horizontal, BorderStyle.Double); + canvas.AddLine (new Point (0, 1), 1, Orientation.Horizontal, BorderStyle.Double); + canvas.AddLine (new Point (0, 2), 2, Orientation.Horizontal, BorderStyle.Double); + + var bmp = canvas.GenerateImage (new Rect (xOffset, yOffset, 3, 3)); + var actual = BmpToString (bmp); + Assert.Equal (expect.TrimStart (), actual); + + } + + private string BmpToString (System.Rune? [,] bmp) + { + var sb = new StringBuilder (); + for (int y = 0; y < bmp.GetLength (1); y++) { + for (int x = 0; x < bmp.GetLength (0); x++) { + sb.Append (bmp [y, x]); + } + sb.AppendLine (); + } + + return sb.ToString ().TrimEnd (); + } + + private View GetCanvas (out LineCanvas canvas) { var v = new View { From fd989430bc2d926b123932f467015fd1aab5f526 Mon Sep 17 00:00:00 2001 From: tznind Date: Mon, 13 Feb 2023 01:58:19 +0000 Subject: [PATCH 2/5] whitespace formatting fixes --- Terminal.Gui/Core/Graphs/LineCanvas.cs | 137 ++++++++++++------------- UnitTests/Core/LineCanvasTests.cs | 44 ++++---- 2 files changed, 87 insertions(+), 94 deletions(-) diff --git a/Terminal.Gui/Core/Graphs/LineCanvas.cs b/Terminal.Gui/Core/Graphs/LineCanvas.cs index abb17005c..7009c5b71 100644 --- a/Terminal.Gui/Core/Graphs/LineCanvas.cs +++ b/Terminal.Gui/Core/Graphs/LineCanvas.cs @@ -11,10 +11,10 @@ namespace Terminal.Gui.Graphs { /// public class LineCanvas { - + private List lines = new List (); - Dictionary runeResolvers = new Dictionary { + Dictionary runeResolvers = new Dictionary { {IntersectionRuneType.ULCorner,new ULIntersectionRuneResolver()}, {IntersectionRuneType.URCorner,new URIntersectionRuneResolver()}, {IntersectionRuneType.LLCorner,new LLIntersectionRuneResolver()}, @@ -100,15 +100,14 @@ namespace Terminal.Gui.Graphs { } } - private abstract class IntersectionRuneResolver - { + private abstract class IntersectionRuneResolver { readonly Rune round; readonly Rune doubleH; readonly Rune doubleV; readonly Rune doubleBoth; readonly Rune normal; - public IntersectionRuneResolver(Rune round, Rune doubleH, Rune doubleV, Rune doubleBoth, Rune normal) + public IntersectionRuneResolver (Rune round, Rune doubleH, Rune doubleV, Rune doubleBoth, Rune normal) { this.round = round; this.doubleH = doubleH; @@ -121,17 +120,15 @@ namespace Terminal.Gui.Graphs { { var useRounded = intersects.Any (i => i.Line.Style == BorderStyle.Rounded && i.Line.Length != 0); - bool doubleHorizontal = intersects.Any(l=>l.Line.Orientation == Orientation.Horizontal && l.Line.Style == BorderStyle.Double); - bool doubleVertical = intersects.Any(l=>l.Line.Orientation == Orientation.Vertical && l.Line.Style == BorderStyle.Double); + bool doubleHorizontal = intersects.Any (l => l.Line.Orientation == Orientation.Horizontal && l.Line.Style == BorderStyle.Double); + bool doubleVertical = intersects.Any (l => l.Line.Orientation == Orientation.Vertical && l.Line.Style == BorderStyle.Double); - if(doubleHorizontal) - { - return doubleVertical ? doubleBoth : doubleH; + if (doubleHorizontal) { + return doubleVertical ? doubleBoth : doubleH; } - - if(doubleVertical) - { + + if (doubleVertical) { return doubleV; } @@ -139,75 +136,71 @@ namespace Terminal.Gui.Graphs { } } - private class ULIntersectionRuneResolver : IntersectionRuneResolver - { - public ULIntersectionRuneResolver() : - base('╭','╒','╓','╔','┌') + private class ULIntersectionRuneResolver : IntersectionRuneResolver { + public ULIntersectionRuneResolver () : + base ('╭', '╒', '╓', '╔', '┌') { - - } - } - private class URIntersectionRuneResolver : IntersectionRuneResolver - { - public URIntersectionRuneResolver() : - base('╮','╕','╖','╗','┐') - { - } } - private class LLIntersectionRuneResolver : IntersectionRuneResolver - { + private class URIntersectionRuneResolver : IntersectionRuneResolver { - public LLIntersectionRuneResolver() : - base('╰','╘','╙','╚','└') + public URIntersectionRuneResolver () : + base ('╮', '╕', '╖', '╗', '┐') { - + } } - private class LRIntersectionRuneResolver : IntersectionRuneResolver - { - public LRIntersectionRuneResolver() : - base('╯','╛','╜','╝','┘') + private class LLIntersectionRuneResolver : IntersectionRuneResolver { + + public LLIntersectionRuneResolver () : + base ('╰', '╘', '╙', '╚', '└') { - + + } + } + private class LRIntersectionRuneResolver : IntersectionRuneResolver { + public LRIntersectionRuneResolver () : + base ('╯', '╛', '╜', '╝', '┘') + { + } } - private class TopTeeIntersectionRuneResolver : IntersectionRuneResolver - { - public TopTeeIntersectionRuneResolver(): - base('┬','╤','╥','╦','┬'){ - - } + private class TopTeeIntersectionRuneResolver : IntersectionRuneResolver { + public TopTeeIntersectionRuneResolver () : + base ('┬', '╤', '╥', '╦', '┬') + { + + } } - private class LeftTeeIntersectionRuneResolver : IntersectionRuneResolver - { - public LeftTeeIntersectionRuneResolver(): - base('├','╞','╟','╠','├'){ - - } + private class LeftTeeIntersectionRuneResolver : IntersectionRuneResolver { + public LeftTeeIntersectionRuneResolver () : + base ('├', '╞', '╟', '╠', '├') + { + + } } - private class RightTeeIntersectionRuneResolver : IntersectionRuneResolver - { - public RightTeeIntersectionRuneResolver(): - base('┤','╡','╢','╣','┤'){ - - } + private class RightTeeIntersectionRuneResolver : IntersectionRuneResolver { + public RightTeeIntersectionRuneResolver () : + base ('┤', '╡', '╢', '╣', '┤') + { + + } } - private class BottomTeeIntersectionRuneResolver : IntersectionRuneResolver - { - public BottomTeeIntersectionRuneResolver(): - base('┴','╧','╨','╩','┴'){ - - } + private class BottomTeeIntersectionRuneResolver : IntersectionRuneResolver { + public BottomTeeIntersectionRuneResolver () : + base ('┴', '╧', '╨', '╩', '┴') + { + + } } - private class CrosshairIntersectionRuneResolver : IntersectionRuneResolver - { - public CrosshairIntersectionRuneResolver(): - base('┼','╪','╫','╬','┼'){ - - } + private class CrosshairIntersectionRuneResolver : IntersectionRuneResolver { + public CrosshairIntersectionRuneResolver () : + base ('┼', '╪', '╫', '╬', '┼') + { + + } } private Rune? GetRuneForIntersects (ConsoleDriver driver, IntersectionDefinition [] intersects) @@ -217,7 +210,7 @@ namespace Terminal.Gui.Graphs { var runeType = GetRuneTypeForIntersects (intersects); - if(runeResolvers.ContainsKey (runeType)) { + if (runeResolvers.ContainsKey (runeType)) { return runeResolvers [runeType].GetRuneForIntersects (driver, intersects); } @@ -228,13 +221,13 @@ namespace Terminal.Gui.Graphs { // TODO: maybe make these resolvers to for simplicity? // or for dotted lines later on or that kind of thing? switch (runeType) { - case IntersectionRuneType.None: + case IntersectionRuneType.None: return null; - case IntersectionRuneType.Dot: + case IntersectionRuneType.Dot: return (Rune)'.'; - case IntersectionRuneType.HLine: + case IntersectionRuneType.HLine: return useDouble ? driver.HDLine : driver.HLine; - case IntersectionRuneType.VLine: + case IntersectionRuneType.VLine: return useDouble ? driver.VDLine : driver.VLine; default: throw new Exception ("Could not find resolver or switch case for " + nameof (runeType) + ":" + runeType); } @@ -243,7 +236,7 @@ namespace Terminal.Gui.Graphs { private IntersectionRuneType GetRuneTypeForIntersects (IntersectionDefinition [] intersects) { - if(intersects.All(i=>i.Line.Length == 0)) { + if (intersects.All (i => i.Line.Length == 0)) { return IntersectionRuneType.Dot; } diff --git a/UnitTests/Core/LineCanvasTests.cs b/UnitTests/Core/LineCanvasTests.cs index a56738c72..f6c38c9e3 100644 --- a/UnitTests/Core/LineCanvasTests.cs +++ b/UnitTests/Core/LineCanvasTests.cs @@ -60,7 +60,7 @@ namespace Terminal.Gui.CoreTests { } [InlineData (BorderStyle.Single)] - [InlineData(BorderStyle.Rounded)] + [InlineData (BorderStyle.Rounded)] [Theory, AutoInitShutdown] public void TestLineCanvas_Vertical (BorderStyle style) { @@ -96,7 +96,7 @@ namespace Terminal.Gui.CoreTests { /// Not when they terminate adjacent to one another. /// [Fact, AutoInitShutdown] - public void TestLineCanvas_Corner_NoOverlap() + public void TestLineCanvas_Corner_NoOverlap () { var v = GetCanvas (out var canvas); canvas.AddLine (new Point (0, 0), 1, Orientation.Horizontal, BorderStyle.Single); @@ -130,14 +130,14 @@ namespace Terminal.Gui.CoreTests { │ │"; TestHelpers.AssertDriverContentsAre (looksLike, output); - + } - [Fact,AutoInitShutdown] + [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); @@ -172,10 +172,10 @@ namespace Terminal.Gui.CoreTests { // 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, 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); @@ -224,8 +224,8 @@ namespace Terminal.Gui.CoreTests { [Theory, AutoInitShutdown] - [InlineData(BorderStyle.Single)] - [InlineData(BorderStyle.Rounded)] + [InlineData (BorderStyle.Single)] + [InlineData (BorderStyle.Rounded)] public void TestLineCanvas_Window_DoubleTop_SingleSides (BorderStyle thinStyle) { var v = GetCanvas (out var canvas); @@ -237,7 +237,7 @@ namespace Terminal.Gui.CoreTests { canvas.AddLine (new Point (0, 4), -4, Orientation.Vertical, thinStyle); - canvas.AddLine (new Point (5, 0), 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); @@ -254,8 +254,8 @@ namespace Terminal.Gui.CoreTests { } [Theory, AutoInitShutdown] - [InlineData(BorderStyle.Single)] - [InlineData(BorderStyle.Rounded)] + [InlineData (BorderStyle.Single)] + [InlineData (BorderStyle.Rounded)] public void TestLineCanvas_Window_SingleTop_DoubleSides (BorderStyle thinStyle) { var v = GetCanvas (out var canvas); @@ -263,8 +263,8 @@ namespace Terminal.Gui.CoreTests { // 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 (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); @@ -286,24 +286,24 @@ namespace Terminal.Gui.CoreTests { [Theory, AutoInitShutdown] - [InlineData(0,0,@" + [InlineData (0, 0, @" ═══ ══ ═══")] - [InlineData (1, 0,@" + [InlineData (1, 0, @" ══ ═ ══")] - [InlineData (2, 0,@" + [InlineData (2, 0, @" ═ ═")] - [InlineData (0, 1,@" + [InlineData (0, 1, @" ══ ═══")] - [InlineData (0, 2,@" + [InlineData (0, 2, @" ═══")] - public void TestLineCanvasRenderOffset_NoOffset (int xOffset,int yOffset, string expect) + public void TestLineCanvasRenderOffset_NoOffset (int xOffset, int yOffset, string expect) { var canvas = new LineCanvas (); canvas.AddLine (new Point (0, 0), 2, Orientation.Horizontal, BorderStyle.Double); @@ -338,8 +338,8 @@ namespace Terminal.Gui.CoreTests { Bounds = new Rect (0, 0, 10, 5) }; - var canvasCopy = canvas = new LineCanvas (); - v.DrawContentComplete += (r)=> canvasCopy.Draw (v, v.Bounds); + var canvasCopy = canvas = new LineCanvas (); + v.DrawContentComplete += (r) => canvasCopy.Draw (v, v.Bounds); return v; } From 319fb8a3d498e46c83e176e8d9ad6f0c616a0a07 Mon Sep 17 00:00:00 2001 From: tznind Date: Mon, 13 Feb 2023 08:09:37 +0000 Subject: [PATCH 3/5] Add TestLineCanvas_PositiveLocation --- Terminal.Gui/Core/Graphs/LineCanvas.cs | 9 ++++-- UnitTests/Core/LineCanvasTests.cs | 41 ++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/Terminal.Gui/Core/Graphs/LineCanvas.cs b/Terminal.Gui/Core/Graphs/LineCanvas.cs index 7009c5b71..ef5de3922 100644 --- a/Terminal.Gui/Core/Graphs/LineCanvas.cs +++ b/Terminal.Gui/Core/Graphs/LineCanvas.cs @@ -89,12 +89,15 @@ namespace Terminal.Gui.Graphs { { var runes = GenerateImage (bounds); - for (int y = bounds.Y; y < bounds.Height; y++) { - for (int x = bounds.X; x < bounds.Width; x++) { + var runeRows = runes.GetLength (0); + var runeCols = runes.GetLength (1); + + for (int y = 0; y < runeRows; y++) { + for (int x = 0; x < runeCols; x++) { var rune = runes [y, x]; if (rune.HasValue) { - view.AddRune (x, y, rune.Value); + view.AddRune (bounds.X + x, bounds.Y + y, rune.Value); } } } diff --git a/UnitTests/Core/LineCanvasTests.cs b/UnitTests/Core/LineCanvasTests.cs index f6c38c9e3..723f202ff 100644 --- a/UnitTests/Core/LineCanvasTests.cs +++ b/UnitTests/Core/LineCanvasTests.cs @@ -284,6 +284,35 @@ namespace Terminal.Gui.CoreTests { TestHelpers.AssertDriverContentsAre (looksLike, output); } + [Fact, AutoInitShutdown] + public void TestLineCanvas_PositiveLocation () + { + var x = 1; + var y = 1; + var v = GetCanvas (out var canvas, x, y); + + // outer box + canvas.AddLine (new Point (x, y), 9, Orientation.Horizontal, BorderStyle.Single); + canvas.AddLine (new Point (x + 9, y + 0), 4, Orientation.Vertical, BorderStyle.Single); + canvas.AddLine (new Point (x + 9, y + 4), -9, Orientation.Horizontal, BorderStyle.Single); + canvas.AddLine (new Point (x + 0, y + 4), -4, Orientation.Vertical, BorderStyle.Single); + + + canvas.AddLine (new Point (x + 5, y + 0), 4, Orientation.Vertical, BorderStyle.Single); + canvas.AddLine (new Point (x + 0, y + 2), 9, Orientation.Horizontal, BorderStyle.Single); + + v.Redraw (v.Bounds); + + string looksLike = +@" + + ┌────┬───┐ + │ │ │ + ├────┼───┤ + │ │ │ + └────┴───┘"; + TestHelpers.AssertDriverContentsAre (looksLike, output); + } [Theory, AutoInitShutdown] [InlineData (0, 0, @" @@ -330,12 +359,20 @@ namespace Terminal.Gui.CoreTests { } - private View GetCanvas (out LineCanvas canvas) + /// + /// Creates a new into which a is rendered + /// at time. + /// + /// The you can draw into. + /// How far to offset the in X + /// How far to offset the 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) + Bounds = new Rect (offsetX, offsetY, 10, 5) }; var canvasCopy = canvas = new LineCanvas (); From 90a6c2c34c97c923b46fbfd55a0d3890ee64c235 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 13 Feb 2023 22:08:05 +0000 Subject: [PATCH 4/5] Support for drawing at an offset within client area --- Terminal.Gui/Core/Graphs/LineCanvas.cs | 17 +++++++---- UnitTests/Core/LineCanvasTests.cs | 40 ++++++++++++-------------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/Terminal.Gui/Core/Graphs/LineCanvas.cs b/Terminal.Gui/Core/Graphs/LineCanvas.cs index ef5de3922..dcbf7f2a7 100644 --- a/Terminal.Gui/Core/Graphs/LineCanvas.cs +++ b/Terminal.Gui/Core/Graphs/LineCanvas.cs @@ -79,15 +79,20 @@ namespace Terminal.Gui.Graphs { } /// - /// Draws all the lines that lie within the onto - /// the client area. This method should be called from + /// Draws all the lines that lie within the onto + /// the client area at given . + /// This method should be called from /// . /// /// - /// - public void Draw (View view, Rect bounds) + /// The area of the canvas to draw. + /// The point within the client area of + /// to draw at. + public void Draw (View view, Rect sourceRect, Point? drawOffset = null) { - var runes = GenerateImage (bounds); + var offset = drawOffset ?? Point.Empty; + + var runes = GenerateImage (sourceRect); var runeRows = runes.GetLength (0); var runeCols = runes.GetLength (1); @@ -97,7 +102,7 @@ namespace Terminal.Gui.Graphs { var rune = runes [y, x]; if (rune.HasValue) { - view.AddRune (bounds.X + x, bounds.Y + y, rune.Value); + view.AddRune (offset.X + x, offset.Y + y, rune.Value); } } } diff --git a/UnitTests/Core/LineCanvasTests.cs b/UnitTests/Core/LineCanvasTests.cs index 723f202ff..77055ad54 100644 --- a/UnitTests/Core/LineCanvasTests.cs +++ b/UnitTests/Core/LineCanvasTests.cs @@ -285,32 +285,30 @@ namespace Terminal.Gui.CoreTests { } [Fact, AutoInitShutdown] - public void TestLineCanvas_PositiveLocation () + public void TestLineCanvas_LeaveMargin_Top1_Left1 () { - var x = 1; - var y = 1; - var v = GetCanvas (out var canvas, x, y); + // 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 (x, y), 9, Orientation.Horizontal, BorderStyle.Single); - canvas.AddLine (new Point (x + 9, y + 0), 4, Orientation.Vertical, BorderStyle.Single); - canvas.AddLine (new Point (x + 9, y + 4), -9, Orientation.Horizontal, BorderStyle.Single); - canvas.AddLine (new Point (x + 0, y + 4), -4, Orientation.Vertical, BorderStyle.Single); + 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 (x + 5, y + 0), 4, Orientation.Vertical, BorderStyle.Single); - canvas.AddLine (new Point (x + 0, y + 2), 9, Orientation.Horizontal, 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); } @@ -364,19 +362,19 @@ namespace Terminal.Gui.CoreTests { /// at time. /// /// The you can draw into. - /// How far to offset the in X - /// How far to offset the in Y + /// 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 (offsetX, offsetY, 10, 5) + Bounds = new Rect (0, 0, 10, 5) }; var canvasCopy = canvas = new LineCanvas (); - v.DrawContentComplete += (r) => canvasCopy.Draw (v, v.Bounds); + v.DrawContentComplete += (r) => canvasCopy.Draw (v, v.Bounds, new Point(offsetX,offsetY)); return v; } From 85a44710048901399e1911d48732e33d0594e1a2 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 14 Feb 2023 22:11:18 +0000 Subject: [PATCH 5/5] Remove the Draw method from LineCanvas and make GenerateImage easier to use --- Terminal.Gui/Core/Graphs/LineCanvas.cs | 53 +++++++------------------ UICatalog/Scenarios/LineDrawing.cs | 15 ++++++- UnitTests/Core/LineCanvasTests.cs | 54 +++++--------------------- 3 files changed, 36 insertions(+), 86 deletions(-) diff --git a/Terminal.Gui/Core/Graphs/LineCanvas.cs b/Terminal.Gui/Core/Graphs/LineCanvas.cs index dcbf7f2a7..1b1cbe76b 100644 --- a/Terminal.Gui/Core/Graphs/LineCanvas.cs +++ b/Terminal.Gui/Core/Graphs/LineCanvas.cs @@ -48,64 +48,39 @@ namespace Terminal.Gui.Graphs { } /// /// Evaluate all currently defined lines that lie within - /// and generate a 'bitmap' that + /// and map that /// shows what characters (if any) should be rendered at each /// point so that all lines connect up correctly with appropriate /// intersection symbols. /// /// /// - /// Map as 2D array where first index is rows and second is column - public Rune? [,] GenerateImage (Rect inArea) + /// Mapping of all the points within to + /// line or intersection runes which should be drawn there. + public Dictionary GenerateImage (Rect inArea) { - Rune? [,] canvas = new Rune? [inArea.Height, inArea.Width]; + var map = new Dictionary(); // walk through each pixel of the bitmap - for (int y = 0; y < inArea.Height; y++) { - for (int x = 0; x < inArea.Width; x++) { + for (int y = inArea.Y; y < inArea.Height; y++) { + for (int x = inArea.X; x < inArea.Width; x++) { var intersects = lines - .Select (l => l.Intersects (inArea.X + x, inArea.Y + y)) + .Select (l => l.Intersects (x, y)) .Where (i => i != null) .ToArray (); // TODO: use Driver and LineStyle to map - canvas [y, x] = GetRuneForIntersects (Application.Driver, intersects); + var rune = GetRuneForIntersects (Application.Driver, intersects); - } - } - - return canvas; - } - - /// - /// Draws all the lines that lie within the onto - /// the client area at given . - /// This method should be called from - /// . - /// - /// - /// The area of the canvas to draw. - /// The point within the client area of - /// to draw at. - public void Draw (View view, Rect sourceRect, Point? drawOffset = null) - { - var offset = drawOffset ?? Point.Empty; - - var runes = GenerateImage (sourceRect); - - var runeRows = runes.GetLength (0); - var runeCols = runes.GetLength (1); - - for (int y = 0; y < runeRows; y++) { - for (int x = 0; x < runeCols; x++) { - var rune = runes [y, x]; - - if (rune.HasValue) { - view.AddRune (offset.X + x, offset.Y + y, rune.Value); + if(rune != null) + { + map.Add(new Point(x,y),rune.Value); } } } + + return map; } private abstract class IntersectionRuneResolver { diff --git a/UICatalog/Scenarios/LineDrawing.cs b/UICatalog/Scenarios/LineDrawing.cs index f3adac86d..f5670c0c4 100644 --- a/UICatalog/Scenarios/LineDrawing.cs +++ b/UICatalog/Scenarios/LineDrawing.cs @@ -71,7 +71,12 @@ namespace UICatalog.Scenarios { base.Redraw (bounds); Driver.SetAttribute (new Terminal.Gui.Attribute (Color.DarkGray, ColorScheme.Normal.Background)); - grid.Draw (this, bounds); + + + foreach(var p in grid.GenerateImage(bounds)) + { + this.AddRune(p.Key.X,p.Key.Y,p.Value); + } foreach (var swatch in swatches) { Driver.SetAttribute (new Terminal.Gui.Attribute (swatch.Value, ColorScheme.Normal.Background)); @@ -151,7 +156,13 @@ namespace UICatalog.Scenarios { foreach (var kvp in colorLayers) { Driver.SetAttribute (new Terminal.Gui.Attribute (kvp.Key, ColorScheme.Normal.Background)); - canvases [kvp.Value].Draw (this, bounds); + + var canvas = canvases [kvp.Value]; + + foreach(var p in canvas.GenerateImage(bounds)) + { + this.AddRune(p.Key.X,p.Key.Y,p.Value); + } } } public override bool OnMouseEvent (MouseEvent mouseEvent) diff --git a/UnitTests/Core/LineCanvasTests.cs b/UnitTests/Core/LineCanvasTests.cs index 77055ad54..65bc1f3a2 100644 --- a/UnitTests/Core/LineCanvasTests.cs +++ b/UnitTests/Core/LineCanvasTests.cs @@ -312,50 +312,6 @@ namespace Terminal.Gui.CoreTests { TestHelpers.AssertDriverContentsAre (looksLike, output); } - [Theory, AutoInitShutdown] - [InlineData (0, 0, @" -═══ -══ -═══")] - [InlineData (1, 0, @" -══ -═ -══")] - [InlineData (2, 0, @" -═ - -═")] - [InlineData (0, 1, @" -══ -═══")] - [InlineData (0, 2, @" -═══")] - public void TestLineCanvasRenderOffset_NoOffset (int xOffset, int yOffset, string expect) - { - var canvas = new LineCanvas (); - canvas.AddLine (new Point (0, 0), 2, Orientation.Horizontal, BorderStyle.Double); - canvas.AddLine (new Point (0, 1), 1, Orientation.Horizontal, BorderStyle.Double); - canvas.AddLine (new Point (0, 2), 2, Orientation.Horizontal, BorderStyle.Double); - - var bmp = canvas.GenerateImage (new Rect (xOffset, yOffset, 3, 3)); - var actual = BmpToString (bmp); - Assert.Equal (expect.TrimStart (), actual); - - } - - private string BmpToString (System.Rune? [,] bmp) - { - var sb = new StringBuilder (); - for (int y = 0; y < bmp.GetLength (1); y++) { - for (int x = 0; x < bmp.GetLength (0); x++) { - sb.Append (bmp [y, x]); - } - sb.AppendLine (); - } - - return sb.ToString ().TrimEnd (); - } - /// /// Creates a new into which a is rendered @@ -374,7 +330,15 @@ namespace Terminal.Gui.CoreTests { }; var canvasCopy = canvas = new LineCanvas (); - v.DrawContentComplete += (r) => canvasCopy.Draw (v, v.Bounds, new Point(offsetX,offsetY)); + 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; }