Jelajahi Sumber

Simplifiede

Tigger Kindel 2 tahun lalu
induk
melakukan
108c0e6cfe

+ 11 - 8
Terminal.Gui/Core/Application.cs

@@ -672,7 +672,7 @@ namespace Terminal.Gui {
 		}
 
 		/// <summary>
-		/// Finds the deepest view at the specified coordinates.
+		/// Finds the deepest view at the specified coordinates, specified relative to <paramref name="start"/>'s superview.
 		/// </summary>
 		/// <param name="start"></param>
 		/// <param name="x"></param>
@@ -682,22 +682,25 @@ namespace Terminal.Gui {
 		/// <returns></returns>
 		static View FindDeepestView (View start, int x, int y, out int resx, out int resy)
 		{
-			var startFrame = start.Frame;
+			//var startFrame = start.Frame;
 
-			if (!startFrame.Contains (x, y)) {
+			var startRect = new Rect (start.Frame.X + start.GetBoundsOffset().X, start.Frame.Y + start.GetBoundsOffset ().Y, start.Bounds.Width, start.Bounds.Height);
+
+			if (!startRect.Contains (x, y)) {
 				resx = 0;
 				resy = 0;
 				return null;
 			}
 
-			startFrame = start.Padding.Thickness.GetInside (start.BorderFrame.Thickness.GetInside (start.Margin.Thickness.GetInside (startFrame)));
+			//startFrame = start.Padding.Thickness.GetInside (start.BorderFrame.Thickness.GetInside (start.Margin.Thickness.GetInside (startFrame)));
 			if (start.InternalSubviews != null) {
 				int count = start.InternalSubviews.Count;
 				if (count > 0) {
-					var rx = x - startFrame.X;
-					var ry = y - startFrame.Y;
+					var rx = x - startRect.X;
+					var ry = y - startRect.Y;
 					for (int i = count - 1; i >= 0; i--) {
 						View v = start.InternalSubviews [i];
+						// BUGBUG: v2 - I think it's a bug that we use v.Frame.Contains here vs. Frame + v.GetBoundsOffset
 						if (v.Visible && v.Frame.Contains (rx, ry)) {
 							var deep = FindDeepestView (v, rx, ry, out resx, out resy);
 							if (deep == null)
@@ -707,8 +710,8 @@ namespace Terminal.Gui {
 					}
 				}
 			}
-			resx = x - startFrame.X;
-			resy = y - startFrame.Y;
+			resx = x - startRect.X;
+			resy = y - startRect.Y;
 			return start;
 		}
 

+ 1 - 0
Terminal.Gui/Core/Frame.cs

@@ -19,6 +19,7 @@ namespace Terminal.Gui {
 		private Thickness _thickness = Thickness.Empty;
 
 		internal override void CreateFrames () { /* Do nothing - Frames do not have Frames */ }
+		internal override void LayoutFrames () { /* Do nothing - Frames do not have Frames */ }
 
 		/// <summary>
 		/// The Parent of this Frame (the View this Frame surrounds).

+ 22 - 14
Terminal.Gui/Core/Thickness.cs

@@ -9,9 +9,17 @@ namespace Terminal.Gui {
 	/// <summary>
 	/// Describes the thickness of a frame around a rectangle. Four <see cref="int"/> values describe
 	///  the <see cref="Left"/>, <see cref="Top"/>, <see cref="Right"/>, and <see cref="Bottom"/> sides
-	///  of the rectangle, respectively. Provides a helper API (<see cref="Draw(Rect, string)"/> for
-	///  drawing a frame with the specified thickness.
+	///  of the rectangle, respectively.
 	/// </summary>
+	/// <remarks>
+	/// <para>
+	/// Use the helper API (<see cref="GetInside(Rect)"/> to get the rectangle describing the insides of the frame,
+	/// with the thickness widths subtracted.
+	/// </para>
+	/// <para>
+	/// Use the helper API (<see cref="Draw(Rect, string)"/> to draw the frame with the specified thickness.
+	/// </para>
+	/// </remarks>
 	public class Thickness : IEquatable<Thickness> {
 		private int validate (int width)
 		{
@@ -44,6 +52,7 @@ namespace Terminal.Gui {
 		/// </summary>
 		[JsonInclude]
 		public int Bottom;
+		private Rect inside;
 
 		/// <summary>
 		/// Initializes a new instance of the <see cref="Thickness"/> class with all widths
@@ -97,24 +106,23 @@ namespace Terminal.Gui {
 			}
 		}
 
-		//public virtual void OnChanged()
-		//{
-		//	Changed?.Invoke (this, new ThicknessEventArgs () { Thickness = this });
-		//}
-		//public event EventHandler<ThicknessEventArgs> Changed;
-
 		/// <summary>
-		/// Returns a rectangle describing the location and size of the inner area of <paramref name="rect"/>
-		/// with the thickness widths subracted. The height and width of the retunred rect may be zero.
+		/// Returns a rectangle describing the location and size of the inside area of <paramref name="rect"/>
+		/// with the thickness widths subtracted. The height and width of the returned rectangle will
+		/// never be less than 0.
 		/// </summary>
+		/// <remarks>If a thickness width is negative, the inside rectangle will be larger than <paramref name="rect"/>. e.g.
+		/// a <c>Thickness (-1, -1, -1, -1) will result in a rectangle skewed -1 in the X and Y directions and 
+		/// with a Size increased by 1.</c></remarks>
 		/// <param name="rect">The source rectangle</param>
 		/// <returns></returns>
 		public Rect GetInside (Rect rect)
 		{
-			var width = rect.Size.Width - (Left + Right);
-			var height = rect.Size.Height - (Top + Bottom);
-			var size = new Size (Math.Max (0, width), Math.Max (0, height));
-			return new Rect (new Point (rect.X + Left, rect.Y + Top), size);
+			var x = rect.X + Left;
+			var y = rect.Y + Top;
+			var width = Math.Max (0, rect.Size.Width - Horizontal);
+			var height = Math.Max (0, rect.Size.Height - Vertical);
+			return new Rect (new Point (x, y), new Size (width, height));
 		}
 
 		/// <summary>

+ 50 - 81
Terminal.Gui/Core/View.cs

@@ -498,19 +498,10 @@ namespace Terminal.Gui {
 		public Frame Padding { get; private set; }
 
 		/// <summary>
-		/// Gets the rectangle that describes the location and size of the area within the View where
-		/// content and subviews are rendered. This is Bounds offset by all of the top/left thicknesses.
+		/// Helper to get the X and Y offset of the Bounds from the Frame. This is the sum of the Left and Top properties of
+		/// <see cref="Margin"/>, <see cref="BorderFrame"/> and <see cref="Padding"/>.
 		/// </summary>
-		public Rect ContentArea {
-			get {
-				// BUGBUG: 
-				if (Padding == null || BorderFrame == null || Margin == null) {
-					return Bounds;
-				}
-
-				return Padding.Thickness.GetInside (BorderFrame.Thickness.GetInside (Margin.Thickness.GetInside (new Rect (default, Frame.Size))));
-			}
-		}
+		public Point GetBoundsOffset () => new Point (Padding?.Thickness.GetInside (Padding.Frame).X ?? 0, Padding?.Thickness.GetInside (Padding.Frame).Y ?? 0);
 
 		/// <summary>
 		/// Creates the view's <see cref="Frame"/> objects. This internal method is overridden by Frame to do nothing
@@ -551,45 +542,6 @@ namespace Terminal.Gui {
 			Padding.Parent = this;
 		}
 
-		/// <summary>
-		/// Lays out the view's <see cref="Frame"/> objects (<see cref="Margin"/>, <see cref="BorderFrame"/>, and <see cref="Padding"/> 
-		/// as needed. Causes each Frame to Layout its SubViews.
-		/// </summary>
-		public void LayoutFrames ()
-		{
-			if (Margin != null) {
-				Margin.X = 0;
-				Margin.Y = 0;
-				Margin.Width = Frame.Size.Width;
-				Margin.Height = Frame.Size.Height;
-				Margin.SetNeedsLayout ();
-				Margin.LayoutSubviews ();
-				Margin.SetNeedsDisplay ();
-			}
-			if (BorderFrame != null) {
-				var border = Margin?.Thickness.GetInside (Margin.Frame) ?? Frame;
-				BorderFrame.X = border.Location.X;
-				BorderFrame.Y = border.Location.Y;
-				BorderFrame.Width = border.Size.Width;
-				BorderFrame.Height = border.Size.Height;
-				BorderFrame.SetNeedsLayout ();
-				BorderFrame.LayoutSubviews ();
-				BorderFrame.SetNeedsDisplay ();
-			}
-			if (Padding != null) {
-				var padding = BorderFrame?.Thickness.GetInside (BorderFrame?.Frame ??
-					(Margin?.Thickness.GetInside (Margin.Frame) ?? Frame)) ??
-						Margin?.Thickness.GetInside (Margin.Frame) ?? Frame;
-				Padding.X = padding.Location.X;
-				Padding.Y = padding.Location.Y;
-				Padding.Width = padding.Size.Width;
-				Padding.Height = padding.Size.Height;
-				Padding.SetNeedsLayout ();
-				Padding.LayoutSubviews ();
-				Padding.SetNeedsDisplay ();
-			}
-		}
-
 		ustring title;
 
 		/// <summary>
@@ -636,20 +588,20 @@ namespace Terminal.Gui {
 		/// <value>The bounds.</value>
 		/// <remarks>
 		/// <para>
-		/// The <see cref="Rect.Location"/> of Bounds is always (0, 0). 
-		/// To obtain the Frame-relative location of the content area use <see cref="ContentArea"/>.
+		/// The <see cref="Rect.Location"/> of Bounds is always (0, 0). To obtain the offset of the Bounds from the Frame use 
+		/// <see cref="GetBoundsOffset"/>.
+		/// </para>
+		/// <para>
+		/// To obtain the SuperView-relative location of the content area use <see cref="ContentArea"/>.
 		/// </para>
 		/// </remarks>
 		public virtual Rect Bounds {
 			get {
-				// BUGBUG: 
-				if (Padding == null || BorderFrame == null || Margin == null) {
-					return new Rect (default, Frame.Size);
-				}
-				var frameRelativeBounds = Padding.Thickness.GetInside (Padding.Frame);
+				var frameRelativeBounds = Padding?.Thickness.GetInside (Padding.Frame) ?? new Rect (default, Frame.Size);
 				return new Rect (default, frameRelativeBounds.Size);
 			}
 			set {
+				// BUGBUG: Margin etc.. can be null (if typeof(Frame))
 				Frame = new Rect (Frame.Location, value.Size
 					+ new Size (Margin.Thickness.Right, Margin.Thickness.Bottom)
 					+ new Size (BorderFrame.Thickness.Right, BorderFrame.Thickness.Bottom)
@@ -1151,7 +1103,7 @@ namespace Terminal.Gui {
 			}
 			SetNeedsLayout ();
 			SetNeedsDisplay ();
-      
+
 			OnAdded (new SuperViewChangedEventArgs (this, view));
 			if (IsInitialized && !view.IsInitialized) {
 				view.BeginInit ();
@@ -1360,8 +1312,7 @@ namespace Terminal.Gui {
 		public Point ScreenToBounds (int x, int y)
 		{
 			if (SuperView == null) {
-				var inner = Padding.Thickness.GetInside (BorderFrame.Thickness.GetInside (Margin.Thickness.GetInside (Frame)));
-				return new Point (x - inner.X, y - inner.Y);
+				return new Point (x - Frame.X + GetBoundsOffset ().X, y - Frame.Y + GetBoundsOffset ().Y);
 			} else {
 				var parent = SuperView.ScreenToView (x, y);
 				return new Point (parent.X - frame.X, parent.Y - frame.Y);
@@ -1380,26 +1331,13 @@ namespace Terminal.Gui {
 		/// <see cref="ConsoleDriver.Rows"/>, respectively.</param>
 		public virtual void ViewToScreen (int col, int row, out int rcol, out int rrow, bool clamped = true)
 		{
-			// Computes the real row, col relative to the screen.
-			if (Padding == null || BorderFrame == null || Margin == null) {
-				rrow = row + Frame.Y;
-				rcol = col + Frame.X;
-			} else {
-				var inner = Padding.Thickness.GetInside (BorderFrame.Thickness.GetInside (Margin.Thickness.GetInside (Frame)));
-				rrow = row + inner.Y;
-				rcol = col + inner.X;
-			}
+			rcol = col + Frame.X + GetBoundsOffset ().X;
+			rrow = row + Frame.Y + GetBoundsOffset ().Y;
 
 			var super = SuperView;
 			while (super != null) {
-				if (!(super.Padding == null || super.BorderFrame == null || super.Margin == null)) {
-					var inner = super.Padding.Thickness.GetInside (super.BorderFrame.Thickness.GetInside (super.Margin.Thickness.GetInside (super.Frame)));
-					rrow += inner.Y;
-					rcol += inner.X;
-				} else {
-					rrow += super.Frame.Y;
-					rcol += super.Frame.X;
-				}
+				rcol += super.Frame.X + super.GetBoundsOffset ().X;
+				rrow += super.Frame.Y + super.GetBoundsOffset ().Y;
 				super = super.SuperView;
 			}
 
@@ -2629,6 +2567,37 @@ namespace Terminal.Gui {
 			return result;
 		} // TopologicalSort
 
+		/// <summary>
+		/// Overriden by <see cref="Frame"/> to do nothing, as the <see cref="Frame"/> does not have frames.
+		/// </summary>
+		internal virtual void LayoutFrames ()
+		{
+			Margin.X = 0;
+			Margin.Y = 0;
+			Margin.Width = Frame.Size.Width;
+			Margin.Height = Frame.Size.Height;
+			Margin.SetNeedsLayout ();
+			Margin.LayoutSubviews ();
+			Margin.SetNeedsDisplay ();
+
+			var border = Margin.Thickness.GetInside (Margin.Frame);
+			BorderFrame.X = border.Location.X;
+			BorderFrame.Y = border.Location.Y;
+			BorderFrame.Width = border.Size.Width;
+			BorderFrame.Height = border.Size.Height;
+			BorderFrame.SetNeedsLayout ();
+			BorderFrame.LayoutSubviews ();
+			BorderFrame.SetNeedsDisplay ();
+
+			var padding = BorderFrame.Thickness.GetInside (BorderFrame.Frame);
+			Padding.X = padding.Location.X;
+			Padding.Y = padding.Location.Y;
+			Padding.Width = padding.Size.Width;
+			Padding.Height = padding.Size.Height;
+			Padding.SetNeedsLayout ();
+			Padding.LayoutSubviews ();
+			Padding.SetNeedsDisplay ();
+		}
 
 		/// <summary>
 		/// Invoked when a view starts executing or when the dimensions of the view have changed, for example in
@@ -2656,7 +2625,7 @@ namespace Terminal.Gui {
 			CollectAll (this, ref nodes, ref edges);
 			var ordered = View.TopologicalSort (SuperView, nodes, edges);
 			foreach (var v in ordered) {
-				LayoutSubview (v, ContentArea);
+				LayoutSubview (v, new Rect (GetBoundsOffset (), Bounds.Size));
 			}
 
 			// If the 'to' is rooted to 'from' and the layoutstyle is Computed it's a special-case.
@@ -2673,10 +2642,10 @@ namespace Terminal.Gui {
 			OnLayoutComplete (new LayoutEventArgs () { OldBounds = oldBounds });
 		}
 
-		private void LayoutSubview (View v, Rect hostFrame)
+		private void LayoutSubview (View v, Rect contentArea)
 		{
 			if (v.LayoutStyle == LayoutStyle.Computed) {
-				v.SetRelativeLayout (hostFrame);
+				v.SetRelativeLayout (contentArea);
 			}
 
 			v.LayoutSubviews ();

+ 3 - 2
UICatalog/Scenarios/ViewExperiments.cs

@@ -268,6 +268,7 @@ namespace UICatalog.Scenarios {
 				Width = Dim.Fill (2),
 				Title = "View with 2xMargin, 2xBorder, & 2xPadding",
 				ColorScheme = Colors.ColorSchemes ["Base"],
+				Id = "DaView"
 			};
 
 			//Application.Top.Add (view);
@@ -451,8 +452,8 @@ namespace UICatalog.Scenarios {
 			};
 			view.Add (edit);
 
-			containerLabel.LayoutComplete += (s, e) => {
-				containerLabel.Text = $"Container.Frame: {Application.Top.Frame} .Bounds: {Application.Top.Bounds}\nView.Frame: {view.Frame} .Bounds: {view.Bounds}\nView.ContentArea: {view.ContentArea}";
+			view.LayoutComplete += (s, e) => {
+				containerLabel.Text = $"Container.Frame: {Application.Top.Frame} .Bounds: {Application.Top.Bounds}\nView.Frame: {view.Frame} .Bounds: {view.Bounds} .BoundsOffset: {view.GetBoundsOffset ()}\n .Padding.Frame: {view.Padding.Frame} .Padding.Bounds: {view.Padding.Bounds}";
 			};
 
 			view.X = Pos.Center ();

+ 243 - 10
UnitTests/Core/ThicknessTests.cs

@@ -153,17 +153,250 @@ namespace Terminal.Gui.CoreTests {
 
 		}
 
+		[Fact ()]
+		public void GetInsideTests_Zero_Thickness ()
+		{
+			var t = new Thickness (0, 0, 0, 0);
+			var r = Rect.Empty;
+			var inside = t.GetInside (r);
+			Assert.Equal (0, inside.X);
+			Assert.Equal (0, inside.Y);
+			Assert.Equal (0, inside.Width);
+			Assert.Equal (0, inside.Height);
+
+			t = new Thickness (0, 0, 0, 0);
+			r = new Rect (0, 0, 1, 1);
+			inside = t.GetInside (r);
+			Assert.Equal (0, inside.X);
+			Assert.Equal (0, inside.Y);
+			Assert.Equal (1, inside.Width);
+			Assert.Equal (1, inside.Height);
+
+			t = new Thickness (0, 0, 0, 0);
+			r = new Rect (1, 1, 1, 1);
+			inside = t.GetInside (r);
+			Assert.Equal (1, inside.X);
+			Assert.Equal (1, inside.Y);
+			Assert.Equal (1, inside.Width);
+			Assert.Equal (1, inside.Height);
+
+			t = new Thickness (0, 0, 0, 0);
+			r = new Rect (0, 0, 1, 0);
+			inside = t.GetInside (r);
+			Assert.Equal (0, inside.X);
+			Assert.Equal (0, inside.Y);
+			Assert.Equal (1, inside.Width);
+			Assert.Equal (0, inside.Height);
+
+			t = new Thickness (0, 0, 0, 0);
+			r = new Rect (0, 0, 0, 1);
+			inside = t.GetInside (r);
+			Assert.Equal (0, inside.X);
+			Assert.Equal (0, inside.Y);
+			Assert.Equal (0, inside.Width);
+			Assert.Equal (1, inside.Height);
+
+			t = new Thickness (0, 0, 0, 0);
+			r = new Rect (-1, -1, 0, 1);
+			inside = t.GetInside (r);
+			Assert.Equal (-1, inside.X);
+			Assert.Equal (-1, inside.Y);
+			Assert.Equal (0, inside.Width);
+			Assert.Equal (1, inside.Height);
+		}
 
 		[Fact ()]
-		public void GetInsideTest ()
+		public void GetInsideTests_Positive_Thickness_Too_Small_Rect_Means_Empty_Size ()
 		{
-			var t = new Thickness (1, 2, 3, 4);
-			var r = new Rect (10, 20, 30, 40);
-			var r2 = t.GetInside (r);
-			Assert.Equal (11, r2.X);
-			Assert.Equal (22, r2.Y);
-			Assert.Equal (26, r2.Width);
-			Assert.Equal (34, r2.Height);
+			var t = new Thickness (1, 1, 1, 1);
+			var r = Rect.Empty;
+			var inside = t.GetInside (r);
+			Assert.Equal (1, inside.X);
+			Assert.Equal (1, inside.Y);
+			Assert.Equal (0, inside.Width);
+			Assert.Equal (0, inside.Height);
+
+			t = new Thickness (1, 1, 1, 1);
+			r = new Rect (0, 0, 1, 1);
+			inside = t.GetInside (r);
+			Assert.Equal (1, inside.X);
+			Assert.Equal (1, inside.Y);
+			Assert.Equal (0, inside.Width);
+			Assert.Equal (0, inside.Height);
+
+			t = new Thickness (1, 1, 1, 1);
+			r = new Rect (1, 1, 1, 1);
+			inside = t.GetInside (r);
+			Assert.Equal (2, inside.X);
+			Assert.Equal (2, inside.Y);
+			Assert.Equal (0, inside.Width);
+			Assert.Equal (0, inside.Height);
+
+			t = new Thickness (1, 1, 1, 1);
+			r = new Rect (0, 0, 1, 0);
+			inside = t.GetInside (r);
+			Assert.Equal (1, inside.X);
+			Assert.Equal (1, inside.Y);
+			Assert.Equal (0, inside.Width);
+			Assert.Equal (0, inside.Height);
+
+			t = new Thickness (1, 1, 1, 1);
+			r = new Rect (0, 0, 0, 1);
+			inside = t.GetInside (r);
+			Assert.Equal (1, inside.X);
+			Assert.Equal (1, inside.Y);
+			Assert.Equal (0, inside.Width);
+			Assert.Equal (0, inside.Height);
+
+			t = new Thickness (1, 1, 1, 1);
+			r = new Rect (-1, -1, 0, 1);
+			inside = t.GetInside (r);
+			Assert.Equal (0, inside.X);
+			Assert.Equal (0, inside.Y);
+			Assert.Equal (0, inside.Width);
+			Assert.Equal (0, inside.Height);
+
+			t = new Thickness (1, 1, 1, 1);
+			r = new Rect (0, 0, 2, 2);
+			inside = t.GetInside (r);
+			Assert.Equal (1, inside.X);
+			Assert.Equal (1, inside.Y);
+			Assert.Equal (0, inside.Width);
+			Assert.Equal (0, inside.Height);
+
+			t = new Thickness (1, 1, 1, 1);
+			r = new Rect (-1, -1, 2, 2);
+			inside = t.GetInside (r);
+			Assert.Equal (0, inside.X);
+			Assert.Equal (0, inside.Y);
+			Assert.Equal (0, inside.Width);
+			Assert.Equal (0, inside.Height);
+
+			t = new Thickness (1, 1, 1, 1);
+			r = new Rect (1, 1, 2, 2);
+			inside = t.GetInside (r);
+			Assert.Equal (2, inside.X);
+			Assert.Equal (2, inside.Y);
+			Assert.Equal (0, inside.Width);
+			Assert.Equal (0, inside.Height);
+
+			t = new Thickness (1, 2, 3, 4);
+			r = new Rect (-1, 0, 4, 6);
+			inside = t.GetInside (r);
+			Assert.Equal (0, inside.X);
+			Assert.Equal (2, inside.Y);
+			Assert.Equal (0, inside.Width);
+			Assert.Equal (0, inside.Height);
+		}
+
+		[Fact ()]
+		public void GetInsideTests_Positive_Thickness_Non_Empty_Size()
+		{
+
+			var t = new Thickness (1, 1, 1, 1);
+			var r = new Rect (0, 0, 3, 3);
+			var inside = t.GetInside (r);
+			Assert.Equal (1, inside.X);
+			Assert.Equal (1, inside.Y);
+			Assert.Equal (1, inside.Width);
+			Assert.Equal (1, inside.Height);
+
+			t = new Thickness (1, 1, 1, 1);
+			r = new Rect (-1, -1, 3, 3);
+			inside = t.GetInside (r);
+			Assert.Equal (0, inside.X);
+			Assert.Equal (0, inside.Y);
+			Assert.Equal (1, inside.Width);
+			Assert.Equal (1, inside.Height);
+
+			t = new Thickness (1, 1, 1, 1);
+			r = new Rect (1, 1, 3, 3);
+			inside = t.GetInside (r);
+			Assert.Equal (2, inside.X);
+			Assert.Equal (2, inside.Y);
+			Assert.Equal (1, inside.Width);
+			Assert.Equal (1, inside.Height);
+
+			t = new Thickness (1, 2, 3, 4);
+			r = new Rect (-1, 0, 50, 60);
+			inside = t.GetInside (r);
+			Assert.Equal (0, inside.X);
+			Assert.Equal (2, inside.Y);
+			Assert.Equal (46, inside.Width);
+			Assert.Equal (54, inside.Height);
+		}
+
+		[Fact ()]
+		public void GetInsideTests_Negative_Thickness_Non_Empty_Size ()
+		{
+			var t = new Thickness (-1, -1, -1, -1);
+			var r = new Rect (0, 0, 3, 3);
+			var inside = t.GetInside (r);
+			Assert.Equal (-1, inside.X);
+			Assert.Equal (-1, inside.Y);
+			Assert.Equal (5, inside.Width);
+			Assert.Equal (5, inside.Height);
+
+			t = new Thickness (-1, -1, -1, -1);
+			r = new Rect (-1, -1, 3, 3);
+			inside = t.GetInside (r);
+			Assert.Equal (-2, inside.X);
+			Assert.Equal (-2, inside.Y);
+			Assert.Equal (5, inside.Width);
+			Assert.Equal (5, inside.Height);
+
+			t = new Thickness (-1, -1, -1, -1);
+			r = new Rect (1, 1, 3, 3);
+			inside = t.GetInside (r);
+			Assert.Equal (0, inside.X);
+			Assert.Equal (0, inside.Y);
+			Assert.Equal (5, inside.Width);
+			Assert.Equal (5, inside.Height);
+
+			t = new Thickness (-1, -2, -3, -4);
+			r = new Rect (-1, 0, 50, 60);
+			inside = t.GetInside (r);
+			Assert.Equal (-2, inside.X);
+			Assert.Equal (-2, inside.Y);
+			Assert.Equal (54, inside.Width);
+			Assert.Equal (66, inside.Height);
+		}
+
+
+		[Fact ()]
+		public void GetInsideTests_Mixed_Pos_Neg_Thickness_Non_Empty_Size ()
+		{
+			var t = new Thickness (-1, 1, -1, 1);
+			var r = new Rect (0, 0, 3, 3);
+			var inside = t.GetInside (r);
+			Assert.Equal (-1, inside.X);
+			Assert.Equal (1, inside.Y);
+			Assert.Equal (5, inside.Width);
+			Assert.Equal (1, inside.Height);
+
+			t = new Thickness (-1, 1, -1, 1);
+			r = new Rect (-1, -1, 3, 3);
+			inside = t.GetInside (r);
+			Assert.Equal (-2, inside.X);
+			Assert.Equal (0, inside.Y);
+			Assert.Equal (5, inside.Width);
+			Assert.Equal (1, inside.Height);
+
+			t = new Thickness (-1, 1, -1, 1);
+			r = new Rect (1, 1, 3, 3);
+			inside = t.GetInside (r);
+			Assert.Equal (0, inside.X);
+			Assert.Equal (2, inside.Y);
+			Assert.Equal (5, inside.Width);
+			Assert.Equal (1, inside.Height);
+
+			t = new Thickness (-2, -1, 0, 1);
+			r = new Rect (-1, 0, 50, 60);
+			inside = t.GetInside (r);
+			Assert.Equal (-3, inside.X);
+			Assert.Equal (-1, inside.Y);
+			Assert.Equal (52, inside.Width);
+			Assert.Equal (60, inside.Height);
 		}
 
 		[Fact (), AutoInitShutdown]
@@ -202,11 +435,11 @@ namespace Terminal.Gui.CoreTests {
      T                                      T
      T                                      T
      TTTest (Left=1,Top=1,Right=1,Bottom=1)TT", output);
-			
+
 			t = new Thickness (1, 2, 3, 4);
 			r = new Rect (5, 5, 40, 15);
 			ConsoleDriver.Diagnostics |= ConsoleDriver.DiagnosticFlags.FramePadding;
-			Application.Driver.FillRect (new Rect (0,0, Application.Driver.Cols, Application.Driver.Rows), ' ');
+			Application.Driver.FillRect (new Rect (0, 0, Application.Driver.Cols, Application.Driver.Rows), ' ');
 			t.Draw (r, "Test");
 			ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.Off;
 			TestHelpers.AssertDriverContentsWithFrameAre (@"