2
0
Эх сурвалжийг харах

Fixes #1557 - Border and PanelView fixes (#1563)

* Fixes #1557. Ensures the border child not to be null.

* Improves the PanelView and some bug fixes.

* Implementing rounded corners border.

* Fixes some items not showing on page down/up.
BDisp 3 жил өмнө
parent
commit
87f6cfc8ed

+ 42 - 13
Terminal.Gui/Core/Border.cs

@@ -16,7 +16,11 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// The border is drawn with a double line limits.
 		/// </summary>
-		Double
+		Double,
+		/// <summary>
+		/// The border is drawn with a single line and rounded corners limits.
+		/// </summary>
+		Rounded
 	}
 
 	/// <summary>
@@ -75,6 +79,13 @@ namespace Terminal.Gui {
 			Right = right;
 			Bottom = bottom;
 		}
+
+		/// <summary>Returns the fully qualified type name of this instance.</summary>
+		/// <returns>The fully qualified type name.</returns>
+		public override string ToString ()
+		{
+			return $"(Left={Left},Top={Top},Right={Right},Bottom={Bottom})";
+		}
 	}
 
 	/// <summary>
@@ -295,6 +306,8 @@ namespace Terminal.Gui {
 		private bool drawMarginFrame;
 		private Thickness borderThickness;
 		private Thickness padding;
+		private bool effect3D;
+		private Point effect3DOffset = new Point (1, 1);
 
 		/// <summary>
 		/// Specifies the <see cref="Gui.BorderStyle"/> for a view.
@@ -406,13 +419,24 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// Gets or sets the 3D effect around the <see cref="Border"/>.
 		/// </summary>
-		public bool Effect3D { get; set; }
+		public bool Effect3D {
+			get => effect3D;
+			set {
+				effect3D = value;
+				OnBorderChanged ();
+			}
+		}
 
 		/// <summary>
 		/// Get or sets the offset start position for the <see cref="Effect3D"/>
 		/// </summary>
-		public Point Effect3DOffset { get; set; } = new Point (1, 1);
-
+		public Point Effect3DOffset {
+			get => effect3DOffset;
+			set {
+				effect3DOffset = value;
+				OnBorderChanged ();
+			}
+		}
 		/// <summary>
 		/// Gets or sets the color for the <see cref="Border"/>
 		/// </summary>
@@ -436,8 +460,11 @@ namespace Terminal.Gui {
 		/// Drawn the <see cref="BorderThickness"/> more the <see cref="Padding"/>
 		///  more the <see cref="Border.BorderStyle"/> and the <see cref="Effect3D"/>.
 		/// </summary>
-		public void DrawContent ()
+		public void DrawContent (View view = null)
 		{
+			if (Child == null) {
+				Child = view;
+			}
 			if (Parent?.Border != null) {
 				DrawParentBorder (Parent.ViewToScreen (Parent.Bounds));
 			} else {
@@ -644,9 +671,9 @@ namespace Terminal.Gui {
 
 				// Draw the upper Effect3D
 				for (int r = frame.Y - drawMarginFrame - sumThickness.Top + effect3DOffset.Y;
-					r < frame.Y - drawMarginFrame - sumThickness.Top; r++) {
+					r >= 0 && r < frame.Y - drawMarginFrame - sumThickness.Top; r++) {
 					for (int c = frame.X - drawMarginFrame - sumThickness.Left + effect3DOffset.X;
-						c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right + effect3DOffset.X, driver.Cols); c++) {
+						c >= 0 && c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right + effect3DOffset.X, driver.Cols); c++) {
 
 						AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
 					}
@@ -654,9 +681,9 @@ namespace Terminal.Gui {
 
 				// Draw the left Effect3D
 				for (int r = frame.Y - drawMarginFrame - sumThickness.Top + effect3DOffset.Y;
-					r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom + effect3DOffset.Y, driver.Rows); r++) {
+					r >= 0 && r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom + effect3DOffset.Y, driver.Rows); r++) {
 					for (int c = frame.X - drawMarginFrame - sumThickness.Left + effect3DOffset.X;
-						c < frame.X - drawMarginFrame - sumThickness.Left; c++) {
+						c >= 0 && c < frame.X - drawMarginFrame - sumThickness.Left; c++) {
 
 						AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
 					}
@@ -664,9 +691,9 @@ namespace Terminal.Gui {
 
 				// Draw the right Effect3D
 				for (int r = frame.Y - drawMarginFrame - sumThickness.Top + effect3DOffset.Y;
-					r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom + effect3DOffset.Y, driver.Rows); r++) {
+					r >= 0 && r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom + effect3DOffset.Y, driver.Rows); r++) {
 					for (int c = frame.Right + drawMarginFrame + sumThickness.Right;
-						c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right + effect3DOffset.X, driver.Cols); c++) {
+						c >= 0 && c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right + effect3DOffset.X, driver.Cols); c++) {
 
 						AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
 					}
@@ -674,14 +701,15 @@ namespace Terminal.Gui {
 
 				// Draw the lower Effect3D
 				for (int r = frame.Bottom + drawMarginFrame + sumThickness.Bottom;
-					r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom + effect3DOffset.Y, driver.Rows); r++) {
+					r >= 0 && r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom + effect3DOffset.Y, driver.Rows); r++) {
 					for (int c = frame.X - drawMarginFrame - sumThickness.Left + effect3DOffset.X;
-						c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right + effect3DOffset.X, driver.Cols); c++) {
+						c >= 0 && c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right + effect3DOffset.X, driver.Cols); c++) {
 
 						AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
 					}
 				}
 			}
