Browse Source

Fixes #2578 - Updates mouse events to be relative to `View.Bounds` (#2920)

* initial commit

* Clarified RootMouseEvent

* Added application mouse coord tests

* ViewToScreen -> BoundsToScreen

* Simplified View.Move

* Simplified View.Move

* Updated API docs; made some functions private

* more ViewLayout cleanup

* more ViewLayout cleanup

* Added View.ScreenToBounds and low-level coord unit tests

* Partial fix

* Refactored Application.OnMouseEvent... Tests still fail and views are broken

* Added Bounds/FrameToScreen

* Remamed ScreenToView->ScreenToFrame

* All unit tests pass

* Fixed ListView

* Fixed TableView

* Fixed ColorPicker

* Fixed RadioGroup

* Fixed ListView unit tests

* Fixed line drawing scenario

* Updated comment

* fixed api doc typo

* fixed formatting

* added some thickness Contains unit tests

* MouseEvent api doc updates

* More thickness tests

* More thickness tests
Tig 1 year ago
parent
commit
42b9ad1d61
35 changed files with 2299 additions and 1418 deletions
  1. 140 57
      Terminal.Gui/Application.cs
  2. 13 0
      Terminal.Gui/Drawing/Thickness.cs
  3. 24 11
      Terminal.Gui/Input/Event.cs
  4. 2 2
      Terminal.Gui/Input/GrabMouseEventArgs.cs
  5. 5 2
      Terminal.Gui/Input/Responder.cs
  6. 155 85
      Terminal.Gui/Text/ViewLayout.cs
  7. 21 5
      Terminal.Gui/View/Frame.cs
  8. 11 11
      Terminal.Gui/View/ViewDrawing.cs
  9. 4 3
      Terminal.Gui/View/ViewText.cs
  10. 2 4
      Terminal.Gui/Views/ColorPicker.cs
  11. 1 1
      Terminal.Gui/Views/ComboBox.cs
  12. 2 2
      Terminal.Gui/Views/ContextMenu.cs
  13. 1 1
      Terminal.Gui/Views/Line.cs
  14. 4 5
      Terminal.Gui/Views/ListView.cs
  15. 9 9
      Terminal.Gui/Views/Menu.cs
  16. 2 2
      Terminal.Gui/Views/ProgressBar.cs
  17. 2 2
      Terminal.Gui/Views/RadioGroup.cs
  18. 2 3
      Terminal.Gui/Views/TableView/TableView.cs
  19. 4 4
      Terminal.Gui/Views/TextField.cs
  20. 4 4
      Terminal.Gui/Views/TileView.cs
  21. 2 0
      Terminal.Gui/Views/Toplevel.cs
  22. 1 1
      Terminal.Gui/Views/TreeView/TreeView.cs
  23. 2 2
      UICatalog/Scenarios/LineDrawing.cs
  24. 1 1
      UICatalog/Scenarios/Notepad.cs
  25. 2 138
      UnitTests/Application/ApplicationTests.cs
  26. 0 7
      UnitTests/Application/MainLoopTests.cs
  27. 348 0
      UnitTests/Application/MouseTests.cs
  28. 595 488
      UnitTests/Drawing/ThicknessTests.cs
  29. 35 36
      UnitTests/View/BorderTests.cs
  30. 522 412
      UnitTests/View/FrameTests.cs
  31. 262 0
      UnitTests/View/Layout/CoordinateTests.cs
  32. 52 52
      UnitTests/View/NavigationTests.cs
  33. 3 3
      UnitTests/View/ViewTests.cs
  34. 65 64
      UnitTests/Views/ListViewTests.cs
  35. 1 1
      UnitTests/Views/ToplevelTests.cs

+ 140 - 57
Terminal.Gui/Application.cs

