From bb5c89986420bcb12a0b01bf4e8a21ae43a6d3c5 Mon Sep 17 00:00:00 2001 From: Tig Date: Wed, 6 Mar 2024 09:44:21 -0700 Subject: [PATCH] cherry picked from old branch --- Terminal.Gui/View/Adornment/Adornment.cs | 7 +- Terminal.Gui/View/Layout/ViewLayout.cs | 33 +- Terminal.Gui/Views/TileView.cs | 2 +- UnitTests/View/Adornment/ToScreenTests.cs | 502 ++++++++++++++++++++++ UnitTests/View/Layout/ToScreenTests.cs | 454 +++++++++++++++++++ 5 files changed, 968 insertions(+), 30 deletions(-) create mode 100644 UnitTests/View/Adornment/ToScreenTests.cs create mode 100644 UnitTests/View/Layout/ToScreenTests.cs diff --git a/Terminal.Gui/View/Adornment/Adornment.cs b/Terminal.Gui/View/Adornment/Adornment.cs index 26b9043bf..bd76ee214 100644 --- a/Terminal.Gui/View/Adornment/Adornment.cs +++ b/Terminal.Gui/View/Adornment/Adornment.cs @@ -83,18 +83,17 @@ public class Adornment : View } /// - public override void BoundsToScreen (int col, int row, out int rcol, out int rrow) + public override Rectangle BoundsToScreen (Rectangle bounds) { // Adornments are *Children* of a View, not SubViews. Thus View.BoundsToScreen will not work. // To get the screen-relative coordinates of a Adornment, we need to know who // the Parent is Rectangle parentFrame = Parent?.Frame ?? Frame; - rrow = row + parentFrame.Y; - rcol = col + parentFrame.X; + bounds.Offset (parentFrame.X, parentFrame.Y); // We now have rcol/rrow in coordinates relative to our View's SuperView. If our View's SuperView has // a SuperView, keep going... - Parent?.SuperView?.BoundsToScreen (rcol, rrow, out rcol, out rrow); + return Parent?.SuperView?.BoundsToScreen (bounds) ?? bounds; } /// diff --git a/Terminal.Gui/View/Layout/ViewLayout.cs b/Terminal.Gui/View/Layout/ViewLayout.cs index a88cbbdb8..20cea94b4 100644 --- a/Terminal.Gui/View/Layout/ViewLayout.cs +++ b/Terminal.Gui/View/Layout/ViewLayout.cs @@ -498,39 +498,22 @@ public partial class View /// public event EventHandler Initialized; - /// Converts a -relative region to a screen-relative region. - public Rectangle BoundsToScreen (Rectangle region) + /// Converts a -relative rectangle to a screen-relative rectangle. + public virtual Rectangle BoundsToScreen (Rectangle bounds) { - BoundsToScreen (region.X, region.Y, out int screenX, out int screenY); - - return region with { X = screenX, Y = screenY }; - } - - /// - /// Converts a -relative coordinate to a screen-relative coordinate. The output is optionally - /// clamped to the screen dimensions. - /// - /// -relative column. - /// -relative row. - /// Absolute column; screen-relative. - /// Absolute row; screen-relative. - public virtual void BoundsToScreen (int x, int y, out int rx, out int ry) - { - // PERF: Use Point.Offset - // Already dealing with Point here. Point boundsOffset = GetBoundsOffset (); - rx = x + Frame.X + boundsOffset.X; - ry = y + Frame.Y + boundsOffset.Y; + bounds.Offset(Frame.X + boundsOffset.X, Frame.Y + boundsOffset.Y); View super = SuperView; while (super is { }) { boundsOffset = super.GetBoundsOffset (); - rx += super.Frame.X + boundsOffset.X; - ry += super.Frame.Y + boundsOffset.Y; + bounds.Offset(super.Frame.X + boundsOffset.X, super.Frame.Y + boundsOffset.Y); super = super.SuperView; } + + return bounds; } #nullable enable @@ -626,7 +609,7 @@ public partial class View int right = Margin.Thickness.Right + Border.Thickness.Right + Padding.Thickness.Right; int bottom = Margin.Thickness.Bottom + Border.Thickness.Bottom + Padding.Thickness.Bottom; - return new Thickness (left, top, right, bottom); + return new (left, top, right, bottom); } /// @@ -635,7 +618,7 @@ public partial class View /// public Point GetBoundsOffset () { - return new Point ( + return new ( Padding?.Thickness.GetInside (Padding.Frame).X ?? 0, Padding?.Thickness.GetInside (Padding.Frame).Y ?? 0 ); diff --git a/Terminal.Gui/Views/TileView.cs b/Terminal.Gui/Views/TileView.cs index d32827243..20a7b30e9 100644 --- a/Terminal.Gui/Views/TileView.cs +++ b/Terminal.Gui/Views/TileView.cs @@ -217,7 +217,7 @@ public class TileView : View { bool isRoot = _splitterLines.Contains (line); - Rectangle screen = line.BoundsToScreen (new (new (0, 0), Size.Empty)); + Rectangle screen = line.BoundsToScreen (Rectangle.Empty); Point origin = ScreenToFrame (screen.X, screen.Y); int length = line.Orientation == Orientation.Horizontal ? line.Frame.Width : line.Frame.Height; diff --git a/UnitTests/View/Adornment/ToScreenTests.cs b/UnitTests/View/Adornment/ToScreenTests.cs new file mode 100644 index 000000000..4b05783cc --- /dev/null +++ b/UnitTests/View/Adornment/ToScreenTests.cs @@ -0,0 +1,502 @@ +using Xunit.Abstractions; + +namespace Terminal.Gui.ViewTests; + +/// +/// Test the and methods. +/// DOES NOT TEST View.xxxToScreen methods. Those are in ./View/Layout/ToScreenTests.cs +/// +/// +public class AdornmentToScreenTests (ITestOutputHelper output) +{ + private readonly ITestOutputHelper _output = output; + + [Theory] + [InlineData (0, 0)] + [InlineData (1, 1)] + [InlineData (-1, -1)] + [InlineData (11, 11)] + public void FrameToScreen_NoSuperView_WithoutAdornments (int x, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (x, 0, 10, 10); + + var view = new View (); + view.Frame = frame; + + // Act + var marginScreen = view.Margin.FrameToScreen(); + var borderScreen = view.Border.FrameToScreen (); + var paddingScreen = view.Padding.FrameToScreen (); + + // Assert + Assert.Equal(expectedX, marginScreen.X); + Assert.Equal (expectedX, borderScreen.X); + Assert.Equal (expectedX, paddingScreen.X); + } + + [Theory] + [InlineData (0, 0)] + [InlineData (1, 1)] + [InlineData (-1, -1)] + [InlineData (11, 11)] + public void FrameToScreen_NoSuperView_WithAdornments (int x, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (x, 0, 10, 10); + + var view = new View (); + view.Border.Thickness = new (1); + view.Frame = frame; + + // Act + var marginScreen = view.Margin.FrameToScreen (); + var borderScreen = view.Border.FrameToScreen (); + var paddingScreen = view.Padding.FrameToScreen (); + + // Assert + Assert.Equal (expectedX, marginScreen.X); + Assert.Equal (expectedX + view.Margin.Thickness.Left, borderScreen.X); + Assert.Equal (expectedX + view.Border.Thickness.Left, paddingScreen.X); + } + + [Theory] + [InlineData (0, 0)] + [InlineData (1, 1)] + [InlineData (-1, -1)] + [InlineData (11, 11)] + public void FrameToScreen_SuperView_WithoutAdornments (int x, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (x, 0, 10, 10); + + var superView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + + var view = new View (); + view.Frame = frame; + + superView.Add (view); + superView.LayoutSubviews (); + + // Act + var marginScreen = view.Margin.FrameToScreen (); + var borderScreen = view.Border.FrameToScreen (); + var paddingScreen = view.Padding.FrameToScreen (); + + // Assert + Assert.Equal (expectedX, marginScreen.X); + Assert.Equal (expectedX + view.Margin.Thickness.Left, borderScreen.X); + Assert.Equal (expectedX + view.Border.Thickness.Left, paddingScreen.X); + } + + [Theory] + [InlineData (0, 1)] + [InlineData (1, 2)] + [InlineData (-1, 0)] + [InlineData (11, 12)] + public void FrameToScreen_SuperView_WithAdornments (int x, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (x, 0, 10, 10); + + var superView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + superView.Border.Thickness = new (1); + + var view = new View (); + view.Frame = frame; + + superView.Add (view); + superView.LayoutSubviews (); + + // Act + var marginScreen = view.Margin.FrameToScreen (); + var borderScreen = view.Border.FrameToScreen (); + var paddingScreen = view.Padding.FrameToScreen (); + + // Assert + Assert.Equal (expectedX, marginScreen.X); + Assert.Equal (expectedX + view.Margin.Thickness.Left, borderScreen.X); + Assert.Equal (expectedX + view.Border.Thickness.Left, paddingScreen.X); + } + + [Theory] + [InlineData (0, 0)] + [InlineData (1, 1)] + [InlineData (-1, -1)] + [InlineData (11, 11)] + public void FrameToScreen_NestedSuperView_WithoutAdornments (int x, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (x, 0, 10, 10); + + var superSuperView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + + var superView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + + superSuperView.Add (superView); + + var view = new View (); + view.Frame = frame; + + superView.Add (view); + superView.LayoutSubviews (); + + // Act + var marginScreen = view.Margin.FrameToScreen (); + var borderScreen = view.Border.FrameToScreen (); + var paddingScreen = view.Padding.FrameToScreen (); + + // Assert + Assert.Equal (expectedX, marginScreen.X); + Assert.Equal (expectedX + view.Margin.Thickness.Left, borderScreen.X); + Assert.Equal (expectedX + view.Border.Thickness.Left, paddingScreen.X); + } + + [Theory] + [InlineData (0, 2)] + [InlineData (1, 3)] + [InlineData (-1, 1)] + [InlineData (11, 13)] + public void FrameToScreen_NestedSuperView_WithAdornments (int x, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (x, 0, 10, 10); + + var superSuperView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + superSuperView.Border.Thickness = new (1); + + var superView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + + superSuperView.Add (superView); + superView.Border.Thickness = new (1); + + var view = new View (); + view.Frame = frame; + + superView.Add (view); + superView.LayoutSubviews (); + + // Act + var marginScreen = view.Margin.FrameToScreen (); + var borderScreen = view.Border.FrameToScreen (); + var paddingScreen = view.Padding.FrameToScreen (); + + // Assert + Assert.Equal (expectedX, marginScreen.X); + Assert.Equal (expectedX + view.Margin.Thickness.Left, borderScreen.X); + Assert.Equal (expectedX + view.Border.Thickness.Left, paddingScreen.X); + } + + + + [Theory] + [InlineData (0, 0, 0)] + [InlineData (1, 0, 1)] + [InlineData (-1, 0, -1)] + [InlineData (11, 0, 11)] + public void BoundsToScreen_NoSuperView_WithoutAdornments (int frameX, int boundsX, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (frameX, 0, 10, 10); + + var view = new View (); + view.Frame = frame; + + // Act + var marginScreen = view.Margin.BoundsToScreen (new (boundsX, 0, 0, 0)); + var borderScreen = view.Border.BoundsToScreen (new (boundsX, 0, 0, 0)); + var paddingScreen = view.Padding.BoundsToScreen (new (boundsX, 0, 0, 0)); + + // Assert + Assert.Equal (expectedX, marginScreen.X); + Assert.Equal (expectedX + view.Margin.Thickness.Left, borderScreen.X); + Assert.Equal (expectedX + view.Border.Thickness.Left, paddingScreen.X); + } + + [Theory] + [InlineData (0, 0, 0)] + [InlineData (1, 0, 1)] + [InlineData (-1, 0, -1)] + [InlineData (11, 0, 11)] + + [InlineData (0, 1, 1)] + [InlineData (1, 1, 2)] + [InlineData (-1, 1, 0)] + [InlineData (11, 1, 12)] + + [InlineData (0, -1, -1)] + [InlineData (1, -1, 0)] + [InlineData (-1, -1, -2)] + [InlineData (11, -1, 10)] + public void BoundsToScreen_NoSuperView_WithAdornments (int frameX, int boundsX, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (frameX, 0, 10, 10); + + var view = new View (); + view.Border.Thickness = new (1); + view.Frame = frame; + + // Act + var marginScreen = view.Margin.BoundsToScreen (new (boundsX, 0, 0, 0)); + var borderScreen = view.Border.BoundsToScreen (new (boundsX, 0, 0, 0)); + var paddingScreen = view.Padding.BoundsToScreen (new (boundsX, 0, 0, 0)); + + // Assert + Assert.Equal (expectedX, marginScreen.X); + Assert.Equal (expectedX, borderScreen.X); + Assert.Equal (expectedX, paddingScreen.X); + } + + [Theory] + [InlineData (0, 0, 0)] + [InlineData (1, 0, 1)] + [InlineData (-1, 0, -1)] + [InlineData (11, 0, 11)] + + [InlineData (0, 1, 1)] + [InlineData (1, 1, 2)] + [InlineData (-1, 1, 0)] + [InlineData (11, 1, 12)] + + [InlineData (0, -1, -1)] + [InlineData (1, -1, 0)] + [InlineData (-1, -1, -2)] + [InlineData (11, -1, 10)] + public void BoundsToScreen_SuperView_WithoutAdornments (int frameX, int boundsX, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (frameX, 0, 10, 10); + + var superView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + + var view = new View (); + view.Frame = frame; + + superView.Add (view); + superView.LayoutSubviews (); + + // Act + var marginScreen = view.Margin.BoundsToScreen (new (boundsX, 0, 0, 0)); + var borderScreen = view.Border.BoundsToScreen (new (boundsX, 0, 0, 0)); + var paddingScreen = view.Padding.BoundsToScreen (new (boundsX, 0, 0, 0)); + + // Assert + Assert.Equal (expectedX, marginScreen.X); + Assert.Equal (expectedX + view.Margin.Thickness.Left, borderScreen.X); + Assert.Equal (expectedX + view.Border.Thickness.Left, paddingScreen.X); + } + + [Theory] + [InlineData (0, 0, 1)] + [InlineData (1, 0, 2)] + [InlineData (-1, 0, 0)] + [InlineData (11, 0, 12)] + + [InlineData (0, 1, 2)] + [InlineData (1, 1, 3)] + [InlineData (-1, 1, 1)] + [InlineData (11, 1, 13)] + + [InlineData (0, -1, 0)] + [InlineData (1, -1, 1)] + [InlineData (-1, -1, -1)] + [InlineData (11, -1, 11)] + public void BoundsToScreen_SuperView_WithAdornments (int frameX, int boundsX, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (frameX, 0, 10, 10); + + var superView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + superView.Border.Thickness = new (1); + + var view = new View (); + view.Frame = frame; + + superView.Add (view); + superView.LayoutSubviews (); + + // Act + var marginScreen = view.Margin.BoundsToScreen (new (boundsX, 0, 0, 0)); + var borderScreen = view.Border.BoundsToScreen (new (boundsX, 0, 0, 0)); + var paddingScreen = view.Padding.BoundsToScreen (new (boundsX, 0, 0, 0)); + + // Assert + Assert.Equal (expectedX, marginScreen.X); + Assert.Equal (expectedX + view.Margin.Thickness.Left, borderScreen.X); + Assert.Equal (expectedX + view.Border.Thickness.Left, paddingScreen.X); + } + + [Theory] + [InlineData (0, 0, 0)] + [InlineData (1, 0, 1)] + [InlineData (-1, 0, -1)] + [InlineData (11, 0, 11)] + + [InlineData (0, 1, 1)] + [InlineData (1, 1, 2)] + [InlineData (-1, 1, 0)] + [InlineData (11, 1, 12)] + + [InlineData (0, -1, -1)] + [InlineData (1, -1, 0)] + [InlineData (-1, -1, -2)] + [InlineData (11, -1, 10)] + public void BoundsToScreen_NestedSuperView_WithoutAdornments (int frameX, int boundsX, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (frameX, 0, 10, 10); + + var superSuperView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + + var superView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + + superSuperView.Add (superView); + + var view = new View (); + view.Frame = frame; + + superView.Add (view); + superView.LayoutSubviews (); + + // Act + var marginScreen = view.Margin.BoundsToScreen (new (boundsX, 0, 0, 0)); + var borderScreen = view.Border.BoundsToScreen (new (boundsX, 0, 0, 0)); + var paddingScreen = view.Padding.BoundsToScreen (new (boundsX, 0, 0, 0)); + + // Assert + Assert.Equal (expectedX, marginScreen.X); + Assert.Equal (expectedX + view.Margin.Thickness.Left, borderScreen.X); + Assert.Equal (expectedX + view.Border.Thickness.Left, paddingScreen.X); + } + + [Theory] + [InlineData (0, 0, 2)] + [InlineData (1, 0, 3)] + [InlineData (-1, 0, 1)] + [InlineData (11, 0, 13)] + + [InlineData (0, 1, 3)] + [InlineData (1, 1, 4)] + [InlineData (-1, 1, 2)] + [InlineData (11, 1, 14)] + + [InlineData (0, -1, 1)] + [InlineData (1, -1, 2)] + [InlineData (-1, -1, 0)] + [InlineData (11, -1, 12)] + public void BoundsToScreen_NestedSuperView_WithAdornments (int frameX, int boundsX, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (frameX, 0, 10, 10); + + var superSuperView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + superSuperView.Border.Thickness = new (1); + + var superView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + + superSuperView.Add (superView); + superView.Border.Thickness = new (1); + + var view = new View (); + view.Frame = frame; + + superView.Add (view); + superView.LayoutSubviews (); + + // Act + var marginScreen = view.Margin.BoundsToScreen (new (boundsX, 0, 0, 0)); + var borderScreen = view.Border.BoundsToScreen (new (boundsX, 0, 0, 0)); + var paddingScreen = view.Padding.BoundsToScreen (new (boundsX, 0, 0, 0)); + + // Assert + Assert.Equal (expectedX, marginScreen.X); + Assert.Equal (expectedX + view.Margin.Thickness.Left, borderScreen.X); + Assert.Equal (expectedX + view.Border.Thickness.Left, paddingScreen.X); + } + +} diff --git a/UnitTests/View/Layout/ToScreenTests.cs b/UnitTests/View/Layout/ToScreenTests.cs new file mode 100644 index 000000000..a31715776 --- /dev/null +++ b/UnitTests/View/Layout/ToScreenTests.cs @@ -0,0 +1,454 @@ +using Xunit.Abstractions; + +namespace Terminal.Gui.ViewTests; + +/// +/// Test the and methods. +/// DOES NOT TEST Adornment.xxxToScreen methods. Those are in ./Adornment/ToScreenTests.cs +/// +/// +public class ToScreenTests (ITestOutputHelper output) +{ + private readonly ITestOutputHelper _output = output; + + [Theory] + [InlineData (0, 0)] + [InlineData (1, 1)] + [InlineData (-1, -1)] + [InlineData (11, 11)] + public void FrameToScreen_NoSuperView_WithoutAdornments (int x, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (x, 0, 10, 10); + + var view = new View (); + view.Frame = frame; + + // Act + var screen = view.FrameToScreen(); + + // Assert + Assert.Equal(expectedX, screen.X); + } + + [Theory] + [InlineData (0, 0)] + [InlineData (1, 1)] + [InlineData (-1, -1)] + [InlineData (11, 11)] + public void FrameToScreen_NoSuperView_WithAdornments (int x, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (x, 0, 10, 10); + + var view = new View (); + view.BorderStyle = LineStyle.Single; + view.Frame = frame; + + // Act + var screen = view.FrameToScreen (); + + // Assert + Assert.Equal (expectedX, screen.X); + } + + [Theory] + [InlineData (0, 0)] + [InlineData (1, 1)] + [InlineData (-1, -1)] + [InlineData (11, 11)] + public void FrameToScreen_SuperView_WithoutAdornments (int x, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (x, 0, 10, 10); + + var superView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + + var view = new View (); + view.Frame = frame; + + superView.Add (view); + superView.LayoutSubviews (); + + // Act + var screen = view.FrameToScreen (); + + // Assert + Assert.Equal (expectedX, screen.X); + } + + [Theory] + [InlineData (0, 1)] + [InlineData (1, 2)] + [InlineData (-1, 0)] + [InlineData (11, 12)] + public void FrameToScreen_SuperView_WithAdornments (int x, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (x, 0, 10, 10); + + var superView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + superView.BorderStyle = LineStyle.Single; + + var view = new View (); + view.Frame = frame; + + superView.Add (view); + superView.LayoutSubviews (); + + // Act + var screen = view.FrameToScreen (); + + // Assert + Assert.Equal (expectedX, screen.X); + } + + [Theory] + [InlineData (0, 0)] + [InlineData (1, 1)] + [InlineData (-1, -1)] + [InlineData (11, 11)] + public void FrameToScreen_NestedSuperView_WithoutAdornments (int x, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (x, 0, 10, 10); + + var superSuperView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + + var superView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + + superSuperView.Add (superView); + + var view = new View (); + view.Frame = frame; + + superView.Add (view); + superView.LayoutSubviews (); + + // Act + var screen = view.FrameToScreen (); + + // Assert + Assert.Equal (expectedX, screen.X); + } + + [Theory] + [InlineData (0, 2)] + [InlineData (1, 3)] + [InlineData (-1, 1)] + [InlineData (11, 13)] + public void FrameToScreen_NestedSuperView_WithAdornments (int x, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (x, 0, 10, 10); + + var superSuperView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + superSuperView.BorderStyle = LineStyle.Single; + + var superView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + + superSuperView.Add (superView); + superView.BorderStyle = LineStyle.Single; + + var view = new View (); + view.Frame = frame; + + superView.Add (view); + superView.LayoutSubviews (); + + // Act + var screen = view.FrameToScreen (); + + // Assert + Assert.Equal (expectedX, screen.X); + } + + + + [Theory] + [InlineData (0, 0, 0)] + [InlineData (1, 0, 1)] + [InlineData (-1, 0, -1)] + [InlineData (11, 0, 11)] + public void BoundsToScreen_NoSuperView_WithoutAdornments (int frameX, int boundsX, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (frameX, 0, 10, 10); + + var view = new View (); + view.Frame = frame; + + // Act + var screen = view.BoundsToScreen (new (boundsX, 0, 0, 0)); + + // Assert + Assert.Equal (expectedX, screen.X); + } + + [Theory] + [InlineData (0, 0, 1)] + [InlineData (1, 0, 2)] + [InlineData (-1, 0, 0)] + [InlineData (11, 0, 12)] + + [InlineData (0, 1, 2)] + [InlineData (1, 1, 3)] + [InlineData (-1, 1, 1)] + [InlineData (11, 1, 13)] + + [InlineData (0, -1, 0)] + [InlineData (1, -1, 1)] + [InlineData (-1, -1, -1)] + [InlineData (11, -1, 11)] + public void BoundsToScreen_NoSuperView_WithAdornments (int frameX, int boundsX, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (frameX, 0, 10, 10); + + var view = new View (); + view.BorderStyle = LineStyle.Single; + view.Frame = frame; + + // Act + var screen = view.BoundsToScreen (new (boundsX, 0, 0, 0)); + + // Assert + Assert.Equal (expectedX, screen.X); + } + + [Theory] + [InlineData (0, 0, 0)] + [InlineData (1, 0, 1)] + [InlineData (-1, 0, -1)] + [InlineData (11, 0, 11)] + + [InlineData (0, 1, 1)] + [InlineData (1, 1, 2)] + [InlineData (-1, 1, 0)] + [InlineData (11, 1, 12)] + + [InlineData (0, -1, -1)] + [InlineData (1, -1, 0)] + [InlineData (-1, -1, -2)] + [InlineData (11, -1, 10)] + public void BoundsToScreen_SuperView_WithoutAdornments (int frameX, int boundsX, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (frameX, 0, 10, 10); + + var superView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + + var view = new View (); + view.Frame = frame; + + superView.Add (view); + superView.LayoutSubviews (); + + // Act + var screen = view.BoundsToScreen (new (boundsX, 0, 0, 0)); + + // Assert + Assert.Equal (expectedX, screen.X); + } + + [Theory] + [InlineData (0, 0, 1)] + [InlineData (1, 0, 2)] + [InlineData (-1, 0, 0)] + [InlineData (11, 0, 12)] + + [InlineData (0, 1, 2)] + [InlineData (1, 1, 3)] + [InlineData (-1, 1, 1)] + [InlineData (11, 1, 13)] + + [InlineData (0, -1, 0)] + [InlineData (1, -1, 1)] + [InlineData (-1, -1, -1)] + [InlineData (11, -1, 11)] + public void BoundsToScreen_SuperView_WithAdornments (int frameX, int boundsX, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (frameX, 0, 10, 10); + + var superView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + superView.BorderStyle = LineStyle.Single; + + var view = new View (); + view.Frame = frame; + + superView.Add (view); + superView.LayoutSubviews (); + + // Act + var screen = view.BoundsToScreen (new (boundsX, 0, 0, 0)); + + // Assert + Assert.Equal (expectedX, screen.X); + } + + [Theory] + [InlineData (0, 0, 0)] + [InlineData (1, 0, 1)] + [InlineData (-1, 0, -1)] + [InlineData (11, 0, 11)] + + [InlineData (0, 1, 1)] + [InlineData (1, 1, 2)] + [InlineData (-1, 1, 0)] + [InlineData (11, 1, 12)] + + [InlineData (0, -1, -1)] + [InlineData (1, -1, 0)] + [InlineData (-1, -1, -2)] + [InlineData (11, -1, 10)] + public void BoundsToScreen_NestedSuperView_WithoutAdornments (int frameX, int boundsX, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (frameX, 0, 10, 10); + + var superSuperView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + + var superView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + + superSuperView.Add (superView); + + var view = new View (); + view.Frame = frame; + + superView.Add (view); + superView.LayoutSubviews (); + + // Act + var screen = view.BoundsToScreen (new (boundsX, 0, 0, 0)); + + // Assert + Assert.Equal (expectedX, screen.X); + } + + [Theory] + [InlineData (0, 0, 2)] + [InlineData (1, 0, 3)] + [InlineData (-1, 0, 1)] + [InlineData (11, 0, 13)] + + [InlineData (0, 1, 3)] + [InlineData (1, 1, 4)] + [InlineData (-1, 1, 2)] + [InlineData (11, 1, 14)] + + [InlineData (0, -1, 1)] + [InlineData (1, -1, 2)] + [InlineData (-1, -1, 0)] + [InlineData (11, -1, 12)] + public void BoundsToScreen_NestedSuperView_WithAdornments (int frameX, int boundsX, int expectedX) + { + // We test with only X because Y is equivalent. Height/Width are irrelevant. + // Arrange + var frame = new Rectangle (frameX, 0, 10, 10); + + var superSuperView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + superSuperView.BorderStyle = LineStyle.Single; + + var superView = new View () + { + X = 0, + Y = 0, + Height = Dim.Fill (), + Width = Dim.Fill () + }; + + superSuperView.Add (superView); + superView.BorderStyle = LineStyle.Single; + + var view = new View (); + view.Frame = frame; + + superView.Add (view); + superView.LayoutSubviews (); + + // Act + var screen = view.BoundsToScreen (new (boundsX, 0, 0, 0)); + + // Assert + Assert.Equal (expectedX, screen.X); + } + +}