+			driver.SetAttribute (savedAttribute);
 		}
 
 		private void DrawParentBorder (Rect frame)
@@ -833,6 +861,7 @@ namespace Terminal.Gui {
 					}
 				}
 			}
+			driver.SetAttribute (savedAttribute);
 		}
 
 		private Attribute GetEffect3DBrush ()

+ 65 - 6
Terminal.Gui/Core/ConsoleDriver.cs

@@ -910,12 +910,41 @@ namespace Terminal.Gui {
 
 			var borderStyle = borderContent == null ? BorderStyle.Single : borderContent.BorderStyle;
 
-			Rune hLine = border ? (borderStyle == BorderStyle.Single ? HLine : HDLine) : clearChar;
-			Rune vLine = border ? (borderStyle == BorderStyle.Single ? VLine : VDLine) : clearChar;
-			Rune uRCorner = border ? (borderStyle == BorderStyle.Single ? URCorner : URDCorner) : clearChar;
-			Rune uLCorner = border ? (borderStyle == BorderStyle.Single ? ULCorner : ULDCorner) : clearChar;
-			Rune lLCorner = border ? (borderStyle == BorderStyle.Single ? LLCorner : LLDCorner) : clearChar;
-			Rune lRCorner = border ? (borderStyle == BorderStyle.Single ? LRCorner : LRDCorner) : clearChar;
+			Rune hLine = default, vLine = default,
+				uRCorner = default, uLCorner = default, lLCorner = default, lRCorner = default;
+
+			if (border) {
+				switch (borderStyle) {
+				case BorderStyle.None:
+					break;
+				case BorderStyle.Single:
+					hLine = HLine;
+					vLine = VLine;
+					uRCorner = URCorner;
+					uLCorner = ULCorner;
+					lLCorner = LLCorner;
+					lRCorner = LRCorner;
+					break;
+				case BorderStyle.Double:
+					hLine = HDLine;
+					vLine = VDLine;
+					uRCorner = URDCorner;
+					uLCorner = ULDCorner;
+					lLCorner = LLDCorner;
+					lRCorner = LRDCorner;
+					break;
+				case BorderStyle.Rounded:
+					hLine = HRLine;
+					vLine = VRLine;
+					uRCorner = URRCorner;
+					uLCorner = ULRCorner;
+					lLCorner = LLRCorner;
+					lRCorner = LRRCorner;
+					break;
+				}
+			} else {
+				hLine = vLine = uRCorner = uLCorner = lLCorner = lRCorner = clearChar;
+			}
 
 			// Outside top
 			if (paddingTop > 1) {
@@ -1235,6 +1264,36 @@ namespace Terminal.Gui {
 		/// </summary>
 		public Rune LRDCorner = '\u255d';
 
+		/// <summary>
+		/// Horizontal line character for rounded corners.
+		/// </summary>
+		public Rune HRLine = '\u2500';
+
+		/// <summary>
+		/// Vertical line character for rounded corners.
+		/// </summary>
+		public Rune VRLine = '\u2502';
+
+		/// <summary>
+		/// Upper left rounded corner
+		/// </summary>
+		public Rune ULRCorner = '\u256d';
+
+		/// <summary>
+		/// Lower left rounded corner
+		/// </summary>
+		public Rune LLRCorner = '\u2570';
+
+		/// <summary>
+		/// Upper right rounded corner
+		/// </summary>
+		public Rune URRCorner = '\u256e';
+
+		/// <summary>
+		/// Lower right rounded corner
+		/// </summary>
+		public Rune LRRCorner = '\u256f';
+
 		/// <summary>
 		/// Make the attribute for the foreground and background colors.
 		/// </summary>

+ 1 - 1
Terminal.Gui/Core/View.cs

@@ -1385,7 +1385,7 @@ namespace Terminal.Gui {
 			}
 
 			if (Border != null) {
-				Border.DrawContent ();
+				Border.DrawContent (this);
 			}
 
 			if (!ustring.IsNullOrEmpty (Text) || (this is Label && !AutoSize)) {

+ 54 - 24
Terminal.Gui/Views/PanelView.cs

@@ -77,20 +77,15 @@ namespace Terminal.Gui {
 					Visible = false;
 					return;
 				}
-				child.X = 0;
-				child.Y = 0;
-				AdjustContainer ();
 				if (child?.Border != null) {
-					child.Border.BorderChanged += Border_BorderChanged;
 					Border = child.Border;
-					Border.Child = childContentView;
 				} else {
 					if (Border == null) {
 						Border = new Border ();
 					}
-					Border.BorderChanged += Border_BorderChanged;
-					Border.Child = childContentView;
+					Child.Border = Border;
 				}
+				Border.Child = childContentView;
 				if (!child.IsInitialized) {
 					child.Initialized += Child_Initialized;
 				}
@@ -98,6 +93,29 @@ namespace Terminal.Gui {
 			}
 		}
 
+		/// <inheritdoc />
+		public override Border Border {
+			get => base.Border;
+			set {
+				if (base.Border?.Child != null && value.Child == null) {
+					value.Child = base.Border.Child;
+				}
+				base.Border = value;
+				if (value == null) {
+					return;
+				}
+				Border.BorderChanged += Border_BorderChanged;
+				if (Child != null && (Child?.Border == null || Child?.Border != value)) {
+					if (Child?.Border == null) {
+						Child.Border = new Border ();
+					}
+					Child.Border = Border;
+					Child.Border.BorderChanged += Border_BorderChanged;
+				}
+				AdjustContainer ();
+			}
+		}
+
 		private void Child_Initialized (object sender, EventArgs e)
 		{
 			savedPanel = new SavedPosDim () {
@@ -118,23 +136,26 @@ namespace Terminal.Gui {
 		private void AdjustContainer ()
 		{
 			if (Child?.IsInitialized == true) {
-				var borderLength = Child.Border != null
-					? Child.Border.DrawMarginFrame ? 1 : 0
-					: 0;
-				var sumPadding = Child.Border != null
-					? Child.Border.GetSumThickness ()
-					: new Thickness ();
+				if (Child?.Border != null && Child.Border != Border) {
+					Border = Child.Border;
+				}
+				var borderLength = Child.Border.DrawMarginFrame ? 1 : 0;
+				var sumPadding = Child.Border.GetSumThickness ();
+				var effect3DOffset = Child.Border.Effect3D ? Child.Border.Effect3DOffset : new Point ();
 				if (!UsePanelFrame) {
-					X = savedChild.X;
+					X = savedPanel.X;
 					childContentView.X = borderLength + sumPadding.Left;
-					Y = savedChild.Y;
+					Y = savedPanel.Y;
 					childContentView.Y = borderLength + sumPadding.Top;
 					if (savedChild.Width is Dim.DimFill) {
 						var margin = -savedChild.Width.Anchor (0);
 						Width = Dim.Fill (margin);
 						childContentView.Width = Dim.Fill (margin + borderLength + sumPadding.Right);
 					} else {
-						Width = savedChild.Width + (2 * borderLength) + sumPadding.Right + sumPadding.Left;
+						var savedLayout = LayoutStyle;
+						LayoutStyle = LayoutStyle.Absolute;
+						Width = savedChild.X.Anchor (0) + savedChild.Width + (2 * borderLength) + sumPadding.Right + sumPadding.Left;
+						LayoutStyle = savedLayout;
 						childContentView.Width = Dim.Fill (borderLength + sumPadding.Right);
 					}
 					if (savedChild.Height is Dim.DimFill) {
@@ -142,25 +163,34 @@ namespace Terminal.Gui {
 						Height = Dim.Fill (margin);
 						childContentView.Height = Dim.Fill (margin + borderLength + sumPadding.Bottom);
 					} else {
-						Height = savedChild.Height + (2 * borderLength) + sumPadding.Bottom + sumPadding.Top;
+						var savedLayout = LayoutStyle;
+						LayoutStyle = LayoutStyle.Absolute;
+						Height = savedChild.Y.Anchor (0) + savedChild.Height + (2 * borderLength) + sumPadding.Bottom + sumPadding.Top;
+						LayoutStyle = savedLayout;
 						childContentView.Height = Dim.Fill (borderLength + sumPadding.Bottom);
 					}
 				} else {
-					X = savedPanel.X;
+					X = savedPanel.X - (effect3DOffset.X < 0 ? effect3DOffset.X : 0);
 					childContentView.X = borderLength + sumPadding.Left;
-					Y = savedPanel.Y;
+					Y = savedPanel.Y - (effect3DOffset.Y < 0 ? effect3DOffset.Y : 0);
 					childContentView.Y = borderLength + sumPadding.Top;
 					Width = savedPanel.Width;
 					Height = savedPanel.Height;
 					if (Width is Dim.DimFill) {
-						var margin = -savedPanel.Width.Anchor (0);
-						childContentView.Width = Dim.Fill (margin + borderLength + sumPadding.Right);
+						var margin = -savedPanel.Width.Anchor (0) +
+							(effect3DOffset.X > 0 ? effect3DOffset.X : 0);
+						Width = Dim.Fill (margin);
+						childContentView.Width = Dim.Fill (margin + borderLength + sumPadding.Right +
+							(effect3DOffset.X > 0 ? effect3DOffset.X : 0));
 					} else {
 						childContentView.Width = Dim.Fill (borderLength + sumPadding.Right);
 					}
 					if (Height is Dim.DimFill) {
-						var margin = -savedPanel.Height.Anchor (0);
-						childContentView.Height = Dim.Fill (margin + borderLength + sumPadding.Bottom);
+						var margin = -savedPanel.Height.Anchor (0) +
+							(effect3DOffset.Y > 0 ? effect3DOffset.Y : 0);
+						Height = Dim.Fill (margin);
+						childContentView.Height = Dim.Fill (margin + borderLength + sumPadding.Bottom +
+							(effect3DOffset.Y > 0 ? effect3DOffset.Y : 0));
 					} else {
 						childContentView.Height = Dim.Fill (borderLength + sumPadding.Bottom);
 					}
@@ -206,7 +236,7 @@ namespace Terminal.Gui {
 		{
 			if (!NeedDisplay.IsEmpty) {
 				Driver.SetAttribute (Child.GetNormalColor ());
-				Border.DrawContent ();
+				Child.Border.DrawContent (Border.Child);
 			}
 			var savedClip = childContentView.ClipToBounds ();
 			childContentView.Redraw (childContentView.Bounds);

+ 6 - 6
UICatalog/Scenarios/Borders.cs

@@ -18,12 +18,6 @@ namespace UICatalog.Scenarios {
 			var effect3D = true;
 
 			var smartPanel = new PanelView () {
-				X = Pos.Center () - 38,
-				Y = Pos.Center () - 3,
-				Width = 24,
-				Height = 13
-			};
-			smartPanel.Add (new Label () { // Or smartPanel.Child = 
 				X = Pos.Center () - 38,
 				Y = Pos.Center () - 3,
 				Width = 24,
@@ -37,6 +31,12 @@ namespace UICatalog.Scenarios {
 					Background = background,
 					Effect3D = effect3D
 				},
+			};
+			smartPanel.Add (new Label () { // Or smartPanel.Child = 
+				X = 0,
+				Y = 0,
+				Width = 24,
+				Height = 13,
 				ColorScheme = Colors.TopLevel,
 				Text = "This is a test\nwith a \nPanelView",
 				TextAlignment = TextAlignment.Centered

+ 17 - 0
UICatalog/Scenarios/CharacterMap.cs

@@ -166,5 +166,22 @@ namespace UICatalog.Scenarios {
 			base.OnDrawContent (viewport);
 		}
 #endif
+
+		public override bool ProcessKey (KeyEvent kb)
+		{
+			if (kb.Key == Key.PageDown) {
+				ContentOffset = new Point (0, ContentOffset.Y - Bounds.Height / 2 + 1);
+				return true;
+			}
+			if (kb.Key == Key.PageUp) {
+				if (ContentOffset.Y + Bounds.Height / 2 - 1 < 0) {
+					ContentOffset = new Point (0, ContentOffset.Y + Bounds.Height / 2 - 1);
+				} else {
+					ContentOffset = Point.Empty;
+				}
+				return true;
+			}
+			return base.ProcessKey (kb);
+		}
 	}
 }

+ 18 - 0
UnitTests/BorderTests.cs

@@ -538,5 +538,23 @@ namespace Terminal.Gui.Core {
 				}
 			}
 		}
+
+		[Fact]
+		[AutoInitShutdown]
+		public void BorderOnControlWithNoChildren ()
+		{
+			var label = new TextField ("Loading...") {
+				Border = new Border () {
+					BorderStyle = BorderStyle.Single,
+					DrawMarginFrame = true,
+					Padding = new Thickness (1),
+					BorderBrush = Color.White
+				}
+			};
+
+			Application.Top.Add (label);
+
+			Assert.Null (Record.Exception (() => label.Redraw (label.Bounds)));
+		}
 	}
 }

+ 84 - 10
UnitTests/PanelViewTests.cs

@@ -24,7 +24,7 @@ namespace Terminal.Gui.Views {
 			Assert.False (pv.UsePanelFrame);
 			Assert.NotNull (pv.Child);
 			Assert.NotNull (pv.Border);
-			Assert.Null (pv.Child.Border);
+			Assert.NotNull (pv.Child.Border);
 		}
 
 		[Fact]
@@ -120,6 +120,19 @@ namespace Terminal.Gui.Views {
 
 			Application.Begin (top);
 
+			Assert.False (pv.Child.Border.Effect3D);
+			Assert.Equal (new Rect (0, 0, 25, 15), pv.Frame);
+			Assert.Equal (new Rect (0, 0, 15, 1), pv.Child.Frame);
+
+			pv.Child.Border.Effect3D = true;
+
+			Assert.True (pv.Child.Border.Effect3D);
+			Assert.Equal (new Rect (0, 0, 25, 15), pv.Frame);
+			Assert.Equal (new Rect (0, 0, 15, 1), pv.Child.Frame);
+
+			pv.Child.Border.Effect3DOffset = new Point (-1, -1);
+
+			Assert.Equal (new Point (-1, -1), pv.Child.Border.Effect3DOffset);
 			Assert.Equal (new Rect (0, 0, 25, 15), pv.Frame);
 			Assert.Equal (new Rect (0, 0, 15, 1), pv.Child.Frame);
 		}
@@ -171,11 +184,31 @@ namespace Terminal.Gui.Views {
 			Assert.Equal (new Rect (0, 0, 65, 6), pv1.Child.Frame);
 			Assert.Equal (new Rect (0, 0, 76, 21), pv2.Frame);
 			Assert.Equal (new Rect (0, 0, 62, 3), pv2.Child.Frame);
+
+			pv.Child.Border.Effect3D = pv1.Child.Border.Effect3D = pv2.Child.Border.Effect3D = true;
+
+			Assert.True (pv.Child.Border.Effect3D);
+			Assert.Equal (new Rect (0, 0, 78, 23), pv.Frame);
+			Assert.Equal (new Rect (0, 0, 68, 9), pv.Child.Frame);
+			Assert.Equal (new Rect (0, 0, 77, 22), pv1.Frame);
+			Assert.Equal (new Rect (0, 0, 65, 6), pv1.Child.Frame);
+			Assert.Equal (new Rect (0, 0, 76, 21), pv2.Frame);
+			Assert.Equal (new Rect (0, 0, 62, 3), pv2.Child.Frame);
+
+			pv.Child.Border.Effect3DOffset = pv1.Child.Border.Effect3DOffset = pv2.Child.Border.Effect3DOffset = new Point (-1, -1);
+
+			Assert.Equal (new Point (-1, -1), pv.Child.Border.Effect3DOffset);
+			Assert.Equal (new Rect (0, 0, 78, 23), pv.Frame);
+			Assert.Equal (new Rect (0, 0, 68, 9), pv.Child.Frame);
+			Assert.Equal (new Rect (0, 0, 77, 22), pv1.Frame);
+			Assert.Equal (new Rect (0, 0, 65, 6), pv1.Child.Frame);
+			Assert.Equal (new Rect (0, 0, 76, 21), pv2.Frame);
+			Assert.Equal (new Rect (0, 0, 62, 3), pv2.Child.Frame);
 		}
 
 		[Fact]
 		[AutoInitShutdown]
-		public void UsePanelFrame_False_PanelView_Always_Respect_The_Child_Upper_Left_Corner_Position_And_Size ()
+		public void UsePanelFrame_False_PanelView_Always_Respect_The_PanelView_Upper_Left_Corner_Position_And_The_Child_Size ()
 		{
 			var top = Application.Top;
 			var win = new Window ();
@@ -208,17 +241,44 @@ namespace Terminal.Gui.Views {
 
 			Application.Begin (top);
 
-			Assert.Equal (new Rect (0, 0, 15, 1), pv.Frame);
+			Assert.False (pv.UsePanelFrame);
+			Assert.False (pv.Border.Effect3D);
+			Assert.Equal (pv.Child.Border, pv.Border);
+			Assert.False (pv1.UsePanelFrame);
+			Assert.False (pv1.Border.Effect3D);
+			Assert.Equal (pv1.Child.Border, pv1.Border);
+			Assert.False (pv2.UsePanelFrame);
+			Assert.False (pv2.Border.Effect3D);
+			Assert.Equal (pv2.Child.Border, pv2.Border);
+			Assert.Equal (new Rect (2, 4, 15, 1), pv.Frame);
+			Assert.Equal (new Rect (0, 0, 15, 1), pv.Child.Frame);
+			Assert.Equal (new Rect (2, 4, 18, 5), pv1.Frame);
+			Assert.Equal (new Rect (3, 4, 15, 1), pv1.Child.Frame);
+			Assert.Equal (new Rect (2, 4, 76, 19), pv2.Frame);
+			Assert.Equal (new Rect (5, 6, 71, 13), pv2.Child.Frame);
+
+			pv.Border.Effect3D = pv1.Border.Effect3D = pv2.Border.Effect3D = true;
+
+			Assert.Equal (new Rect (2, 4, 15, 1), pv.Frame);
 			Assert.Equal (new Rect (0, 0, 15, 1), pv.Child.Frame);
-			Assert.Equal (new Rect (3, 4, 15, 1), pv1.Frame);
-			Assert.Equal (new Rect (0, 0, 15, 1), pv1.Child.Frame);
-			Assert.Equal (new Rect (5, 6, 73, 17), pv2.Frame);
-			Assert.Equal (new Rect (0, 0, 73, 17), pv2.Child.Frame);
+			Assert.Equal (new Rect (2, 4, 18, 5), pv1.Frame);
+			Assert.Equal (new Rect (3, 4, 15, 1), pv1.Child.Frame);
+			Assert.Equal (new Rect (2, 4, 76, 19), pv2.Frame);
+			Assert.Equal (new Rect (5, 6, 71, 13), pv2.Child.Frame);
+
+			pv.Border.Effect3DOffset = pv1.Border.Effect3DOffset = pv2.Border.Effect3DOffset = new Point (-1, -1);
+
+			Assert.Equal (new Rect (2, 4, 15, 1), pv.Frame);
+			Assert.Equal (new Rect (0, 0, 15, 1), pv.Child.Frame);
+			Assert.Equal (new Rect (2, 4, 18, 5), pv1.Frame);
+			Assert.Equal (new Rect (3, 4, 15, 1), pv1.Child.Frame);
+			Assert.Equal (new Rect (2, 4, 76, 19), pv2.Frame);
+			Assert.Equal (new Rect (5, 6, 71, 13), pv2.Child.Frame);
 		}
 
 		[Fact]
 		[AutoInitShutdown]
-		public void UsePanelFrame_True_PanelView_Position_And_Size_Are_Used ()
+		public void UsePanelFrame_True_PanelView_Position_And_Size_Are_Used_Depending_On_Effect3DOffset ()
 		{
 			var top = Application.Top;
 			var win = new Window ();
@@ -253,9 +313,23 @@ namespace Terminal.Gui.Views {
 			Application.Begin (top);
 
 			Assert.Equal (new Rect (5, 6, 73, 17), pv.Frame);
-			Assert.Equal (new Rect (0, 0, 20, 10), pv.Child.Frame);
+			Assert.Equal (new Rect (2, 4, 20, 10), pv.Child.Frame);
 			Assert.Equal (new Rect (2, 4, 20, 10), pv1.Frame);
-			Assert.Equal (new Rect (0, 0, 20, 10), pv1.Child.Frame);
+			Assert.Equal (new Rect (5, 6, 15, 4), pv1.Child.Frame);
+
+			pv.Border.Effect3D = pv1.Border.Effect3D = true;
+
+			Assert.Equal (new Rect (5, 6, 73, 17), pv.Frame);
+			Assert.Equal (new Rect (2, 4, 20, 10), pv.Child.Frame);
+			Assert.Equal (new Rect (2, 4, 20, 10), pv1.Frame);
+			Assert.Equal (new Rect (5, 6, 15, 4), pv1.Child.Frame);
+
+			pv.Border.Effect3DOffset = pv1.Border.Effect3DOffset = new Point (-1, -1);
+
+			Assert.Equal (new Rect (6, 7, 73, 17), pv.Frame);
+			Assert.Equal (new Rect (2, 4, 20, 10), pv.Child.Frame);
+			Assert.Equal (new Rect (3, 5, 20, 10), pv1.Frame);
+			Assert.Equal (new Rect (5, 6, 15, 4), pv1.Child.Frame);
 		}
 	}
 }