@@ -248,8 +248,8 @@ namespace Terminal.Gui {
 			NotifyNewRunState = null;
 			NotifyStopRunState = null;
 			_initialized = false;
-			_mouseGrabView = null;
-			_lastMouseOwnerView = null;
+			MouseGrabView = null;
+			_mouseEnteredView = null;
 
 			// Reset synchronization context to allow the user to run async/await,
 			// as the main loop has been ended, the synchronization context from 
@@ -304,7 +304,7 @@ namespace Terminal.Gui {
 			}
 
 			// Ensure the mouse is ungrabed.
-			_mouseGrabView = null;
+			MouseGrabView = null;
 
 			var rs = new RunState (Toplevel);
 
@@ -656,7 +656,7 @@ namespace Terminal.Gui {
 				}
 
 				MainLoop.RunIteration ();
-				Iteration?.Invoke (null, new IterationEventArgs());
+				Iteration?.Invoke (null, new IterationEventArgs ());
 
 				EnsureModalOrVisibleAlwaysOnTop (state.Toplevel);
 				if (state.Toplevel != Current) {
@@ -1018,12 +1018,11 @@ namespace Terminal.Gui {
 		/// </summary>
 		public static View WantContinuousButtonPressedView { get; private set; }
 
-		static View _mouseGrabView;
-
 		/// <summary>
-		/// The view that grabbed the mouse, to where mouse events will be routed to.
+		/// Gets the view that grabbed the mouse (e.g. for dragging). When this is set, all mouse events will be
+		/// routed to this view until the view calls <see cref="UngrabMouse"/> or the mouse is released.
 		/// </summary>
-		public static View MouseGrabView => _mouseGrabView;
+		public static View MouseGrabView { get; private set; }
 
 		/// <summary>
 		/// Invoked when a view wants to grab the mouse; can be canceled.
@@ -1031,7 +1030,7 @@ namespace Terminal.Gui {
 		public static event EventHandler<GrabMouseEventArgs> GrabbingMouse;
 
 		/// <summary>
-		/// Invoked when a view wants ungrab the mouse; can be canceled.
+		/// Invoked when a view wants un-grab the mouse; can be canceled.
 		/// </summary>
 		public static event EventHandler<GrabMouseEventArgs> UnGrabbingMouse;
 
@@ -1041,7 +1040,7 @@ namespace Terminal.Gui {
 		public static event EventHandler<ViewEventArgs> GrabbedMouse;
 
 		/// <summary>
-		/// Invoked after a view has ungrabbed the mouse.
+		/// Invoked after a view has un-grabbed the mouse.
 		/// </summary>
 		public static event EventHandler<ViewEventArgs> UnGrabbedMouse;
 
@@ -1051,12 +1050,12 @@ namespace Terminal.Gui {
 		/// <param name="view">View that will receive all mouse events until <see cref="UngrabMouse"/> is invoked.</param>
 		public static void GrabMouse (View view)
 		{
-			if (view == null)
+			if (view == null) {
 				return;
+			}
 			if (!OnGrabbingMouse (view)) {
 				OnGrabbedMouse (view);
-				_mouseGrabView = view;
-				//Driver.UncookMouse ();
+				MouseGrabView = view;
 			}
 		}
 
@@ -1065,19 +1064,20 @@ namespace Terminal.Gui {
 		/// </summary>
 		public static void UngrabMouse ()
 		{
-			if (_mouseGrabView == null)
+			if (MouseGrabView == null) {
 				return;
-			if (!OnUnGrabbingMouse (_mouseGrabView)) {
-				OnUnGrabbedMouse (_mouseGrabView);
-				_mouseGrabView = null;
-				//Driver.CookMouse ();
+			}
+			if (!OnUnGrabbingMouse (MouseGrabView)) {
+				OnUnGrabbedMouse (MouseGrabView);
+				MouseGrabView = null;
 			}
 		}
 
 		static bool OnGrabbingMouse (View view)
 		{
-			if (view == null)
+			if (view == null) {
 				return false;
+			}
 			var evArgs = new GrabMouseEventArgs (view);
 			GrabbingMouse?.Invoke (view, evArgs);
 			return evArgs.Cancel;
@@ -1085,8 +1085,9 @@ namespace Terminal.Gui {
 
 		static bool OnUnGrabbingMouse (View view)
 		{
-			if (view == null)
+			if (view == null) {
 				return false;
+			}
 			var evArgs = new GrabMouseEventArgs (view);
 			UnGrabbingMouse?.Invoke (view, evArgs);
 			return evArgs.Cancel;
@@ -1094,19 +1095,22 @@ namespace Terminal.Gui {
 
 		static void OnGrabbedMouse (View view)
 		{
-			if (view == null)
+			if (view == null) {
 				return;
+			}
 			GrabbedMouse?.Invoke (view, new ViewEventArgs (view));
 		}
 
 		static void OnUnGrabbedMouse (View view)
 		{
-			if (view == null)
+			if (view == null) {
 				return;
+			}
 			UnGrabbedMouse?.Invoke (view, new ViewEventArgs (view));
 		}
 
-		static View _lastMouseOwnerView;
+		// Used by OnMouseEvent to track the last view that was clicked on.
+		static View _mouseEnteredView;
 
 		/// <summary>
 		/// Event fired when a mouse move or click occurs. Coordinates are screen relative.
@@ -1128,16 +1132,16 @@ namespace Terminal.Gui {
 		/// <remarks>
 		/// This method can be used to simulate a mouse event, e.g. in unit tests.
 		/// </remarks>
-		/// <param name="a"></param>
+		/// <param name="a">The mouse event with coordinates relative to the screen.</param>
 		public static void OnMouseEvent (MouseEventEventArgs a)
 		{
-			static bool OutsideBounds (Point p, Rect r) => p.X < 0 || p.X > r.Right || p.Y < 0 || p.Y > r.Bottom;
+			static bool OutsideRect (Point p, Rect r) => p.X < 0 || p.X > r.Right || p.Y < 0 || p.Y > r.Bottom;
 
 			if (IsMouseDisabled) {
 				return;
 			}
 
-			var view = View.FindDeepestView (Current, a.MouseEvent.X, a.MouseEvent.Y, out int rx, out int ry);
+			var view = View.FindDeepestView (Current, a.MouseEvent.X, a.MouseEvent.Y, out int screenX, out int screenY);
 
 			if (view != null && view.WantContinuousButtonPressed) {
 				WantContinuousButtonPressedView = view;
@@ -1153,8 +1157,10 @@ namespace Terminal.Gui {
 				return;
 			}
 
-			if (_mouseGrabView != null) {
-				var newxy = _mouseGrabView.ScreenToView (a.MouseEvent.X, a.MouseEvent.Y);
+			if (MouseGrabView != null) {
+				// If the mouse is grabbed, send the event to the view that grabbed it.
+				// The coordinates are relative to the Bounds of the view that grabbed the mouse.
+				var newxy = MouseGrabView.ScreenToFrame (a.MouseEvent.X, a.MouseEvent.Y);
 				var nme = new MouseEvent () {
 					X = newxy.X,
 					Y = newxy.Y,
@@ -1163,57 +1169,134 @@ namespace Terminal.Gui {
 					OfY = a.MouseEvent.Y - newxy.Y,
 					View = view
 				};
-				if (OutsideBounds (new Point (nme.X, nme.Y), _mouseGrabView.Bounds)) {
-					_lastMouseOwnerView?.OnMouseLeave (a.MouseEvent);
+				if (OutsideRect (new Point (nme.X, nme.Y), MouseGrabView.Bounds)) {
+					// The mouse has moved outside the bounds of the the view that
+					// grabbed the mouse, so we tell the view that last got 
+					// OnMouseEnter the mouse is leaving
+					// BUGBUG: That sentence makes no sense. Either I'm missing something
+					// or this logic is flawed.
+					_mouseEnteredView?.OnMouseLeave (a.MouseEvent);
 				}
 				//System.Diagnostics.Debug.WriteLine ($"{nme.Flags};{nme.X};{nme.Y};{mouseGrabView}");
-				if (_mouseGrabView?.OnMouseEvent (nme) == true) {
+				if (MouseGrabView?.OnMouseEvent (nme) == true) {
 					return;
 				}
 			}
 
-			if ((view == null || view == OverlappedTop) && !Current.Modal && OverlappedTop != null
-				&& a.MouseEvent.Flags != MouseFlags.ReportMousePosition && a.MouseEvent.Flags != 0) {
+			if ((view == null || view == OverlappedTop) &&
+				Current is { Modal: false } && OverlappedTop != null &&
+				a.MouseEvent.Flags != MouseFlags.ReportMousePosition &&
+				a.MouseEvent.Flags != 0) {
 
 				var top = FindDeepestTop (Top, a.MouseEvent.X, a.MouseEvent.Y, out _, out _);
-				view = View.FindDeepestView (top, a.MouseEvent.X, a.MouseEvent.Y, out rx, out ry);
+				view = View.FindDeepestView (top, a.MouseEvent.X, a.MouseEvent.Y, out screenX, out screenY);
 
 				if (view != null && view != OverlappedTop && top != Current) {
 					MoveCurrent ((Toplevel)top);
 				}
 			}
 
+			bool FrameHandledMouseEvent (Frame frame)
+			{
+				if (frame?.Thickness.Contains (frame.FrameToScreen (), a.MouseEvent.X, a.MouseEvent.Y) ?? false) {
+					var boundsPoint = frame.ScreenToBounds (a.MouseEvent.X, a.MouseEvent.Y);
+					var me = new MouseEvent () {
+						X = boundsPoint.X,
+						Y = boundsPoint.Y,
+						Flags = a.MouseEvent.Flags,
+						OfX = boundsPoint.X,
+						OfY = boundsPoint.Y,
+						View = frame
+					};
+					frame.OnMouseEvent (me);
+					return true;
+				}
+				return false;
+			}
+
 			if (view != null) {
-				var nme = new MouseEvent () {
-					X = rx,
-					Y = ry,
-					Flags = a.MouseEvent.Flags,
-					OfX = 0,
-					OfY = 0,
-					View = view
-				};
+				// Work inside-out (Padding, Border, Margin)
+				// TODO: Debate whether inside-out or outside-in is the right strategy
+				if (FrameHandledMouseEvent (view?.Padding)) {
+					return;
+				}
+				if (FrameHandledMouseEvent (view?.Border)) {
+					if (view is Toplevel) {
+						// TODO: This is a temporary hack to work around the fact that 
+						// drag handling is handled in Toplevel (See Issue #2537)
+
+						var me = new MouseEvent () {
+							X = screenX,
+							Y = screenY,
+							Flags = a.MouseEvent.Flags,
+							OfX = screenX,
+							OfY = screenY,
+							View = view
+						};
+
+						if (_mouseEnteredView == null) {
+							_mouseEnteredView = view;
+							view.OnMouseEnter (me);
+						} else if (_mouseEnteredView != view) {
+							_mouseEnteredView.OnMouseLeave (me);
+							view.OnMouseEnter (me);
+							_mouseEnteredView = view;
+						}
+
+						if (!view.WantMousePositionReports && a.MouseEvent.Flags == MouseFlags.ReportMousePosition) {
+							return;
+						}
 
-				if (_lastMouseOwnerView == null) {
-					_lastMouseOwnerView = view;
-					view.OnMouseEnter (nme);
-				} else if (_lastMouseOwnerView != view) {
-					_lastMouseOwnerView.OnMouseLeave (nme);
-					view.OnMouseEnter (nme);
-					_lastMouseOwnerView = view;
+						WantContinuousButtonPressedView = view.WantContinuousButtonPressed ? view : null;
+
+						if (view.OnMouseEvent (me)) {
+							// Should we bubble up the event, if it is not handled?
+							//return;
+						}
+
+						BringOverlappedTopToFront ();
+					}
+					return;
 				}
 
-				if (!view.WantMousePositionReports && a.MouseEvent.Flags == MouseFlags.ReportMousePosition)
+				if (FrameHandledMouseEvent (view?.Margin)) {
 					return;
+				}
+
+				var bounds = view.BoundsToScreen (view.Bounds);
+				if (bounds.Contains (a.MouseEvent.X, a.MouseEvent.Y)) {
+					var boundsPoint = view.ScreenToBounds (a.MouseEvent.X, a.MouseEvent.Y);
+					var me = new MouseEvent () {
+						X = boundsPoint.X,
+						Y = boundsPoint.Y,
+						Flags = a.MouseEvent.Flags,
+						OfX = boundsPoint.X,
+						OfY = boundsPoint.Y,
+						View = view
+					};
+
+					if (_mouseEnteredView == null) {
+						_mouseEnteredView = view;
+						view.OnMouseEnter (me);
+					} else if (_mouseEnteredView != view) {
+						_mouseEnteredView.OnMouseLeave (me);
+						view.OnMouseEnter (me);
+						_mouseEnteredView = view;
+					}
 
-				if (view.WantContinuousButtonPressed)
-					WantContinuousButtonPressedView = view;
-				else
-					WantContinuousButtonPressedView = null;
+					if (!view.WantMousePositionReports && a.MouseEvent.Flags == MouseFlags.ReportMousePosition) {
+						return;
+					}
+
+					WantContinuousButtonPressedView = view.WantContinuousButtonPressed ? view : null;
 
-				// Should we bubbled up the event, if it is not handled?
-				view.OnMouseEvent (nme);
+					if (view.OnMouseEvent (me)) {
+						// Should we bubble up the event, if it is not handled?
+						//return;
+					}
 
-				BringOverlappedTopToFront ();
+					BringOverlappedTopToFront ();
+				}
 			}
 		}
 		#endregion Mouse handling

+ 13 - 0
Terminal.Gui/Drawing/Thickness.cs

@@ -104,6 +104,19 @@ namespace Terminal.Gui {
 			}
 		}
 
+		/// <summary>
+		/// Gets whether the specified coordinates lie within the thickness (inside the bounding rectangle but outside of
+		/// the rectangle described by <see cref="GetInside(Rect)"/>.
+		/// </summary>
+		/// <param name="x"></param>
+		/// <param name="y"></param>
+		/// <returns><see langword="true"/> if the specified coordinate is within the thickness; <see langword="false"/> otherwise.</returns>
+		public bool Contains (Rect outside, int x, int y)
+		{
+			var inside = GetInside (outside);
+			return outside.Contains (x, y) && !inside.Contains (x, y);
+		}
+
 		/// <summary>
 		/// 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

+ 24 - 11
Terminal.Gui/Input/Event.cs

@@ -770,45 +770,58 @@ namespace Terminal.Gui {
 
 	/// <summary>
 	/// Low-level construct that conveys the details of mouse events, such
-	/// as coordinates and button state, from ConsoleDrivers up to <see cref="Application"/> and
+	/// as coordinates and button state, from ConsoleDrivers up to <see cref="Application"/> and then to
 	/// Views.
 	/// </summary>
-	/// <remarks>The <see cref="Application"/> class includes the <see cref="Application.MouseEvent"/>
-	/// Action which takes a MouseEvent argument.</remarks>
+	/// <remarks>See <see cref="Application.OnMouseEvent(MouseEventEventArgs)"/> and <see cref="Responder.OnMouseEnter(MouseEvent)"/>.</remarks>
 	public class MouseEvent {
 		/// <summary>
-		/// The X (column) location for the mouse event.
+		/// The X (column) location for the mouse event relative to <see cref="View.Bounds"/>.
 		/// </summary>
 		public int X { get; set; }
 
 		/// <summary>
-		/// The Y (column) location for the mouse event.
+		/// The Y (column) location for the mouse event relative to <see cref="View.Bounds"/>.
 		/// </summary>
 		public int Y { get; set; }
 
 		/// <summary>
-		/// Flags indicating the kind of mouse event that is being posted.
+		/// Gets or sets the flags that indicate the kind of mouse event that is being posted.
 		/// </summary>
 		public MouseFlags Flags { get; set; }
 
 		/// <summary>
-		/// The offset X (column) location for the mouse event.
+		/// Provides the X (column) mouse position offset from the grabbed view (see <see cref="Application.GrabMouse"/>.
 		/// </summary>
+		/// <remarks>
+		/// Calculated and processed in <see cref="Application.OnMouseEvent(MouseEventEventArgs)"/>.
+		/// Whichever view that has called <see cref="Application.GrabMouse"/>, will receive all the mouse event
+		/// with <see cref="View.Bounds"/> relative coordinates. The <see cref="OfX"/> and <see cref="OfY"/> provide
+		/// the screen-relative offset of these coordinates.
+		/// Using these properties, the view that has grabbed the mouse will know how much the mouse has moved.
+		/// </remarks>
 		public int OfX { get; set; }
 
 		/// <summary>
-		/// The offset Y (column) location for the mouse event.
+		/// Provides the Y (row) mouse position offset from the grabbed view (see <see cref="Application.GrabMouse"/>.
 		/// </summary>
+		/// <remarks>
+		/// Calculated and processed in <see cref="Application.OnMouseEvent(MouseEventEventArgs)"/>.
+		/// Whichever view that has called <see cref="Application.GrabMouse"/>, will receive all the mouse event
+		/// with <see cref="View.Bounds"/> relative coordinates. The <see cref="OfX"/> and <see cref="OfY"/> provide
+		/// the screen-relative offset of these coordinates.
+		/// Using these properties, the view that has grabbed the mouse will know how much the mouse has moved.
+		/// </remarks>
 		public int OfY { get; set; }
 
 		/// <summary>
-		/// The current view at the location for the mouse event.
+		/// Gets or sets the view that should process the mouse event.
 		/// </summary>
 		public View View { get; set; }
 
 		/// <summary>
-		/// Indicates if the current mouse event has already been processed and the driver should stop notifying any other event subscriber.
-		/// Its important to set this value to true specially when updating any View's layout from inside the subscriber method.
+		/// Indicates if the mouse event has been handled by a view and other subscribers should ignore the event.
+		/// IMPORTANT: Set this value to <see langword="true"/> when updating any View's layout from inside the subscriber method.
 		/// </summary>
 		public bool Handled { get; set; }
 

+ 2 - 2
Terminal.Gui/Input/GrabMouseEventArgs.cs

@@ -2,7 +2,7 @@
 
 namespace Terminal.Gui {
 	/// <summary>
-	/// Args for events that relate to specific <see cref="Application.MouseGrabView"/>
+	/// Args <see cref="Application.GrabMouse"/> related events.
 	/// </summary>
 	public class GrabMouseEventArgs : EventArgs {
 
@@ -16,7 +16,7 @@ namespace Terminal.Gui {
 		}
 
 		/// <summary>
-		/// The view that the event is about.
+		/// Gets the view that grabbed the mouse.
 		/// </summary>
 		public View View { get; }
 

+ 5 - 2
Terminal.Gui/Input/Responder.cs

@@ -183,7 +183,9 @@ namespace Terminal.Gui {
 		}
 
 		/// <summary>
-		/// Method invoked when a mouse event is generated for the first time.
+		/// Called when the mouse first enters the view; the view will now
+		/// receives mouse events until the mouse leaves the view. At which time, <see cref="OnMouseLeave(Gui.MouseEvent)"/>
+		/// will be called.
 		/// </summary>
 		/// <param name="mouseEvent"></param>
 		/// <returns><c>true</c>, if the event was handled, <c>false</c> otherwise.</returns>
@@ -193,7 +195,8 @@ namespace Terminal.Gui {
 		}
 
 		/// <summary>
-		/// Method invoked when a mouse event is generated for the last time.
+		/// Called when the mouse has moved outside of the view; the view will no longer receive mouse events (until
+		/// the mouse moves within the view again and <see cref="OnMouseEnter(Gui.MouseEvent)"/> is called).
 		/// </summary>
 		/// <param name="mouseEvent"></param>
 		/// <returns><c>true</c>, if the event was handled, <c>false</c> otherwise.</returns>

+ 155 - 85
Terminal.Gui/View/ViewLayout.cs → Terminal.Gui/Text/ViewLayout.cs

@@ -28,11 +28,11 @@ namespace Terminal.Gui {
 
 	public partial class View {
 
-		// The frame for the object. Superview relative.
+		// The frame for the object. Relative to the SuperView's Bounds.
 		Rect _frame;
 
 		/// <summary>
-		/// Gets or sets the frame for the view. The frame is relative to the view's container (<see cref="SuperView"/>).
+		/// Gets or sets the frame for the view. The frame is relative to the <see cref="SuperView"/>'s <see cref="Bounds"/>.
 		/// </summary>
 		/// <value>The frame.</value>
 		/// <remarks>
@@ -58,19 +58,41 @@ namespace Terminal.Gui {
 		}
 
 		/// <summary>
-		/// The Thickness that separates a View from other SubViews of the same SuperView. 
-		/// The Margin is not part of the View's content and is not clipped by the View's Clip Area. 
+		/// The frame (specified as a <see cref="Thickness"/>) that separates a View from other SubViews of the same SuperView. 
+		/// The margin offsets the <see cref="Bounds"/> from the <see cref="Frame"/>. 
 		/// </summary>
+		/// <remarks>
+		/// <para>
+		/// The frames (<see cref="Margin"/>, <see cref="Border"/>, and <see cref="Padding"/>) are not part of the View's content
+		/// and are not clipped by the View's Clip Area.
+		/// </para>
+		/// <para>
+		/// Changing the size of a frame (<see cref="Margin"/>, <see cref="Border"/>, or <see cref="Padding"/>)
+		/// will change the size of the <see cref="Frame"/> and trigger <see cref="LayoutSubviews"/> to update the layout of the
+		/// <see cref="SuperView"/> and its <see cref="Subviews"/>.
+		/// </para>
+		/// </remarks>
 		public Frame Margin { get; private set; }
 
 		/// <summary>
-		///  Thickness where a visual border (drawn using line-drawing glyphs) and the Title are drawn. 
+		/// The frame (specified as a <see cref="Thickness"/>) inside of the view that offsets the <see cref="Bounds"/> from the <see cref="Margin"/>. 
+		///  The Border provides the space for a visual border (drawn using line-drawing glyphs) and the Title. 
 		///  The Border expands inward; in other words if `Border.Thickness.Top == 2` the border and 
 		///  title will take up the first row and the second row will be filled with spaces. 
-		///  The Border is not part of the View's content and is not clipped by the View's `ClipArea`.
 		/// </summary>
 		/// <remarks>
+		/// <para>
 		/// <see cref="BorderStyle"/> provides a simple helper for turning a simple border frame on or off.
+		/// </para>
+		/// <para>
+		/// The frames (<see cref="Margin"/>, <see cref="Border"/>, and <see cref="Padding"/>) are not part of the View's content
+		/// and are not clipped by the View's Clip Area.
+		/// </para>
+		/// <para>
+		/// Changing the size of a frame (<see cref="Margin"/>, <see cref="Border"/>, or <see cref="Padding"/>)
+		/// will change the size of the <see cref="Frame"/> and trigger <see cref="LayoutSubviews"/> to update the layout of the
+		/// <see cref="SuperView"/> and its <see cref="Subviews"/>.
+		/// </para>
 		/// </remarks>
 		public Frame Border { get; private set; }
 
@@ -111,11 +133,18 @@ namespace Terminal.Gui {
 		}
 
 		/// <summary>
-		/// Means the Thickness inside of an element that offsets the `Content` from the Border. 
-		/// Padding is `{0, 0, 0, 0}` by default. Padding is not part of the View's content and is not clipped by the View's `ClipArea`.
+		/// The frame (specified as a <see cref="Thickness"/>) inside of the view that offsets the <see cref="Bounds"/> from the <see cref="Border"/>. 
 		/// </summary>
 		/// <remarks>
-		/// (NOTE: in v1 `Padding` is OUTSIDE of the `Border`). 
+		/// <para>
+		/// The frames (<see cref="Margin"/>, <see cref="Border"/>, and <see cref="Padding"/>) are not part of the View's content
+		/// and are not clipped by the View's Clip Area.
+		/// </para>
+		/// <para>
+		/// Changing the size of a frame (<see cref="Margin"/>, <see cref="Border"/>, or <see cref="Padding"/>)
+		/// will change the size of the <see cref="Frame"/> and trigger <see cref="LayoutSubviews"/> to update the layout of the
+		/// <see cref="SuperView"/> and its <see cref="Subviews"/>.
+		/// </para>
 		/// </remarks>
 		public Frame Padding { get; private set; }
 
@@ -181,9 +210,9 @@ namespace Terminal.Gui {
 		LayoutStyle _layoutStyle;
 
 		/// <summary>
-		/// Controls how the View's <see cref="Frame"/> is computed during the LayoutSubviews method, if the style is set to
-		/// <see cref="Terminal.Gui.LayoutStyle.Absolute"/>, 
-		/// LayoutSubviews does not change the <see cref="Frame"/>. If the style is <see cref="Terminal.Gui.LayoutStyle.Computed"/>
+		/// Controls how the View's <see cref="Frame"/> is computed during <see cref="LayoutSubviews"/>. If the style is set to
+		/// <see cref="LayoutStyle.Absolute"/>, 
+		/// LayoutSubviews does not change the <see cref="Frame"/>. If the style is <see cref="LayoutStyle.Computed"/>
 		/// the <see cref="Frame"/> is updated using
 		/// the <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties.
 		/// </summary>
@@ -197,16 +226,27 @@ namespace Terminal.Gui {
 		}
 
 		/// <summary>
-		/// The View-relative rectangle where View content is displayed. SubViews are positioned relative to 
-		/// Bounds.<see cref="Rect.Location">Location</see> (which is always (0, 0)) and <see cref="Draw()"/> clips drawing to 
-		/// Bounds.<see cref="Rect.Size">Size</see>.
+		/// The view's content area.
+		/// <para>
+		/// SubViews are positioned relative to Bounds.
+		/// </para>
+		/// <para>
+		/// Drawing is clipped to Bounds (<see cref="Draw()"/> clips drawing to Bounds.<see cref="Rect.Size">Size</see>).
+		/// </para>
+		/// <para>
+		/// Mouse events are reported relative to Bounds.
+		/// </para>
 		/// </summary>
-		/// <value>The bounds.</value>
+		/// <value>The view's content area.</value>
 		/// <remarks>
 		/// <para>
 		/// 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>
+		/// When using <see cref="LayoutStyle.Computed"/>, Bounds is not valid until after the view has been initialized (after <see cref="EndInit"/> has been called and <see cref="Initialized"/>
+		/// has fired). Accessing this property before the view is initialized is considered an error./>
+		/// </para>
 		/// </remarks>
 		public virtual Rect Bounds {
 			get {
@@ -242,7 +282,7 @@ namespace Terminal.Gui {
 		}
 
 		// Diagnostics to highlight when X or Y is read before the view has been initialized
-		private Pos VerifyIsIntialized (Pos pos)
+		Pos VerifyIsInitialized (Pos pos)
 		{
 #if DEBUG
 			if (LayoutStyle == LayoutStyle.Computed && (!IsInitialized)) {
@@ -253,7 +293,7 @@ namespace Terminal.Gui {
 		}
 
 		// Diagnostics to highlight when Width or Height is read before the view has been initialized
-		private Dim VerifyIsIntialized (Dim dim)
+		Dim VerifyIsInitialized (Dim dim)
 		{
 #if DEBUG
 			if (LayoutStyle == LayoutStyle.Computed && (!IsInitialized)) {
@@ -273,7 +313,7 @@ namespace Terminal.Gui {
 		/// If <see cref="LayoutStyle"/> is <see cref="Terminal.Gui.LayoutStyle.Absolute"/> changing this property has no effect and its value is indeterminate. 
 		/// </remarks>
 		public Pos X {
-			get => VerifyIsIntialized (_x);
+			get => VerifyIsInitialized (_x);
 			set {
 				if (ForceValidatePosDim && !ValidatePosDim (_x, value)) {
 					throw new ArgumentException ();
@@ -293,7 +333,7 @@ namespace Terminal.Gui {
 		/// If <see cref="LayoutStyle"/> is <see cref="Terminal.Gui.LayoutStyle.Absolute"/> changing this property has no effect and its value is indeterminate. 
 		/// </remarks>
 		public Pos Y {
-			get => VerifyIsIntialized (_y);
+			get => VerifyIsInitialized (_y);
 			set {
 				if (ForceValidatePosDim && !ValidatePosDim (_y, value)) {
 					throw new ArgumentException ();
@@ -314,7 +354,7 @@ namespace Terminal.Gui {
 		/// If <see cref="LayoutStyle"/> is <see cref="Terminal.Gui.LayoutStyle.Absolute"/> changing this property has no effect and its value is indeterminate. 
 		/// </remarks>
 		public Dim Width {
-			get => VerifyIsIntialized (_width);
+			get => VerifyIsInitialized (_width);
 			set {
 				if (ForceValidatePosDim && !ValidatePosDim (_width, value)) {
 					throw new ArgumentException ("ForceValidatePosDim is enabled", nameof (Width));
@@ -339,7 +379,7 @@ namespace Terminal.Gui {
 		/// <value>The height.</value>
 		/// If <see cref="LayoutStyle"/> is <see cref="Terminal.Gui.LayoutStyle.Absolute"/> changing this property has no effect and its value is indeterminate. 
 		public Dim Height {
-			get => VerifyIsIntialized (_height);
+			get => VerifyIsInitialized (_height);
 			set {
 				if (ForceValidatePosDim && !ValidatePosDim (_height, value)) {
 					throw new ArgumentException ("ForceValidatePosDim is enabled", nameof (Height));
@@ -377,8 +417,8 @@ namespace Terminal.Gui {
 			return false;
 		}
 
-		// BUGBUG: This API is broken - It should be renamed to `GetMinimumBoundsForFrame and 
-		// should not assume Frame.Height == Bounds.Height
+		// BUGBUG: This API is broken - should not assume Frame.Height == Bounds.Height
+		// BUGBUG: this function does not belong in ViewLayout.cs - it should be in ViewText.cs
 		/// <summary>
 		/// Gets the minimum dimensions required to fit the View's <see cref="Text"/>, factoring in <see cref="TextDirection"/>.
 		/// </summary>
@@ -389,7 +429,7 @@ namespace Terminal.Gui {
 		/// if <see cref="Height"/> (Horizontal) or <see cref="Width"/> (Vertical) are not not set or zero.
 		/// Does not take into account word wrapping.
 		/// </remarks>
-		public bool GetMinimumBounds (out Size size)
+		bool GetMinimumBoundsForFrame (out Size size)
 		{
 			if (!IsInitialized) {
 				size = new Size (0, 0);
@@ -426,15 +466,15 @@ namespace Terminal.Gui {
 			return false;
 		}
 
-		// BUGBUG - v2 - Should be renamed "SetBoundsToFitFrame"
+		// BUGBUG: this function does not belong in ViewLayout.cs - it should be in ViewText.cs
 		/// <summary>
-		/// Sets the size of the View to the minimum width or height required to fit <see cref="Text"/> (see <see cref="GetMinimumBounds(out Size)"/>.
+		/// Sets the size of the View to the minimum width or height required to fit <see cref="Text"/> (see <see cref="GetMinimumBoundsForFrame"/>.
 		/// </summary>
 		/// <returns><see langword="true"/> if the size was changed, <see langword="false"/> if <see cref="Text"/>
 		/// will not fit.</returns>
-		public bool SetMinWidthHeight ()
+		bool SetBoundsToFitFrame ()
 		{
-			if (GetMinimumBounds (out Size size)) {
+			if (GetMinimumBoundsForFrame (out Size size)) {
 				_frame = new Rect (_frame.Location, size);
 				return true;
 			}
@@ -470,7 +510,7 @@ namespace Terminal.Gui {
 			}
 			//// BUGBUG: I think these calls are redundant or should be moved into just the AutoSize case
 			if (IsInitialized || LayoutStyle == LayoutStyle.Absolute) {
-				SetMinWidthHeight ();
+				SetBoundsToFitFrame ();
 				LayoutFrames ();
 				TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey ();
 				SetNeedsLayout ();
@@ -502,69 +542,99 @@ namespace Terminal.Gui {
 		}
 
 		/// <summary>
-		/// Converts a point from screen-relative coordinates to view-relative coordinates.
+		/// Converts a screen-relative coordinate to a Frame-relative coordinate. Frame-relative means
+		/// relative to the View's <see cref="SuperView"/>'s <see cref="Bounds"/>.
 		/// </summary>
-		/// <returns>The mapped point.</returns>
-		/// <param name="x">X screen-coordinate point.</param>
-		/// <param name="y">Y screen-coordinate point.</param>
-		public Point ScreenToView (int x, int y)
+		/// <returns>The coordinate relative to the <see cref="SuperView"/>'s <see cref="Bounds"/>.</returns>
+		/// <param name="x">Screen-relative column.</param>
+		/// <param name="y">Screen-relative row.</param>
+		public Point ScreenToFrame (int x, int y)
 		{
-			Point boundsOffset = SuperView == null ? Point.Empty : SuperView.GetBoundsOffset ();
-			if (SuperView == null) {
-				return new Point (x - Frame.X + boundsOffset.X, y - Frame.Y + boundsOffset.Y);
-			} else {
-				var parent = SuperView.ScreenToView (x - boundsOffset.X, y - boundsOffset.Y);
-				return new Point (parent.X - Frame.X, parent.Y - Frame.Y);
+			Point superViewBoundsOffset = SuperView?.GetBoundsOffset () ?? Point.Empty;
+			var ret = new Point (x - Frame.X - superViewBoundsOffset.X, y - Frame.Y - superViewBoundsOffset.Y);
+			if (SuperView != null) {
+				var superFrame = SuperView.ScreenToFrame (x - superViewBoundsOffset.X, y - superViewBoundsOffset.Y);
+				ret = new Point (superFrame.X - Frame.X, superFrame.Y - Frame.Y);
 			}
+			return ret;
 		}
 
 		/// <summary>
-		/// Converts a view-relative location to a screen-relative location (col,row). The output is optionally clamped to the screen dimensions.
+		/// Converts a screen-relative coordinate to a bounds-relative coordinate. 
 		/// </summary>
-		/// <param name="col">View-relative column.</param>
-		/// <param name="row">View-relative row.</param>
-		/// <param name="rcol">Absolute column; screen-relative.</param>
-		/// <param name="rrow">Absolute row; screen-relative.</param>
-		/// <param name="clamped">If <see langword="true"/>, <paramref name="rcol"/> and <paramref name="rrow"/> will be clamped to the 
-		/// screen dimensions (they never be negative and will always be less than to <see cref="ConsoleDriver.Cols"/> and
+		/// <returns>The coordinate relative to this view's <see cref="Bounds"/>.</returns>
+		/// <param name="x">Screen-relative column.</param>
+		/// <param name="y">Screen-relative row.</param>
+		public Point ScreenToBounds (int x, int y)
+		{
+			var screen = ScreenToFrame (x, y);
+			var boundsOffset = GetBoundsOffset ();
+			return new Point (screen.X - boundsOffset.X, screen.Y - boundsOffset.Y);
+		}
+
+		/// <summary>
+		/// Converts a <see cref="Bounds"/>-relative coordinate to a screen-relative coordinate. The output is optionally clamped to the screen dimensions.
+		/// </summary>
+		/// <param name="x"><see cref="Bounds"/>-relative column.</param>
+		/// <param name="y"><see cref="Bounds"/>-relative row.</param>
+		/// <param name="rx">Absolute column; screen-relative.</param>
+		/// <param name="ry">Absolute row; screen-relative.</param>
+		/// <param name="clamped">If <see langword="true"/>, <paramref name="rx"/> and <paramref name="ry"/> will be clamped to the 
+		/// screen dimensions (will never be negative and will always be less than <see cref="ConsoleDriver.Cols"/> and
 		/// <see cref="ConsoleDriver.Rows"/>, respectively.</param>
-		public virtual void ViewToScreen (int col, int row, out int rcol, out int rrow, bool clamped = true)
+		public virtual void BoundsToScreen (int x, int y, out int rx, out int ry, bool clamped = true)
 		{
 			var boundsOffset = GetBoundsOffset ();
-			rcol = col + Frame.X + boundsOffset.X;
-			rrow = row + Frame.Y + boundsOffset.Y;
+			rx = x + Frame.X + boundsOffset.X;
+			ry = y + Frame.Y + boundsOffset.Y;
 
 			var super = SuperView;
 			while (super != null) {
 				boundsOffset = super.GetBoundsOffset ();
-				rcol += super.Frame.X + boundsOffset.X;
-				rrow += super.Frame.Y + boundsOffset.Y;
+				rx += super.Frame.X + boundsOffset.X;
+				ry += super.Frame.Y + boundsOffset.Y;
 				super = super.SuperView;
 			}
 
 			// The following ensures that the cursor is always in the screen boundaries.
 			if (clamped) {
-				rrow = Math.Min (rrow, Driver.Rows - 1);
-				rcol = Math.Min (rcol, Driver.Cols - 1);
+				ry = Math.Min (ry, Driver.Rows - 1);
+				rx = Math.Min (rx, Driver.Cols - 1);
 			}
 		}
 
 		/// <summary>
-		/// Converts a region in view-relative coordinates to screen-relative coordinates.
+		/// Converts a <see cref="Bounds"/>-relative region to a screen-relative region. 
 		/// </summary>
-		public Rect ViewToScreen (Rect region)
+		public Rect BoundsToScreen (Rect region)
 		{
-			ViewToScreen (region.X, region.Y, out var x, out var y, clamped: false);
+			BoundsToScreen (region.X, region.Y, out var x, out var y, clamped: false);
 			return new Rect (x, y, region.Width, region.Height);
 		}
 
+		/// <summary>
+		/// Gets the <see cref="Frame"/> with a screen-relative location. 
+		/// </summary>
+		/// <returns>The location and size of the view in screen-relative coordinates.</returns>
+		public virtual Rect FrameToScreen ()
+		{
+			var ret = Frame;
+			var super = SuperView;
+			while (super != null) {
+				var boundsOffset = super.GetBoundsOffset ();
+				ret.X += super.Frame.X + boundsOffset.X;
+				ret.Y += super.Frame.Y + boundsOffset.Y;
+				super = super.SuperView;
+			}
+			return ret;
+		}
 
 		/// <summary>
 		/// Sets the View's <see cref="Frame"/> to the frame-relative coordinates if its container. The
 		/// container size and location are specified by <paramref name="superviewFrame"/> and are relative to the
 		/// View's superview.
 		/// </summary>
-		/// <param name="superviewFrame">The supserview-relative rectangle describing View's container (nominally the 
+		/// <param name="superviewFrame">The SuperView-relative rectangle describing View's container (nominally the 
 		/// same as <c>this.SuperView.Frame</c>).</param>
 		internal void SetRelativeLayout (Rect superviewFrame)
 		{
@@ -668,7 +738,7 @@ namespace Terminal.Gui {
 			if (Frame != r) {
 				Frame = r;
 				// BUGBUG: Why is this AFTER setting Frame? Seems duplicative.
-				if (!SetMinWidthHeight ()) {
+				if (!SetBoundsToFitFrame ()) {
 					TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey ();
 				}
 			}
@@ -959,51 +1029,52 @@ namespace Terminal.Gui {
 				return false;
 			}
 
-			var aSize = true;
-			var nBoundsSize = GetAutoSize ();
-			if (IsInitialized && nBoundsSize != Bounds.Size) {
+			var boundsChanged = true;
+			var newFrameSize = GetAutoSize ();
+			if (IsInitialized && newFrameSize != Frame.Size) {
 				if (ForceValidatePosDim) {
-					aSize = SetWidthHeight (nBoundsSize);
+					// BUGBUG: This ain't right, obviously.  We need to figure out how to handle this.
+					boundsChanged = ResizeBoundsToFit (newFrameSize);
 				} else {
-					Height = nBoundsSize.Height;
-					Width = nBoundsSize.Width; // = new Rect (Bounds.X, Bounds.Y, nBoundsSize.Width, nBoundsSize.Height);
+					Height = newFrameSize.Height;
+					Width = newFrameSize.Width; 
 				}
 			}
 			// BUGBUG: This call may be redundant
 			TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey ();
-			return aSize;
+			return boundsChanged;
 		}
 
 		/// <summary>
-		/// Resizes the View to fit the specified <see cref="Bounds"/> size.
+		/// Resizes the View to fit the specified size. Factors in the HotKey.
 		/// </summary>
-		/// <param name="nBounds"></param>
-		/// <returns></returns>
-		bool SetWidthHeight (Size nBounds)
+		/// <param name="size"></param>
+		/// <returns>whether the Bounds was changed or not</returns>
+		bool ResizeBoundsToFit (Size size)
 		{
-			var aSize = false;
-			var canSizeW = TrySetWidth (nBounds.Width - GetHotKeySpecifierLength (), out var rW);
-			var canSizeH = TrySetHeight (nBounds.Height - GetHotKeySpecifierLength (false), out var rH);
+			var boundsChanged = false;
+			var canSizeW = TrySetWidth (size.Width - GetHotKeySpecifierLength (), out var rW);
+			var canSizeH = TrySetHeight (size.Height - GetHotKeySpecifierLength (false), out var rH);
 			if (canSizeW) {
-				aSize = true;
+				boundsChanged = true;
 				_width = rW;
 			}
 			if (canSizeH) {
-				aSize = true;
+				boundsChanged = true;
 				_height = rH;
 			}
-			if (aSize) {
+			if (boundsChanged) {
 				Bounds = new Rect (Bounds.X, Bounds.Y, canSizeW ? rW : Bounds.Width, canSizeH ? rH : Bounds.Height);
 			}
 
-			return aSize;
+			return boundsChanged;
 		}
 
 		/// <summary>
-		/// Gets the Frame dimensions required to fit <see cref="Text"/> using the text <see cref="Direction"/> specified by the
+		/// Gets the Frame dimensions required to fit <see cref="Text"/> within <see cref="Bounds"/> using the text <see cref="Direction"/> specified by the
 		/// <see cref="TextFormatter"/> property and accounting for any <see cref="HotKeySpecifier"/> characters.
 		/// </summary>
-		/// <returns>The <see cref="Size"/> required to fit the text.</returns>
+		/// <returns>The <see cref="Size"/> of the view required to fit the text.</returns>
 		public Size GetAutoSize ()
 		{
 			int x = 0;
@@ -1130,13 +1201,12 @@ namespace Terminal.Gui {
 		/// </returns>
 		public static View FindDeepestView (View start, int x, int y, out int resx, out int resy)
 		{
-			var startFrame = start.Frame;
-
-			if (!startFrame.Contains (x, y)) {
-				resx = 0;
-				resy = 0;
+			resy = resx = 0;
+			if (start == null || !start.Frame.Contains (x, y)) {
 				return null;
 			}
+			
+			var startFrame = start.Frame;
 			if (start.InternalSubviews != null) {
 				int count = start.InternalSubviews.Count;
 				if (count > 0) {

+ 21 - 5
Terminal.Gui/View/Frame.cs

@@ -41,9 +41,9 @@ namespace Terminal.Gui {
 		}
 
 		/// <inheritdoc/>
-		public override void ViewToScreen (int col, int row, out int rcol, out int rrow, bool clipped = true)
+		public override void BoundsToScreen (int col, int row, out int rcol, out int rrow, bool clipped = true)
 		{
-			// Frames are *Children* of a View, not SubViews. Thus View.ViewToScreen will not work.
+			// Frames are *Children* of a View, not SubViews. Thus View.BoundsToScreen will not work.
 			// To get the screen-relative coordinates of a Frame, we need to know who
 			// the Parent is
 			var parentFrame = Parent?.Frame ?? Frame;
@@ -52,7 +52,23 @@ namespace Terminal.Gui {
 
 			// 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?.ViewToScreen (rcol, rrow, out rcol, out rrow, clipped);
+			Parent?.SuperView?.BoundsToScreen (rcol, rrow, out rcol, out rrow, clipped);
+		}
+
+		/// <inheritdoc/>
+		public override Rect FrameToScreen ()
+		{
+			// Frames are *Children* of a View, not SubViews. Thus View.FramToScreen will not work.
+			// To get the screen-relative coordinates of a Frame, we need to know who
+			// the Parent is
+			var ret = Parent?.Frame ?? Frame;
+			ret.Size = Frame.Size;
+
+			ret.Location = Parent?.FrameToScreen ().Location ?? ret.Location;
+
+			// We now have coordinates relative to our View. If our View's SuperView has
+			// a SuperView, keep going...
+			return ret;
 		}
 
 		/// <summary>
@@ -128,7 +144,7 @@ namespace Terminal.Gui {
 			}
 
 			//Driver.SetAttribute (Colors.Error.Normal);
-			var screenBounds = ViewToScreen (Frame);
+			var screenBounds = BoundsToScreen (Frame);
 
 			// This just draws/clears the thickness, not the insides.
 			Thickness.Draw (screenBounds, (string)(Data != null ? Data : string.Empty));
@@ -368,7 +384,7 @@ namespace Terminal.Gui {
 		public void DrawFrame (Rect region, bool clear)
 		{
 			var savedClip = ClipToBounds ();
-			var screenBounds = ViewToScreen (region);
+			var screenBounds = BoundsToScreen (region);
 
 			if (clear) {
 				Driver.FillRect (region);

+ 11 - 11
Terminal.Gui/View/ViewDrawing.cs

@@ -72,10 +72,12 @@ namespace Terminal.Gui {
 		/// <param name="ch">Ch.</param>
 		public void AddRune (int col, int row, Rune ch)
 		{
-			if (row < 0 || col < 0)
+			if (row < 0 || col < 0) {
 				return;
-			if (row > _frame.Height - 1 || col > _frame.Width - 1)
+			}
+			if (row > _frame.Height - 1 || col > _frame.Width - 1) {
 				return;
+			}
 			Move (col, row);
 			Driver.AddRune (ch);
 		}
@@ -185,7 +187,7 @@ namespace Terminal.Gui {
 		///     This clears the Bounds used by this view.
 		///   </para>
 		/// </remarks>
-		public void Clear () => Clear (ViewToScreen(Bounds));
+		public void Clear () => Clear (BoundsToScreen(Bounds));
 
 		// BUGBUG: This version of the Clear API should be removed. We should have a tenet that says 
 		// "View APIs only deal with View-relative coords". This is only used by ComboBox which can
@@ -226,7 +228,7 @@ namespace Terminal.Gui {
 		public Rect ClipToBounds ()
 		{
 			var previous = Driver.Clip;
-			Driver.Clip = Rect.Intersect (previous, ViewToScreen (Bounds));
+			Driver.Clip = Rect.Intersect (previous, BoundsToScreen (Bounds));
 			return previous;
 		}
 
@@ -274,15 +276,13 @@ namespace Terminal.Gui {
 		/// <returns>The move.</returns>
 		/// <param name="col">The column to move to, in view-relative coordinates.</param>
 		/// <param name="row">the row to move to, in view-relative coordinates.</param>
-		/// <param name="clipped">Whether to clip the result of the ViewToScreen method,
-		///  If  <see langword="true"/>, the <paramref name="col"/> and <paramref name="row"/> values are clamped to the screen (terminal) dimensions (0..TerminalDim-1).</param>
-		public void Move (int col, int row, bool clipped = true)
+		public void Move (int col, int row)
 		{
 			if (Driver.Rows == 0) {
 				return;
 			}
-
-			ViewToScreen (col, row, out var rCol, out var rRow, clipped);
+			
+			BoundsToScreen (col, row, out var rCol, out var rRow, false);
 			Driver.Move (rCol, rRow);
 		}
 		/// <summary>
@@ -438,7 +438,7 @@ namespace Terminal.Gui {
 		{
 			if (NeedsDisplay) {
 				if (SuperView != null) {
-					Clear (ViewToScreen (Bounds));
+					Clear (BoundsToScreen (Bounds));
 				}
 
 				if (!string.IsNullOrEmpty (TextFormatter.Text)) {
@@ -447,7 +447,7 @@ namespace Terminal.Gui {
 					}
 				}
 				// This should NOT clear 
-				TextFormatter?.Draw (ViewToScreen (Bounds), HasFocus ? GetFocusColor () : GetNormalColor (),
+				TextFormatter?.Draw (BoundsToScreen (Bounds), HasFocus ? GetFocusColor () : GetNormalColor (),
 					HasFocus ? ColorScheme.HotFocus : GetHotNormalColor (),
 					Rect.Empty, false);
 				SetSubViewNeedsDisplay ();

+ 4 - 3
Terminal.Gui/View/ViewText.cs

@@ -131,10 +131,11 @@ namespace Terminal.Gui {
 			    || (ForceValidatePosDim && directionChanged && AutoSize && isValidOldAutoSize)) {
 				OnResizeNeeded ();
 			} else if (directionChanged && IsAdded) {
-				SetWidthHeight (Bounds.Size);
-				SetMinWidthHeight ();
+				ResizeBoundsToFit (Bounds.Size);
+				// BUGBUG: I think this call is redundant.
+				SetBoundsToFitFrame ();
 			} else {
-				SetMinWidthHeight ();
+				SetBoundsToFitFrame ();
 			}
 			TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey ();
 			SetNeedsDisplay ();

+ 2 - 4
Terminal.Gui/Views/ColorPicker.cs

@@ -268,12 +268,10 @@ namespace Terminal.Gui {
 			}
 
 			SetFocus ();
-			if (me.X < GetFramesThickness ().Left || me.Y < GetFramesThickness ().Top || me.X > Bounds.Width || me.Y > Bounds.Height) {
+			if (me.X > Bounds.Width || me.Y > Bounds.Height) {
 				return true;
 			}
-			//var x = Math.Max (GetFramesThickness().Left, me.X);
-			//var y = Math.Max (GetFramesThickness ().Top, me.Y);
-			Cursor = new Point ((me.X - GetFramesThickness ().Left) / _boxWidth, (me.Y - GetFramesThickness ().Top) / _boxHeight);
+			Cursor = new Point ((me.X ) / _boxWidth, (me.Y) / _boxHeight);
 
 			return true;
 		}

+ 1 - 1
Terminal.Gui/Views/ComboBox.cs

@@ -873,7 +873,7 @@ namespace Terminal.Gui {
 			if (lastSelectedItem != selectedItem) {
 				OnOpenSelectedItem ();
 			}
-			var rect = listview.ViewToScreen (listview.Bounds);
+			var rect = listview.BoundsToScreen (listview.Bounds);
 			Reset (keepSearchText: true);
 			listview.Clear (rect);
 			listview.TabStop = false;

+ 2 - 2
Terminal.Gui/Views/ContextMenu.cs

@@ -95,7 +95,7 @@ namespace Terminal.Gui {
 			var frame = new Rect (0, 0, View.Driver.Cols, View.Driver.Rows);
 			var position = Position;
 			if (Host != null) {
-				Host.ViewToScreen (frame.X, frame.Y, out int x, out int y);
+				Host.BoundsToScreen (frame.X, frame.Y, out int x, out int y);
 				var pos = new Point (x, y);
 				pos.Y += Host.Frame.Height - 1;
 				if (position != pos) {
@@ -117,7 +117,7 @@ namespace Terminal.Gui {
 					if (Host == null) {
 						position.Y = frame.Bottom - rect.Height - 1;
 					} else {
-						Host.ViewToScreen (frame.X, frame.Y, out int x, out int y);
+						Host.BoundsToScreen (frame.X, frame.Y, out int x, out int y);
 						var pos = new Point (x, y);
 						position.Y = pos.Y - rect.Height - 1;
 					}

+ 1 - 1
Terminal.Gui/Views/Line.cs

@@ -25,7 +25,7 @@ namespace Terminal.Gui {
 		/// <inheritdoc/>
 		public override bool OnDrawFrames ()
 		{
-			var screenBounds = ViewToScreen (Bounds);
+			var screenBounds = BoundsToScreen (Bounds);
 			LineCanvas lc;
 
 			lc = SuperView?.LineCanvas;

+ 4 - 5
Terminal.Gui/Views/ListView.cs

@@ -794,14 +794,13 @@ namespace Terminal.Gui {
 				return true;
 			}
 
-			var framesThickness = GetFramesThickness ();
-			if (me.Y + top - framesThickness.Top >= source.Count
-				|| me.Y + top - framesThickness.Top < 0
-				|| me.Y + top > top + Frame.Height - (framesThickness.Top + framesThickness.Bottom)) {
+			if (me.Y + top >= source.Count
+				|| me.Y + top  < 0
+				|| me.Y + top > top + Bounds.Height) {
 				return true;
 			}
 
-			selected = top - GetFramesThickness ().Top + me.Y;
+			selected = top + me.Y;
 			if (AllowsAll ()) {
 				Source.SetMark (SelectedItem, !Source.IsMarked (SelectedItem));
 				SetNeedsDisplay ();

+ 9 - 9
Terminal.Gui/Views/Menu.cs

@@ -582,7 +582,7 @@ namespace Terminal.Gui {
 				if (i < 0) {
 					continue;
 				}
-				if (ViewToScreen (Bounds).Y + i >= Driver.Rows) {
+				if (BoundsToScreen (Bounds).Y + i >= Driver.Rows) {
 					break;
 				}
 				var item = barItems.Children [i];
@@ -600,7 +600,7 @@ namespace Terminal.Gui {
 					if (p < 0) {
 						continue;
 					}
-					if (ViewToScreen (Bounds).X + p >= Driver.Cols) {
+					if (BoundsToScreen (Bounds).X + p >= Driver.Cols) {
 						break;
 					}
 					if (item == null)
@@ -643,7 +643,7 @@ namespace Terminal.Gui {
 					textToDraw = item.Title;
 				}
 
-				ViewToScreen (0, i, out int vtsCol, out int vtsRow, false);
+				BoundsToScreen (0, i, out int vtsCol, out int vtsRow, false);
 				if (vtsCol < Driver.Cols) {
 					Driver.Move (vtsCol + 1, vtsRow);
 					if (!item.IsEnabled ()) {
@@ -655,10 +655,10 @@ namespace Terminal.Gui {
 							Text = textToDraw
 						};
 						// The -3 is left/right border + one space (not sure what for)
-						tf.Draw (ViewToScreen (new Rect (1, i, Frame.Width - 3, 1)),
+						tf.Draw (BoundsToScreen (new Rect (1, i, Frame.Width - 3, 1)),
 							i == current ? ColorScheme.Focus : GetNormalColor (),
 							i == current ? ColorScheme.HotFocus : ColorScheme.HotNormal,
-							SuperView == null ? default : SuperView.ViewToScreen (SuperView.Bounds));
+							SuperView == null ? default : SuperView.BoundsToScreen (SuperView.Bounds));
 					} else {
 						DrawHotString (textToDraw,
 							i == current ? ColorScheme.HotFocus : ColorScheme.HotNormal,
@@ -668,7 +668,7 @@ namespace Terminal.Gui {
 					// The help string
 					var l = item.ShortcutTag.GetColumns () == 0 ? item.Help.GetColumns () : item.Help.GetColumns () + item.ShortcutTag.GetColumns () + 2;
 					var col = Frame.Width - l - 3;
-					ViewToScreen (col, i, out vtsCol, out vtsRow, false);
+					BoundsToScreen (col, i, out vtsCol, out vtsRow, false);
 					if (vtsCol < Driver.Cols) {
 						Driver.Move (vtsCol, vtsRow);
 						Driver.AddStr (item.Help);
@@ -1912,7 +1912,7 @@ namespace Terminal.Gui {
 			}
 
 			if (mi.IsTopLevel) {
-				ViewToScreen (i, 0, out int rx, out int ry);
+				BoundsToScreen (i, 0, out int rx, out int ry);
 				var menu = new Menu (this, rx, ry, mi, null, MenusBorderStyle);
 				menu.Run (mi.Action);
 				menu.Dispose ();
@@ -2040,7 +2040,7 @@ namespace Terminal.Gui {
 					if (cx >= pos && cx < pos + leftPadding + Menus [i].TitleLength + Menus [i].Help.GetColumns () + rightPadding) {
 						if (me.Flags == MouseFlags.Button1Clicked) {
 							if (Menus [i].IsTopLevel) {
-								ViewToScreen (i, 0, out int rx, out int ry);
+								BoundsToScreen (i, 0, out int rx, out int ry);
 								var menu = new Menu (this, rx, ry, Menus [i], null, MenusBorderStyle);
 								menu.Run (Menus [i].Action);
 								menu.Dispose ();
@@ -2104,7 +2104,7 @@ namespace Terminal.Gui {
 						Application.GrabMouse (v);
 						MouseEvent nme;
 						if (me.Y > -1) {
-							var newxy = v.ScreenToView (me.X, me.Y);
+							var newxy = v.ScreenToFrame (me.X, me.Y);
 							nme = new MouseEvent () {
 								X = newxy.X,
 								Y = newxy.Y,

+ 2 - 2
Terminal.Gui/Views/ProgressBar.cs

@@ -246,10 +246,10 @@ public class ProgressBar : View {
 			if (_fraction > .5) {
 				attr = new Attribute (ColorScheme.HotNormal.Background, ColorScheme.HotNormal.Foreground);
 			}
-			tf?.Draw (ViewToScreen (Bounds),
+			tf?.Draw (BoundsToScreen (Bounds),
 				attr,
 				ColorScheme.Normal,
-				SuperView?.ViewToScreen (SuperView.Bounds) ?? default,
+				SuperView?.BoundsToScreen (SuperView.Bounds) ?? default,
 				fillRemaining: false);
 
 

+ 2 - 2
Terminal.Gui/Views/RadioGroup.cs

@@ -375,8 +375,8 @@ namespace Terminal.Gui {
 			}
 			SetFocus ();
 
-			int boundsX = me.X - GetFramesThickness ().Left;
-			int boundsY = me.Y - GetFramesThickness ().Top;
+			int boundsX = me.X;
+			int boundsY = me.Y;
 
 			var pos = displayMode == DisplayModeLayout.Horizontal ? boundsX : boundsY;
 			var rCount = displayMode == DisplayModeLayout.Horizontal ? horizontal.Last ().pos + horizontal.Last ().length : radioLabels.Count;

+ 2 - 3
Terminal.Gui/Views/TableView/TableView.cs

@@ -1229,9 +1229,8 @@ namespace Terminal.Gui {
 				return true;
 			}
 
-			// TODO: Revert this (or not) once #2578 is solved
-			var boundsX = me.X - GetFramesThickness ().Left;
-			var boundsY = me.Y - GetFramesThickness ().Top;
+			var boundsX = me.X;
+			var boundsY = me.Y;
 
 			if (me.Flags.HasFlag (MouseFlags.Button1Clicked)) {
 

+ 4 - 4
Terminal.Gui/Views/TextField.cs

@@ -406,8 +406,8 @@ namespace Terminal.Gui {
 			}
 			var pos = _point - _first + Math.Min (Frame.X, 0);
 			var offB = OffSetBackground ();
-			var containerFrame = SuperView?.ViewToScreen (SuperView.Bounds) ?? default;
-			var thisFrame = ViewToScreen (Bounds);
+			var containerFrame = SuperView?.BoundsToScreen (SuperView.Bounds) ?? default;
+			var thisFrame = BoundsToScreen (Bounds);
 			if (pos > -1 && col >= pos && pos < Frame.Width + offB
 				&& containerFrame.IntersectsWith (thisFrame)) {
 				RestoreCursorVisibility ();
@@ -415,9 +415,9 @@ namespace Terminal.Gui {
 			} else {
 				HideCursorVisibility ();
 				if (pos < 0) {
-					Move (pos, 0, false);
+					Move (pos, 0);
 				} else {
-					Move (pos - offB, 0, false);
+					Move (pos - offB, 0);
 				}
 			}
 		}

+ 4 - 4
Terminal.Gui/Views/TileView.cs

@@ -331,8 +331,8 @@ namespace Terminal.Gui {
 				foreach (var line in allLines) {
 					bool isRoot = splitterLines.Contains (line);
 
-					line.ViewToScreen (0, 0, out var x1, out var y1);
-					var origin = ScreenToView (x1, y1);
+					line.BoundsToScreen (0, 0, out var x1, out var y1);
+					var origin = ScreenToFrame (x1, y1);
 					var length = line.Orientation == Orientation.Horizontal ?
 							line.Frame.Width :
 							line.Frame.Height;
@@ -747,9 +747,9 @@ namespace Terminal.Gui {
 			/// </summary>
 			public Point GetLocalCoordinateForTitle (TileView intoCoordinateSpace)
 			{
-				Tile.ContentView.ViewToScreen (0, 0, out var screenCol, out var screenRow);
+				Tile.ContentView.BoundsToScreen (0, 0, out var screenCol, out var screenRow);
 				screenRow--;
-				return intoCoordinateSpace.ScreenToView (screenCol, screenRow);
+				return intoCoordinateSpace.ScreenToFrame (screenCol, screenRow);
 			}
 
 			internal string GetTrimmedTitle ()

+ 2 - 0
Terminal.Gui/Views/Toplevel.cs

@@ -812,6 +812,7 @@ namespace Terminal.Gui {
 				Application.BringOverlappedTopToFront ();
 
 				// Only start grabbing if the user clicks on the title bar.
+				// BUGBUG: Assumes Frame == Border and Title is always at Y == 0
 				if (mouseEvent.Y == 0 && mouseEvent.Flags == MouseFlags.Button1Pressed) {
 					_startGrabPoint = new Point (mouseEvent.X, mouseEvent.Y);
 					_dragPosition = new Point ();
@@ -836,6 +837,7 @@ namespace Terminal.Gui {
 					} else {
 						SuperView.SetNeedsDisplay ();
 					}
+					// BUGBUG: Assumes Frame == Border?
 					GetLocationThatFits (this, mouseEvent.X + (SuperView == null ? mouseEvent.OfX - _startGrabPoint.X : Frame.X - _startGrabPoint.X),
 						mouseEvent.Y + (SuperView == null ? mouseEvent.OfY - _startGrabPoint.Y : Frame.Y - _startGrabPoint.Y),
 						out nx, out ny, out _, out _);

+ 1 - 1
Terminal.Gui/Views/TreeView/TreeView.cs

@@ -769,7 +769,7 @@ namespace Terminal.Gui {
 		/// at the provided row. Returns null if no object is at that location.
 		/// <remarks>
 		/// </remarks>
-		/// If you have screen coordinates then use <see cref="View.ScreenToView(int, int)"/>
+		/// If you have screen coordinates then use <see cref="View.ScreenToFrame"/>
 		/// to translate these into the client area of the <see cref="TreeView{T}"/>.
 		/// </summary>
 		/// <param name="row">The row of the <see cref="View.Bounds"/> of the <see cref="TreeView{T}"/>.</param>

+ 2 - 2
UICatalog/Scenarios/LineDrawing.cs

@@ -155,14 +155,14 @@ namespace UICatalog.Scenarios {
 					if (_currentLine == null) {
 						// Mouse pressed down
 						_currentLine = new StraightLine (
-							new Point (mouseEvent.X - GetBoundsOffset ().X, mouseEvent.Y - GetBoundsOffset ().X),
+							new Point (mouseEvent.X, mouseEvent.Y),
 							0, Orientation.Vertical, LineStyle, new Attribute (_currentColor, GetNormalColor ().Background));
 						
 						_currentLayer.AddLine (_currentLine);
 					} else {
 						// Mouse dragged
 						var start = _currentLine.Start;
-						var end = new Point (mouseEvent.X - GetBoundsOffset ().X, mouseEvent.Y - GetBoundsOffset ().Y);
+						var end = new Point (mouseEvent.X, mouseEvent.Y);
 						var orientation = Orientation.Vertical;
 						var length = end.Y - start.Y;
 

+ 1 - 1
UICatalog/Scenarios/Notepad.cs

@@ -108,7 +108,7 @@ namespace UICatalog.Scenarios {
 				});
 			}
 
-		((View)sender).ViewToScreen (e.MouseEvent.X, e.MouseEvent.Y, out int screenX, out int screenY,true);
+		((View)sender).BoundsToScreen (e.MouseEvent.X, e.MouseEvent.Y, out int screenX, out int screenY,true);
 
 		var contextMenu = new ContextMenu (screenX,screenY, items);
 

+ 2 - 138
UnitTests/Application/ApplicationTests.cs

@@ -486,6 +486,8 @@ public class ApplicationTests {
 0000000000
 ", null, attributes);
 
+		// TODO: In PR #2920 this breaks because the mouse is not grabbed anymore.
+		// TODO: Move the mouse grap/drag mode from Toplevel to Border.
 		Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () { X = 2, Y = 2, Flags = MouseFlags.Button1Pressed }));
 		Assert.Equal (d, Application.MouseGrabView);
 
@@ -978,142 +980,4 @@ public class ApplicationTests {
 		Assert.Equal (1, actionCalled);
 		Application.Shutdown ();
 	}
-
-
-	#region mousegrabtests
-	[Fact, AutoInitShutdown]
-	public void MouseGrabView_WithNullMouseEventView ()
-	{
-		var tf = new TextField () { Width = 10 };
-		var sv = new ScrollView () {
-			Width = Dim.Fill (),
-			Height = Dim.Fill (),
-			ContentSize = new Size (100, 100)
-		};
-
-		sv.Add (tf);
-		Application.Top.Add (sv);
-
-		var iterations = -1;
-
-		Application.Iteration += (s, a) => {
-			iterations++;
-			if (iterations == 0) {
-				Assert.True (tf.HasFocus);
-				Assert.Null (Application.MouseGrabView);
-
-				Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () {
-					X = 5,
-					Y = 5,
-					Flags = MouseFlags.ReportMousePosition
-				}));
-
-				Assert.Equal (sv, Application.MouseGrabView);
-
-				MessageBox.Query ("Title", "Test", "Ok");
-
-				Assert.Null (Application.MouseGrabView);
-			} else if (iterations == 1) {
-				// Application.MouseGrabView is null because
-				// another toplevel (Dialog) was opened
-				Assert.Null (Application.MouseGrabView);
-
-				Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () {
-					X = 5,
-					Y = 5,
-					Flags = MouseFlags.ReportMousePosition
-				}));
-
-				Assert.Null (Application.MouseGrabView);
-
-				Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () {
-					X = 40,
-					Y = 12,
-					Flags = MouseFlags.ReportMousePosition
-				}));
-
-				Assert.Null (Application.MouseGrabView);
-
-				Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () {
-					X = 0,
-					Y = 0,
-					Flags = MouseFlags.Button1Pressed
-				}));
-
-				Assert.Null (Application.MouseGrabView);
-
-				Application.RequestStop ();
-			} else if (iterations == 2) {
-				Assert.Null (Application.MouseGrabView);
-
-				Application.RequestStop ();
-			}
-		};
-
-		Application.Run ();
-	}
-
-	[Fact, AutoInitShutdown]
-	public void MouseGrabView_GrabbedMouse_UnGrabbedMouse ()
-	{
-		View grabView = null;
-		var count = 0;
-
-		var view1 = new View ();
-		var view2 = new View ();
-
-		Application.GrabbedMouse += Application_GrabbedMouse;
-		Application.UnGrabbedMouse += Application_UnGrabbedMouse;
-
-		Application.GrabMouse (view1);
-		Assert.Equal (0, count);
-		Assert.Equal (grabView, view1);
-		Assert.Equal (view1, Application.MouseGrabView);
-
-		Application.UngrabMouse ();
-		Assert.Equal (1, count);
-		Assert.Equal (grabView, view1);
-		Assert.Null (Application.MouseGrabView);
-
-		Application.GrabbedMouse += Application_GrabbedMouse;
-		Application.UnGrabbedMouse += Application_UnGrabbedMouse;
-
-		Application.GrabMouse (view2);
-		Assert.Equal (1, count);
-		Assert.Equal (grabView, view2);
-		Assert.Equal (view2, Application.MouseGrabView);
-
-		Application.UngrabMouse ();
-		Assert.Equal (2, count);
-		Assert.Equal (grabView, view2);
-		Assert.Null (Application.MouseGrabView);
-
-		void Application_GrabbedMouse (object sender, ViewEventArgs e)
-		{
-			if (count == 0) {
-				Assert.Equal (view1, e.View);
-				grabView = view1;
-			} else {
-				Assert.Equal (view2, e.View);
-				grabView = view2;
-			}
-
-			Application.GrabbedMouse -= Application_GrabbedMouse;
-		}
-
-		void Application_UnGrabbedMouse (object sender, ViewEventArgs e)
-		{
-			if (count == 0) {
-				Assert.Equal (view1, e.View);
-				Assert.Equal (grabView, e.View);
-			} else {
-				Assert.Equal (view2, e.View);
-				Assert.Equal (grabView, e.View);
-			}
-			count++;
-
-			Application.UnGrabbedMouse -= Application_UnGrabbedMouse;
-		}
-	}
-	#endregion
 }

+ 0 - 7
UnitTests/Application/MainLoopTests.cs

@@ -1,17 +1,10 @@
 using System;
 using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-using System.Globalization;
-using System.Linq;
-using System.Runtime.InteropServices.ComTypes;
 using System.Threading;
 using System.Threading.Tasks;
-using Terminal.Gui;
 using Xunit;
-using Xunit.Sdk;
 
 // Alias Console to MockConsole so we don't accidentally use Console
-using Console = Terminal.Gui.FakeConsole;
 
 namespace Terminal.Gui.ApplicationTests;
 /// <summary>

+ 348 - 0
UnitTests/Application/MouseTests.cs

@@ -0,0 +1,348 @@
+using Xunit;
+using Xunit.Abstractions;
+
+// Alias Console to MockConsole so we don't accidentally use Console
+
+namespace Terminal.Gui.ApplicationTests;
+
+public class MouseTests {
+	readonly ITestOutputHelper _output;
+
+	public MouseTests (ITestOutputHelper output)
+	{
+		this._output = output;
+#if DEBUG_IDISPOSABLE
+		Responder.Instances.Clear ();
+		RunState.Instances.Clear ();
+#endif
+	}
+
+	#region mouse coordinate tests
+	// test Application.MouseEvent - ensure coordinates are screen relative
+	[Theory]
+	// inside tests
+	[InlineData (0, 0, 0, 0, true)]
+	[InlineData (1, 0, 1, 0, true)]
+	[InlineData (0, 1, 0, 1, true)]
+	[InlineData (9, 0, 9, 0, true)]
+	[InlineData (0, 9, 0, 9, true)]
+
+	// outside tests
+	[InlineData (-1, -1, -1, -1, true)]
+	[InlineData (0, -1, 0, -1, true)]
+	[InlineData (-1, 0, -1, 0, true)]
+	public void MouseEventCoordinatesAreScreenRelative (int clickX, int clickY, int expectedX, int expectedY, bool expectedClicked)
+	{
+		var mouseEvent = new MouseEvent () {
+			X = clickX,
+			Y = clickY,
+			Flags = MouseFlags.Button1Pressed
+		};
+		var mouseEventArgs = new MouseEventEventArgs (mouseEvent);
+		var clicked = false;
+
+		void OnApplicationOnMouseEvent (object s, MouseEventEventArgs e)
+		{
+			Assert.Equal (expectedX, e.MouseEvent.X);
+			Assert.Equal (expectedY, e.MouseEvent.Y);
+			clicked = true;
+		}
+		Application.MouseEvent += OnApplicationOnMouseEvent;
+
+		Application.OnMouseEvent (mouseEventArgs);
+		Assert.Equal (expectedClicked, clicked);
+		Application.MouseEvent -= OnApplicationOnMouseEvent;
+	}
+
+	/// <summary>
+	/// Tests that the mouse coordinates passed to the focused view are correct when the mouse is clicked.
+	/// No frames; Frame == Bounds
+	/// </summary>
+	[AutoInitShutdown]
+	[Theory]
+	// click inside view tests
+	[InlineData (0, 0, 0, 0, 0, true)]
+	[InlineData (0, 1, 0, 1, 0, true)]
+	[InlineData (0, 0, 1, 0, 1, true)]
+	[InlineData (0, 9, 0, 9, 0, true)]
+	[InlineData (0, 0, 9, 0, 9, true)]
+
+	// view is offset from origin ; click is inside view 
+	[InlineData (1, 1, 1, 0, 0, true)]
+	[InlineData (1, 2, 1, 1, 0, true)]
+	[InlineData (1, 1, 2, 0, 1, true)]
+	[InlineData (1, 9, 1, 8, 0, true)]
+	[InlineData (1, 1, 9, 0, 8, true)]
+
+	// click outside view tests
+	[InlineData (0, -1, -1, 0, 0, false)]
+	[InlineData (0, 0, -1, 0, 0, false)]
+	[InlineData (0, -1, 0, 0, 0, false)]
+	[InlineData (0, 0, 10, 0, 0, false)]
+	[InlineData (0, 10, 0, 0, 0, false)]
+	[InlineData (0, 10, 10, 0, 0, false)]
+
+	// view is offset from origin ; click is outside view 
+	[InlineData (1, 0, 0, 0, 0, false)]
+	[InlineData (1, 1, 0, 0, 0, false)]
+	[InlineData (1, 0, 1, 0, 0, false)]
+	[InlineData (1, 9, 0, 0, 0, false)]
+	[InlineData (1, 0, 9, 0, 0, false)]
+	public void MouseCoordinatesTest_NoFrames (int offset, int clickX, int clickY, int expectedX, int expectedY, bool expectedClicked)
+	{
+		var size = new Size (10, 10);
+		var pos = new Point (offset, offset);
+
+		var clicked = false;
+		Application.Top.X = pos.X;
+		Application.Top.Y = pos.Y;
+		Application.Top.Width = size.Width;
+		Application.Top.Height = size.Height;
+
+		var mouseEvent = new MouseEvent () {
+			X = clickX,
+			Y = clickY,
+			Flags = MouseFlags.Button1Pressed
+		};
+		var mouseEventArgs = new MouseEventEventArgs (mouseEvent);
+
+		Application.Top.MouseClick += (s, e) => {
+			Assert.Equal (expectedX, e.MouseEvent.X);
+			Assert.Equal (expectedY, e.MouseEvent.Y);
+			clicked = true;
+		};
+
+		Application.OnMouseEvent (mouseEventArgs);
+		Assert.Equal (expectedClicked, clicked);
+	}
+
+	/// <summary>
+	/// Tests that the mouse coordinates passed to the focused view are correct when the mouse is clicked.
+	/// With Frames; Frame != Bounds
+	/// </summary>
+	[AutoInitShutdown]
+	[Theory]
+	// click on border
+	[InlineData (0, 0, 0, 0, 0, false)]
+	[InlineData (0, 1, 0, 0, 0, false)]
+	[InlineData (0, 0, 1, 0, 0, false)]
+	[InlineData (0, 9, 0, 0, 0, false)]
+	[InlineData (0, 0, 9, 0, 0, false)]
+
+	// outside border
+	[InlineData (0, 10, 0, 0, 0, false)]
+	[InlineData (0, 0, 10, 0, 0, false)]
+
+	// view is offset from origin ; click is on border 
+	[InlineData (1, 1, 1, 0, 0, false)]
+	[InlineData (1, 2, 1, 0, 0, false)]
+	[InlineData (1, 1, 2, 0, 0, false)]
+	[InlineData (1, 10, 1, 0, 0, false)]
+	[InlineData (1, 1, 10, 0, 0, false)]
+
+	// outside border
+	[InlineData (1, -1, 0, 0, 0, false)]
+	[InlineData (1, 0, -1, 0, 0, false)]
+	[InlineData (1, 10, 10, 0, 0, false)]
+	[InlineData (1, 11, 11, 0, 0, false)]
+
+	// view is at origin, click is inside border
+	[InlineData (0, 1, 1, 0, 0, true)]
+	[InlineData (0, 2, 1, 1, 0, true)]
+	[InlineData (0, 1, 2, 0, 1, true)]
+	[InlineData (0, 8, 1, 7, 0, true)]
+	[InlineData (0, 1, 8, 0, 7, true)]
+	[InlineData (0, 8, 8, 7, 7, true)]
+
+	// view is offset from origin ; click inside border
+	// our view is 10x10, but has a border, so it's bounds is 8x8
+	[InlineData (1, 2, 2, 0, 0, true)]
+	[InlineData (1, 3, 2, 1, 0, true)]
+	[InlineData (1, 2, 3, 0, 1, true)]
+	[InlineData (1, 9, 2, 7, 0, true)]
+	[InlineData (1, 2, 9, 0, 7, true)]
+	[InlineData (1, 9, 9, 7, 7, true)]
+	[InlineData (1, 10, 10, 7, 7, false)]
+	//01234567890123456789
+	// |12345678|
+	// |xxxxxxxx
+	public void MouseCoordinatesTest_Border (int offset, int clickX, int clickY, int expectedX, int expectedY, bool expectedClicked)
+	{
+		var size = new Size (10, 10);
+		var pos = new Point (offset, offset);
+
+		var clicked = false;
+
+		Application.Top.X = 0;
+		Application.Top.Y = 0;
+		Application.Top.Width = size.Width * 2;
+		Application.Top.Height = size.Height * 2;
+		Application.Top.BorderStyle = LineStyle.None;
+
+		var view = new View () {
+			X = pos.X,
+			Y = pos.Y,
+			Width = size.Width,
+			Height = size.Height
+		};
+
+		// Give the view a border. With PR #2920, mouse clicks are only passed if they are inside the view's Bounds.
+		view.BorderStyle = LineStyle.Single;
+		view.CanFocus = true;
+
+		Application.Top.Add (view);
+		var mouseEvent = new MouseEvent () {
+			X = clickX,
+			Y = clickY,
+			Flags = MouseFlags.Button1Pressed
+		};
+		var mouseEventArgs = new MouseEventEventArgs (mouseEvent);
+
+		view.MouseClick += (s, e) => {
+			Assert.Equal (expectedX, e.MouseEvent.X);
+			Assert.Equal (expectedY, e.MouseEvent.Y);
+			clicked = true;
+		};
+
+		Application.OnMouseEvent (mouseEventArgs);
+		Assert.Equal (expectedClicked, clicked);
+	}
+	#endregion mouse coordinate tests 
+
+	#region mouse grab tests
+	[Fact, AutoInitShutdown]
+	public void MouseGrabView_WithNullMouseEventView ()
+	{
+		var tf = new TextField () { Width = 10 };
+		var sv = new ScrollView () {
+			Width = Dim.Fill (),
+			Height = Dim.Fill (),
+			ContentSize = new Size (100, 100)
+		};
+
+		sv.Add (tf);
+		Application.Top.Add (sv);
+
+		var iterations = -1;
+
+		Application.Iteration += (s, a) => {
+			iterations++;
+			if (iterations == 0) {
+				Assert.True (tf.HasFocus);
+				Assert.Null (Application.MouseGrabView);
+
+				Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () {
+					X = 5,
+					Y = 5,
+					Flags = MouseFlags.ReportMousePosition
+				}));
+
+				Assert.Equal (sv, Application.MouseGrabView);
+
+				MessageBox.Query ("Title", "Test", "Ok");
+
+				Assert.Null (Application.MouseGrabView);
+			} else if (iterations == 1) {
+				// Application.MouseGrabView is null because
+				// another toplevel (Dialog) was opened
+				Assert.Null (Application.MouseGrabView);
+
+				Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () {
+					X = 5,
+					Y = 5,
+					Flags = MouseFlags.ReportMousePosition
+				}));
+
+				Assert.Null (Application.MouseGrabView);
+
+				Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () {
+					X = 40,
+					Y = 12,
+					Flags = MouseFlags.ReportMousePosition
+				}));
+
+				Assert.Null (Application.MouseGrabView);
+
+				Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () {
+					X = 0,
+					Y = 0,
+					Flags = MouseFlags.Button1Pressed
+				}));
+
+				Assert.Null (Application.MouseGrabView);
+
+				Application.RequestStop ();
+			} else if (iterations == 2) {
+				Assert.Null (Application.MouseGrabView);
+
+				Application.RequestStop ();
+			}
+		};
+
+		Application.Run ();
+	}
+
+	[Fact, AutoInitShutdown]
+	public void MouseGrabView_GrabbedMouse_UnGrabbedMouse ()
+	{
+		View grabView = null;
+		var count = 0;
+
+		var view1 = new View ();
+		var view2 = new View ();
+
+		Application.GrabbedMouse += Application_GrabbedMouse;
+		Application.UnGrabbedMouse += Application_UnGrabbedMouse;
+
+		Application.GrabMouse (view1);
+		Assert.Equal (0, count);
+		Assert.Equal (grabView, view1);
+		Assert.Equal (view1, Application.MouseGrabView);
+
+		Application.UngrabMouse ();
+		Assert.Equal (1, count);
+		Assert.Equal (grabView, view1);
+		Assert.Null (Application.MouseGrabView);
+
+		Application.GrabbedMouse += Application_GrabbedMouse;
+		Application.UnGrabbedMouse += Application_UnGrabbedMouse;
+
+		Application.GrabMouse (view2);
+		Assert.Equal (1, count);
+		Assert.Equal (grabView, view2);
+		Assert.Equal (view2, Application.MouseGrabView);
+
+		Application.UngrabMouse ();
+		Assert.Equal (2, count);
+		Assert.Equal (grabView, view2);
+		Assert.Null (Application.MouseGrabView);
+
+		void Application_GrabbedMouse (object sender, ViewEventArgs e)
+		{
+			if (count == 0) {
+				Assert.Equal (view1, e.View);
+				grabView = view1;
+			} else {
+				Assert.Equal (view2, e.View);
+				grabView = view2;
+			}
+
+			Application.GrabbedMouse -= Application_GrabbedMouse;
+		}
+
+		void Application_UnGrabbedMouse (object sender, ViewEventArgs e)
+		{
+			if (count == 0) {
+				Assert.Equal (view1, e.View);
+				Assert.Equal (grabView, e.View);
+			} else {
+				Assert.Equal (view2, e.View);
+				Assert.Equal (grabView, e.View);
+			}
+			count++;
+
+			Application.UnGrabbedMouse -= Application_UnGrabbedMouse;
+		}
+	}
+	#endregion
+}

+ 595 - 488
UnitTests/Drawing/ThicknessTests.cs

@@ -10,412 +10,412 @@ using Xunit.Abstractions;
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 
-namespace Terminal.Gui.DrawingTests {
-	public class ThicknessTests {
-
-		readonly ITestOutputHelper output;
-
-		public ThicknessTests (ITestOutputHelper output)
-		{
-			this.output = output;
-		}
-
-		[Fact ()]
-		public void Constructor_Defaults ()
-		{
-			var t = new Thickness ();
-			Assert.Equal (0, t.Left);
-			Assert.Equal (0, t.Top);
-			Assert.Equal (0, t.Right);
-			Assert.Equal (0, t.Bottom);
-		}
-
-		[Fact ()]
-		public void Empty_Is_empty ()
-		{
-			var t = Thickness.Empty;
-			Assert.Equal (0, t.Left);
-			Assert.Equal (0, t.Top);
-			Assert.Equal (0, t.Right);
-			Assert.Equal (0, t.Bottom);
-		}
-
-		[Fact ()]
-		public void Constructor_Width ()
-		{
-			var t = new Thickness (1);
-			Assert.Equal (1, t.Left);
-			Assert.Equal (1, t.Top);
-			Assert.Equal (1, t.Right);
-			Assert.Equal (1, t.Bottom);
-		}
-
-		[Fact ()]
-		public void Constructor_params ()
-		{
-			var t = new Thickness (1, 2, 3, 4);
-			Assert.Equal (1, t.Left);
-			Assert.Equal (2, t.Top);
-			Assert.Equal (3, t.Right);
-			Assert.Equal (4, t.Bottom);
-
-			t = new Thickness (0, 0, 0, 0);
-			Assert.Equal (0, t.Left);
-			Assert.Equal (0, t.Top);
-			Assert.Equal (0, t.Right);
-			Assert.Equal (0, t.Bottom);
-
-			t = new Thickness (-1, 0, 0, 0);
-			Assert.Equal (-1, t.Left);
-			Assert.Equal (0, t.Top);
-			Assert.Equal (0, t.Right);
-			Assert.Equal (0, t.Bottom);
-		}
-
-		[Fact ()]
-		public void Vertical_get ()
-		{
-			var t = new Thickness (1, 2, 3, 4);
-			Assert.Equal (6, t.Vertical);
-
-			t = new Thickness (0);
-			Assert.Equal (0, t.Vertical);
-		}
-
-		[Fact ()]
-		public void Horizontal_get ()
-		{
-			var t = new Thickness (1, 2, 3, 4);
-			Assert.Equal (4, t.Horizontal);
-
-			t = new Thickness (0);
-			Assert.Equal (0, t.Horizontal);
-		}
-
-		[Fact ()]
-		public void Vertical_set ()
-		{
-			var t = new Thickness ();
-			t.Vertical = 10;
-			Assert.Equal (10, t.Vertical);
-			Assert.Equal (0, t.Left);
-			Assert.Equal (5, t.Top);
-			Assert.Equal (0, t.Right);
-			Assert.Equal (5, t.Bottom);
-			Assert.Equal (0, t.Horizontal);
-
-			t.Vertical = 11;
-			Assert.Equal (10, t.Vertical);
-			Assert.Equal (0, t.Left);
-			Assert.Equal (5, t.Top);
-			Assert.Equal (0, t.Right);
-			Assert.Equal (5, t.Bottom);
-			Assert.Equal (0, t.Horizontal);
-
-			t.Vertical = 1;
-			Assert.Equal (0, t.Vertical);
-			Assert.Equal (0, t.Left);
-			Assert.Equal (0, t.Top);
-			Assert.Equal (0, t.Right);
-			Assert.Equal (0, t.Bottom);
-			Assert.Equal (0, t.Horizontal);
-		}
-
-		[Fact ()]
-		public void Horizontal_set ()
-		{
-			var t = new Thickness ();
-			t.Horizontal = 10;
-			Assert.Equal (10, t.Horizontal);
-			Assert.Equal (5, t.Left);
-			Assert.Equal (0, t.Top);
-			Assert.Equal (5, t.Right);
-			Assert.Equal (0, t.Bottom);
-			Assert.Equal (0, t.Vertical);
-
-			t.Horizontal = 11;
-			Assert.Equal (10, t.Horizontal);
-			Assert.Equal (5, t.Left);
-			Assert.Equal (0, t.Top);
-			Assert.Equal (5, t.Right);
-			Assert.Equal (0, t.Bottom);
-			Assert.Equal (0, t.Vertical);
-
-			t.Horizontal = 1;
-			Assert.Equal (0, t.Horizontal);
-			Assert.Equal (0, t.Left);
-			Assert.Equal (0, t.Top);
-			Assert.Equal (0, t.Right);
-			Assert.Equal (0, t.Bottom);
-			Assert.Equal (0, t.Vertical);
-
-		}
-
-		[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 GetInsideTests_Positive_Thickness_Too_Small_Rect_Means_Empty_Size ()
-		{
-			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]
-		public void DrawTests ()
-		{
-			((FakeDriver)Application.Driver).SetBufferSize (60, 60);
-			var t = new Thickness (0, 0, 0, 0);
-			var 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), (Rune)' ');
-			t.Draw (r, "Test");
-			ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.Off;
-			TestHelpers.AssertDriverContentsWithFrameAre (@"
+namespace Terminal.Gui.DrawingTests;
+public class ThicknessTests {
+
+	readonly ITestOutputHelper output;
+
+	public ThicknessTests (ITestOutputHelper output)
+	{
+		this.output = output;
+	}
+
+	[Fact ()]
+	public void Constructor_Defaults ()
+	{
+		var t = new Thickness ();
+		Assert.Equal (0, t.Left);
+		Assert.Equal (0, t.Top);
+		Assert.Equal (0, t.Right);
+		Assert.Equal (0, t.Bottom);
+	}
+
+	[Fact ()]
+	public void Empty_Is_empty ()
+	{
+		var t = Thickness.Empty;
+		Assert.Equal (0, t.Left);
+		Assert.Equal (0, t.Top);
+		Assert.Equal (0, t.Right);
+		Assert.Equal (0, t.Bottom);
+	}
+
+	[Fact ()]
+	public void Constructor_Width ()
+	{
+		var t = new Thickness (1);
+		Assert.Equal (1, t.Left);
+		Assert.Equal (1, t.Top);
+		Assert.Equal (1, t.Right);
+		Assert.Equal (1, t.Bottom);
+	}
+
+	[Fact ()]
+	public void Constructor_params ()
+	{
+		var t = new Thickness (1, 2, 3, 4);
+		Assert.Equal (1, t.Left);
+		Assert.Equal (2, t.Top);
+		Assert.Equal (3, t.Right);
+		Assert.Equal (4, t.Bottom);
+
+		t = new Thickness (0, 0, 0, 0);
+		Assert.Equal (0, t.Left);
+		Assert.Equal (0, t.Top);
+		Assert.Equal (0, t.Right);
+		Assert.Equal (0, t.Bottom);
+
+		t = new Thickness (-1, 0, 0, 0);
+		Assert.Equal (-1, t.Left);
+		Assert.Equal (0, t.Top);
+		Assert.Equal (0, t.Right);
+		Assert.Equal (0, t.Bottom);
+	}
+
+	[Fact ()]
+	public void Vertical_get ()
+	{
+		var t = new Thickness (1, 2, 3, 4);
+		Assert.Equal (6, t.Vertical);
+
+		t = new Thickness (0);
+		Assert.Equal (0, t.Vertical);
+	}
+
+	[Fact ()]
+	public void Horizontal_get ()
+	{
+		var t = new Thickness (1, 2, 3, 4);
+		Assert.Equal (4, t.Horizontal);
+
+		t = new Thickness (0);
+		Assert.Equal (0, t.Horizontal);
+	}
+
+	[Fact ()]
+	public void Vertical_set ()
+	{
+		var t = new Thickness ();
+		t.Vertical = 10;
+		Assert.Equal (10, t.Vertical);
+		Assert.Equal (0, t.Left);
+		Assert.Equal (5, t.Top);
+		Assert.Equal (0, t.Right);
+		Assert.Equal (5, t.Bottom);
+		Assert.Equal (0, t.Horizontal);
+
+		t.Vertical = 11;
+		Assert.Equal (10, t.Vertical);
+		Assert.Equal (0, t.Left);
+		Assert.Equal (5, t.Top);
+		Assert.Equal (0, t.Right);
+		Assert.Equal (5, t.Bottom);
+		Assert.Equal (0, t.Horizontal);
+
+		t.Vertical = 1;
+		Assert.Equal (0, t.Vertical);
+		Assert.Equal (0, t.Left);
+		Assert.Equal (0, t.Top);
+		Assert.Equal (0, t.Right);
+		Assert.Equal (0, t.Bottom);
+		Assert.Equal (0, t.Horizontal);
+	}
+
+	[Fact ()]
+	public void Horizontal_set ()
+	{
+		var t = new Thickness ();
+		t.Horizontal = 10;
+		Assert.Equal (10, t.Horizontal);
+		Assert.Equal (5, t.Left);
+		Assert.Equal (0, t.Top);
+		Assert.Equal (5, t.Right);
+		Assert.Equal (0, t.Bottom);
+		Assert.Equal (0, t.Vertical);
+
+		t.Horizontal = 11;
+		Assert.Equal (10, t.Horizontal);
+		Assert.Equal (5, t.Left);
+		Assert.Equal (0, t.Top);
+		Assert.Equal (5, t.Right);
+		Assert.Equal (0, t.Bottom);
+		Assert.Equal (0, t.Vertical);
+
+		t.Horizontal = 1;
+		Assert.Equal (0, t.Horizontal);
+		Assert.Equal (0, t.Left);
+		Assert.Equal (0, t.Top);
+		Assert.Equal (0, t.Right);
+		Assert.Equal (0, t.Bottom);
+		Assert.Equal (0, t.Vertical);
+
+	}
+
+	[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 GetInsideTests_Positive_Thickness_Too_Small_Rect_Means_Empty_Size ()
+	{
+		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]
+	public void DrawTests ()
+	{
+		((FakeDriver)Application.Driver).SetBufferSize (60, 60);
+		var t = new Thickness (0, 0, 0, 0);
+		var 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), (Rune)' ');
+		t.Draw (r, "Test");
+		ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.Off;
+		TestHelpers.AssertDriverContentsWithFrameAre (@"
        Test (Left=0,Top=0,Right=0,Bottom=0)", output);
 
-			t = new Thickness (1, 1, 1, 1);
-			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), (Rune)' ');
-			t.Draw (r, "Test");
-			ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.Off;
-			TestHelpers.AssertDriverContentsWithFrameAre (@"
+		t = new Thickness (1, 1, 1, 1);
+		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), (Rune)' ');
+		t.Draw (r, "Test");
+		ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.Off;
+		TestHelpers.AssertDriverContentsWithFrameAre (@"
      TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
      T                                      T
      T                                      T
@@ -432,13 +432,13 @@ namespace Terminal.Gui.DrawingTests {
      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), (Rune)' ');
-			t.Draw (r, "Test");
-			ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.Off;
-			TestHelpers.AssertDriverContentsWithFrameAre (@"
+		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), (Rune)' ');
+		t.Draw (r, "Test");
+		ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.Off;
+		TestHelpers.AssertDriverContentsWithFrameAre (@"
      TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
      TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
      T                                    TTT
@@ -455,13 +455,13 @@ namespace Terminal.Gui.DrawingTests {
      TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
      TTTest (Left=1,Top=2,Right=3,Bottom=4)TT", output);
 
-			t = new Thickness (-1, 1, 1, 1);
-			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), (Rune)' ');
-			t.Draw (r, "Test");
-			ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.Off;
-			TestHelpers.AssertDriverContentsWithFrameAre (@"
+		t = new Thickness (-1, 1, 1, 1);
+		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), (Rune)' ');
+		t.Draw (r, "Test");
+		ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.Off;
+		TestHelpers.AssertDriverContentsWithFrameAre (@"
      TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
                                             T
                                             T
@@ -478,30 +478,30 @@ namespace Terminal.Gui.DrawingTests {
                                             T
      TTest (Left=-1,Top=1,Right=1,Bottom=1)TT", output);
 
-		}
-
-		[Fact (), AutoInitShutdown]
-		public void DrawTests_Ruler ()
-		{
-			// Add a frame so we can see the ruler
-			var f = new FrameView () {
-				X = 0,
-				Y = 0,
-				Width = Dim.Fill (),
-				Height = Dim.Fill (),
-			};
-
-			Application.Top.Add (f);
-			Application.Begin (Application.Top);
-
-			((FakeDriver)Application.Driver).SetBufferSize (45, 20);
-			var t = new Thickness (0, 0, 0, 0);
-			var r = new Rect (2, 2, 40, 15);
-			Application.Refresh ();
-			ConsoleDriver.Diagnostics |= ConsoleDriver.DiagnosticFlags.FrameRuler;
-			t.Draw (r, "Test");
-			ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.Off;
-			TestHelpers.AssertDriverContentsAre (@"
+	}
+
+	[Fact (), AutoInitShutdown]
+	public void DrawTests_Ruler ()
+	{
+		// Add a frame so we can see the ruler
+		var f = new FrameView () {
+			X = 0,
+			Y = 0,
+			Width = Dim.Fill (),
+			Height = Dim.Fill (),
+		};
+
+		Application.Top.Add (f);
+		Application.Begin (Application.Top);
+
+		((FakeDriver)Application.Driver).SetBufferSize (45, 20);
+		var t = new Thickness (0, 0, 0, 0);
+		var r = new Rect (2, 2, 40, 15);
+		Application.Refresh ();
+		ConsoleDriver.Diagnostics |= ConsoleDriver.DiagnosticFlags.FrameRuler;
+		t.Draw (r, "Test");
+		ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.Off;
+		TestHelpers.AssertDriverContentsAre (@"
 ┌───────────────────────────────────────────┐
 │                                           │
 │                                           │
@@ -523,13 +523,13 @@ namespace Terminal.Gui.DrawingTests {
 │                                           │
 └───────────────────────────────────────────┘", output);
 
-			t = new Thickness (1, 1, 1, 1);
-			r = new Rect (1, 1, 40, 15);
-			Application.Refresh ();
-			ConsoleDriver.Diagnostics |= ConsoleDriver.DiagnosticFlags.FrameRuler;
-			t.Draw (r, "Test");
-			ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.Off;
-			TestHelpers.AssertDriverContentsAre (@"
+		t = new Thickness (1, 1, 1, 1);
+		r = new Rect (1, 1, 40, 15);
+		Application.Refresh ();
+		ConsoleDriver.Diagnostics |= ConsoleDriver.DiagnosticFlags.FrameRuler;
+		t.Draw (r, "Test");
+		ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.Off;
+		TestHelpers.AssertDriverContentsAre (@"
 ┌───────────────────────────────────────────┐
 │|123456789|123456789|123456789|123456789   │
 │1                                      1   │
@@ -551,13 +551,13 @@ namespace Terminal.Gui.DrawingTests {
 │                                           │
 └───────────────────────────────────────────┘", output);
 
-			t = new Thickness (1, 2, 3, 4);
-			r = new Rect (2, 2, 40, 15);
-			Application.Refresh ();
-			ConsoleDriver.Diagnostics |= ConsoleDriver.DiagnosticFlags.FrameRuler;
-			t.Draw (r, "Test");
-			ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.Off;
-			TestHelpers.AssertDriverContentsWithFrameAre (@"
+		t = new Thickness (1, 2, 3, 4);
+		r = new Rect (2, 2, 40, 15);
+		Application.Refresh ();
+		ConsoleDriver.Diagnostics |= ConsoleDriver.DiagnosticFlags.FrameRuler;
+		t.Draw (r, "Test");
+		ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.Off;
+		TestHelpers.AssertDriverContentsWithFrameAre (@"
 ┌───────────────────────────────────────────┐
 │                                           │
 │ |123456789|123456789|123456789|123456789  │
@@ -579,13 +579,13 @@ namespace Terminal.Gui.DrawingTests {
 │                                           │
 └───────────────────────────────────────────┘", output);
 
-			t = new Thickness (-1, 1, 1, 1);
-			r = new Rect (5, 5, 40, 15);
-			Application.Refresh ();
-			ConsoleDriver.Diagnostics |= ConsoleDriver.DiagnosticFlags.FrameRuler;
-			t.Draw (r, "Test");
-			ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.Off;
-			TestHelpers.AssertDriverContentsWithFrameAre (@"
+		t = new Thickness (-1, 1, 1, 1);
+		r = new Rect (5, 5, 40, 15);
+		Application.Refresh ();
+		ConsoleDriver.Diagnostics |= ConsoleDriver.DiagnosticFlags.FrameRuler;
+		t.Draw (r, "Test");
+		ConsoleDriver.Diagnostics = ConsoleDriver.DiagnosticFlags.Off;
+		TestHelpers.AssertDriverContentsWithFrameAre (@"
 ┌───────────────────────────────────────────┐
 │                                           │
 │                                           │
@@ -607,29 +607,136 @@ namespace Terminal.Gui.DrawingTests {
 │                                           3
 └────|123456789|123456789|123456789|123456789", output);
 
-		}
-		[Fact ()]
-		public void EqualsTest ()
-		{
-			var t = new Thickness (1, 2, 3, 4);
-			var t2 = new Thickness (1, 2, 3, 4);
-			Assert.True (t.Equals (t2));
-			Assert.True (t == t2);
-			Assert.False (t != t2);
-		}
-
-		[Fact ()]
-		public void ToStringTest ()
-		{
-			var t = new Thickness (1, 2, 3, 4);
-			Assert.Equal ("(Left=1,Top=2,Right=3,Bottom=4)", t.ToString ());
-		}
-
-		[Fact ()]
-		public void GetHashCodeTest ()
-		{
-			var t = new Thickness (1, 2, 3, 4);
-			Assert.Equal (t.GetHashCode (), t.GetHashCode ());
-		}
 	}
-}
+
+	[Theory]
+	[InlineData (0, 0, 10, 10, 3, 3, false)] // Inside the inner rectangle
+	[InlineData (0, 0, 10, 10, 0, 0, false)] // On corner, in thickness
+	[InlineData (0, 0, 10, 10, 9, 9, false)] // On opposite corner, in thickness
+	[InlineData (0, 0, 10, 10, 5, 5, false)] // Inside the inner rectangle
+	[InlineData (0, 0, 10, 10, -1, -1, false)] // Outside the outer rectangle
+	[InlineData (0, 0, 10, 10, 3, 3, false)] // Inside the inner rectangle
+
+	[InlineData (0, 0, 0, 0, 3, 3, false)] // Inside the inner rectangle
+	[InlineData (0, 0, 0, 0, 0, 0, false)] // On corner, in thickness
+	[InlineData (0, 0, 0, 0, 9, 9, false)] // On opposite corner, in thickness
+	[InlineData (0, 0, 0, 0, 5, 5, false)] // Inside the inner rectangle
+	[InlineData (0, 0, 0, 0, -1, -1, false)] // Outside the outer rectangle
+	[InlineData (0, 0, 0, 0, 3, 3, false)] // Inside the inner rectangle
+
+	[InlineData (1, 1, 10, 10, 1, 1, false)] // On corner, in thickness
+	[InlineData (1, 1, 10, 10, 10, 10, false)] // On opposite corner, in thickness
+	[InlineData (1, 1, 10, 10, 6, 6, false)] // Inside the inner rectangle
+	[InlineData (1, 1, 10, 10, 0, 0, false)] // Outside the outer rectangle
+
+	[InlineData (-1, -1, 10, 10, -1, -1, false)] // On corner, in thickness
+	[InlineData (-1, -1, 10, 10, 8, 8, false)] // On opposite corner, in thickness
+	[InlineData (-1, -1, 10, 10, 4, 4, false)] // Inside the inner rectangle
+	[InlineData (-1, -1, 10, 10, -2, -2, false)] // Outside the outer rectangle
+	public void TestContains_ZeroThickness (int x, int y, int width, int height, int pointX, int pointY, bool expected)
+	{
+		var rect = new Rect (x, y, width, height);
+		var thickness = new Thickness (0, 0, 0, 0); // Uniform thickness for simplicity
+		bool result = thickness.Contains (rect, pointX, pointY);
+		Assert.Equal (expected, result);
+	}
+
+	[Theory]
+	[InlineData (0, 0, 10, 10, 3, 3, false)] // Inside the inner rectangle
+	[InlineData (0, 0, 10, 10, 0, 0, true)] // On corner, in thickness
+	[InlineData (0, 0, 10, 10, 9, 9, true)] // On opposite corner, in thickness
+	[InlineData (0, 0, 10, 10, 5, 5, false)] // Inside the inner rectangle
+	[InlineData (0, 0, 10, 10, -1, -1, false)] // Outside the outer rectangle
+	[InlineData (0, 0, 10, 10, 3, 3, false)] // Inside the inner rectangle
+
+	[InlineData (0, 0, 0, 0, 3, 3, false)] // Inside the inner rectangle
+	[InlineData (0, 0, 0, 0, 0, 0, false)] // On corner, in thickness
+	[InlineData (0, 0, 0, 0, 9, 9, false)] // On opposite corner, in thickness
+	[InlineData (0, 0, 0, 0, 5, 5, false)] // Inside the inner rectangle
+	[InlineData (0, 0, 0, 0, -1, -1, false)] // Outside the outer rectangle
+	[InlineData (0, 0, 0, 0, 3, 3, false)] // Inside the inner rectangle
+
+	[InlineData (1, 1, 10, 10, 1, 1, true)] // On corner, in thickness
+	[InlineData (1, 1, 10, 10, 10, 10, true)] // On opposite corner, in thickness
+	[InlineData (1, 1, 10, 10, 6, 6, false)] // Inside the inner rectangle
+	[InlineData (1, 1, 10, 10, 0, 0, false)] // Outside the outer rectangle
+
+	[InlineData (-1, -1, 10, 10, -1, -1, true)] // On corner, in thickness
+	[InlineData (-1, -1, 10, 10, 8, 8, true)] // On opposite corner, in thickness
+	[InlineData (-1, -1, 10, 10, 4, 4, false)] // Inside the inner rectangle
+	[InlineData (-1, -1, 10, 10, -2, -2, false)] // Outside the outer rectangle
+	public void TestContains_Uniform1 (int x, int y, int width, int height, int pointX, int pointY, bool expected)
+	{
+		var rect = new Rect (x, y, width, height);
+		var thickness = new Thickness (1, 1, 1, 1); // Uniform thickness for simplicity
+		bool result = thickness.Contains (rect, pointX, pointY);
+		Assert.Equal (expected, result);
+	}
+
+	[Theory]
+	[InlineData (0, 0, 10, 10, 3, 3, false)] // Inside the inner rectangle
+	[InlineData (0, 0, 10, 10, 0, 0, true)] // On corner, in thickness
+	[InlineData (0, 0, 10, 10, 1, 1, true)] // On corner, in thickness
+	[InlineData (0, 0, 10, 10, 9, 9, true)] // On opposite corner, in thickness
+	[InlineData (0, 0, 10, 10, 5, 5, false)] // Inside the inner rectangle
+	[InlineData (0, 0, 10, 10, 8, 8, true)] // On opposite corner, in thickness
+	[InlineData (0, 0, 10, 10, -1, -1, false)] // Outside the outer rectangle
+
+	// Test with a rectangle that is same size as the thickness (inner is empty)
+	[InlineData (0, 0, 4, 4, 0, 0, true)] // in thickness
+	[InlineData (0, 0, 4, 4, 1, 1, true)] // in thickness
+	[InlineData (0, 0, 4, 4, 2, 2, true)] // in thickness
+	[InlineData (0, 0, 4, 4, 3, 3, true)] // in thickness
+	[InlineData (0, 0, 4, 4, 5, 5, false)] // outside outer rect
+	[InlineData (0, 0, 4, 4, 4, 4, false)] // outside outer rect
+
+	[InlineData (1, 1, 10, 10, 4, 4, false)] // Inside the inner rectangle
+	[InlineData (1, 1, 10, 10, 1, 1, true)] // On corner, in thickness
+	[InlineData (1, 1, 10, 10, 2, 2, true)] // On corner, in thickness
+	[InlineData (1, 1, 10, 10, 10, 10, true)] // On opposite corner, in thickness
+	[InlineData (1, 1, 10, 10, 6, 6, false)] // Inside the inner rectangle
+	[InlineData (1, 1, 10, 10, 9, 9, true)] // On opposite corner, in thickness
+	[InlineData (1, 1, 10, 10, 0, 0, false)] // Outside the outer rectangle
+
+	// Test with a rectangle that is same size as the thickness (inner is empty)
+	[InlineData (-1, -1, 4, 4, -1, -1, true)] // in thickness
+	[InlineData (-1, -1, 4, 4, 0, 0, true)] // in thickness
+	[InlineData (-1, -1, 4, 4, 1, 1, true)] // in thickness
+	[InlineData (-1, -1, 4, 4, 2, 2, true)] // in thickness
+	[InlineData (-1, -1, 4, 4, 4, 4, false)] // outside outer rect
+	[InlineData (-1, -1, 4, 4, 3, 3, false)] // outside outer rect
+	public void TestContains_Uniform2 (int x, int y, int width, int height, int pointX, int pointY, bool expected)
+	{
+		var rect = new Rect (x, y, width, height);
+		var thickness = new Thickness (2, 2, 2, 2); // Uniform thickness for simplicity
+		bool result = thickness.Contains (rect, pointX, pointY);
+		Assert.Equal (expected, result);
+	}
+
+	// TODO: Add more test cases:
+	// - Negative thickness values
+
+	[Fact ()]
+	public void EqualsTest ()
+	{
+		var t = new Thickness (1, 2, 3, 4);
+		var t2 = new Thickness (1, 2, 3, 4);
+		Assert.True (t.Equals (t2));
+		Assert.True (t == t2);
+		Assert.False (t != t2);
+	}
+
+	[Fact ()]
+	public void ToStringTest ()
+	{
+		var t = new Thickness (1, 2, 3, 4);
+		Assert.Equal ("(Left=1,Top=2,Right=3,Bottom=4)", t.ToString ());
+	}
+
+	[Fact ()]
+	public void GetHashCodeTest ()
+	{
+		var t = new Thickness (1, 2, 3, 4);
+		Assert.Equal (t.GetHashCode (), t.GetHashCode ());
+	}
+}

+ 35 - 36
UnitTests/View/BorderTests.cs

@@ -1,45 +1,44 @@
 using Xunit;
 using Xunit.Abstractions;
 
-namespace Terminal.Gui.ViewTests {
-	public class BorderTests {
-		readonly ITestOutputHelper output;
+namespace Terminal.Gui.ViewTests;
+public class BorderTests {
+	readonly ITestOutputHelper _output;
 
-		public BorderTests (ITestOutputHelper output)
-		{
-			this.output = output;
-		}
-
-		[Fact]
-		public void View_BorderStyle_Defaults ()
-		{
-			var view = new View ();
-			Assert.Equal (LineStyle.None, view.BorderStyle);
-			Assert.Equal (Thickness.Empty, view.Border.Thickness);
-			view.Dispose ();
-		}
+	public BorderTests (ITestOutputHelper output)
+	{
+		this._output = output;
+	}
 
-		[Fact]
-		public void View_SetBorderStyle ()
-		{
-			var view = new View ();
-			view.BorderStyle = LineStyle.Single;
-			Assert.Equal (LineStyle.Single, view.BorderStyle);
-			Assert.Equal (new Thickness(1), view.Border.Thickness);
+	[Fact]
+	public void View_BorderStyle_Defaults ()
+	{
+		var view = new View ();
+		Assert.Equal (LineStyle.None, view.BorderStyle);
+		Assert.Equal (Thickness.Empty, view.Border.Thickness);
+		view.Dispose ();
+	}
 
-			view.BorderStyle = LineStyle.Double;
-			Assert.Equal (LineStyle.Double, view.BorderStyle);
-			Assert.Equal (new Thickness (1), view.Border.Thickness);
+	[Fact]
+	public void View_SetBorderStyle ()
+	{
+		var view = new View ();
+		view.BorderStyle = LineStyle.Single;
+		Assert.Equal (LineStyle.Single, view.BorderStyle);
+		Assert.Equal (new Thickness (1), view.Border.Thickness);
 
-			view.BorderStyle = LineStyle.None;
-			Assert.Equal (LineStyle.None, view.BorderStyle);
-			Assert.Equal (Thickness.Empty, view.Border.Thickness);
-			view.Dispose ();
-		}
+		view.BorderStyle = LineStyle.Double;
+		Assert.Equal (LineStyle.Double, view.BorderStyle);
+		Assert.Equal (new Thickness (1), view.Border.Thickness);
 
-		//[Fact]
-		//public void View_BorderStyleChanged ()
-		//{
-		//}
+		view.BorderStyle = LineStyle.None;
+		Assert.Equal (LineStyle.None, view.BorderStyle);
+		Assert.Equal (Thickness.Empty, view.Border.Thickness);
+		view.Dispose ();
 	}
-}
+
+	//[Fact]
+	//public void View_BorderStyleChanged ()
+	//{
+	//}
+}

+ 522 - 412
UnitTests/View/FrameTests.cs

@@ -1,612 +1,722 @@
-using System.Text;
-using System;
-using System.Collections.Generic;
-using System.Xml.Linq;
-using Xunit;
+using Xunit;
 using Xunit.Abstractions;
-//using GraphViewTests = Terminal.Gui.Views.GraphViewTests;
 
-// Alias Console to MockConsole so we don't accidentally use Console
-using Console = Terminal.Gui.FakeConsole;
+namespace Terminal.Gui.ViewTests;
+public class FrameTests {
+	readonly ITestOutputHelper _output;
 
-namespace Terminal.Gui.ViewTests {
-	public class FrameTests {
-		readonly ITestOutputHelper output;
+	public FrameTests (ITestOutputHelper output)
+	{
+		this._output = output;
+	}
 
-		public FrameTests (ITestOutputHelper output)
-		{
-			this.output = output;
-		}
+	// Test FrameToScreen
+	[Theory]
+	[InlineData (0, 0, 0, 0)]
+	[InlineData (1, 0, 1, 0)]
+	[InlineData (0, 1, 0, 1)]
+	[InlineData (1, 1, 1, 1)]
+	[InlineData (10, 10, 10, 10)]
+	void FrameToScreen_NoSuperView (int frameX, int frameY, int expectedScreenX, int expectedScreenY)
+	{
+		var view = new View () {
+			X = frameX,
+			Y = frameY,
+			Width = 10,
+			Height = 10
+		};
+		var expected = new Rect (expectedScreenX, expectedScreenY, 10, 10);
+		var actual = view.FrameToScreen ();
+		Assert.Equal (expected, actual);
+	}
 
-		[Fact]
-		public void GetFramesThickness ()
-		{
-			var view = new View ();
-			Assert.Equal (Thickness.Empty, view.GetFramesThickness ());
+	[Theory]
+	[InlineData (0, 0, 0, 0, 0)]
+	[InlineData (1, 0, 0, 1, 1)]
+	[InlineData (2, 0, 0, 2, 2)]
+	[InlineData (1, 1, 0, 2, 1)]
+	[InlineData (1, 0, 1, 1, 2)]
+	[InlineData (1, 1, 1, 2, 2)]
+	[InlineData (1, 10, 10, 11, 11)]
+	void FrameToScreen_SuperView (int superOffset, int frameX, int frameY, int expectedScreenX, int expectedScreenY)
+	{
+		var super = new View() {
+			X = superOffset,
+			Y = superOffset,
+			Width = 20,
+			Height = 20
+		};
+		
+		var view = new View () {
+			X = frameX,
+			Y = frameY,
+			Width = 10,
+			Height = 10
+		};
+		super.Add (view);
+		var expected = new Rect (expectedScreenX, expectedScreenY, 10, 10);
+		var actual = view.FrameToScreen ();
+		Assert.Equal (expected, actual);
+	}
 
-			view.Margin.Thickness = new Thickness (1);
-			Assert.Equal (new Thickness (1), view.GetFramesThickness ());
+	[Theory]
+	[InlineData (0, 0, 0, 1, 1)]
+	[InlineData (1, 0, 0, 2, 2)]
+	[InlineData (2, 0, 0, 3, 3)]
+	[InlineData (1, 1, 0, 3, 2)]
+	[InlineData (1, 0, 1, 2, 3)]
+	[InlineData (1, 1, 1, 3, 3)]
+	[InlineData (1, 10, 10, 12, 12)]
+	void FrameToScreen_SuperView_WithBorder (int superOffset, int frameX, int frameY, int expectedScreenX, int expectedScreenY)
+	{
+		var super = new View () {
+			X = superOffset,
+			Y = superOffset,
+			Width = 20,
+			Height = 20,
+			BorderStyle = LineStyle.Single
+		};
+
+		var view = new View () {
+			X = frameX,
+			Y = frameY,
+			Width = 10,
+			Height = 10
+		};
+		super.Add (view);
+		var expected = new Rect (expectedScreenX, expectedScreenY, 10, 10);
+		var actual = view.FrameToScreen ();
+		Assert.Equal (expected, actual);
+	}
 
-			view.Border.Thickness = new Thickness (1);
-			Assert.Equal (new Thickness (2), view.GetFramesThickness ());
+	[Theory]
+	[InlineData (0, 0, 0, 2, 2)]
+	[InlineData (1, 0, 0, 4, 4)]
+	[InlineData (2, 0, 0, 6, 6)]
+	[InlineData (1, 1, 0, 5, 4)]
+	[InlineData (1, 0, 1, 4, 5)]
+	[InlineData (1, 1, 1, 5, 5)]
+	[InlineData (1, 10, 10, 14, 14)]
+	void FrameToScreen_NestedSuperView_WithBorder (int superOffset, int frameX, int frameY, int expectedScreenX, int expectedScreenY)
+	{
+		var superSuper = new View () {
+			X = superOffset,
+			Y = superOffset,
+			Width = 30,
+			Height = 30,
+			BorderStyle = LineStyle.Single
+		};
+
+		var super = new View () {
+			X = superOffset,
+			Y = superOffset,
+			Width = 20,
+			Height = 20,
+			BorderStyle = LineStyle.Single
+		};
+		superSuper.Add (super);
+
+		var view = new View () {
+			X = frameX,
+			Y = frameY,
+			Width = 10,
+			Height = 10
+		};
+		super.Add (view);
+		var expected = new Rect (expectedScreenX, expectedScreenY, 10, 10);
+		var actual = view.FrameToScreen ();
+		Assert.Equal (expected, actual);
+	}
 
-			view.Padding.Thickness = new Thickness (1);
-			Assert.Equal (new Thickness (3), view.GetFramesThickness ());
 
-			view.Padding.Thickness = new Thickness (2);
-			Assert.Equal (new Thickness (4), view.GetFramesThickness ());
+	[Fact]
+	public void GetFramesThickness ()
+	{
+		var view = new View ();
+		Assert.Equal (Thickness.Empty, view.GetFramesThickness ());
 
-			view.Padding.Thickness = new Thickness (1, 2, 3, 4);
-			Assert.Equal (new Thickness (3, 4, 5, 6), view.GetFramesThickness ());
+		view.Margin.Thickness = new Thickness (1);
+		Assert.Equal (new Thickness (1), view.GetFramesThickness ());
 
-			view.Margin.Thickness = new Thickness (1, 2, 3, 4);
-			Assert.Equal (new Thickness (3, 5, 7, 9), view.GetFramesThickness ());
-			view.Dispose ();
-		}
+		view.Border.Thickness = new Thickness (1);
+		Assert.Equal (new Thickness (2), view.GetFramesThickness ());
+
+		view.Padding.Thickness = new Thickness (1);
+		Assert.Equal (new Thickness (3), view.GetFramesThickness ());
+
+		view.Padding.Thickness = new Thickness (2);
+		Assert.Equal (new Thickness (4), view.GetFramesThickness ());
+
+		view.Padding.Thickness = new Thickness (1, 2, 3, 4);
+		Assert.Equal (new Thickness (3, 4, 5, 6), view.GetFramesThickness ());
+
+		view.Margin.Thickness = new Thickness (1, 2, 3, 4);
+		Assert.Equal (new Thickness (3, 5, 7, 9), view.GetFramesThickness ());
+		view.Dispose ();
+	}
 
-		[Theory, AutoInitShutdown]
-		[InlineData (0)]
-		[InlineData (1)]
-		[InlineData (2)]
-		[InlineData (3)]
-		public void Border_With_Title_Size_Height (int height)
-		{
-			var win = new Window () {
-				Title = "1234",
-				Width = Dim.Fill (),
-				Height = Dim.Fill ()
-			};
-
-			var rs = Application.Begin (win);
-			bool firstIteration = false;
-
-			((FakeDriver)Application.Driver).SetBufferSize (20, height);
-			Application.RunIteration (ref rs, ref firstIteration);
-			var expected = string.Empty;
-
-			switch (height) {
-			case 0:
-				//Assert.Equal (new Rect (0, 0, 17, 0), subview.Frame);
-				expected = @"
+	[Theory, AutoInitShutdown]
+	[InlineData (0)]
+	[InlineData (1)]
+	[InlineData (2)]
+	[InlineData (3)]
+	public void Border_With_Title_Size_Height (int height)
+	{
+		var win = new Window () {
+			Title = "1234",
+			Width = Dim.Fill (),
+			Height = Dim.Fill ()
+		};
+
+		var rs = Application.Begin (win);
+		bool firstIteration = false;
+
+		((FakeDriver)Application.Driver).SetBufferSize (20, height);
+		Application.RunIteration (ref rs, ref firstIteration);
+		var expected = string.Empty;
+
+		switch (height) {
+		case 0:
+			//Assert.Equal (new Rect (0, 0, 17, 0), subview.Frame);
+			expected = @"
 ";
-				break;
-			case 1:
-				//Assert.Equal (new Rect (0, 0, 17, 0), subview.Frame);
-				expected = @"
+			break;
+		case 1:
+			//Assert.Equal (new Rect (0, 0, 17, 0), subview.Frame);
+			expected = @"
 ────────────────────";
-				break;
-			case 2:
-				//Assert.Equal (new Rect (0, 0, 17, 1), subview.Frame);
-				expected = @"
+			break;
+		case 2:
+			//Assert.Equal (new Rect (0, 0, 17, 1), subview.Frame);
+			expected = @"
 ┌┤1234├────────────┐
 └──────────────────┘
 ";
-				break;
-			case 3:
-				//Assert.Equal (new Rect (0, 0, 17, 2), subview.Frame);
-				expected = @"
+			break;
+		case 3:
+			//Assert.Equal (new Rect (0, 0, 17, 2), subview.Frame);
+			expected = @"
 ┌┤1234├────────────┐
 │                  │
 └──────────────────┘
 ";
-				break;
-			}
-			_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
-			Application.End (rs);
+			break;
 		}
+		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+		Application.End (rs);
+	}
 
-		[Theory, AutoInitShutdown]
-		[InlineData (0)]
-		[InlineData (1)]
-		[InlineData (2)]
-		[InlineData (3)]
-		[InlineData (4)]
-		[InlineData (5)]
-		[InlineData (6)]
-		[InlineData (7)]
-		[InlineData (8)]
-		[InlineData (9)]
-		[InlineData (10)]
-		public void Border_With_Title_Size_Width (int width)
-		{
-			var win = new Window () {
-				Title = "1234",
-				Width = Dim.Fill (),
-				Height = Dim.Fill ()
-			};
-
-			var rs = Application.Begin (win);
-			bool firstIteration = false;
-
-			((FakeDriver)Application.Driver).SetBufferSize (width, 3);
-			Application.RunIteration (ref rs, ref firstIteration);
-			var expected = string.Empty;
-
-			switch (width) {
-			case 1:
-				//Assert.Equal (new Rect (0, 0, 17, 0), subview.Frame);
-				expected = @"
+	[Theory, AutoInitShutdown]
+	[InlineData (0)]
+	[InlineData (1)]
+	[InlineData (2)]
+	[InlineData (3)]
+	[InlineData (4)]
+	[InlineData (5)]
+	[InlineData (6)]
+	[InlineData (7)]
+	[InlineData (8)]
+	[InlineData (9)]
+	[InlineData (10)]
+	public void Border_With_Title_Size_Width (int width)
+	{
+		var win = new Window () {
+			Title = "1234",
+			Width = Dim.Fill (),
+			Height = Dim.Fill ()
+		};
+
+		var rs = Application.Begin (win);
+		bool firstIteration = false;
+
+		((FakeDriver)Application.Driver).SetBufferSize (width, 3);
+		Application.RunIteration (ref rs, ref firstIteration);
+		var expected = string.Empty;
+
+		switch (width) {
+		case 1:
+			//Assert.Equal (new Rect (0, 0, 17, 0), subview.Frame);
+			expected = @"
 │";
-				break;
-			case 2:
-				//Assert.Equal (new Rect (0, 0, 17, 1), subview.Frame);
-				expected = @"
+			break;
+		case 2:
+			//Assert.Equal (new Rect (0, 0, 17, 1), subview.Frame);
+			expected = @"
 ┌┐
 ││
 └┘";
-				break;
-			case 3:
-				//Assert.Equal (new Rect (0, 0, 17, 2), subview.Frame);
-				expected = @"
+			break;
+		case 3:
+			//Assert.Equal (new Rect (0, 0, 17, 2), subview.Frame);
+			expected = @"
 ┌─┐
 │ │
 └─┘
 ";
-				break;
-			case 4:
-				//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
-				expected = @"
+			break;
+		case 4:
+			//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
+			expected = @"
 ┌┤├┐
 │  │
 └──┘";
-				break;
-			case 5:
-				//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
-				expected = @"
+			break;
+		case 5:
+			//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
+			expected = @"
 ┌┤1├┐
 │   │
 └───┘";
-				break;
-			case 6:
-				//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
-				expected = @"
+			break;
+		case 6:
+			//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
+			expected = @"
 ┌┤12├┐
 │    │
 └────┘";
-				break;
-			case 7:
-				//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
-				expected = @"
+			break;
+		case 7:
+			//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
+			expected = @"
 ┌┤123├┐
 │     │
 └─────┘";
-				break;
-			case 8:
-				//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
-				expected = @"
+			break;
+		case 8:
+			//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
+			expected = @"
 ┌┤1234├┐
 │      │
 └──────┘";
-				break;
-			case 9:
-				//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
-				expected = @"
+			break;
+		case 9:
+			//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
+			expected = @"
 ┌┤1234├─┐
 │       │
 └───────┘";
-				break;
-			case 10:
-				//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
-				expected = @"
+			break;
+		case 10:
+			//Assert.Equal (new Rect (0, 0, 17, 3), subview.Frame);
+			expected = @"
 ┌┤1234├──┐
 │        │
 └────────┘";
-				break;
-			}
-			_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
+			break;
 		}
+		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+	}
 
-		[Fact, AutoInitShutdown]
-		public void NoSuperView ()
-		{
-			var win = new Window () {
-				Width = Dim.Fill (),
-				Height = Dim.Fill ()
-			};
+	[Fact, AutoInitShutdown]
+	public void NoSuperView ()
+	{
+		var win = new Window () {
+			Width = Dim.Fill (),
+			Height = Dim.Fill ()
+		};
 
-			var rs = Application.Begin (win);
-			bool firstIteration = false;
+		var rs = Application.Begin (win);
+		bool firstIteration = false;
 
-			((FakeDriver)Application.Driver).SetBufferSize (3, 3);
-			Application.RunIteration (ref rs, ref firstIteration);
-			var expected = @"
+		((FakeDriver)Application.Driver).SetBufferSize (3, 3);
+		Application.RunIteration (ref rs, ref firstIteration);
+		var expected = @"
 ┌─┐
 │ │
 └─┘";
 
-			_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
-		}
+		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+	}
 
-		[Fact, AutoInitShutdown]
-		public void HasSuperView ()
-		{
-			Application.Top.BorderStyle = LineStyle.Double;
+	[Fact, AutoInitShutdown]
+	public void HasSuperView ()
+	{
+		Application.Top.BorderStyle = LineStyle.Double;
 
-			var frame = new FrameView () {
-				Width = Dim.Fill (),
-				Height = Dim.Fill ()
-			};
+		var frame = new FrameView () {
+			Width = Dim.Fill (),
+			Height = Dim.Fill ()
+		};
 
-			Application.Top.Add (frame);
-			var rs = Application.Begin (Application.Top);
-			bool firstIteration = false;
+		Application.Top.Add (frame);
+		var rs = Application.Begin (Application.Top);
+		bool firstIteration = false;
 
-			((FakeDriver)Application.Driver).SetBufferSize (5, 5);
-			Application.RunIteration (ref rs, ref firstIteration);
-			var expected = @"
+		((FakeDriver)Application.Driver).SetBufferSize (5, 5);
+		Application.RunIteration (ref rs, ref firstIteration);
+		var expected = @"
 ╔═══╗
 ║┌─┐║
 ║│ │║
 ║└─┘║
 ╚═══╝";
 
-			_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
-			Application.End (rs);
-		}
+		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+		Application.End (rs);
+	}
 
-		[Fact, AutoInitShutdown]
-		public void HasSuperView_Title ()
-		{
-			Application.Top.BorderStyle = LineStyle.Double;
+	[Fact, AutoInitShutdown]
+	public void HasSuperView_Title ()
+	{
+		Application.Top.BorderStyle = LineStyle.Double;
 
-			var frame = new FrameView () {
-				Title = "1234",
-				Width = Dim.Fill (),
-				Height = Dim.Fill ()
-			};
+		var frame = new FrameView () {
+			Title = "1234",
+			Width = Dim.Fill (),
+			Height = Dim.Fill ()
+		};
 
-			Application.Top.Add (frame);
-			var rs = Application.Begin (Application.Top);
-			bool firstIteration = false;
+		Application.Top.Add (frame);
+		var rs = Application.Begin (Application.Top);
+		bool firstIteration = false;
 
-			((FakeDriver)Application.Driver).SetBufferSize (10, 4);
-			Application.RunIteration (ref rs, ref firstIteration);
-			var expected = @"
+		((FakeDriver)Application.Driver).SetBufferSize (10, 4);
+		Application.RunIteration (ref rs, ref firstIteration);
+		var expected = @"
 ╔════════╗
 ║┌┤1234├┐║
 ║└──────┘║
 ╚════════╝";
 
-			_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
-			Application.End (rs);
-		}
+		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+		Application.End (rs);
+	}
 
-		[Theory, AutoInitShutdown]
-		[InlineData (0)]
-		[InlineData (1)]
-		[InlineData (2)]
-		[InlineData (3)]
-		[InlineData (4)]
-		[InlineData (5)]
-		[InlineData (6)]
-		[InlineData (7)]
-		[InlineData (8)]
-		[InlineData (9)]
-		[InlineData (10)]
-		public void Border_With_Title_Border_Double_Thickness_Top_Two_Size_Width (int width)
-		{
-			var win = new Window () {
-				Title = "1234",
-				Width = Dim.Fill (),
-				Height = Dim.Fill (),
-				BorderStyle = LineStyle.Double,
-			};
-			win.Border.Thickness.Top = 2;
-
-			var rs = Application.Begin (win);
-			bool firstIteration = false;
-
-			((FakeDriver)Application.Driver).SetBufferSize (width, 4);
-			Application.RunIteration (ref rs, ref firstIteration);
-			var expected = string.Empty;
-
-			switch (width) {
-			case 1:
-				Assert.Equal (new Rect (0, 0, 1, 4), win.Frame);
-				expected = @"
+	[Theory, AutoInitShutdown]
+	[InlineData (0)]
+	[InlineData (1)]
+	[InlineData (2)]
+	[InlineData (3)]
+	[InlineData (4)]
+	[InlineData (5)]
+	[InlineData (6)]
+	[InlineData (7)]
+	[InlineData (8)]
+	[InlineData (9)]
+	[InlineData (10)]
+	public void Border_With_Title_Border_Double_Thickness_Top_Two_Size_Width (int width)
+	{
+		var win = new Window () {
+			Title = "1234",
+			Width = Dim.Fill (),
+			Height = Dim.Fill (),
+			BorderStyle = LineStyle.Double,
+		};
+		win.Border.Thickness.Top = 2;
+
+		var rs = Application.Begin (win);
+		bool firstIteration = false;
+
+		((FakeDriver)Application.Driver).SetBufferSize (width, 4);
+		Application.RunIteration (ref rs, ref firstIteration);
+		var expected = string.Empty;
+
+		switch (width) {
+		case 1:
+			Assert.Equal (new Rect (0, 0, 1, 4), win.Frame);
+			expected = @"
 ║";
-				break;
-			case 2:
-				Assert.Equal (new Rect (0, 0, 2, 4), win.Frame);
-				expected = @"
+			break;
+		case 2:
+			Assert.Equal (new Rect (0, 0, 2, 4), win.Frame);
+			expected = @"
 ╔╗
 ║║
 ╚╝";
-				break;
-			case 3:
-				Assert.Equal (new Rect (0, 0, 3, 4), win.Frame);
-				expected = @"
+			break;
+		case 3:
+			Assert.Equal (new Rect (0, 0, 3, 4), win.Frame);
+			expected = @"
 ╔═╗
 ║ ║
 ╚═╝";
-				break;
-			case 4:
-				Assert.Equal (new Rect (0, 0, 4, 4), win.Frame);
-				expected = @"
+			break;
+		case 4:
+			Assert.Equal (new Rect (0, 0, 4, 4), win.Frame);
+			expected = @"
  ╒╕ 
 ╔╛╘╗
 ║  ║
 ╚══╝";
-				break;
-			case 5:
-				Assert.Equal (new Rect (0, 0, 5, 4), win.Frame);
-				expected = @"
+			break;
+		case 5:
+			Assert.Equal (new Rect (0, 0, 5, 4), win.Frame);
+			expected = @"
  ╒═╕ 
 ╔╛1╘╗
 ║   ║
 ╚═══╝";
-				break;
-			case 6:
-				Assert.Equal (new Rect (0, 0, 6, 4), win.Frame);
-				expected = @"
+			break;
+		case 6:
+			Assert.Equal (new Rect (0, 0, 6, 4), win.Frame);
+			expected = @"
  ╒══╕ 
 ╔╛12╘╗
 ║    ║
 ╚════╝";
-				break;
-			case 7:
-				Assert.Equal (new Rect (0, 0, 7, 4), win.Frame);
-				expected = @"
+			break;
+		case 7:
+			Assert.Equal (new Rect (0, 0, 7, 4), win.Frame);
+			expected = @"
  ╒═══╕ 
 ╔╛123╘╗
 ║     ║
 ╚═════╝";
-				break;
-			case 8:
-				Assert.Equal (new Rect (0, 0, 8, 4), win.Frame);
-				expected = @"
+			break;
+		case 8:
+			Assert.Equal (new Rect (0, 0, 8, 4), win.Frame);
+			expected = @"
  ╒════╕ 
 ╔╛1234╘╗
 ║      ║
 ╚══════╝";
-				break;
-			case 9:
-				Assert.Equal (new Rect (0, 0, 9, 4), win.Frame);
-				expected = @"
+			break;
+		case 9:
+			Assert.Equal (new Rect (0, 0, 9, 4), win.Frame);
+			expected = @"
  ╒════╕  
 ╔╛1234╘═╗
 ║       ║
 ╚═══════╝";
-				break;
-			case 10:
-				Assert.Equal (new Rect (0, 0, 10, 4), win.Frame);
-				expected = @"
+			break;
+		case 10:
+			Assert.Equal (new Rect (0, 0, 10, 4), win.Frame);
+			expected = @"
  ╒════╕   
 ╔╛1234╘══╗
 ║        ║
 ╚════════╝";
-				break;
-			}
-			_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
-			Application.End (rs);
+			break;
 		}
+		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+		Application.End (rs);
+	}
 
-		[Theory, AutoInitShutdown]
-		[InlineData (0)]
-		[InlineData (1)]
-		[InlineData (2)]
-		[InlineData (3)]
-		[InlineData (4)]
-		[InlineData (5)]
-		[InlineData (6)]
-		[InlineData (7)]
-		[InlineData (8)]
-		[InlineData (9)]
-		[InlineData (10)]
-		public void Border_With_Title_Border_Double_Thickness_Top_Three_Size_Width (int width)
-		{
-			var win = new Window () {
-				Title = "1234",
-				Width = Dim.Fill (),
-				Height = Dim.Fill (),
-				BorderStyle = LineStyle.Double,
-			};
-			win.Border.Thickness.Top = 3;
-
-			var rs = Application.Begin (win);
-			bool firstIteration = false;
-
-			((FakeDriver)Application.Driver).SetBufferSize (width, 4);
-			Application.RunIteration (ref rs, ref firstIteration);
-			var expected = string.Empty;
-
-			switch (width) {
-			case 1:
-				Assert.Equal (new Rect (0, 0, 1, 4), win.Frame);
-				expected = @"
+	[Theory, AutoInitShutdown]
+	[InlineData (0)]
+	[InlineData (1)]
+	[InlineData (2)]
+	[InlineData (3)]
+	[InlineData (4)]
+	[InlineData (5)]
+	[InlineData (6)]
+	[InlineData (7)]
+	[InlineData (8)]
+	[InlineData (9)]
+	[InlineData (10)]
+	public void Border_With_Title_Border_Double_Thickness_Top_Three_Size_Width (int width)
+	{
+		var win = new Window () {
+			Title = "1234",
+			Width = Dim.Fill (),
+			Height = Dim.Fill (),
+			BorderStyle = LineStyle.Double,
+		};
+		win.Border.Thickness.Top = 3;
+
+		var rs = Application.Begin (win);
+		bool firstIteration = false;
+
+		((FakeDriver)Application.Driver).SetBufferSize (width, 4);
+		Application.RunIteration (ref rs, ref firstIteration);
+		var expected = string.Empty;
+
+		switch (width) {
+		case 1:
+			Assert.Equal (new Rect (0, 0, 1, 4), win.Frame);
+			expected = @"
 ║";
-				break;
-			case 2:
-				Assert.Equal (new Rect (0, 0, 2, 4), win.Frame);
-				expected = @"
+			break;
+		case 2:
+			Assert.Equal (new Rect (0, 0, 2, 4), win.Frame);
+			expected = @"
 ╔╗
 ║║
 ╚╝";
-				break;
-			case 3:
-				Assert.Equal (new Rect (0, 0, 3, 4), win.Frame);
-				expected = @"
+			break;
+		case 3:
+			Assert.Equal (new Rect (0, 0, 3, 4), win.Frame);
+			expected = @"
 ╔═╗
 ║ ║
 ╚═╝";
-				break;
-			case 4:
-				Assert.Equal (new Rect (0, 0, 4, 4), win.Frame);
-				expected = @"
+			break;
+		case 4:
+			Assert.Equal (new Rect (0, 0, 4, 4), win.Frame);
+			expected = @"
  ╒╕ 
 ╔╡╞╗
 ║╘╛║
 ╚══╝";
-				break;
-			case 5:
-				Assert.Equal (new Rect (0, 0, 5, 4), win.Frame);
-				expected = @"
+			break;
+		case 5:
+			Assert.Equal (new Rect (0, 0, 5, 4), win.Frame);
+			expected = @"
  ╒═╕ 
 ╔╡1╞╗
 ║╘═╛║
 ╚═══╝";
-				break;
-			case 6:
-				Assert.Equal (new Rect (0, 0, 6, 4), win.Frame);
-				expected = @"
+			break;
+		case 6:
+			Assert.Equal (new Rect (0, 0, 6, 4), win.Frame);
+			expected = @"
  ╒══╕ 
 ╔╡12╞╗
 ║╘══╛║
 ╚════╝";
-				break;
-			case 7:
-				Assert.Equal (new Rect (0, 0, 7, 4), win.Frame);
-				expected = @"
+			break;
+		case 7:
+			Assert.Equal (new Rect (0, 0, 7, 4), win.Frame);
+			expected = @"
  ╒═══╕ 
 ╔╡123╞╗
 ║╘═══╛║
 ╚═════╝";
-				break;
-			case 8:
-				Assert.Equal (new Rect (0, 0, 8, 4), win.Frame);
-				expected = @"
+			break;
+		case 8:
+			Assert.Equal (new Rect (0, 0, 8, 4), win.Frame);
+			expected = @"
  ╒════╕ 
 ╔╡1234╞╗
 ║╘════╛║
 ╚══════╝";
-				break;
-			case 9:
-				Assert.Equal (new Rect (0, 0, 9, 4), win.Frame);
-				expected = @"
+			break;
+		case 9:
+			Assert.Equal (new Rect (0, 0, 9, 4), win.Frame);
+			expected = @"
  ╒════╕  
 ╔╡1234╞═╗
 ║╘════╛ ║
 ╚═══════╝";
-				break;
-			case 10:
-				Assert.Equal (new Rect (0, 0, 10, 4), win.Frame);
-				expected = @"
+			break;
+		case 10:
+			Assert.Equal (new Rect (0, 0, 10, 4), win.Frame);
+			expected = @"
  ╒════╕   
 ╔╡1234╞══╗
 ║╘════╛  ║
 ╚════════╝";
-				break;
-			}
-			_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
-			Application.End (rs);
+			break;
 		}
+		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+		Application.End (rs);
+	}
 
-		[Theory, AutoInitShutdown]
-		[InlineData (0)]
-		[InlineData (1)]
-		[InlineData (2)]
-		[InlineData (3)]
-		[InlineData (4)]
-		[InlineData (5)]
-		[InlineData (6)]
-		[InlineData (7)]
-		[InlineData (8)]
-		[InlineData (9)]
-		[InlineData (10)]
-		public void Border_With_Title_Border_Double_Thickness_Top_Four_Size_Width (int width)
-		{
-			var win = new Window () {
-				Title = "1234",
-				Width = Dim.Fill (),
-				Height = Dim.Fill (),
-				BorderStyle = LineStyle.Double,
-			};
-			win.Border.Thickness.Top = 4;
-
-			var rs = Application.Begin (win);
-			bool firstIteration = false;
-
-			((FakeDriver)Application.Driver).SetBufferSize (width, 5);
-			Application.RunIteration (ref rs, ref firstIteration);
-			var expected = string.Empty;
-
-			switch (width) {
-			case 1:
-				Assert.Equal (new Rect (0, 0, 1, 5), win.Frame);
-				expected = @"
+	[Theory, AutoInitShutdown]
+	[InlineData (0)]
+	[InlineData (1)]
+	[InlineData (2)]
+	[InlineData (3)]
+	[InlineData (4)]
+	[InlineData (5)]
+	[InlineData (6)]
+	[InlineData (7)]
+	[InlineData (8)]
+	[InlineData (9)]
+	[InlineData (10)]
+	public void Border_With_Title_Border_Double_Thickness_Top_Four_Size_Width (int width)
+	{
+		var win = new Window () {
+			Title = "1234",
+			Width = Dim.Fill (),
+			Height = Dim.Fill (),
+			BorderStyle = LineStyle.Double,
+		};
+		win.Border.Thickness.Top = 4;
+
+		var rs = Application.Begin (win);
+		bool firstIteration = false;
+
+		((FakeDriver)Application.Driver).SetBufferSize (width, 5);
+		Application.RunIteration (ref rs, ref firstIteration);
+		var expected = string.Empty;
+
+		switch (width) {
+		case 1:
+			Assert.Equal (new Rect (0, 0, 1, 5), win.Frame);
+			expected = @"
 ║";
-				break;
-			case 2:
-				Assert.Equal (new Rect (0, 0, 2, 5), win.Frame);
-				expected = @"
+			break;
+		case 2:
+			Assert.Equal (new Rect (0, 0, 2, 5), win.Frame);
+			expected = @"
 ╔╗
 ║║
 ╚╝";
-				break;
-			case 3:
-				Assert.Equal (new Rect (0, 0, 3, 5), win.Frame);
-				expected = @"
+			break;
+		case 3:
+			Assert.Equal (new Rect (0, 0, 3, 5), win.Frame);
+			expected = @"
 ╔═╗
 ║ ║
 ╚═╝";
-				break;
-			case 4:
-				Assert.Equal (new Rect (0, 0, 4, 5), win.Frame);
-				expected = @"
+			break;
+		case 4:
+			Assert.Equal (new Rect (0, 0, 4, 5), win.Frame);
+			expected = @"
  ╒╕ 
 ╔╡╞╗
 ║╘╛║
 ╚══╝";
-				break;
-			case 5:
-				Assert.Equal (new Rect (0, 0, 5, 5), win.Frame);
-				expected = @"
+			break;
+		case 5:
+			Assert.Equal (new Rect (0, 0, 5, 5), win.Frame);
+			expected = @"
  ╒═╕ 
 ╔╡1╞╗
 ║╘═╛║
 ╚═══╝";
-				break;
-			case 6:
-				Assert.Equal (new Rect (0, 0, 6, 5), win.Frame);
-				expected = @"
+			break;
+		case 6:
+			Assert.Equal (new Rect (0, 0, 6, 5), win.Frame);
+			expected = @"
  ╒══╕ 
 ╔╡12╞╗
 ║╘══╛║
 ╚════╝";
-				break;
-			case 7:
-				Assert.Equal (new Rect (0, 0, 7, 5), win.Frame);
-				expected = @"
+			break;
+		case 7:
+			Assert.Equal (new Rect (0, 0, 7, 5), win.Frame);
+			expected = @"
  ╒═══╕ 
 ╔╡123╞╗
 ║╘═══╛║
 ╚═════╝";
-				break;
-			case 8:
-				Assert.Equal (new Rect (0, 0, 8, 5), win.Frame);
-				expected = @"
+			break;
+		case 8:
+			Assert.Equal (new Rect (0, 0, 8, 5), win.Frame);
+			expected = @"
  ╒════╕ 
 ╔╡1234╞╗
 ║╘════╛║
 ╚══════╝";
-				break;
-			case 9:
-				Assert.Equal (new Rect (0, 0, 9, 5), win.Frame);
-				expected = @"
+			break;
+		case 9:
+			Assert.Equal (new Rect (0, 0, 9, 5), win.Frame);
+			expected = @"
  ╒════╕  
 ╔╡1234╞═╗
 ║╘════╛ ║
 ╚═══════╝";
-				break;
-			case 10:
-				Assert.Equal (new Rect (0, 0, 10, 5), win.Frame);
-				expected = @"
+			break;
+		case 10:
+			Assert.Equal (new Rect (0, 0, 10, 5), win.Frame);
+			expected = @"
  ╒════╕   
 ╔╡1234╞══╗
 ║╘════╛  ║
 ╚════════╝";
-				break;
-			}
-			_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
-			Application.End (rs);
+			break;
 		}
+		_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
+		Application.End (rs);
 	}
 }

+ 262 - 0
UnitTests/View/Layout/CoordinateTests.cs

@@ -0,0 +1,262 @@
+using System;
+using System.Text;
+using Xunit;
+using Xunit.Abstractions;
+
+// Alias Console to MockConsole so we don't accidentally use Console
+using Console = Terminal.Gui.FakeConsole;
+
+namespace Terminal.Gui.ViewTests;
+/// <summary>
+/// Tests for view coordinate mapping (e.g. <see cref="View.ScreenToFrame"/> etc...).
+/// </summary>
+public class CoordinateTests {
+	readonly ITestOutputHelper _output;
+
+	public CoordinateTests (ITestOutputHelper output)
+	{
+		this._output = output;
+	}
+
+	/// <summary>
+	/// Tests that screen to view mapping works correctly when the view has no superview and there are no Frames on the view.
+	/// </summary>
+	[Theory]
+	[InlineData (0, 0, 0, 0, 0, 0)]
+	[InlineData (0, 0, 1, 1, 1, 1)]
+	[InlineData (0, 0, 9, 9, 9, 9)]
+	[InlineData (0, 0, 11, 11, 11, 11)] // it's ok for the view to return coordinates outside of its bounds
+	[InlineData (1, 1, 0, 0, -1, -1)]
+	[InlineData (1, 1, 1, 1, 0, 0)]
+	[InlineData (1, 1, 9, 9, 8, 8)]
+	[InlineData (1, 1, 11, 11, 10, 10)] // it's ok for the view to return coordinates outside of its bounds
+	public void ScreenToView_NoSuper_NoFrames (int viewX, int viewY, int x, int y, int expectedX, int expectedY)
+	{
+		var view = new View () {
+			X = viewX,
+			Y = viewY,
+			Width = 10,
+			Height = 10
+		};
+
+		var actual = view.ScreenToFrame (x, y);
+		Assert.Equal (expectedX, actual.X);
+		Assert.Equal (expectedY, actual.Y);
+	}
+
+	/// <summary>
+	/// Tests that screen to view mapping works correctly when the view has no superview and there ARE Frames on the view.
+	/// </summary>
+	[Theory]
+	[InlineData (0, 0, 0, 0, 0, 0)]
+	[InlineData (0, 0, 1, 1, 1, 1)]
+	[InlineData (0, 0, 9, 9, 9, 9)]
+	[InlineData (0, 0, 11, 11, 11, 11)] // it's ok for the view to return coordinates outside of its bounds
+	[InlineData (1, 1, 0, 0, -1, -1)]
+	[InlineData (1, 1, 1, 1, 0, 0)]
+	[InlineData (1, 1, 9, 9, 8, 8)]
+	[InlineData (1, 1, 11, 11, 10, 10)] // it's ok for the view to return coordinates outside of its bounds
+	public void ScreenToView_NoSuper_HasFrames (int viewX, int viewY, int x, int y, int expectedX, int expectedY)
+	{
+		var view = new View () {
+			X = viewX,
+			Y = viewY,
+			Width = 10,
+			Height = 10,
+			BorderStyle = LineStyle.Single
+		};
+
+		var actual = view.ScreenToFrame (x, y);
+		Assert.Equal (expectedX, actual.X);
+		Assert.Equal (expectedY, actual.Y);
+	}
+
+	/// <summary>
+	/// Tests that screen to view mapping works correctly when the view has as superview it does not have Frames
+	/// </summary>
+	[Theory]
+	[InlineData (0, 0, 0, 0, 0, 0)]
+	[InlineData (0, 0, 1, 1, 1, 1)]
+	[InlineData (0, 0, 9, 9, 9, 9)]
+	[InlineData (0, 0, 11, 11, 11, 11)] // it's ok for the view to return coordinates outside of its bounds
+	[InlineData (1, 1, 0, 0, -1, -1)]
+	[InlineData (1, 1, 1, 1, 0, 0)]
+	[InlineData (1, 1, 9, 9, 8, 8)]
+	[InlineData (1, 1, 11, 11, 10, 10)] // it's ok for the view to return coordinates outside of its bounds
+	public void ScreenToView_SuperHasNoFrames (int viewX, int viewY, int x, int y, int expectedX, int expectedY)
+	{
+		var super = new View () {
+			X = 0,
+			Y = 0,
+			Width = 10,
+			Height = 10
+		};
+		var view = new View () {
+			X = viewX,
+			Y = viewY,
+			Width = 5,
+			Height = 5
+		};
+		super.Add (view);
+
+		var actual = view.ScreenToFrame (x, y);
+		Assert.Equal (expectedX, actual.X);
+		Assert.Equal (expectedY, actual.Y);
+	}
+
+	/// <summary>
+	/// Tests that screen to view mapping works correctly when the view has as superview it DOES have Frames
+	/// </summary>
+	[Theory]
+	[InlineData (0, 0, 0, 0, -1, -1)] // it's ok for the view to return coordinates outside of its bounds
+	[InlineData (0, 0, 1, 1, 0, 0)]
+	[InlineData (0, 0, 9, 9, 8, 8)]
+	[InlineData (0, 0, 11, 11, 10, 10)] // it's ok for the view to return coordinates outside of its bounds
+	[InlineData (1, 1, 0, 0, -2, -2)]
+	[InlineData (1, 1, 1, 1, -1, -1)]
+	[InlineData (1, 1, 9, 9, 7, 7)]
+	[InlineData (1, 1, 11, 11, 9, 9)] // it's ok for the view to return coordinates outside of its bounds
+	public void ScreenToView_SuperHasFrames (int viewX, int viewY, int x, int y, int expectedX, int expectedY)
+	{
+		var super = new View () {
+			X = 0,
+			Y = 0,
+			Width = 10,
+			Height = 10,
+			BorderStyle = LineStyle.Single
+		};
+		var view = new View () {
+			X = viewX,
+			Y = viewY,
+			Width = 5,
+			Height = 5
+		};
+		super.Add (view);
+
+		var actual = view.ScreenToFrame (x, y);
+		Assert.Equal (expectedX, actual.X);
+		Assert.Equal (expectedY, actual.Y);
+	}
+
+
+
+	/// <summary>
+	/// Tests that screen to bounds mapping works correctly when the view has no superview and there are no Frames on the view.
+	/// </summary>
+	[Theory]
+	[InlineData (0, 0, 0, 0, 0, 0)]
+	[InlineData (0, 0, 1, 1, 1, 1)]
+	[InlineData (0, 0, 9, 9, 9, 9)]
+	[InlineData (0, 0, 11, 11, 11, 11)] // it's ok for the view to return coordinates outside of its bounds
+	[InlineData (1, 1, 0, 0, -1, -1)]
+	[InlineData (1, 1, 1, 1, 0, 0)]
+	[InlineData (1, 1, 9, 9, 8, 8)]
+	[InlineData (1, 1, 11, 11, 10, 10)] // it's ok for the view to return coordinates outside of its bounds
+	public void ScreenToBounds_NoSuper_NoFrames (int viewX, int viewY, int x, int y, int expectedX, int expectedY)
+	{
+		var view = new View () {
+			X = viewX,
+			Y = viewY,
+			Width = 10,
+			Height = 10
+		};
+
+		var actual = view.ScreenToBounds (x, y);
+		Assert.Equal (expectedX, actual.X);
+		Assert.Equal (expectedY, actual.Y);
+	}
+
+	/// <summary>
+	/// Tests that screen to bounds mapping works correctly when the view has no superview and there ARE Frames on the view.
+	/// </summary>
+	[Theory]
+	[InlineData (0, 0, 0, 0, -1, -1)]
+	[InlineData (0, 0, 1, 1, 0, 0)]
+	[InlineData (0, 0, 9, 9, 8, 8)]
+	[InlineData (0, 0, 11, 11, 10, 10)] 
+	[InlineData (1, 1, 0, 0, -2, -2)]
+	[InlineData (1, 1, 1, 1, -1, -1)]
+	[InlineData (1, 1, 9, 9, 7, 7)]
+	[InlineData (1, 1, 11, 11, 9, 9)] 
+	public void ScreenToBounds_NoSuper_HasFrames (int viewX, int viewY, int x, int y, int expectedX, int expectedY)
+	{
+		var view = new View () {
+			X = viewX,
+			Y = viewY,
+			Width = 10,
+			Height = 10,
+			BorderStyle = LineStyle.Single
+		};
+
+		var actual = view.ScreenToBounds (x, y);
+		Assert.Equal (expectedX, actual.X);
+		Assert.Equal (expectedY, actual.Y);
+	}
+
+	/// <summary>
+	/// Tests that screen to bounds mapping works correctly when the view has as superview it does not have Frames
+	/// </summary>
+	[Theory]
+	[InlineData (0, 0, 0, 0, 0, 0)]
+	[InlineData (0, 0, 1, 1, 1, 1)]
+	[InlineData (0, 0, 9, 9, 9, 9)]
+	[InlineData (0, 0, 11, 11, 11, 11)] // it's ok for the view to return coordinates outside of its bounds
+	[InlineData (1, 1, 0, 0, -1, -1)]
+	[InlineData (1, 1, 1, 1, 0, 0)]
+	[InlineData (1, 1, 9, 9, 8, 8)]
+	[InlineData (1, 1, 11, 11, 10, 10)] // it's ok for the view to return coordinates outside of its bounds
+	public void ScreenToBounds_SuperHasNoFrames (int viewX, int viewY, int x, int y, int expectedX, int expectedY)
+	{
+		var super = new View () {
+			X = 0,
+			Y = 0,
+			Width = 10,
+			Height = 10
+		};
+		var view = new View () {
+			X = viewX,
+			Y = viewY,
+			Width = 5,
+			Height = 5
+		};
+		super.Add (view);
+
+		var actual = view.ScreenToBounds (x, y);
+		Assert.Equal (expectedX, actual.X);
+		Assert.Equal (expectedY, actual.Y);
+	}
+
+	/// <summary>
+	/// Tests that screen to bounds mapping works correctly when the view has as superview it DOES have Frames
+	/// </summary>
+	[Theory]
+	[InlineData (0, 0, 0, 0, -1, -1)] // it's ok for the view to return coordinates outside of its bounds
+	[InlineData (0, 0, 1, 1, 0, 0)]
+	[InlineData (0, 0, 9, 9, 8, 8)]
+	[InlineData (0, 0, 11, 11, 10, 10)] // it's ok for the view to return coordinates outside of its bounds
+	[InlineData (1, 1, 0, 0, -2, -2)]
+	[InlineData (1, 1, 1, 1, -1, -1)]
+	[InlineData (1, 1, 9, 9, 7, 7)]
+	[InlineData (1, 1, 11, 11, 9, 9)] // it's ok for the view to return coordinates outside of its bounds
+	public void ScreenToBounds_SuperHasFrames (int viewX, int viewY, int x, int y, int expectedX, int expectedY)
+	{
+		var super = new View () {
+			X = 0,
+			Y = 0,
+			Width = 10,
+			Height = 10,
+			BorderStyle = LineStyle.Single
+		};
+		var view = new View () {
+			X = viewX,
+			Y = viewY,
+			Width = 5,
+			Height = 5
+		};
+		super.Add (view);
+
+		var actual = view.ScreenToFrame (x, y);
+		Assert.Equal (expectedX, actual.X);
+		Assert.Equal (expectedY, actual.Y);
+	}
+}

+ 52 - 52
UnitTests/View/NavigationTests.cs

@@ -1175,27 +1175,27 @@ namespace Terminal.Gui.ViewTests {
 └──────────────────┘", output);
 
 			// top
-			Assert.Equal (Point.Empty, top.ScreenToView (0, 0));
-			top.Margin.ViewToScreen (0, 0, out int col, out int row);
+			Assert.Equal (Point.Empty, top.ScreenToFrame (0, 0));
+			top.Margin.BoundsToScreen (0, 0, out int col, out int row);
 			Assert.Equal (0, col);
 			Assert.Equal (0, row);
-			top.Border.ViewToScreen (0, 0, out col, out row);
+			top.Border.BoundsToScreen (0, 0, out col, out row);
 			Assert.Equal (0, col);
 			Assert.Equal (0, row);
-			top.Padding.ViewToScreen (0, 0, out col, out row);
+			top.Padding.BoundsToScreen (0, 0, out col, out row);
 			Assert.Equal (0, col);
 			Assert.Equal (0, row);
-			top.ViewToScreen (0, 0, out col, out row);
+			top.BoundsToScreen (0, 0, out col, out row);
 			Assert.Equal (1, col);
 			Assert.Equal (1, row);
-			top.ViewToScreen (-1, -1, out col, out row);
+			top.BoundsToScreen (-1, -1, out col, out row);
 			Assert.Equal (0, col);
 			Assert.Equal (0, row);
 			Assert.Equal (top, View.FindDeepestView (top, 0, 0, out int rx, out int ry));
 			Assert.Equal (0, rx);
 			Assert.Equal (0, ry);
-			Assert.Equal (new Point (3, 2), top.ScreenToView (3, 2));
-			top.ViewToScreen (3, 2, out col, out row);
+			Assert.Equal (new Point (3, 2), top.ScreenToFrame (3, 2));
+			top.BoundsToScreen (3, 2, out col, out row);
 			Assert.Equal (4, col);
 			Assert.Equal (3, row);
 			Assert.Equal (view, View.FindDeepestView (top, col, row, out rx, out ry));
@@ -1204,62 +1204,62 @@ namespace Terminal.Gui.ViewTests {
 			Assert.Equal (top, View.FindDeepestView (top, 3, 2, out rx, out ry));
 			Assert.Equal (3, rx);
 			Assert.Equal (2, ry);
-			Assert.Equal (new Point (13, 2), top.ScreenToView (13, 2));
-			top.ViewToScreen (12, 2, out col, out row);
+			Assert.Equal (new Point (13, 2), top.ScreenToFrame (13, 2));
+			top.BoundsToScreen (12, 2, out col, out row);
 			Assert.Equal (13, col);
 			Assert.Equal (3, row);
 			Assert.Equal (view, View.FindDeepestView (top, col, row, out rx, out ry));
 			Assert.Equal (9, rx);
 			Assert.Equal (0, ry);
-			top.ViewToScreen (13, 2, out col, out row);
+			top.BoundsToScreen (13, 2, out col, out row);
 			Assert.Equal (14, col);
 			Assert.Equal (3, row);
 			Assert.Equal (top, View.FindDeepestView (top, 13, 2, out rx, out ry));
 			Assert.Equal (13, rx);
 			Assert.Equal (2, ry);
-			Assert.Equal (new Point (14, 3), top.ScreenToView (14, 3));
-			top.ViewToScreen (14, 3, out col, out row);
+			Assert.Equal (new Point (14, 3), top.ScreenToFrame (14, 3));
+			top.BoundsToScreen (14, 3, out col, out row);
 			Assert.Equal (15, col);
 			Assert.Equal (4, row);
 			Assert.Equal (top, View.FindDeepestView (top, 14, 3, out rx, out ry));
 			Assert.Equal (14, rx);
 			Assert.Equal (3, ry);
 			// view
-			Assert.Equal (new Point (-4, -3), view.ScreenToView (0, 0));
-			view.Margin.ViewToScreen (-3, -2, out col, out row);
+			Assert.Equal (new Point (-4, -3), view.ScreenToFrame (0, 0));
+			view.Margin.BoundsToScreen (-3, -2, out col, out row);
 			Assert.Equal (1, col);
 			Assert.Equal (1, row);
-			view.Border.ViewToScreen (-3, -2, out col, out row);
+			view.Border.BoundsToScreen (-3, -2, out col, out row);
 			Assert.Equal (1, col);
 			Assert.Equal (1, row);
-			view.Padding.ViewToScreen (-3, -2, out col, out row);
+			view.Padding.BoundsToScreen (-3, -2, out col, out row);
 			Assert.Equal (1, col);
 			Assert.Equal (1, row);
-			view.ViewToScreen (-3, -2, out col, out row);
+			view.BoundsToScreen (-3, -2, out col, out row);
 			Assert.Equal (1, col);
 			Assert.Equal (1, row);
-			view.ViewToScreen (-4, -3, out col, out row);
+			view.BoundsToScreen (-4, -3, out col, out row);
 			Assert.Equal (0, col);
 			Assert.Equal (0, row);
 			Assert.Equal (top, View.FindDeepestView (top, 0, 0, out rx, out ry));
 			Assert.Equal (0, rx);
 			Assert.Equal (0, ry);
-			Assert.Equal (new Point (-1, -1), view.ScreenToView (3, 2));
-			view.ViewToScreen (0, 0, out col, out row);
+			Assert.Equal (new Point (-1, -1), view.ScreenToFrame (3, 2));
+			view.BoundsToScreen (0, 0, out col, out row);
 			Assert.Equal (4, col);
 			Assert.Equal (3, row);
 			Assert.Equal (view, View.FindDeepestView (top, 4, 3, out rx, out ry));
 			Assert.Equal (0, rx);
 			Assert.Equal (0, ry);
-			Assert.Equal (new Point (9, -1), view.ScreenToView (13, 2));
-			view.ViewToScreen (10, 0, out col, out row);
+			Assert.Equal (new Point (9, -1), view.ScreenToFrame (13, 2));
+			view.BoundsToScreen (10, 0, out col, out row);
 			Assert.Equal (14, col);
 			Assert.Equal (3, row);
 			Assert.Equal (top, View.FindDeepestView (top, 14, 3, out rx, out ry));
 			Assert.Equal (14, rx);
 			Assert.Equal (3, ry);
-			Assert.Equal (new Point (10, 0), view.ScreenToView (14, 3));
-			view.ViewToScreen (11, 1, out col, out row);
+			Assert.Equal (new Point (10, 0), view.ScreenToFrame (14, 3));
+			view.BoundsToScreen (11, 1, out col, out row);
 			Assert.Equal (15, col);
 			Assert.Equal (4, row);
 			Assert.Equal (top, View.FindDeepestView (top, 15, 4, out rx, out ry));
@@ -1301,93 +1301,93 @@ namespace Terminal.Gui.ViewTests {
 			Assert.Equal (new Rect (3, 2, 23, 10), frame);
 
 			// top
-			Assert.Equal (new Point (-3, -2), top.ScreenToView (0, 0));
-			top.Margin.ViewToScreen (-3, -2, out int col, out int row);
+			Assert.Equal (new Point (-3, -2), top.ScreenToFrame (0, 0));
+			top.Margin.BoundsToScreen (-3, -2, out int col, out int row);
 			Assert.Equal (0, col);
 			Assert.Equal (0, row);
-			top.Border.ViewToScreen (-3, -2, out col, out row);
+			top.Border.BoundsToScreen (-3, -2, out col, out row);
 			Assert.Equal (0, col);
 			Assert.Equal (0, row);
-			top.Padding.ViewToScreen (-3, -2, out col, out row);
+			top.Padding.BoundsToScreen (-3, -2, out col, out row);
 			Assert.Equal (0, col);
 			Assert.Equal (0, row);
-			top.ViewToScreen (-3, -2, out col, out row);
+			top.BoundsToScreen (-3, -2, out col, out row);
 			Assert.Equal (1, col);
 			Assert.Equal (1, row);
-			top.ViewToScreen (-4, -3, out col, out row);
+			top.BoundsToScreen (-4, -3, out col, out row);
 			Assert.Equal (0, col);
 			Assert.Equal (0, row);
 			Assert.Null (View.FindDeepestView (top, -4, -3, out int rx, out int ry));
 			Assert.Equal (0, rx);
 			Assert.Equal (0, ry);
-			Assert.Equal (Point.Empty, top.ScreenToView (3, 2));
-			top.ViewToScreen (0, 0, out col, out row);
+			Assert.Equal (Point.Empty, top.ScreenToFrame (3, 2));
+			top.BoundsToScreen (0, 0, out col, out row);
 			Assert.Equal (4, col);
 			Assert.Equal (3, row);
 			Assert.Equal (top, View.FindDeepestView (top, 3, 2, out rx, out ry));
 			Assert.Equal (0, rx);
 			Assert.Equal (0, ry);
-			Assert.Equal (new Point (10, 0), top.ScreenToView (13, 2));
-			top.ViewToScreen (10, 0, out col, out row);
+			Assert.Equal (new Point (10, 0), top.ScreenToFrame (13, 2));
+			top.BoundsToScreen (10, 0, out col, out row);
 			Assert.Equal (14, col);
 			Assert.Equal (3, row);
 			Assert.Equal (top, View.FindDeepestView (top, 13, 2, out rx, out ry));
 			Assert.Equal (10, rx);
 			Assert.Equal (0, ry);
-			Assert.Equal (new Point (11, 1), top.ScreenToView (14, 3));
-			top.ViewToScreen (11, 1, out col, out row);
+			Assert.Equal (new Point (11, 1), top.ScreenToFrame (14, 3));
+			top.BoundsToScreen (11, 1, out col, out row);
 			Assert.Equal (15, col);
 			Assert.Equal (4, row);
 			Assert.Equal (top, View.FindDeepestView (top, 14, 3, out rx, out ry));
 			Assert.Equal (11, rx);
 			Assert.Equal (1, ry);
 			// view
-			Assert.Equal (new Point (-7, -5), view.ScreenToView (0, 0));
-			view.Margin.ViewToScreen (-6, -4, out col, out row);
+			Assert.Equal (new Point (-7, -5), view.ScreenToFrame (0, 0));
+			view.Margin.BoundsToScreen (-6, -4, out col, out row);
 			Assert.Equal (1, col);
 			Assert.Equal (1, row);
-			view.Border.ViewToScreen (-6, -4, out col, out row);
+			view.Border.BoundsToScreen (-6, -4, out col, out row);
 			Assert.Equal (1, col);
 			Assert.Equal (1, row);
-			view.Padding.ViewToScreen (-6, -4, out col, out row);
+			view.Padding.BoundsToScreen (-6, -4, out col, out row);
 			Assert.Equal (1, col);
 			Assert.Equal (1, row);
-			view.ViewToScreen (-6, -4, out col, out row);
+			view.BoundsToScreen (-6, -4, out col, out row);
 			Assert.Equal (1, col);
 			Assert.Equal (1, row);
 			Assert.Null (View.FindDeepestView (top, 1, 1, out rx, out ry));
 			Assert.Equal (0, rx);
 			Assert.Equal (0, ry);
-			Assert.Equal (new Point (-4, -3), view.ScreenToView (3, 2));
-			view.ViewToScreen (-3, -2, out col, out row);
+			Assert.Equal (new Point (-4, -3), view.ScreenToFrame (3, 2));
+			view.BoundsToScreen (-3, -2, out col, out row);
 			Assert.Equal (4, col);
 			Assert.Equal (3, row);
 			Assert.Equal (top, View.FindDeepestView (top, 4, 3, out rx, out ry));
 			Assert.Equal (1, rx);
 			Assert.Equal (1, ry);
-			Assert.Equal (new Point (-1, -1), view.ScreenToView (6, 4));
-			view.ViewToScreen (0, 0, out col, out row);
+			Assert.Equal (new Point (-1, -1), view.ScreenToFrame (6, 4));
+			view.BoundsToScreen (0, 0, out col, out row);
 			Assert.Equal (7, col);
 			Assert.Equal (5, row);
 			Assert.Equal (view, View.FindDeepestView (top, 7, 5, out rx, out ry));
 			Assert.Equal (0, rx);
 			Assert.Equal (0, ry);
-			Assert.Equal (new Point (6, -1), view.ScreenToView (13, 4));
-			view.ViewToScreen (7, 0, out col, out row);
+			Assert.Equal (new Point (6, -1), view.ScreenToFrame (13, 4));
+			view.BoundsToScreen (7, 0, out col, out row);
 			Assert.Equal (14, col);
 			Assert.Equal (5, row);
 			Assert.Equal (view, View.FindDeepestView (top, 14, 5, out rx, out ry));
 			Assert.Equal (7, rx);
 			Assert.Equal (0, ry);
-			Assert.Equal (new Point (7, -2), view.ScreenToView (14, 3));
-			view.ViewToScreen (8, -1, out col, out row);
+			Assert.Equal (new Point (7, -2), view.ScreenToFrame (14, 3));
+			view.BoundsToScreen (8, -1, out col, out row);
 			Assert.Equal (15, col);
 			Assert.Equal (4, row);
 			Assert.Equal (top, View.FindDeepestView (top, 15, 4, out rx, out ry));
 			Assert.Equal (12, rx);
 			Assert.Equal (2, ry);
-			Assert.Equal (new Point (16, -2), view.ScreenToView (23, 3));
-			view.ViewToScreen (17, -1, out col, out row);
+			Assert.Equal (new Point (16, -2), view.ScreenToFrame (23, 3));
+			view.BoundsToScreen (17, -1, out col, out row);
 			Assert.Equal (24, col);
 			Assert.Equal (4, row);
 			Assert.Null (View.FindDeepestView (top, 24, 4, out rx, out ry));

+ 3 - 3
UnitTests/View/ViewTests.cs

@@ -498,10 +498,10 @@ namespace Terminal.Gui.ViewTests {
 			Assert.False (view._addingView);
 			view._addingView = true;
 			Assert.True (view._addingView);
-			view.ViewToScreen (0, 0, out int rcol, out int rrow);
+			view.BoundsToScreen (0, 0, out int rcol, out int rrow);
 			Assert.Equal (1, rcol);
 			Assert.Equal (1, rrow);
-			Assert.Equal (rect, view.ViewToScreen (view.Bounds));
+			Assert.Equal (rect, view.BoundsToScreen (view.Bounds));
 			Assert.Equal (top.Bounds, view.ScreenClip (top.Bounds));
 			Assert.True (view.LayoutStyle == LayoutStyle.Absolute);
 
@@ -546,7 +546,7 @@ namespace Terminal.Gui.ViewTests {
 			view.Y = Pos.Center () - 13;
 			view.SetRelativeLayout (top.Bounds);
 			top.LayoutSubviews (); // BUGBUG: v2 - ??
-			view.ViewToScreen (0, 0, out rcol, out rrow);
+			view.BoundsToScreen (0, 0, out rcol, out rrow);
 			Assert.Equal (-41, rcol);
 			Assert.Equal (-13, rrow);
 			

+ 65 - 64
UnitTests/Views/ListViewTests.cs

@@ -542,69 +542,70 @@ Item 6", output);
 			Assert.Null (exception);
 		}
 
-		[Fact, AutoInitShutdown]
-		public void Clicking_On_Border_Is_Ignored ()
-		{
-			var selected = "";
-			var lv = new ListView {
-				Height = 5,
-				Width = 7,
-				BorderStyle = LineStyle.Single
-			};
-			lv.SetSource (new List<string> { "One", "Two", "Three", "Four" });
-			lv.SelectedItemChanged += (s, e) => selected = e.Value.ToString ();
-			Application.Top.Add (lv);
-			Application.Begin (Application.Top);
-
-			Assert.Equal (new Thickness (1), lv.Border.Thickness);
-			Assert.Equal (-1, lv.SelectedItem);
-			Assert.Equal ("", lv.Text);
-			TestHelpers.AssertDriverContentsWithFrameAre (@"
-┌─────┐
-│One  │
-│Two  │
-│Three│
-└─────┘", output);
-
-			Assert.True (lv.MouseEvent (new MouseEvent {
-				X = 0,
-				Y = 0,
-				Flags = MouseFlags.Button1Clicked
-			}));
-			Assert.Equal ("", selected);
-			Assert.Equal (-1, lv.SelectedItem);
-
-			Assert.True (lv.MouseEvent (new MouseEvent {
-				X = 0,
-				Y = 1,
-				Flags = MouseFlags.Button1Clicked
-			}));
-			Assert.Equal ("One", selected);
-			Assert.Equal (0, lv.SelectedItem);
-
-			Assert.True (lv.MouseEvent (new MouseEvent {
-				X = 0,
-				Y = 2,
-				Flags = MouseFlags.Button1Clicked
-			}));
-			Assert.Equal ("Two", selected);
-			Assert.Equal (1, lv.SelectedItem);
-
-			Assert.True (lv.MouseEvent (new MouseEvent {
-				X = 0,
-				Y = 3,
-				Flags = MouseFlags.Button1Clicked
-			}));
-			Assert.Equal ("Three", selected);
-			Assert.Equal (2, lv.SelectedItem);
-
-			Assert.True (lv.MouseEvent (new MouseEvent {
-				X = 0,
-				Y = 4,
-				Flags = MouseFlags.Button1Clicked
-			}));
-			Assert.Equal ("Three", selected);
-			Assert.Equal (2, lv.SelectedItem);
-		}
+// No longer needed given PR #2920
+//		[Fact, AutoInitShutdown]
+//		public void Clicking_On_Border_Is_Ignored ()
+//		{
+//			var selected = "";
+//			var lv = new ListView {
+//				Height = 5,
+//				Width = 7,
+//				BorderStyle = LineStyle.Single
+//			};
+//			lv.SetSource (new List<string> { "One", "Two", "Three", "Four" });
+//			lv.SelectedItemChanged += (s, e) => selected = e.Value.ToString ();
+//			Application.Top.Add (lv);
+//			Application.Begin (Application.Top);
+
+//			Assert.Equal (new Thickness (1), lv.Border.Thickness);
+//			Assert.Equal (-1, lv.SelectedItem);
+//			Assert.Equal ("", lv.Text);
+//			TestHelpers.AssertDriverContentsWithFrameAre (@"
+//┌─────┐
+//│One  │
+//│Two  │
+//│Three│
+//└─────┘", output);
+
+//			Assert.True (lv.MouseEvent (new MouseEvent {
+//				X = 0,
+//				Y = 0,
+//				Flags = MouseFlags.Button1Clicked
+//			}));
+//			Assert.Equal ("", selected);
+//			Assert.Equal (-1, lv.SelectedItem);
+
+//			Assert.True (lv.MouseEvent (new MouseEvent {
+//				X = 0,
+//				Y = 1,
+//				Flags = MouseFlags.Button1Clicked
+//			}));
+//			Assert.Equal ("One", selected);
+//			Assert.Equal (0, lv.SelectedItem);
+
+//			Assert.True (lv.MouseEvent (new MouseEvent {
+//				X = 0,
+//				Y = 2,
+//				Flags = MouseFlags.Button1Clicked
+//			}));
+//			Assert.Equal ("Two", selected);
+//			Assert.Equal (1, lv.SelectedItem);
+
+//			Assert.True (lv.MouseEvent (new MouseEvent {
+//				X = 0,
+//				Y = 3,
+//				Flags = MouseFlags.Button1Clicked
+//			}));
+//			Assert.Equal ("Three", selected);
+//			Assert.Equal (2, lv.SelectedItem);
+
+//			Assert.True (lv.MouseEvent (new MouseEvent {
+//				X = 0,
+//				Y = 4,
+//				Flags = MouseFlags.Button1Clicked
+//			}));
+//			Assert.Equal ("Three", selected);
+//			Assert.Equal (2, lv.SelectedItem);
+//		}
 	}
 }

+ 1 - 1
UnitTests/Views/ToplevelTests.cs

@@ -1432,7 +1432,7 @@ namespace Terminal.Gui.ViewsTests {
 
 			var btnPopup = new Button ("Popup");
 			btnPopup.Clicked += (s, e) => {
-				var viewToScreen = btnPopup.ViewToScreen (top.Frame);
+				var viewToScreen = btnPopup.BoundsToScreen (top.Frame);
 				var view = new View () {
 					X = 1,
 					Y = viewToScreen.Y + 1,