diff --git a/Terminal.Gui/Core/Border.cs b/Terminal.Gui/Core/Border.cs index 55d73a65c..e06870a4a 100644 --- a/Terminal.Gui/Core/Border.cs +++ b/Terminal.Gui/Core/Border.cs @@ -1,5 +1,6 @@ using NStack; using System; +using Terminal.Gui.Graphs; namespace Terminal.Gui { /// @@ -707,14 +708,20 @@ namespace Terminal.Gui { // Draw the MarginFrame if (DrawMarginFrame) { - var rect = new Rect () { - X = frame.X - drawMarginFrame, - Y = frame.Y - drawMarginFrame, - Width = frame.Width + (2 * drawMarginFrame), - Height = frame.Height + (2 * drawMarginFrame) - }; + var rect = Child.ViewToScreen (new Rect (-1, -1, Child.Frame.Width + 2, Child.Frame.Height + 2)); if (rect.Width > 0 && rect.Height > 0) { - driver.DrawWindowFrame (rect, 1, 1, 1, 1, BorderStyle != BorderStyle.None, fill, this); + + var lc = new LineCanvas (); + + lc.AddLine (rect.Location, rect.Width, Orientation.Horizontal, BorderStyle); + lc.AddLine (rect.Location, rect.Height, Orientation.Vertical, BorderStyle); + + lc.AddLine (new Point (rect.X, rect.Y + rect.Height), rect.Width, Orientation.Horizontal, BorderStyle); + lc.AddLine (new Point (rect.X + rect.Width, rect.Y), rect.Height, Orientation.Vertical, BorderStyle); + + driver.SetAttribute (new Attribute(Color.Red, Color.BrightYellow)); + + lc.Draw (null, rect); DrawTitle (Child); } } diff --git a/Terminal.Gui/Core/Graphs/LineCanvas.cs b/Terminal.Gui/Core/Graphs/LineCanvas.cs index ab45c0264..ed93dc22f 100644 --- a/Terminal.Gui/Core/Graphs/LineCanvas.cs +++ b/Terminal.Gui/Core/Graphs/LineCanvas.cs @@ -48,24 +48,24 @@ namespace Terminal.Gui.Graphs { } /// /// Evaluate all currently defined lines that lie within - /// and generate a 'bitmap' that + /// and generate a 'bitmap' 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) + public Rune? [,] GenerateImage (Rect bounds) { - Rune? [,] canvas = new Rune? [inArea.Height, inArea.Width]; + Rune? [,] canvas = new Rune? [bounds.Height, bounds.Width]; // 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 = 0; y < bounds.Height; y++) { + for (int x = 0; x < bounds.Width; x++) { var intersects = lines - .Select (l => l.Intersects (x, y)) + .Select (l => l.Intersects (bounds.X + x, bounds.Y + y)) .Where (i => i != null) .ToArray (); @@ -88,13 +88,18 @@ namespace Terminal.Gui.Graphs { public void Draw (View view, Rect bounds) { var runes = GenerateImage (bounds); - - for (int y = bounds.Y; y < bounds.Height; y++) { - for (int x = bounds.X; x < bounds.Width; x++) { - var rune = runes [y, x]; + + for (int y = bounds.Y; y < bounds.Y + bounds.Height; y++) { + for (int x = bounds.X; x < bounds.X + bounds.Width; x++) { + var rune = runes [y - bounds.Y, x - bounds.X]; if (rune.HasValue) { - view.AddRune (x, y, rune.Value); + if (view != null) { + view.AddRune (x - bounds.X, y - bounds.Y, rune.Value); + } else { + Application.Driver.Move (x, y); + Application.Driver.AddRune (rune.Value); + } } } } diff --git a/Terminal.Gui/Views/FrameView.cs b/Terminal.Gui/Views/FrameView.cs index 072d2a70a..4071a0448 100644 --- a/Terminal.Gui/Views/FrameView.cs +++ b/Terminal.Gui/Views/FrameView.cs @@ -252,14 +252,14 @@ namespace Terminal.Gui { lc.AddLine (new Point (bounds.Width - 1, bounds.Height - 1), -bounds.Height + 1, Orientation.Vertical, Border.BorderStyle); } - foreach (var subview in contentView.Subviews) { - lc.AddLine (new Point (subview.Frame.X + 1, subview.Frame.Y + 1), subview.Frame.Width - 1, Orientation.Horizontal, subview.Border.BorderStyle); - lc.AddLine (new Point (subview.Frame.X + 1, subview.Frame.Y + 1), subview.Frame.Height - 1, Orientation.Vertical, subview.Border.BorderStyle); + //foreach (var subview in contentView.Subviews) { + // lc.AddLine (new Point (subview.Frame.X + 1, subview.Frame.Y + 1), subview.Frame.Width - 1, Orientation.Horizontal, subview.Border.BorderStyle); + // lc.AddLine (new Point (subview.Frame.X + 1, subview.Frame.Y + 1), subview.Frame.Height - 1, Orientation.Vertical, subview.Border.BorderStyle); - lc.AddLine (new Point (subview.Frame.X + subview.Frame.Width, subview.Frame.Y + subview.Frame.Height), -subview.Frame.Width + 1, Orientation.Horizontal, subview.Border.BorderStyle); - lc.AddLine (new Point (subview.Frame.X + subview.Frame.Width, subview.Frame.Y + subview.Frame.Height), -subview.Frame.Height + 1, Orientation.Vertical, subview.Border.BorderStyle); + // lc.AddLine (new Point (subview.Frame.X + subview.Frame.Width, subview.Frame.Y + subview.Frame.Height), -subview.Frame.Width + 1, Orientation.Horizontal, subview.Border.BorderStyle); + // lc.AddLine (new Point (subview.Frame.X + subview.Frame.Width, subview.Frame.Y + subview.Frame.Height), -subview.Frame.Height + 1, Orientation.Vertical, subview.Border.BorderStyle); - } + //} Driver.SetAttribute (ColorScheme.Normal); lc.Draw (this, bounds); diff --git a/UICatalog/Scenarios/TileViewExperiment.cs b/UICatalog/Scenarios/TileViewExperiment.cs index eeca74535..931b6ddce 100644 --- a/UICatalog/Scenarios/TileViewExperiment.cs +++ b/UICatalog/Scenarios/TileViewExperiment.cs @@ -32,78 +32,85 @@ namespace UICatalog.Scenarios { Y = 1, Width = Dim.Fill (), Height = Dim.Fill (), - IgnoreBorderPropertyOnRedraw = true + //IgnoreBorderPropertyOnRedraw = true }; frame.Border.BorderStyle = BorderStyle.Double; Application.Top.Add (frame); - var view1 = new FrameView () { - Title = "View 1", + var view1 = new View () { + //Title = "View 1", Text = "View1 30%/50% Single", - X = -1, - Y = -1, - Width = Dim.Percent (30), - Height = Dim.Percent (50), + X = 5, + Y = 5, + Width = Dim.Percent (30) - 5, + Height = Dim.Percent (50) - 5, ColorScheme = Colors.ColorSchemes ["Dialog"], - Border = new Border () { BorderStyle = BorderStyle.Single } + Border = new Border () { + BorderStyle = BorderStyle.Single, + //BorderThickness = new Thickness (1), + DrawMarginFrame = true, + //Padding = new Thickness(1), + BorderBrush = Color.BrightMagenta, + Title = "Border Title" + } }; frame.Add (view1); //var view12splitter = new SplitterEventArgs - var view2 = new FrameView () { - Title = "View 2", - Text = "View2 right of view1, 30%/70% Single.", - X = Pos.Right (view1) - 1, - Y = -1, - Width = Dim.Percent (30), - Height = Dim.Percent (70), - ColorScheme = Colors.ColorSchemes ["Error"], - Border = new Border () { BorderStyle = BorderStyle.Single } - }; + //var view2 = new FrameView () { + // Title = "View 2", + // Text = "View2 right of view1, 30%/70% Single.", + // X = Pos.Right (view1) - 1, + // Y = -1, + // Width = Dim.Percent (30), + // Height = Dim.Percent (70), + // ColorScheme = Colors.ColorSchemes ["Error"], + // Border = new Border () { BorderStyle = BorderStyle.Single } + //}; - frame.Add (view2); + //frame.Add (view2); - var view3 = new FrameView () { - Title = "View 3", - Text = "View3 right of View2 Fill/Fill Single", - X = Pos.Right (view2) - 1, - Y = -1, - Width = Dim.Fill (-1), - Height = Dim.Fill (-1), - ColorScheme = Colors.ColorSchemes ["Menu"], - Border = new Border () { BorderStyle = BorderStyle.Single } - }; + //var view3 = new FrameView () { + // Title = "View 3", + // Text = "View3 right of View2 Fill/Fill Single", + // X = Pos.Right (view2) - 1, + // Y = -1, + // Width = Dim.Fill (-1), + // Height = Dim.Fill (-1), + // ColorScheme = Colors.ColorSchemes ["Menu"], + // Border = new Border () { BorderStyle = BorderStyle.Single } + //}; - frame.Add (view3); + //frame.Add (view3); - var view4 = new FrameView () { - Title = "View 4", - Text = "View4 below View2 view2.Width/5 Single", - X = Pos.Left (view2), - Y = Pos.Bottom (view2) - 1, - Width = view2.Width, - Height = 5, - ColorScheme = Colors.ColorSchemes ["TopLevel"], - Border = new Border () { BorderStyle = BorderStyle.Single } - }; + //var view4 = new FrameView () { + // Title = "View 4", + // Text = "View4 below View2 view2.Width/5 Single", + // X = Pos.Left (view2), + // Y = Pos.Bottom (view2) - 1, + // Width = view2.Width, + // Height = 5, + // ColorScheme = Colors.ColorSchemes ["TopLevel"], + // Border = new Border () { BorderStyle = BorderStyle.Single } + //}; - frame.Add (view4); + //frame.Add (view4); - var view5 = new FrameView () { - Title = "View 5", - Text = "View5 below View4 view4.Width/5 Double", - X = Pos.Left (view2), - Y = Pos.Bottom (view4) - 1, - Width = view4.Width, - Height = 5, - ColorScheme = Colors.ColorSchemes ["TopLevel"], - Border = new Border () { BorderStyle = BorderStyle.Double } - }; + //var view5 = new FrameView () { + // Title = "View 5", + // Text = "View5 below View4 view4.Width/5 Double", + // X = Pos.Left (view2), + // Y = Pos.Bottom (view4) - 1, + // Width = view4.Width, + // Height = 5, + // ColorScheme = Colors.ColorSchemes ["TopLevel"], + // Border = new Border () { BorderStyle = BorderStyle.Double } + //}; - frame.Add (view5); + //frame.Add (view5); } } } \ No newline at end of file diff --git a/UnitTests/Core/LineCanvasTests.cs b/UnitTests/Core/LineCanvasTests.cs index 7e988b0de..8e20cfda9 100644 --- a/UnitTests/Core/LineCanvasTests.cs +++ b/UnitTests/Core/LineCanvasTests.cs @@ -57,7 +57,7 @@ namespace Terminal.Gui.CoreTests { } [InlineData (BorderStyle.Single)] - [InlineData(BorderStyle.Rounded)] + [InlineData (BorderStyle.Rounded)] [Theory, AutoInitShutdown] public void TestLineCanvas_Vertical (BorderStyle style) { @@ -93,7 +93,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); @@ -127,13 +127,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); @@ -156,6 +157,36 @@ 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); + } + /// /// Demonstrates when corners are used. Notice how /// not all lines declare rounded. If there are 1+ lines intersecting and a corner is @@ -168,10 +199,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); @@ -220,8 +251,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); @@ -233,7 +264,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); @@ -250,8 +281,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); @@ -259,8 +290,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); @@ -280,16 +311,16 @@ namespace Terminal.Gui.CoreTests { TestHelpers.AssertDriverContentsAre (looksLike, output); } - private View GetCanvas (out LineCanvas canvas) + private View GetCanvas (out LineCanvas canvas, int x = 0, int y = 0) { var v = new View { Width = 10, Height = 5, - Bounds = new Rect (0, 0, 10, 5) + Bounds = new Rect (x, y, 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; }