فهرست منبع

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 سال پیش
والد
کامیت
42b9ad1d61
35فایلهای تغییر یافته به همراه2299 افزوده شده و 1418 حذف شده
  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;
 			NotifyNewRunState = null;
 			NotifyStopRunState = null;
 			NotifyStopRunState = null;
 			_initialized = false;
 			_initialized = false;
-			_mouseGrabView = null;
-			_lastMouseOwnerView = null;
+			MouseGrabView = null;
+			_mouseEnteredView = null;
 
 
 			// Reset synchronization context to allow the user to run async/await,
 			// Reset synchronization context to allow the user to run async/await,
 			// as the main loop has been ended, the synchronization context from 
 			// as the main loop has been ended, the synchronization context from 
@@ -304,7 +304,7 @@ namespace Terminal.Gui {
 			}
 			}
 
 
 			// Ensure the mouse is ungrabed.
 			// Ensure the mouse is ungrabed.
-			_mouseGrabView = null;
+			MouseGrabView = null;
 
 
 			var rs = new RunState (Toplevel);
 			var rs = new RunState (Toplevel);
 
 
@@ -656,7 +656,7 @@ namespace Terminal.Gui {
 				}
 				}
 
 
 				MainLoop.RunIteration ();
 				MainLoop.RunIteration ();
-				Iteration?.Invoke (null, new IterationEventArgs());
+				Iteration?.Invoke (null, new IterationEventArgs ());
 
 
 				EnsureModalOrVisibleAlwaysOnTop (state.Toplevel);
 				EnsureModalOrVisibleAlwaysOnTop (state.Toplevel);
 				if (state.Toplevel != Current) {
 				if (state.Toplevel != Current) {
@@ -1018,12 +1018,11 @@ namespace Terminal.Gui {
 		/// </summary>
 		/// </summary>
 		public static View WantContinuousButtonPressedView { get; private set; }
 		public static View WantContinuousButtonPressedView { get; private set; }
 
 
-		static View _mouseGrabView;
-
 		/// <summary>
 		/// <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>
 		/// </summary>
-		public static View MouseGrabView => _mouseGrabView;
+		public static View MouseGrabView { get; private set; }
 
 
 		/// <summary>
 		/// <summary>
 		/// Invoked when a view wants to grab the mouse; can be canceled.
 		/// 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;
 		public static event EventHandler<GrabMouseEventArgs> GrabbingMouse;
 
 
 		/// <summary>
 		/// <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>
 		/// </summary>
 		public static event EventHandler<GrabMouseEventArgs> UnGrabbingMouse;
 		public static event EventHandler<GrabMouseEventArgs> UnGrabbingMouse;
 
 
@@ -1041,7 +1040,7 @@ namespace Terminal.Gui {
 		public static event EventHandler<ViewEventArgs> GrabbedMouse;
 		public static event EventHandler<ViewEventArgs> GrabbedMouse;
 
 
 		/// <summary>
 		/// <summary>
-		/// Invoked after a view has ungrabbed the mouse.
+		/// Invoked after a view has un-grabbed the mouse.
 		/// </summary>
 		/// </summary>
 		public static event EventHandler<ViewEventArgs> UnGrabbedMouse;
 		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>
 		/// <param name="view">View that will receive all mouse events until <see cref="UngrabMouse"/> is invoked.</param>
 		public static void GrabMouse (View view)
 		public static void GrabMouse (View view)
 		{
 		{
-			if (view == null)
+			if (view == null) {
 				return;
 				return;
+			}
 			if (!OnGrabbingMouse (view)) {
 			if (!OnGrabbingMouse (view)) {
 				OnGrabbedMouse (view);
 				OnGrabbedMouse (view);
-				_mouseGrabView = view;
-				//Driver.UncookMouse ();
+				MouseGrabView = view;
 			}
 			}
 		}
 		}
 
 
@@ -1065,19 +1064,20 @@ namespace Terminal.Gui {
 		/// </summary>
 		/// </summary>
 		public static void UngrabMouse ()
 		public static void UngrabMouse ()
 		{
 		{
-			if (_mouseGrabView == null)
+			if (MouseGrabView == null) {
 				return;
 				return;
-			if (!OnUnGrabbingMouse (_mouseGrabView)) {
-				OnUnGrabbedMouse (_mouseGrabView);
-				_mouseGrabView = null;
-				//Driver.CookMouse ();
+			}
+			if (!OnUnGrabbingMouse (MouseGrabView)) {
+				OnUnGrabbedMouse (MouseGrabView);
+				MouseGrabView = null;
 			}
 			}
 		}
 		}
 
 
 		static bool OnGrabbingMouse (View view)
 		static bool OnGrabbingMouse (View view)
 		{
 		{
-			if (view == null)
+			if (view == null) {
 				return false;
 				return false;
+			}
 			var evArgs = new GrabMouseEventArgs (view);
 			var evArgs = new GrabMouseEventArgs (view);
 			GrabbingMouse?.Invoke (view, evArgs);
 			GrabbingMouse?.Invoke (view, evArgs);
 			return evArgs.Cancel;
 			return evArgs.Cancel;
@@ -1085,8 +1085,9 @@ namespace Terminal.Gui {
 
 
 		static bool OnUnGrabbingMouse (View view)
 		static bool OnUnGrabbingMouse (View view)
 		{
 		{
-			if (view == null)
+			if (view == null) {
 				return false;
 				return false;
+			}
 			var evArgs = new GrabMouseEventArgs (view);
 			var evArgs = new GrabMouseEventArgs (view);
 			UnGrabbingMouse?.Invoke (view, evArgs);
 			UnGrabbingMouse?.Invoke (view, evArgs);
 			return evArgs.Cancel;
 			return evArgs.Cancel;
@@ -1094,19 +1095,22 @@ namespace Terminal.Gui {
 
 
 		static void OnGrabbedMouse (View view)
 		static void OnGrabbedMouse (View view)
 		{
 		{
-			if (view == null)
+			if (view == null) {
 				return;
 				return;
+			}
 			GrabbedMouse?.Invoke (view, new ViewEventArgs (view));
 			GrabbedMouse?.Invoke (view, new ViewEventArgs (view));
 		}
 		}
 
 
 		static void OnUnGrabbedMouse (View view)
 		static void OnUnGrabbedMouse (View view)
 		{
 		{
-			if (view == null)
+			if (view == null) {
 				return;
 				return;
+			}
 			UnGrabbedMouse?.Invoke (view, new ViewEventArgs (view));
 			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>
 		/// <summary>
 		/// Event fired when a mouse move or click occurs. Coordinates are screen relative.
 		/// Event fired when a mouse move or click occurs. Coordinates are screen relative.
@@ -1128,16 +1132,16 @@ namespace Terminal.Gui {
 		/// <remarks>
 		/// <remarks>
 		/// This method can be used to simulate a mouse event, e.g. in unit tests.
 		/// This method can be used to simulate a mouse event, e.g. in unit tests.
 		/// </remarks>
 		/// </remarks>
-		/// <param name="a"></param>
+		/// <param name="a">The mouse event with coordinates relative to the screen.</param>
 		public static void OnMouseEvent (MouseEventEventArgs a)
 		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) {
 			if (IsMouseDisabled) {
 				return;
 				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) {
 			if (view != null && view.WantContinuousButtonPressed) {
 				WantContinuousButtonPressedView = view;
 				WantContinuousButtonPressedView = view;
@@ -1153,8 +1157,10 @@ namespace Terminal.Gui {
 				return;
 				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 () {
 				var nme = new MouseEvent () {
 					X = newxy.X,
 					X = newxy.X,
 					Y = newxy.Y,
 					Y = newxy.Y,
@@ -1163,57 +1169,134 @@ namespace Terminal.Gui {
 					OfY = a.MouseEvent.Y - newxy.Y,
 					OfY = a.MouseEvent.Y - newxy.Y,
 					View = view
 					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}");
 				//System.Diagnostics.Debug.WriteLine ($"{nme.Flags};{nme.X};{nme.Y};{mouseGrabView}");
-				if (_mouseGrabView?.OnMouseEvent (nme) == true) {
+				if (MouseGrabView?.OnMouseEvent (nme) == true) {
 					return;
 					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 _);
 				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) {
 				if (view != null && view != OverlappedTop && top != Current) {
 					MoveCurrent ((Toplevel)top);
 					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) {
 			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;
 					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
 		#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>
 		/// <summary>
 		/// Returns a rectangle describing the location and size of the inside area of <paramref name="rect"/>
 		/// 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
 		/// 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>
 	/// <summary>
 	/// Low-level construct that conveys the details of mouse events, such
 	/// 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.
 	/// Views.
 	/// </summary>
 	/// </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 {
 	public class MouseEvent {
 		/// <summary>
 		/// <summary>
-		/// The X (column) location for the mouse event.
+		/// The X (column) location for the mouse event relative to <see cref="View.Bounds"/>.
 		/// </summary>
 		/// </summary>
 		public int X { get; set; }
 		public int X { get; set; }
 
 
 		/// <summary>
 		/// <summary>
-		/// The Y (column) location for the mouse event.
+		/// The Y (column) location for the mouse event relative to <see cref="View.Bounds"/>.
 		/// </summary>
 		/// </summary>
 		public int Y { get; set; }
 		public int Y { get; set; }
 
 
 		/// <summary>
 		/// <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>
 		/// </summary>
 		public MouseFlags Flags { get; set; }
 		public MouseFlags Flags { get; set; }
 
 
 		/// <summary>
 		/// <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>
 		/// </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; }
 		public int OfX { get; set; }
 
 
 		/// <summary>
 		/// <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>
 		/// </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; }
 		public int OfY { get; set; }
 
 
 		/// <summary>
 		/// <summary>
-		/// The current view at the location for the mouse event.
+		/// Gets or sets the view that should process the mouse event.
 		/// </summary>
 		/// </summary>
 		public View View { get; set; }
 		public View View { get; set; }
 
 
 		/// <summary>
 		/// <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>
 		/// </summary>
 		public bool Handled { get; set; }
 		public bool Handled { get; set; }
 
 

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

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

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

@@ -183,7 +183,9 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		/// <summary>
 		/// <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>
 		/// </summary>
 		/// <param name="mouseEvent"></param>
 		/// <param name="mouseEvent"></param>
 		/// <returns><c>true</c>, if the event was handled, <c>false</c> otherwise.</returns>
 		/// <returns><c>true</c>, if the event was handled, <c>false</c> otherwise.</returns>
@@ -193,7 +195,8 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		/// <summary>
 		/// <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>
 		/// </summary>
 		/// <param name="mouseEvent"></param>
 		/// <param name="mouseEvent"></param>
 		/// <returns><c>true</c>, if the event was handled, <c>false</c> otherwise.</returns>
 		/// <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 {
 	public partial class View {
 
 
-		// The frame for the object. Superview relative.
+		// The frame for the object. Relative to the SuperView's Bounds.
 		Rect _frame;
 		Rect _frame;
 
 
 		/// <summary>
 		/// <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>
 		/// </summary>
 		/// <value>The frame.</value>
 		/// <value>The frame.</value>
 		/// <remarks>
 		/// <remarks>
@@ -58,19 +58,41 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		/// <summary>
 		/// <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>
 		/// </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; }
 		public Frame Margin { get; private set; }
 
 
 		/// <summary>
 		/// <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 
 		///  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. 
 		///  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>
 		/// </summary>
 		/// <remarks>
 		/// <remarks>
+		/// <para>
 		/// <see cref="BorderStyle"/> provides a simple helper for turning a simple border frame on or off.
 		/// <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>
 		/// </remarks>
 		public Frame Border { get; private set; }
 		public Frame Border { get; private set; }
 
 
@@ -111,11 +133,18 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		/// <summary>
 		/// <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>
 		/// </summary>
 		/// <remarks>
 		/// <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>
 		/// </remarks>
 		public Frame Padding { get; private set; }
 		public Frame Padding { get; private set; }
 
 
@@ -181,9 +210,9 @@ namespace Terminal.Gui {
 		LayoutStyle _layoutStyle;
 		LayoutStyle _layoutStyle;
 
 
 		/// <summary>
 		/// <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="Frame"/> is updated using
 		/// the <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties.
 		/// the <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties.
 		/// </summary>
 		/// </summary>
@@ -197,16 +226,27 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		/// <summary>
 		/// <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>
 		/// </summary>
-		/// <value>The bounds.</value>
+		/// <value>The view's content area.</value>
 		/// <remarks>
 		/// <remarks>
 		/// <para>
 		/// <para>
 		/// The <see cref="Rect.Location"/> of Bounds is always (0, 0). To obtain the offset of the Bounds from the Frame use 
 		/// 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"/>.
 		/// <see cref="GetBoundsOffset"/>.
 		/// </para>
 		/// </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>
 		/// </remarks>
 		public virtual Rect Bounds {
 		public virtual Rect Bounds {
 			get {
 			get {
@@ -242,7 +282,7 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		// Diagnostics to highlight when X or Y is read before the view has been initialized
 		// 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 DEBUG
 			if (LayoutStyle == LayoutStyle.Computed && (!IsInitialized)) {
 			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
 		// 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 DEBUG
 			if (LayoutStyle == LayoutStyle.Computed && (!IsInitialized)) {
 			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. 
 		/// If <see cref="LayoutStyle"/> is <see cref="Terminal.Gui.LayoutStyle.Absolute"/> changing this property has no effect and its value is indeterminate. 
 		/// </remarks>
 		/// </remarks>
 		public Pos X {
 		public Pos X {
-			get => VerifyIsIntialized (_x);
+			get => VerifyIsInitialized (_x);
 			set {
 			set {
 				if (ForceValidatePosDim && !ValidatePosDim (_x, value)) {
 				if (ForceValidatePosDim && !ValidatePosDim (_x, value)) {
 					throw new ArgumentException ();
 					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. 
 		/// If <see cref="LayoutStyle"/> is <see cref="Terminal.Gui.LayoutStyle.Absolute"/> changing this property has no effect and its value is indeterminate. 
 		/// </remarks>
 		/// </remarks>
 		public Pos Y {
 		public Pos Y {
-			get => VerifyIsIntialized (_y);
+			get => VerifyIsInitialized (_y);
 			set {
 			set {
 				if (ForceValidatePosDim && !ValidatePosDim (_y, value)) {
 				if (ForceValidatePosDim && !ValidatePosDim (_y, value)) {
 					throw new ArgumentException ();
 					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. 
 		/// If <see cref="LayoutStyle"/> is <see cref="Terminal.Gui.LayoutStyle.Absolute"/> changing this property has no effect and its value is indeterminate. 
 		/// </remarks>
 		/// </remarks>
 		public Dim Width {
 		public Dim Width {
-			get => VerifyIsIntialized (_width);
+			get => VerifyIsInitialized (_width);
 			set {
 			set {
 				if (ForceValidatePosDim && !ValidatePosDim (_width, value)) {
 				if (ForceValidatePosDim && !ValidatePosDim (_width, value)) {
 					throw new ArgumentException ("ForceValidatePosDim is enabled", nameof (Width));
 					throw new ArgumentException ("ForceValidatePosDim is enabled", nameof (Width));
@@ -339,7 +379,7 @@ namespace Terminal.Gui {
 		/// <value>The height.</value>
 		/// <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. 
 		/// 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 {
 		public Dim Height {
-			get => VerifyIsIntialized (_height);
+			get => VerifyIsInitialized (_height);
 			set {
 			set {
 				if (ForceValidatePosDim && !ValidatePosDim (_height, value)) {
 				if (ForceValidatePosDim && !ValidatePosDim (_height, value)) {
 					throw new ArgumentException ("ForceValidatePosDim is enabled", nameof (Height));
 					throw new ArgumentException ("ForceValidatePosDim is enabled", nameof (Height));
@@ -377,8 +417,8 @@ namespace Terminal.Gui {
 			return false;
 			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>
 		/// <summary>
 		/// Gets the minimum dimensions required to fit the View's <see cref="Text"/>, factoring in <see cref="TextDirection"/>.
 		/// Gets the minimum dimensions required to fit the View's <see cref="Text"/>, factoring in <see cref="TextDirection"/>.
 		/// </summary>
 		/// </summary>
@@ -389,7 +429,7 @@ namespace Terminal.Gui {
 		/// if <see cref="Height"/> (Horizontal) or <see cref="Width"/> (Vertical) are not not set or zero.
 		/// if <see cref="Height"/> (Horizontal) or <see cref="Width"/> (Vertical) are not not set or zero.
 		/// Does not take into account word wrapping.
 		/// Does not take into account word wrapping.
 		/// </remarks>
 		/// </remarks>
-		public bool GetMinimumBounds (out Size size)
+		bool GetMinimumBoundsForFrame (out Size size)
 		{
 		{
 			if (!IsInitialized) {
 			if (!IsInitialized) {
 				size = new Size (0, 0);
 				size = new Size (0, 0);
@@ -426,15 +466,15 @@ namespace Terminal.Gui {
 			return false;
 			return false;
 		}
 		}
 
 
-		// BUGBUG - v2 - Should be renamed "SetBoundsToFitFrame"
+		// BUGBUG: this function does not belong in ViewLayout.cs - it should be in ViewText.cs
 		/// <summary>
 		/// <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>
 		/// </summary>
 		/// <returns><see langword="true"/> if the size was changed, <see langword="false"/> if <see cref="Text"/>
 		/// <returns><see langword="true"/> if the size was changed, <see langword="false"/> if <see cref="Text"/>
 		/// will not fit.</returns>
 		/// 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);
 				_frame = new Rect (_frame.Location, size);
 				return true;
 				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
 			//// BUGBUG: I think these calls are redundant or should be moved into just the AutoSize case
 			if (IsInitialized || LayoutStyle == LayoutStyle.Absolute) {
 			if (IsInitialized || LayoutStyle == LayoutStyle.Absolute) {
-				SetMinWidthHeight ();
+				SetBoundsToFitFrame ();
 				LayoutFrames ();
 				LayoutFrames ();
 				TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey ();
 				TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey ();
 				SetNeedsLayout ();
 				SetNeedsLayout ();
@@ -502,69 +542,99 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		/// <summary>
 		/// <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>
 		/// </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>
 		/// <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>
 		/// </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>
 		/// <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 ();
 			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;
 			var super = SuperView;
 			while (super != null) {
 			while (super != null) {
 				boundsOffset = super.GetBoundsOffset ();
 				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;
 				super = super.SuperView;
 			}
 			}
 
 
 			// The following ensures that the cursor is always in the screen boundaries.
 			// The following ensures that the cursor is always in the screen boundaries.
 			if (clamped) {
 			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>
 		/// <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>
 		/// </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);
 			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>
 		/// <summary>
 		/// Sets the View's <see cref="Frame"/> to the frame-relative coordinates if its container. The
 		/// 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
 		/// container size and location are specified by <paramref name="superviewFrame"/> and are relative to the
 		/// View's superview.
 		/// View's superview.
 		/// </summary>
 		/// </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>
 		/// same as <c>this.SuperView.Frame</c>).</param>
 		internal void SetRelativeLayout (Rect superviewFrame)
 		internal void SetRelativeLayout (Rect superviewFrame)
 		{
 		{
@@ -668,7 +738,7 @@ namespace Terminal.Gui {
 			if (Frame != r) {
 			if (Frame != r) {
 				Frame = r;
 				Frame = r;
 				// BUGBUG: Why is this AFTER setting Frame? Seems duplicative.
 				// BUGBUG: Why is this AFTER setting Frame? Seems duplicative.
-				if (!SetMinWidthHeight ()) {
+				if (!SetBoundsToFitFrame ()) {
 					TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey ();
 					TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey ();
 				}
 				}
 			}
 			}
@@ -959,51 +1029,52 @@ namespace Terminal.Gui {
 				return false;
 				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) {
 				if (ForceValidatePosDim) {
-					aSize = SetWidthHeight (nBoundsSize);
+					// BUGBUG: This ain't right, obviously.  We need to figure out how to handle this.
+					boundsChanged = ResizeBoundsToFit (newFrameSize);
 				} else {
 				} 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
 			// BUGBUG: This call may be redundant
 			TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey ();
 			TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey ();
-			return aSize;
+			return boundsChanged;
 		}
 		}
 
 
 		/// <summary>
 		/// <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>
 		/// </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) {
 			if (canSizeW) {
-				aSize = true;
+				boundsChanged = true;
 				_width = rW;
 				_width = rW;
 			}
 			}
 			if (canSizeH) {
 			if (canSizeH) {
-				aSize = true;
+				boundsChanged = true;
 				_height = rH;
 				_height = rH;
 			}
 			}
-			if (aSize) {
+			if (boundsChanged) {
 				Bounds = new Rect (Bounds.X, Bounds.Y, canSizeW ? rW : Bounds.Width, canSizeH ? rH : Bounds.Height);
 				Bounds = new Rect (Bounds.X, Bounds.Y, canSizeW ? rW : Bounds.Width, canSizeH ? rH : Bounds.Height);
 			}
 			}
 
 
-			return aSize;
+			return boundsChanged;
 		}
 		}
 
 
 		/// <summary>
 		/// <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.
 		/// <see cref="TextFormatter"/> property and accounting for any <see cref="HotKeySpecifier"/> characters.
 		/// </summary>
 		/// </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 ()
 		public Size GetAutoSize ()
 		{
 		{
 			int x = 0;
 			int x = 0;
@@ -1130,13 +1201,12 @@ namespace Terminal.Gui {
 		/// </returns>
 		/// </returns>
 		public static View FindDeepestView (View start, int x, int y, out int resx, out int resy)
 		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;
 				return null;
 			}
 			}
+			
+			var startFrame = start.Frame;
 			if (start.InternalSubviews != null) {
 			if (start.InternalSubviews != null) {
 				int count = start.InternalSubviews.Count;
 				int count = start.InternalSubviews.Count;
 				if (count > 0) {
 				if (count > 0) {

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

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

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

@@ -72,10 +72,12 @@ namespace Terminal.Gui {
 		/// <param name="ch">Ch.</param>
 		/// <param name="ch">Ch.</param>
 		public void AddRune (int col, int row, Rune ch)
 		public void AddRune (int col, int row, Rune ch)
 		{
 		{
-			if (row < 0 || col < 0)
+			if (row < 0 || col < 0) {
 				return;
 				return;
-			if (row > _frame.Height - 1 || col > _frame.Width - 1)
+			}
+			if (row > _frame.Height - 1 || col > _frame.Width - 1) {
 				return;
 				return;
+			}
 			Move (col, row);
 			Move (col, row);
 			Driver.AddRune (ch);
 			Driver.AddRune (ch);
 		}
 		}
@@ -185,7 +187,7 @@ namespace Terminal.Gui {
 		///     This clears the Bounds used by this view.
 		///     This clears the Bounds used by this view.
 		///   </para>
 		///   </para>
 		/// </remarks>
 		/// </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 
 		// 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
 		// "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 ()
 		public Rect ClipToBounds ()
 		{
 		{
 			var previous = Driver.Clip;
 			var previous = Driver.Clip;
-			Driver.Clip = Rect.Intersect (previous, ViewToScreen (Bounds));
+			Driver.Clip = Rect.Intersect (previous, BoundsToScreen (Bounds));
 			return previous;
 			return previous;
 		}
 		}
 
 
@@ -274,15 +276,13 @@ namespace Terminal.Gui {
 		/// <returns>The move.</returns>
 		/// <returns>The move.</returns>
 		/// <param name="col">The column to move to, in view-relative coordinates.</param>
 		/// <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="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) {
 			if (Driver.Rows == 0) {
 				return;
 				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);
 			Driver.Move (rCol, rRow);
 		}
 		}
 		/// <summary>
 		/// <summary>
@@ -438,7 +438,7 @@ namespace Terminal.Gui {
 		{
 		{
 			if (NeedsDisplay) {
 			if (NeedsDisplay) {
 				if (SuperView != null) {
 				if (SuperView != null) {
-					Clear (ViewToScreen (Bounds));
+					Clear (BoundsToScreen (Bounds));
 				}
 				}
 
 
 				if (!string.IsNullOrEmpty (TextFormatter.Text)) {
 				if (!string.IsNullOrEmpty (TextFormatter.Text)) {
@@ -447,7 +447,7 @@ namespace Terminal.Gui {
 					}
 					}
 				}
 				}
 				// This should NOT clear 
 				// This should NOT clear 
-				TextFormatter?.Draw (ViewToScreen (Bounds), HasFocus ? GetFocusColor () : GetNormalColor (),
+				TextFormatter?.Draw (BoundsToScreen (Bounds), HasFocus ? GetFocusColor () : GetNormalColor (),
 					HasFocus ? ColorScheme.HotFocus : GetHotNormalColor (),
 					HasFocus ? ColorScheme.HotFocus : GetHotNormalColor (),
 					Rect.Empty, false);
 					Rect.Empty, false);
 				SetSubViewNeedsDisplay ();
 				SetSubViewNeedsDisplay ();

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

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

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

@@ -268,12 +268,10 @@ namespace Terminal.Gui {
 			}
 			}
 
 
 			SetFocus ();
 			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;
 				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;
 			return true;
 		}
 		}

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

@@ -873,7 +873,7 @@ namespace Terminal.Gui {
 			if (lastSelectedItem != selectedItem) {
 			if (lastSelectedItem != selectedItem) {
 				OnOpenSelectedItem ();
 				OnOpenSelectedItem ();
 			}
 			}
-			var rect = listview.ViewToScreen (listview.Bounds);
+			var rect = listview.BoundsToScreen (listview.Bounds);
 			Reset (keepSearchText: true);
 			Reset (keepSearchText: true);
 			listview.Clear (rect);
 			listview.Clear (rect);
 			listview.TabStop = false;
 			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 frame = new Rect (0, 0, View.Driver.Cols, View.Driver.Rows);
 			var position = Position;
 			var position = Position;
 			if (Host != null) {
 			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);
 				var pos = new Point (x, y);
 				pos.Y += Host.Frame.Height - 1;
 				pos.Y += Host.Frame.Height - 1;
 				if (position != pos) {
 				if (position != pos) {
@@ -117,7 +117,7 @@ namespace Terminal.Gui {
 					if (Host == null) {
 					if (Host == null) {
 						position.Y = frame.Bottom - rect.Height - 1;
 						position.Y = frame.Bottom - rect.Height - 1;
 					} else {
 					} 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);
 						var pos = new Point (x, y);
 						position.Y = pos.Y - rect.Height - 1;
 						position.Y = pos.Y - rect.Height - 1;
 					}
 					}

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

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

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

@@ -794,14 +794,13 @@ namespace Terminal.Gui {
 				return true;
 				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;
 				return true;
 			}
 			}
 
 
-			selected = top - GetFramesThickness ().Top + me.Y;
+			selected = top + me.Y;
 			if (AllowsAll ()) {
 			if (AllowsAll ()) {
 				Source.SetMark (SelectedItem, !Source.IsMarked (SelectedItem));
 				Source.SetMark (SelectedItem, !Source.IsMarked (SelectedItem));
 				SetNeedsDisplay ();
 				SetNeedsDisplay ();

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

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

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

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

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

@@ -375,8 +375,8 @@ namespace Terminal.Gui {
 			}
 			}
 			SetFocus ();
 			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 pos = displayMode == DisplayModeLayout.Horizontal ? boundsX : boundsY;
 			var rCount = displayMode == DisplayModeLayout.Horizontal ? horizontal.Last ().pos + horizontal.Last ().length : radioLabels.Count;
 			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;
 				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)) {
 			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 pos = _point - _first + Math.Min (Frame.X, 0);
 			var offB = OffSetBackground ();
 			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
 			if (pos > -1 && col >= pos && pos < Frame.Width + offB
 				&& containerFrame.IntersectsWith (thisFrame)) {
 				&& containerFrame.IntersectsWith (thisFrame)) {
 				RestoreCursorVisibility ();
 				RestoreCursorVisibility ();
@@ -415,9 +415,9 @@ namespace Terminal.Gui {
 			} else {
 			} else {
 				HideCursorVisibility ();
 				HideCursorVisibility ();
 				if (pos < 0) {
 				if (pos < 0) {
-					Move (pos, 0, false);
+					Move (pos, 0);
 				} else {
 				} 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) {
 				foreach (var line in allLines) {
 					bool isRoot = splitterLines.Contains (line);
 					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 ?
 					var length = line.Orientation == Orientation.Horizontal ?
 							line.Frame.Width :
 							line.Frame.Width :
 							line.Frame.Height;
 							line.Frame.Height;
@@ -747,9 +747,9 @@ namespace Terminal.Gui {
 			/// </summary>
 			/// </summary>
 			public Point GetLocalCoordinateForTitle (TileView intoCoordinateSpace)
 			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--;
 				screenRow--;
-				return intoCoordinateSpace.ScreenToView (screenCol, screenRow);
+				return intoCoordinateSpace.ScreenToFrame (screenCol, screenRow);
 			}
 			}
 
 
 			internal string GetTrimmedTitle ()
 			internal string GetTrimmedTitle ()

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

@@ -812,6 +812,7 @@ namespace Terminal.Gui {
 				Application.BringOverlappedTopToFront ();
 				Application.BringOverlappedTopToFront ();
 
 
 				// Only start grabbing if the user clicks on the title bar.
 				// 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) {
 				if (mouseEvent.Y == 0 && mouseEvent.Flags == MouseFlags.Button1Pressed) {
 					_startGrabPoint = new Point (mouseEvent.X, mouseEvent.Y);
 					_startGrabPoint = new Point (mouseEvent.X, mouseEvent.Y);
 					_dragPosition = new Point ();
 					_dragPosition = new Point ();
@@ -836,6 +837,7 @@ namespace Terminal.Gui {
 					} else {
 					} else {
 						SuperView.SetNeedsDisplay ();
 						SuperView.SetNeedsDisplay ();
 					}
 					}
+					// BUGBUG: Assumes Frame == Border?
 					GetLocationThatFits (this, mouseEvent.X + (SuperView == null ? mouseEvent.OfX - _startGrabPoint.X : Frame.X - _startGrabPoint.X),
 					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),
 						mouseEvent.Y + (SuperView == null ? mouseEvent.OfY - _startGrabPoint.Y : Frame.Y - _startGrabPoint.Y),
 						out nx, out ny, out _, out _);
 						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.
 		/// at the provided row. Returns null if no object is at that location.
 		/// <remarks>
 		/// <remarks>
 		/// </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}"/>.
 		/// to translate these into the client area of the <see cref="TreeView{T}"/>.
 		/// </summary>
 		/// </summary>
 		/// <param name="row">The row of the <see cref="View.Bounds"/> of the <see cref="TreeView{T}"/>.</param>
 		/// <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) {
 					if (_currentLine == null) {
 						// Mouse pressed down
 						// Mouse pressed down
 						_currentLine = new StraightLine (
 						_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));
 							0, Orientation.Vertical, LineStyle, new Attribute (_currentColor, GetNormalColor ().Background));
 						
 						
 						_currentLayer.AddLine (_currentLine);
 						_currentLayer.AddLine (_currentLine);
 					} else {
 					} else {
 						// Mouse dragged
 						// Mouse dragged
 						var start = _currentLine.Start;
 						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 orientation = Orientation.Vertical;
 						var length = end.Y - start.Y;
 						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);
 		var contextMenu = new ContextMenu (screenX,screenY, items);
 
 

+ 2 - 138
UnitTests/Application/ApplicationTests.cs

@@ -486,6 +486,8 @@ public class ApplicationTests {
 0000000000
 0000000000
 ", null, attributes);
 ", 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 }));
 		Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () { X = 2, Y = 2, Flags = MouseFlags.Button1Pressed }));
 		Assert.Equal (d, Application.MouseGrabView);
 		Assert.Equal (d, Application.MouseGrabView);
 
 
@@ -978,142 +980,4 @@ public class ApplicationTests {
 		Assert.Equal (1, actionCalled);
 		Assert.Equal (1, actionCalled);
 		Application.Shutdown ();
 		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;
 using System.Collections.Generic;
 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;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
-using Terminal.Gui;
 using Xunit;
 using Xunit;
-using Xunit.Sdk;
 
 
 // Alias Console to MockConsole so we don't accidentally use Console
 // Alias Console to MockConsole so we don't accidentally use Console
-using Console = Terminal.Gui.FakeConsole;
 
 
 namespace Terminal.Gui.ApplicationTests;
 namespace Terminal.Gui.ApplicationTests;
 /// <summary>
 /// <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
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 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);
        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
      TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
      T                                      T
      T                                      T
      T                                      T
      T                                      T
@@ -432,13 +432,13 @@ namespace Terminal.Gui.DrawingTests {
      T                                      T
      T                                      T
      TTTest (Left=1,Top=1,Right=1,Bottom=1)TT", output);
      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
      TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
      TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
      T                                    TTT
      T                                    TTT
@@ -455,13 +455,13 @@ namespace Terminal.Gui.DrawingTests {
      TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
      TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
      TTTest (Left=1,Top=2,Right=3,Bottom=4)TT", output);
      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
      TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
                                             T
                                             T
                                             T
                                             T
@@ -478,30 +478,30 @@ namespace Terminal.Gui.DrawingTests {
                                             T
                                             T
      TTest (Left=-1,Top=1,Right=1,Bottom=1)TT", output);
      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);
 └───────────────────────────────────────────┘", 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   │
 │|123456789|123456789|123456789|123456789   │
 │1                                      1   │
 │1                                      1   │
@@ -551,13 +551,13 @@ namespace Terminal.Gui.DrawingTests {
 │                                           │
 │                                           │
 └───────────────────────────────────────────┘", output);
 └───────────────────────────────────────────┘", 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  │
 │ |123456789|123456789|123456789|123456789  │
@@ -579,13 +579,13 @@ namespace Terminal.Gui.DrawingTests {
 │                                           │
 │                                           │
 └───────────────────────────────────────────┘", output);
 └───────────────────────────────────────────┘", 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
 │                                           3
 └────|123456789|123456789|123456789|123456789", output);
 └────|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;
 using Xunit.Abstractions;
 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 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├────────────┐
 ┌┤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├────────────┐
 ┌┤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├┐
 ┌┤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├┐
 ┌┤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├┐
 ┌┤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├┐
 ┌┤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├─┐
 ┌┤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├──┐
 ┌┤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├┐║
 ║┌┤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╘╗
 ╔╛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╘╗
 ╔╛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╘╗
 ╔╛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╘╗
 ╔╛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╘═╗
 ╔╛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╘══╗
 ╔╛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╞╗
 ╔╡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╞╗
 ╔╡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╞╗
 ╔╡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╞╗
 ╔╡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╞═╗
 ╔╡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╞══╗
 ╔╡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╞╗
 ╔╡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╞╗
 ╔╡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╞╗
 ╔╡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╞╗
 ╔╡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╞═╗
 ╔╡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╞══╗
 ╔╡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);
 └──────────────────┘", output);
 
 
 			// top
 			// 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, col);
 			Assert.Equal (0, row);
 			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, col);
 			Assert.Equal (0, row);
 			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, col);
 			Assert.Equal (0, row);
 			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, col);
 			Assert.Equal (1, row);
 			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, col);
 			Assert.Equal (0, row);
 			Assert.Equal (0, row);
 			Assert.Equal (top, View.FindDeepestView (top, 0, 0, out int rx, out int ry));
 			Assert.Equal (top, View.FindDeepestView (top, 0, 0, out int rx, out int ry));
 			Assert.Equal (0, rx);
 			Assert.Equal (0, rx);
 			Assert.Equal (0, ry);
 			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 (4, col);
 			Assert.Equal (3, row);
 			Assert.Equal (3, row);
 			Assert.Equal (view, View.FindDeepestView (top, col, row, out rx, out ry));
 			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 (top, View.FindDeepestView (top, 3, 2, out rx, out ry));
 			Assert.Equal (3, rx);
 			Assert.Equal (3, rx);
 			Assert.Equal (2, ry);
 			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 (13, col);
 			Assert.Equal (3, row);
 			Assert.Equal (3, row);
 			Assert.Equal (view, View.FindDeepestView (top, col, row, out rx, out ry));
 			Assert.Equal (view, View.FindDeepestView (top, col, row, out rx, out ry));
 			Assert.Equal (9, rx);
 			Assert.Equal (9, rx);
 			Assert.Equal (0, ry);
 			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 (14, col);
 			Assert.Equal (3, row);
 			Assert.Equal (3, row);
 			Assert.Equal (top, View.FindDeepestView (top, 13, 2, out rx, out ry));
 			Assert.Equal (top, View.FindDeepestView (top, 13, 2, out rx, out ry));
 			Assert.Equal (13, rx);
 			Assert.Equal (13, rx);
 			Assert.Equal (2, ry);
 			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 (15, col);
 			Assert.Equal (4, row);
 			Assert.Equal (4, row);
 			Assert.Equal (top, View.FindDeepestView (top, 14, 3, out rx, out ry));
 			Assert.Equal (top, View.FindDeepestView (top, 14, 3, out rx, out ry));
 			Assert.Equal (14, rx);
 			Assert.Equal (14, rx);
 			Assert.Equal (3, ry);
 			Assert.Equal (3, ry);
 			// view
 			// 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, col);
 			Assert.Equal (1, row);
 			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, col);
 			Assert.Equal (1, row);
 			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, col);
 			Assert.Equal (1, row);
 			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, col);
 			Assert.Equal (1, row);
 			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, col);
 			Assert.Equal (0, row);
 			Assert.Equal (0, row);
 			Assert.Equal (top, View.FindDeepestView (top, 0, 0, out rx, out ry));
 			Assert.Equal (top, View.FindDeepestView (top, 0, 0, out rx, out ry));
 			Assert.Equal (0, rx);
 			Assert.Equal (0, rx);
 			Assert.Equal (0, ry);
 			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 (4, col);
 			Assert.Equal (3, row);
 			Assert.Equal (3, row);
 			Assert.Equal (view, View.FindDeepestView (top, 4, 3, out rx, out ry));
 			Assert.Equal (view, View.FindDeepestView (top, 4, 3, out rx, out ry));
 			Assert.Equal (0, rx);
 			Assert.Equal (0, rx);
 			Assert.Equal (0, ry);
 			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 (14, col);
 			Assert.Equal (3, row);
 			Assert.Equal (3, row);
 			Assert.Equal (top, View.FindDeepestView (top, 14, 3, out rx, out ry));
 			Assert.Equal (top, View.FindDeepestView (top, 14, 3, out rx, out ry));
 			Assert.Equal (14, rx);
 			Assert.Equal (14, rx);
 			Assert.Equal (3, ry);
 			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 (15, col);
 			Assert.Equal (4, row);
 			Assert.Equal (4, row);
 			Assert.Equal (top, View.FindDeepestView (top, 15, 4, out rx, out ry));
 			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);
 			Assert.Equal (new Rect (3, 2, 23, 10), frame);
 
 
 			// top
 			// 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, col);
 			Assert.Equal (0, row);
 			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, col);
 			Assert.Equal (0, row);
 			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, col);
 			Assert.Equal (0, row);
 			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, col);
 			Assert.Equal (1, row);
 			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, col);
 			Assert.Equal (0, row);
 			Assert.Equal (0, row);
 			Assert.Null (View.FindDeepestView (top, -4, -3, out int rx, out int ry));
 			Assert.Null (View.FindDeepestView (top, -4, -3, out int rx, out int ry));
 			Assert.Equal (0, rx);
 			Assert.Equal (0, rx);
 			Assert.Equal (0, ry);
 			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 (4, col);
 			Assert.Equal (3, row);
 			Assert.Equal (3, row);
 			Assert.Equal (top, View.FindDeepestView (top, 3, 2, out rx, out ry));
 			Assert.Equal (top, View.FindDeepestView (top, 3, 2, out rx, out ry));
 			Assert.Equal (0, rx);
 			Assert.Equal (0, rx);
 			Assert.Equal (0, ry);
 			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 (14, col);
 			Assert.Equal (3, row);
 			Assert.Equal (3, row);
 			Assert.Equal (top, View.FindDeepestView (top, 13, 2, out rx, out ry));
 			Assert.Equal (top, View.FindDeepestView (top, 13, 2, out rx, out ry));
 			Assert.Equal (10, rx);
 			Assert.Equal (10, rx);
 			Assert.Equal (0, ry);
 			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 (15, col);
 			Assert.Equal (4, row);
 			Assert.Equal (4, row);
 			Assert.Equal (top, View.FindDeepestView (top, 14, 3, out rx, out ry));
 			Assert.Equal (top, View.FindDeepestView (top, 14, 3, out rx, out ry));
 			Assert.Equal (11, rx);
 			Assert.Equal (11, rx);
 			Assert.Equal (1, ry);
 			Assert.Equal (1, ry);
 			// view
 			// 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, col);
 			Assert.Equal (1, row);
 			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, col);
 			Assert.Equal (1, row);
 			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, col);
 			Assert.Equal (1, row);
 			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, col);
 			Assert.Equal (1, row);
 			Assert.Equal (1, row);
 			Assert.Null (View.FindDeepestView (top, 1, 1, out rx, out ry));
 			Assert.Null (View.FindDeepestView (top, 1, 1, out rx, out ry));
 			Assert.Equal (0, rx);
 			Assert.Equal (0, rx);
 			Assert.Equal (0, ry);
 			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 (4, col);
 			Assert.Equal (3, row);
 			Assert.Equal (3, row);
 			Assert.Equal (top, View.FindDeepestView (top, 4, 3, out rx, out ry));
 			Assert.Equal (top, View.FindDeepestView (top, 4, 3, out rx, out ry));
 			Assert.Equal (1, rx);
 			Assert.Equal (1, rx);
 			Assert.Equal (1, ry);
 			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 (7, col);
 			Assert.Equal (5, row);
 			Assert.Equal (5, row);
 			Assert.Equal (view, View.FindDeepestView (top, 7, 5, out rx, out ry));
 			Assert.Equal (view, View.FindDeepestView (top, 7, 5, out rx, out ry));
 			Assert.Equal (0, rx);
 			Assert.Equal (0, rx);
 			Assert.Equal (0, ry);
 			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 (14, col);
 			Assert.Equal (5, row);
 			Assert.Equal (5, row);
 			Assert.Equal (view, View.FindDeepestView (top, 14, 5, out rx, out ry));
 			Assert.Equal (view, View.FindDeepestView (top, 14, 5, out rx, out ry));
 			Assert.Equal (7, rx);
 			Assert.Equal (7, rx);
 			Assert.Equal (0, ry);
 			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 (15, col);
 			Assert.Equal (4, row);
 			Assert.Equal (4, row);
 			Assert.Equal (top, View.FindDeepestView (top, 15, 4, out rx, out ry));
 			Assert.Equal (top, View.FindDeepestView (top, 15, 4, out rx, out ry));
 			Assert.Equal (12, rx);
 			Assert.Equal (12, rx);
 			Assert.Equal (2, ry);
 			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 (24, col);
 			Assert.Equal (4, row);
 			Assert.Equal (4, row);
 			Assert.Null (View.FindDeepestView (top, 24, 4, out rx, out ry));
 			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);
 			Assert.False (view._addingView);
 			view._addingView = true;
 			view._addingView = true;
 			Assert.True (view._addingView);
 			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, rcol);
 			Assert.Equal (1, rrow);
 			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.Equal (top.Bounds, view.ScreenClip (top.Bounds));
 			Assert.True (view.LayoutStyle == LayoutStyle.Absolute);
 			Assert.True (view.LayoutStyle == LayoutStyle.Absolute);
 
 
@@ -546,7 +546,7 @@ namespace Terminal.Gui.ViewTests {
 			view.Y = Pos.Center () - 13;
 			view.Y = Pos.Center () - 13;
 			view.SetRelativeLayout (top.Bounds);
 			view.SetRelativeLayout (top.Bounds);
 			top.LayoutSubviews (); // BUGBUG: v2 - ??
 			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 (-41, rcol);
 			Assert.Equal (-13, rrow);
 			Assert.Equal (-13, rrow);
 			
 			

+ 65 - 64
UnitTests/Views/ListViewTests.cs

@@ -542,69 +542,70 @@ Item 6", output);
 			Assert.Null (exception);
 			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");
 			var btnPopup = new Button ("Popup");
 			btnPopup.Clicked += (s, e) => {
 			btnPopup.Clicked += (s, e) => {
-				var viewToScreen = btnPopup.ViewToScreen (top.Frame);
+				var viewToScreen = btnPopup.BoundsToScreen (top.Frame);
 				var view = new View () {
 				var view = new View () {
 					X = 1,
 					X = 1,
 					Y = viewToScreen.Y + 1,
 					Y = viewToScreen.Y + 1,