Browse Source

Everything appears to work (except ScrollView which I broke but will fix).

Tig 1 year ago
parent
commit
d25f98f8e3

+ 12 - 6
Terminal.Gui/Application.cs

@@ -88,7 +88,7 @@ public static partial class Application
 #if DEBUG_IDISPOSABLE
 #if DEBUG_IDISPOSABLE
 
 
             // Don't dispose the toplevels. It's up to caller dispose them
             // Don't dispose the toplevels. It's up to caller dispose them
-            Debug.Assert (t.WasDisposed);
+            //Debug.Assert (t.WasDisposed);
 #endif
 #endif
         }
         }
 
 
@@ -1495,7 +1495,7 @@ public static partial class Application
                 View = view
                 View = view
             };
             };
 
 
-            if (MouseGrabView.Viewport.Contains (viewRelativeMouseEvent.X, viewRelativeMouseEvent.Y) is false)
+            if ((MouseGrabView.Viewport with { Location = Point.Empty }).Contains (viewRelativeMouseEvent.X, viewRelativeMouseEvent.Y) is false)
             {
             {
                 // The mouse has moved outside the Viewport of the view that
                 // The mouse has moved outside the Viewport of the view that
                 // grabbed the mouse, so we tell the view that last got 
                 // grabbed the mouse, so we tell the view that last got 
@@ -1551,7 +1551,7 @@ public static partial class Application
                 View = view
                 View = view
             };
             };
         }
         }
-        else if (view.ViewportToScreen (view.Viewport).Contains (a.MouseEvent.X, a.MouseEvent.Y))
+        else if (view.ViewportToScreen (Rectangle.Empty with {Size = view.Viewport.Size}).Contains (a.MouseEvent.X, a.MouseEvent.Y))
         {
         {
             Point viewportLocation = view.ScreenToViewport (a.MouseEvent.X, a.MouseEvent.Y);
             Point viewportLocation = view.ScreenToViewport (a.MouseEvent.X, a.MouseEvent.Y);
 
 
@@ -1591,10 +1591,16 @@ public static partial class Application
 
 
         //Debug.WriteLine ($"OnMouseEvent: ({a.MouseEvent.X},{a.MouseEvent.Y}) - {a.MouseEvent.Flags}");
         //Debug.WriteLine ($"OnMouseEvent: ({a.MouseEvent.X},{a.MouseEvent.Y}) - {a.MouseEvent.Flags}");
 
 
-        if (view.OnMouseEvent (me))
+        while (view is {} && !view.OnMouseEvent (me))
         {
         {
-            // Should we bubble up the event, if it is not handled?
-            //return;
+            if (view is Adornment ad)
+            {
+                view = ad.Parent.SuperView;
+            }
+            else
+            {
+                view = view.SuperView;
+            }
         }
         }
 
 
         BringOverlappedTopToFront ();
         BringOverlappedTopToFront ();

+ 37 - 37
Terminal.Gui/Text/TextFormatter.cs

@@ -202,14 +202,14 @@ public class TextFormatter
     ///     Causes the text to be formatted (references <see cref="GetLines"/>). Sets <see cref="NeedsFormat"/> to
     ///     Causes the text to be formatted (references <see cref="GetLines"/>). Sets <see cref="NeedsFormat"/> to
     ///     <c>false</c>.
     ///     <c>false</c>.
     /// </remarks>
     /// </remarks>
-    /// <param name="viewport">Specifies the screen-relative location and maximum size for drawing the text.</param>
+    /// <param name="screen">Specifies the screen-relative location and maximum size for drawing the text.</param>
     /// <param name="normalColor">The color to use for all text except the hotkey</param>
     /// <param name="normalColor">The color to use for all text except the hotkey</param>
     /// <param name="hotColor">The color to use to draw the hotkey</param>
     /// <param name="hotColor">The color to use to draw the hotkey</param>
     /// <param name="maximum">Specifies the screen-relative location and maximum container size.</param>
     /// <param name="maximum">Specifies the screen-relative location and maximum container size.</param>
     /// <param name="driver">The console driver currently used by the application.</param>
     /// <param name="driver">The console driver currently used by the application.</param>
     /// <exception cref="ArgumentOutOfRangeException"></exception>
     /// <exception cref="ArgumentOutOfRangeException"></exception>
     public void Draw (
     public void Draw (
-        Rectangle viewport,
+        Rectangle screen,
         Attribute normalColor,
         Attribute normalColor,
         Attribute hotColor,
         Attribute hotColor,
         Rectangle maximum = default,
         Rectangle maximum = default,
@@ -240,46 +240,46 @@ public class TextFormatter
         }
         }
 
 
         bool isVertical = IsVerticalDirection (Direction);
         bool isVertical = IsVerticalDirection (Direction);
-        Rectangle maxViewport = viewport;
+        Rectangle maxScreen = screen;
 
 
         if (driver is { })
         if (driver is { })
         {
         {
             // INTENT: What, exactly, is the intent of this?
             // INTENT: What, exactly, is the intent of this?
-            maxViewport = maximum == default (Rectangle)
-                            ? viewport
+            maxScreen = maximum == default (Rectangle)
+                            ? screen
                             : new (
                             : new (
-                                   Math.Max (maximum.X, viewport.X),
-                                   Math.Max (maximum.Y, viewport.Y),
+                                   Math.Max (maximum.X, screen.X),
+                                   Math.Max (maximum.Y, screen.Y),
                                    Math.Max (
                                    Math.Max (
-                                             Math.Min (maximum.Width, maximum.Right - viewport.Left),
+                                             Math.Min (maximum.Width, maximum.Right - screen.Left),
                                              0
                                              0
                                             ),
                                             ),
                                    Math.Max (
                                    Math.Max (
                                              Math.Min (
                                              Math.Min (
                                                        maximum.Height,
                                                        maximum.Height,
-                                                       maximum.Bottom - viewport.Top
+                                                       maximum.Bottom - screen.Top
                                                       ),
                                                       ),
                                              0
                                              0
                                             )
                                             )
                                   );
                                   );
         }
         }
 
 
-        if (maxViewport.Width == 0 || maxViewport.Height == 0)
+        if (maxScreen.Width == 0 || maxScreen.Height == 0)
         {
         {
             return;
             return;
         }
         }
 
 
-        int lineOffset = !isVertical && viewport.Y < 0 ? Math.Abs (viewport.Y) : 0;
+        int lineOffset = !isVertical && screen.Y < 0 ? Math.Abs (screen.Y) : 0;
 
 
         for (int line = lineOffset; line < linesFormatted.Count; line++)
         for (int line = lineOffset; line < linesFormatted.Count; line++)
         {
         {
-            if ((isVertical && line > viewport.Width) || (!isVertical && line > viewport.Height))
+            if ((isVertical && line > screen.Width) || (!isVertical && line > screen.Height))
             {
             {
                 continue;
                 continue;
             }
             }
 
 
-            if ((isVertical && line >= maxViewport.Left + maxViewport.Width)
-                || (!isVertical && line >= maxViewport.Top + maxViewport.Height + lineOffset))
+            if ((isVertical && line >= maxScreen.Left + maxScreen.Width)
+                || (!isVertical && line >= maxScreen.Top + maxScreen.Height + lineOffset))
             {
             {
                 break;
                 break;
             }
             }
@@ -305,14 +305,14 @@ public class TextFormatter
                 if (isVertical)
                 if (isVertical)
                 {
                 {
                     int runesWidth = GetWidestLineLength (linesFormatted, line, TabWidth);
                     int runesWidth = GetWidestLineLength (linesFormatted, line, TabWidth);
-                    x = viewport.Right - runesWidth;
-                    CursorPosition = viewport.Width - runesWidth + (_hotKeyPos > -1 ? _hotKeyPos : 0);
+                    x = screen.Right - runesWidth;
+                    CursorPosition = screen.Width - runesWidth + (_hotKeyPos > -1 ? _hotKeyPos : 0);
                 }
                 }
                 else
                 else
                 {
                 {
                     int runesWidth = StringExtensions.ToString (runes).GetColumns ();
                     int runesWidth = StringExtensions.ToString (runes).GetColumns ();
-                    x = viewport.Right - runesWidth;
-                    CursorPosition = viewport.Width - runesWidth + (_hotKeyPos > -1 ? _hotKeyPos : 0);
+                    x = screen.Right - runesWidth;
+                    CursorPosition = screen.Width - runesWidth + (_hotKeyPos > -1 ? _hotKeyPos : 0);
                 }
                 }
             }
             }
             else if (Alignment is TextAlignment.Left or TextAlignment.Justified)
             else if (Alignment is TextAlignment.Left or TextAlignment.Justified)
@@ -322,11 +322,11 @@ public class TextFormatter
                     int runesWidth = line > 0
                     int runesWidth = line > 0
                                          ? GetWidestLineLength (linesFormatted, 0, line, TabWidth)
                                          ? GetWidestLineLength (linesFormatted, 0, line, TabWidth)
                                          : 0;
                                          : 0;
-                    x = viewport.Left + runesWidth;
+                    x = screen.Left + runesWidth;
                 }
                 }
                 else
                 else
                 {
                 {
-                    x = viewport.Left;
+                    x = screen.Left;
                 }
                 }
 
 
                 CursorPosition = _hotKeyPos > -1 ? _hotKeyPos : 0;
                 CursorPosition = _hotKeyPos > -1 ? _hotKeyPos : 0;
@@ -336,16 +336,16 @@ public class TextFormatter
                 if (isVertical)
                 if (isVertical)
                 {
                 {
                     int runesWidth = GetWidestLineLength (linesFormatted, line, TabWidth);
                     int runesWidth = GetWidestLineLength (linesFormatted, line, TabWidth);
-                    x = viewport.Left + line + (viewport.Width - runesWidth) / 2;
+                    x = screen.Left + line + (screen.Width - runesWidth) / 2;
 
 
-                    CursorPosition = (viewport.Width - runesWidth) / 2 + (_hotKeyPos > -1 ? _hotKeyPos : 0);
+                    CursorPosition = (screen.Width - runesWidth) / 2 + (_hotKeyPos > -1 ? _hotKeyPos : 0);
                 }
                 }
                 else
                 else
                 {
                 {
                     int runesWidth = StringExtensions.ToString (runes).GetColumns ();
                     int runesWidth = StringExtensions.ToString (runes).GetColumns ();
-                    x = viewport.Left + (viewport.Width - runesWidth) / 2;
+                    x = screen.Left + (screen.Width - runesWidth) / 2;
 
 
-                    CursorPosition = (viewport.Width - runesWidth) / 2 + (_hotKeyPos > -1 ? _hotKeyPos : 0);
+                    CursorPosition = (screen.Width - runesWidth) / 2 + (_hotKeyPos > -1 ? _hotKeyPos : 0);
                 }
                 }
             }
             }
             else
             else
@@ -358,35 +358,35 @@ public class TextFormatter
             {
             {
                 if (isVertical)
                 if (isVertical)
                 {
                 {
-                    y = viewport.Bottom - runes.Length;
+                    y = screen.Bottom - runes.Length;
                 }
                 }
                 else
                 else
                 {
                 {
-                    y = viewport.Bottom - linesFormatted.Count + line;
+                    y = screen.Bottom - linesFormatted.Count + line;
                 }
                 }
             }
             }
             else if (VerticalAlignment is VerticalTextAlignment.Top or VerticalTextAlignment.Justified)
             else if (VerticalAlignment is VerticalTextAlignment.Top or VerticalTextAlignment.Justified)
             {
             {
                 if (isVertical)
                 if (isVertical)
                 {
                 {
-                    y = viewport.Top;
+                    y = screen.Top;
                 }
                 }
                 else
                 else
                 {
                 {
-                    y = viewport.Top + line;
+                    y = screen.Top + line;
                 }
                 }
             }
             }
             else if (VerticalAlignment == VerticalTextAlignment.Middle)
             else if (VerticalAlignment == VerticalTextAlignment.Middle)
             {
             {
                 if (isVertical)
                 if (isVertical)
                 {
                 {
-                    int s = (viewport.Height - runes.Length) / 2;
-                    y = viewport.Top + s;
+                    int s = (screen.Height - runes.Length) / 2;
+                    y = screen.Top + s;
                 }
                 }
                 else
                 else
                 {
                 {
-                    int s = (viewport.Height - linesFormatted.Count) / 2;
-                    y = viewport.Top + line + s;
+                    int s = (screen.Height - linesFormatted.Count) / 2;
+                    y = screen.Top + line + s;
                 }
                 }
             }
             }
             else
             else
@@ -394,9 +394,9 @@ public class TextFormatter
                 throw new ArgumentOutOfRangeException ($"{nameof (VerticalAlignment)}");
                 throw new ArgumentOutOfRangeException ($"{nameof (VerticalAlignment)}");
             }
             }
 
 
-            int colOffset = viewport.X < 0 ? Math.Abs (viewport.X) : 0;
-            int start = isVertical ? viewport.Top : viewport.Left;
-            int size = isVertical ? viewport.Height : viewport.Width;
+            int colOffset = screen.X < 0 ? Math.Abs (screen.X) : 0;
+            int start = isVertical ? screen.Top : screen.Left;
+            int size = isVertical ? screen.Height : screen.Width;
             int current = start + colOffset;
             int current = start + colOffset;
             List<Point?> lastZeroWidthPos = null;
             List<Point?> lastZeroWidthPos = null;
             Rune rune = default;
             Rune rune = default;
@@ -422,8 +422,8 @@ public class TextFormatter
                         break;
                         break;
                     }
                     }
 
 
-                    if ((!isVertical && current - start > maxViewport.Left + maxViewport.Width - viewport.X + colOffset)
-                        || (isVertical && idx > maxViewport.Top + maxViewport.Height - viewport.Y))
+                    if ((!isVertical && current - start > maxScreen.Left + maxScreen.Width - screen.X + colOffset)
+                        || (isVertical && idx > maxScreen.Top + maxScreen.Height - screen.Y))
                     {
                     {
                         break;
                         break;
                     }
                     }

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

@@ -267,7 +267,7 @@ public class Adornment : View
 
 
         if (!Parent.CanFocus || !Parent.Arrangement.HasFlag (ViewArrangement.Movable))
         if (!Parent.CanFocus || !Parent.Arrangement.HasFlag (ViewArrangement.Movable))
         {
         {
-            return true;
+            return false;
         }
         }
 
 
         // BUGBUG: See https://github.com/gui-cs/Terminal.Gui/issues/3312
         // BUGBUG: See https://github.com/gui-cs/Terminal.Gui/issues/3312

+ 5 - 0
Terminal.Gui/View/Adornment/Border.cs

@@ -186,6 +186,11 @@ public class Border : Adornment
     /// <inheritdoc/>
     /// <inheritdoc/>
     public override void OnDrawContent (Rectangle viewport)
     public override void OnDrawContent (Rectangle viewport)
     {
     {
+        if (Parent?.Title == "Title")
+        {
+
+        }
+
         base.OnDrawContent (viewport);
         base.OnDrawContent (viewport);
 
 
         if (Thickness == Thickness.Empty)
         if (Thickness == Thickness.Empty)

+ 57 - 171
Terminal.Gui/View/Layout/ViewLayout.cs

@@ -1,4 +1,5 @@
 using System.Diagnostics;
 using System.Diagnostics;
+using System.IO.Compression;
 
 
 namespace Terminal.Gui;
 namespace Terminal.Gui;
 
 
@@ -73,12 +74,9 @@ public partial class View
             _height = _frame.Height;
             _height = _frame.Height;
 
 
             // TODO: Figure out if the below can be optimized.
             // TODO: Figure out if the below can be optimized.
-            if (IsInitialized /*|| LayoutStyle == LayoutStyle.Absolute*/)
+            if (IsInitialized)
             {
             {
-                LayoutAdornments ();
-                SetTextFormatterSize ();
-                SetNeedsLayout ();
-                SetNeedsDisplay ();
+                OnResizeNeeded ();
             }
             }
         }
         }
     }
     }
@@ -102,12 +100,11 @@ public partial class View
             }
             }
 
 
             Point viewportOffset = super.GetViewportOffset ();
             Point viewportOffset = super.GetViewportOffset ();
-            viewportOffset.Offset (super.Frame.X, super.Frame.Y);
+            viewportOffset.Offset (super.Frame.X - super.Viewport.X, super.Frame.Y - super.Viewport.Y);
             ret.X += viewportOffset.X;
             ret.X += viewportOffset.X;
             ret.Y += viewportOffset.Y;
             ret.Y += viewportOffset.Y;
             super = super.SuperView;
             super = super.SuperView;
         }
         }
-
         return ret;
         return ret;
     }
     }
 
 
@@ -120,15 +117,18 @@ public partial class View
     /// <param name="y">Screen-relative row.</param>
     /// <param name="y">Screen-relative row.</param>
     public virtual Point ScreenToFrame (int x, int y)
     public virtual Point ScreenToFrame (int x, int y)
     {
     {
-        Point superViewBoundsOffset = SuperView?.GetViewportOffset () ?? Point.Empty;
+        Point superViewViewportOffset = SuperView?.GetViewportOffset () ?? Point.Empty;
+
         if (SuperView is null)
         if (SuperView is null)
         {
         {
-            superViewBoundsOffset.Offset (x - Frame.X, y - Frame.Y);
-            return superViewBoundsOffset;
-        }
+            superViewViewportOffset.Offset (x - Frame.X, y - Frame.Y);
 
 
-        var frame = SuperView.ScreenToFrame (x - superViewBoundsOffset.X, y - superViewBoundsOffset.Y);
+            return superViewViewportOffset;
+        }
+        superViewViewportOffset.Offset (-SuperView.Viewport.X, -SuperView.Viewport.Y);
+        Point frame = SuperView.ScreenToFrame (x - superViewViewportOffset.X, y - superViewViewportOffset.Y);
         frame.Offset (-Frame.X, -Frame.Y);
         frame.Offset (-Frame.X, -Frame.Y);
+
         return frame;
         return frame;
     }
     }
 
 
@@ -284,126 +284,6 @@ public partial class View
 
 
     #endregion Frame
     #endregion Frame
 
 
-    #region Viewport
-
-    private Point _viewportOffset;
-
-    /// <summary>
-    ///     Gets or sets the rectangle describing the portion of the View's content that is visible to the user.
-    ///     The viewport Location is relative to the top-left corner of the inner rectangle of the <see cref="Adornment"/>s.
-    ///     If the viewport Size is the sames as the <see cref="ContentSize"/> the Location will be <c>0, 0</c>.
-    ///     Non-zero values for the location indicate the visible area is offset into the View's virtual <see cref="ContentSize"/>.
-    /// </summary>
-    /// <value>The rectangle describing the location and size of the viewport into the View's virtual content, described by <see cref="ContentSize"/>.</value>
-    /// <remarks>
-    ///     <para>
-    ///         If <see cref="LayoutStyle"/> is <see cref="LayoutStyle.Computed"/> the value of Viewport is indeterminate until
-    ///         the view has been initialized ( <see cref="IsInitialized"/> is true) and <see cref="LayoutSubviews"/> has been
-    ///         called.
-    ///     </para>
-    ///     <para>
-    ///         Updates to the Viewport Size updates <see cref="Frame"/>, and has the same impact as updating the
-    ///         <see cref="Frame"/>.
-    ///     </para>
-    ///     <para>
-    ///         Altering the Viewport Size will eventually (when the view is next laid out) cause the
-    ///         <see cref="LayoutSubview(View, Rectangle)"/> and <see cref="OnDrawContent(Rectangle)"/> methods to be called.
-    ///     </para>
-    /// </remarks>
-    public virtual Rectangle Viewport
-    {
-        get
-        {
-#if DEBUG
-            if (LayoutStyle == LayoutStyle.Computed && !IsInitialized)
-            {
-                Debug.WriteLine (
-                                 $"WARNING: Viewport is being accessed before the View has been initialized. This is likely a bug in {this}"
-                                );
-            }
-#endif // DEBUG
-
-            if (Margin is null || Border is null || Padding is null)
-            {
-                // CreateAdornments has not been called yet.
-                return new (_viewportOffset, Frame.Size);
-            }
-
-            Thickness totalThickness = GetAdornmentsThickness ();
-
-            return new (_viewportOffset,
-                new (Math.Max (0, Frame.Size.Width - totalThickness.Horizontal),
-                     Math.Max (0, Frame.Size.Height - totalThickness.Vertical)));
-        }
-        set
-        {
-            _viewportOffset = value.Location;
-
-            Thickness totalThickness = GetAdornmentsThickness ();
-
-            Frame = Frame with
-            {
-                Size = new (
-                            value.Size.Width + totalThickness.Horizontal,
-                            value.Size.Height + totalThickness.Vertical)
-            };
-        }
-    }
-
-    /// <summary>Converts a <see cref="Viewport"/>-relative rectangle to a screen-relative rectangle.</summary>
-    public Rectangle ViewportToScreen (in Rectangle viewport)
-    {
-        // Translate bounds to Frame (our SuperView's Viewport-relative coordinates)
-        Rectangle screen = FrameToScreen ();
-        Point viewportOffset = GetViewportOffset ();
-        screen.Offset (viewportOffset.X + viewport.X, viewportOffset.Y + viewport.Y);
-
-        if (SuperView is { })
-        {
-            screen.Offset(-SuperView.Viewport.X, -SuperView.Viewport.Y);
-        }
-
-
-        return new (screen.Location, viewport.Size);
-    }
-
-    /// <summary>Converts a screen-relative coordinate to a Viewport-relative coordinate.</summary>
-    /// <returns>The coordinate relative to this view's <see cref="Viewport"/>.</returns>
-    /// <param name="x">Screen-relative column.</param>
-    /// <param name="y">Screen-relative row.</param>
-    public Point ScreenToViewport (int x, int y)
-    {
-        Point viewportOffset = GetViewportOffset ();
-        Point screen = ScreenToFrame (x, y);
-        screen.Offset (-viewportOffset.X + Viewport.X, -viewportOffset.Y + Viewport.Y);
-
-        return screen;
-    }
-
-    /// <summary>
-    ///     Helper to get the X and Y offset of the Viewport from the Frame. This is the sum of the Left and Top properties
-    ///     of <see cref="Margin"/>, <see cref="Border"/> and <see cref="Padding"/>.
-    /// </summary>
-    public Point GetViewportOffset ()
-    {
-        return Padding is null ? Point.Empty : Padding.Thickness.GetInside (Padding.Frame).Location;
-    }
-
-    private Size _contentSize;
-    /// <summary>
-    /// Gets or sets the size of the View's content. If the value is <c>Size.Empty</c> the size of the content is
-    /// the same as the size of the <see cref="Viewport"/>, and <c>Viewport.Location</c> will always be <c>0, 0</c>.
-    /// If a positive size is provided, <see cref="Viewport"/> describes the portion of the content currently visible
-    /// to the view. This enables virtual scrolling.
-    /// </summary>
-    public Size ContentSize
-    {
-        get => _contentSize == Size.Empty ? Viewport.Size : _contentSize;
-        set => _contentSize = value;
-    }
-
-    #endregion Viewport
-
     #region AutoSize
     #region AutoSize
 
 
     private bool _autoSize;
     private bool _autoSize;
@@ -657,25 +537,20 @@ public partial class View
 
 
     #endregion Layout Engine
     #endregion Layout Engine
 
 
-    internal bool LayoutNeeded { get; private set; } = true;
-
     /// <summary>
     /// <summary>
-    /// Indicates whether the specified SuperView-relative coordinates are within the View's <see cref="Frame"/>.
+    ///     Indicates whether the specified SuperView-relative coordinates are within the View's <see cref="Frame"/>.
     /// </summary>
     /// </summary>
     /// <param name="x">SuperView-relative X coordinate.</param>
     /// <param name="x">SuperView-relative X coordinate.</param>
     /// <param name="y">SuperView-relative Y coordinate.</param>
     /// <param name="y">SuperView-relative Y coordinate.</param>
     /// <returns><see langword="true"/> if the specified SuperView-relative coordinates are within the View.</returns>
     /// <returns><see langword="true"/> if the specified SuperView-relative coordinates are within the View.</returns>
-    public virtual bool Contains (int x, int y)
-    {
-        return Frame.Contains (x, y);
-    }
+    public virtual bool Contains (int x, int y) { return Frame.Contains (x, y); }
 
 
 #nullable enable
 #nullable enable
     /// <summary>Finds the first Subview of <paramref name="start"/> that is visible at the provided location.</summary>
     /// <summary>Finds the first Subview of <paramref name="start"/> that is visible at the provided location.</summary>
     /// <remarks>
     /// <remarks>
-    /// <para>
-    ///     Used to determine what view the mouse is over.
-    /// </para>
+    ///     <para>
+    ///         Used to determine what view the mouse is over.
+    ///     </para>
     /// </remarks>
     /// </remarks>
     /// <param name="start">The view to scope the search by.</param>
     /// <param name="start">The view to scope the search by.</param>
     /// <param name="x"><paramref name="start"/>.SuperView-relative X coordinate.</param>
     /// <param name="x"><paramref name="start"/>.SuperView-relative X coordinate.</param>
@@ -725,10 +600,10 @@ public partial class View
             {
             {
                 View nextStart = start.InternalSubviews [i];
                 View nextStart = start.InternalSubviews [i];
 
 
-                if (nextStart.Visible && nextStart.Contains (startOffsetX, startOffsetY))
+                if (nextStart.Visible && nextStart.Contains (startOffsetX + start.Viewport.X, startOffsetY + start.Viewport.Y))
                 {
                 {
                     // TODO: Remove recursion
                     // TODO: Remove recursion
-                    return FindDeepestView (nextStart, startOffsetX, startOffsetY) ?? nextStart;
+                    return FindDeepestView (nextStart, startOffsetX + start.Viewport.X, startOffsetY + start.Viewport.Y) ?? nextStart;
                 }
                 }
             }
             }
         }
         }
@@ -767,6 +642,7 @@ public partial class View
     {
     {
         int maxDimension;
         int maxDimension;
         View superView;
         View superView;
+        statusBar = null;
 
 
         if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
         if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
         {
         {
@@ -801,7 +677,8 @@ public partial class View
         }
         }
 
 
         //System.Diagnostics.Debug.WriteLine ($"nx:{nx}, rWidth:{rWidth}");
         //System.Diagnostics.Debug.WriteLine ($"nx:{nx}, rWidth:{rWidth}");
-        bool menuVisible, statusVisible;
+        bool menuVisible = false;
+        bool statusVisible = false;
 
 
         if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
         if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
         {
         {
@@ -811,12 +688,15 @@ public partial class View
         {
         {
             View t = viewToMove.SuperView;
             View t = viewToMove.SuperView;
 
 
-            while (t is not Toplevel)
+            while (t is { } and not Toplevel)
             {
             {
                 t = t.SuperView;
                 t = t.SuperView;
             }
             }
 
 
-            menuVisible = ((Toplevel)t).MenuBar?.Visible == true;
+            if (t is Toplevel toplevel)
+            {
+                menuVisible = toplevel.MenuBar?.Visible == true;
+            }
         }
         }
 
 
         if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
         if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
@@ -839,13 +719,16 @@ public partial class View
         {
         {
             View t = viewToMove.SuperView;
             View t = viewToMove.SuperView;
 
 
-            while (t is not Toplevel)
+            while (t is { } and not Toplevel)
             {
             {
                 t = t.SuperView;
                 t = t.SuperView;
             }
             }
 
 
-            statusVisible = ((Toplevel)t).StatusBar?.Visible == true;
-            statusBar = ((Toplevel)t).StatusBar;
+            if (t is Toplevel toplevel)
+            {
+                statusVisible = toplevel.StatusBar?.Visible == true;
+                statusBar = toplevel.StatusBar;
+            }
         }
         }
 
 
         if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
         if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
@@ -854,7 +737,7 @@ public partial class View
         }
         }
         else
         else
         {
         {
-            maxDimension = statusVisible ? viewToMove.SuperView.Frame.Height - 1 : viewToMove.SuperView.Frame.Height;
+            maxDimension = statusVisible ? viewToMove.SuperView.Viewport.Height - 1 : viewToMove.SuperView.Viewport.Height;
         }
         }
 
 
         if (superView.Margin is { } && superView == viewToMove.SuperView)
         if (superView.Margin is { } && superView == viewToMove.SuperView)
@@ -935,7 +818,7 @@ public partial class View
 
 
         foreach (View v in ordered)
         foreach (View v in ordered)
         {
         {
-            LayoutSubview (v, new (GetViewportOffset (), ContentSize));
+            LayoutSubview (v, ContentSize);
         }
         }
 
 
         // If the 'to' is rooted to 'from' and the layoutstyle is Computed it's a special-case.
         // If the 'to' is rooted to 'from' and the layoutstyle is Computed it's a special-case.
@@ -944,7 +827,7 @@ public partial class View
         {
         {
             foreach ((View from, View to) in edges)
             foreach ((View from, View to) in edges)
             {
             {
-                LayoutSubview (to, from.Frame);
+                LayoutSubview (to, from.ContentSize);
             }
             }
         }
         }
 
 
@@ -952,6 +835,12 @@ public partial class View
 
 
         OnLayoutComplete (new () { OldViewport = oldViewport });
         OnLayoutComplete (new () { OldViewport = oldViewport });
     }
     }
+    private void LayoutSubview (View v, Size contentSize)
+    {
+        v.SetRelativeLayout (contentSize);
+        v.LayoutSubviews ();
+        v.LayoutNeeded = false;
+    }
 
 
     /// <summary>Indicates that the view does not need to be laid out.</summary>
     /// <summary>Indicates that the view does not need to be laid out.</summary>
     protected void ClearLayoutNeeded () { LayoutNeeded = false; }
     protected void ClearLayoutNeeded () { LayoutNeeded = false; }
@@ -985,8 +874,8 @@ public partial class View
         // First try SuperView.Viewport, then Application.Top, then Driver.Viewport.
         // First try SuperView.Viewport, then Application.Top, then Driver.Viewport.
         // Finally, if none of those are valid, use int.MaxValue (for Unit tests).
         // Finally, if none of those are valid, use int.MaxValue (for Unit tests).
         Size contentSize = SuperView is { IsInitialized: true } ? SuperView.ContentSize :
         Size contentSize = SuperView is { IsInitialized: true } ? SuperView.ContentSize :
-                                   Application.Top is { } && Application.Top.IsInitialized ? Application.Top.ContentSize :
-                                   Application.Driver?.Viewport.Size ?? new (int.MaxValue, int.MaxValue);
+                           Application.Top is { } && Application.Top.IsInitialized ? Application.Top.ContentSize :
+                           Application.Driver?.Viewport.Size ?? new (int.MaxValue, int.MaxValue);
         SetRelativeLayout (contentSize);
         SetRelativeLayout (contentSize);
 
 
         // TODO: Determine what, if any of the below is actually needed here.
         // TODO: Determine what, if any of the below is actually needed here.
@@ -1003,6 +892,7 @@ public partial class View
             SetNeedsLayout ();
             SetNeedsLayout ();
         }
         }
     }
     }
+    internal bool LayoutNeeded { get; private set; } = true;
 
 
     /// <summary>
     /// <summary>
     ///     Sets the internal <see cref="LayoutNeeded"/> flag for this View and all of it's subviews and it's SuperView.
     ///     Sets the internal <see cref="LayoutNeeded"/> flag for this View and all of it's subviews and it's SuperView.
@@ -1027,13 +917,20 @@ public partial class View
     }
     }
 
 
     /// <summary>
     /// <summary>
-    ///     Applies the view's position (<see cref="X"/>, <see cref="Y"/>) and dimension (<see cref="Width"/>, and
-    ///     <see cref="Height"/>) to <see cref="Frame"/>, given the SuperView's ContentSize (nominally the
-    ///     same as <c>this.SuperView.ContentSize</c>).
+    ///     Adjusts <see cref="Frame"/> given the SuperView's ContentSize (nominally the same as
+    ///     <c>this.SuperView.ContentSize</c>)
+    ///     and the position (<see cref="X"/>, <see cref="Y"/>) and dimension (<see cref="Width"/>, and
+    ///     <see cref="Height"/>).
     /// </summary>
     /// </summary>
+    /// <remarks>
+    /// <para>
+    /// If <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, or <see cref="Height"/> are
+    /// absolute, they will be updated to reflect the new size and position of the view. Otherwise, they
+    /// are left unchanged.
+    /// </para>
+    /// </remarks>
     /// <param name="superviewContentSize">
     /// <param name="superviewContentSize">
-    ///     The size of the SuperView's content (nominally the same as
-    ///     <c>this.SuperView.ContentSize</c>).
+    ///     The size of the SuperView's content (nominally the same as <c>this.SuperView.ContentSize</c>).
     /// </param>
     /// </param>
     internal void SetRelativeLayout (Size superviewContentSize)
     internal void SetRelativeLayout (Size superviewContentSize)
     {
     {
@@ -1423,17 +1320,6 @@ public partial class View
         return result;
         return result;
     } // TopologicalSort
     } // TopologicalSort
 
 
-    private void LayoutSubview (View v, Rectangle viewport)
-    {
-        //if (v.LayoutStyle == LayoutStyle.Computed) {
-        v.SetRelativeLayout (viewport.Size);
-
-        //}
-
-        v.LayoutSubviews ();
-        v.LayoutNeeded = false;
-    }
-
     #region Diagnostics
     #region Diagnostics
 
 
     // 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

+ 40 - 12
Terminal.Gui/View/ViewDrawing.cs

@@ -85,7 +85,30 @@ public partial class View
 
 
     /// <summary>Clears <see cref="Viewport"/> with the normal background.</summary>
     /// <summary>Clears <see cref="Viewport"/> with the normal background.</summary>
     /// <remarks></remarks>
     /// <remarks></remarks>
-    public void Clear () { Clear (Viewport); }
+    public void Clear () { Clear (new (Point.Empty, Viewport.Size)); }
+
+    /// <summary>Clears the portion of the content that is visible with the normal background. If the content does not fill the Viewport,
+    /// the area not filled will be cleared with DarkGray.</summary>
+    /// <remarks></remarks>
+    public void ClearVisibleContent ()
+    {
+        if (Driver is null)
+        {
+            return;
+        }
+
+        Rectangle toClear = new (-Viewport.Location.X, -Viewport.Location.Y, ContentSize.Width, ContentSize.Height);
+
+        // If toClear does not fill the Viewport, we need to clear the area outside toClear with DarkGray.
+        // TODO: Need a configurable color for this
+        Attribute prev = Driver.SetAttribute (new Attribute (ColorName.DarkGray, ColorName.DarkGray));
+
+        Rectangle viewport = new (Point.Empty, Viewport.Size);
+        Driver.FillRect (ViewportToScreen (viewport));
+        Driver.SetAttribute (prev);
+
+        Clear (toClear);
+    }
 
 
     /// <summary>Clears the specified <see cref="Viewport"/>-relative rectangle with the normal background.</summary>
     /// <summary>Clears the specified <see cref="Viewport"/>-relative rectangle with the normal background.</summary>
     /// <remarks></remarks>
     /// <remarks></remarks>
@@ -100,7 +123,7 @@ public partial class View
         Attribute prev = Driver.SetAttribute (GetNormalColor ());
         Attribute prev = Driver.SetAttribute (GetNormalColor ());
 
 
         // Clamp the region to the bounds of the view
         // Clamp the region to the bounds of the view
-        viewport = Rectangle.Intersect (viewport, Viewport);
+        viewport = Rectangle.Intersect (viewport, new (Point.Empty, Viewport.Size));
         Driver.FillRect (ViewportToScreen (viewport));
         Driver.FillRect (ViewportToScreen (viewport));
         Driver.SetAttribute (prev);
         Driver.SetAttribute (prev);
     }
     }
@@ -124,7 +147,7 @@ public partial class View
         }
         }
 
 
         Rectangle previous = Driver.Clip;
         Rectangle previous = Driver.Clip;
-        Driver.Clip = Rectangle.Intersect (previous, ViewportToScreen (Viewport));
+        Driver.Clip = Rectangle.Intersect (previous, ViewportToScreen (Viewport with { Location = Point.Empty }));
 
 
         return previous;
         return previous;
     }
     }
@@ -321,12 +344,12 @@ public partial class View
 
 
     /// <summary>Moves the drawing cursor to the specified view-relative column and row in the view.</summary>
     /// <summary>Moves the drawing cursor to the specified view-relative column and row in the view.</summary>
     /// <remarks>
     /// <remarks>
-    /// <para>
-    ///     If the provided coordinates are outside the visible content area, this method does nothing.
-    /// </para>
-    /// <para>
-    ///     The top-left corner of the visible content area is <c>ViewPort.Location</c>.
-    /// </para>
+    ///     <para>
+    ///         If the provided coordinates are outside the visible content area, this method does nothing.
+    ///     </para>
+    ///     <para>
+    ///         The top-left corner of the visible content area is <c>ViewPort.Location</c>.
+    ///     </para>
     /// </remarks>
     /// </remarks>
     /// <param name="col">Column (viewport-relative).</param>
     /// <param name="col">Column (viewport-relative).</param>
     /// <param name="row">Row (viewport-relative).</param>
     /// <param name="row">Row (viewport-relative).</param>
@@ -406,7 +429,7 @@ public partial class View
         {
         {
             if (SuperView is { })
             if (SuperView is { })
             {
             {
-                Clear (viewport);
+                ClearVisibleContent ();
             }
             }
 
 
             if (!string.IsNullOrEmpty (TextFormatter.Text))
             if (!string.IsNullOrEmpty (TextFormatter.Text))
@@ -419,8 +442,13 @@ public partial class View
 
 
             // This should NOT clear 
             // This should NOT clear 
             // TODO: If the output is not in the Viewport, do nothing
             // TODO: If the output is not in the Viewport, do nothing
+            if (Viewport.Y != 0)
+            { }
+
+            var drawRect = new Rectangle (ContentToScreen (Point.Empty), ContentSize);
+
             TextFormatter?.Draw (
             TextFormatter?.Draw (
-                                 ViewportToScreen (new Rectangle(Point.Empty, ContentSize)),
+                                 drawRect,
                                  HasFocus ? GetFocusColor () : GetNormalColor (),
                                  HasFocus ? GetFocusColor () : GetNormalColor (),
                                  HasFocus ? ColorScheme.HotFocus : GetHotNormalColor (),
                                  HasFocus ? ColorScheme.HotFocus : GetHotNormalColor (),
                                  Rectangle.Empty
                                  Rectangle.Empty
@@ -609,7 +637,7 @@ public partial class View
 
 
         foreach (View subview in Subviews)
         foreach (View subview in Subviews)
         {
         {
-            subview.ClearNeedsDisplay();
+            subview.ClearNeedsDisplay ();
         }
         }
     }
     }
 }
 }

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

@@ -104,7 +104,7 @@ public partial class View
     {
     {
         if (!Enabled)
         if (!Enabled)
         {
         {
-            return true;
+            return false;
         }
         }
 
 
         if (!CanBeVisible (this))
         if (!CanBeVisible (this))

+ 261 - 0
Terminal.Gui/View/ViewScrolling.cs

@@ -0,0 +1,261 @@
+using System.Diagnostics;
+
+namespace Terminal.Gui;
+
+/// <summary>
+///     Controls the scrolling behavior of a view.
+/// </summary>
+[Flags]
+public enum ScrollSettings
+{
+    /// <summary>
+    ///     Default settings.
+    /// </summary>
+    Default = 0,
+
+    /// <summary>
+    ///     If set, does not restrict vertical scrolling to the content size.
+    /// </summary>
+    NoRestrictVertical = 1,
+
+    /// <summary>
+    ///     If set, does not restrict horizontal scrolling to the content size.
+    /// </summary>
+    NoRestrictHorizontal = 2,
+
+    /// <summary>
+    ///     If set, does not restrict either vertical or horizontal scrolling to the content size.
+    /// </summary>
+    NoRestrict = NoRestrictVertical | NoRestrictHorizontal
+}
+
+public partial class View
+{
+    #region Content Area
+
+    private Size _contentSize;
+
+    /// <summary>
+    ///     Gets or sets the size of the View's content. If the value is <c>Size.Empty</c> the size of the content is
+    ///     the same as the size of the <see cref="Viewport"/>, and <c>Viewport.Location</c> will always be <c>0, 0</c>.
+    ///     If a positive size is provided, <see cref="Viewport"/> describes the portion of the content currently visible
+    ///     to the view. This enables virtual scrolling.
+    /// </summary>
+    public Size ContentSize
+    {
+        get => _contentSize == Size.Empty ? Viewport.Size : _contentSize;
+        set => _contentSize = value;
+    }
+
+    /// <summary>
+    ///     Converts a content-relative location to a screen-relative location.
+    /// </summary>
+    /// <param name="location"></param>
+    /// <returns>The screen-relative location.</returns>
+    public Point ContentToScreen (in Point location)
+    {
+        // Translate to Viewport
+        Point viewportOffset = GetViewportOffset ();
+        Point contentRelativeToViewport = location;
+        contentRelativeToViewport.Offset (-Viewport.X, -Viewport.Y);
+
+        // Translate to Frame (our SuperView's Viewport-relative coordinates)
+        Rectangle screen = ViewportToScreen (new (contentRelativeToViewport, Size.Empty));
+
+        return screen.Location;
+    }
+
+    /// <summary>Converts a screen-relative coordinate to a Content-relative coordinate.</summary>
+    /// <remarks>
+    ///     Content-relative means relative to the top-left corner of the view's Content.
+    /// </remarks>
+    /// <param name="x">Column relative to the left side of the Content.</param>
+    /// <param name="y">Row relative to the top of the Content</param>
+    /// <returns>The coordinate relative to this view's Content.</returns>
+    public Point ScreenToContent (int x, int y)
+    {
+        Point viewportOffset = GetViewportOffset ();
+        Point screen = ScreenToFrame (x, y);
+        screen.Offset (Viewport.X - viewportOffset.X, Viewport.Y - viewportOffset.Y);
+
+        return screen;
+    }
+
+    #endregion Content Area
+
+    #region Viewport
+
+    /// <summary>
+    ///     Gets or sets the scrolling behavior of the view.
+    /// </summary>
+    public ScrollSettings ScrollSettings { get; set; }
+
+    private Point _viewportOffset;
+
+    /// <summary>
+    ///     Gets or sets the rectangle describing the portion of the View's content that is visible to the user.
+    ///     The viewport Location is relative to the top-left corner of the inner rectangle of the <see cref="Adornment"/>s.
+    ///     If the viewport Size is the sames as the <see cref="ContentSize"/> the Location will be <c>0, 0</c>.
+    ///     Non-zero values for the location indicate the visible area is offset into the View's virtual
+    ///     <see cref="ContentSize"/>.
+    /// </summary>
+    /// <value>
+    ///     The rectangle describing the location and size of the viewport into the View's virtual content, described by
+    ///     <see cref="ContentSize"/>.
+    /// </value>
+    /// <remarks>
+    ///     <para>
+    ///         If <see cref="LayoutStyle"/> is <see cref="LayoutStyle.Computed"/> the value of Viewport is indeterminate until
+    ///         the view has been initialized ( <see cref="IsInitialized"/> is true) and <see cref="LayoutSubviews"/> has been
+    ///         called.
+    ///     </para>
+    ///     <para>
+    ///         Updates to the Viewport Size updates <see cref="Frame"/>, and has the same impact as updating the
+    ///         <see cref="Frame"/>.
+    ///     </para>
+    ///     <para>
+    ///         Altering the Viewport Size will eventually (when the view is next laid out) cause the
+    ///         <see cref="LayoutSubview(View, Rectangle)"/> and <see cref="OnDrawContent(Rectangle)"/> methods to be called.
+    ///     </para>
+    /// </remarks>
+    public virtual Rectangle Viewport
+    {
+        get
+        {
+#if DEBUG
+            if (LayoutStyle == LayoutStyle.Computed && !IsInitialized)
+            {
+                Debug.WriteLine (
+                                 $"WARNING: Viewport is being accessed before the View has been initialized. This is likely a bug in {this}"
+                                );
+            }
+#endif // DEBUG
+
+            if (Margin is null || Border is null || Padding is null)
+            {
+                // CreateAdornments has not been called yet.
+                return new (_viewportOffset, Frame.Size);
+            }
+
+            Thickness totalThickness = GetAdornmentsThickness ();
+
+            return new (
+                        _viewportOffset,
+                        new (
+                             Math.Max (0, Frame.Size.Width - totalThickness.Horizontal),
+                             Math.Max (0, Frame.Size.Height - totalThickness.Vertical)));
+        }
+        set
+        {
+            _viewportOffset = value.Location;
+
+            Thickness totalThickness = GetAdornmentsThickness ();
+            Size newSize = new (value.Size.Width + totalThickness.Horizontal,
+                                value.Size.Height + totalThickness.Vertical);
+            if (newSize == Frame.Size)
+            {
+                SetNeedsLayout ();
+                return;
+            }
+
+            Frame = Frame with
+            {
+                Size = newSize
+            };
+        }
+    }
+
+    /// <summary>
+    ///     Converts a <see cref="Viewport"/>-relative location to a screen-relative location.
+    /// </summary>
+    /// <remarks>
+    ///     Viewport-relative means relative to the top-left corner of the inner rectangle of the <see cref="Padding"/>.
+    /// </remarks>
+    public Rectangle ViewportToScreen (in Rectangle location)
+    {
+        // Translate bounds to Frame (our SuperView's Viewport-relative coordinates)
+        Rectangle screen = FrameToScreen ();
+        Point viewportOffset = GetViewportOffset ();
+        screen.Offset (viewportOffset.X + location.X, viewportOffset.Y + location.Y);
+
+        return new (screen.Location, location.Size);
+    }
+
+    /// <summary>Converts a screen-relative coordinate to a Viewport-relative coordinate.</summary>
+    /// <returns>The coordinate relative to this view's <see cref="Viewport"/>.</returns>
+    /// <remarks>
+    ///     Viewport-relative means relative to the top-left corner of the inner rectangle of the <see cref="Padding"/>.
+    /// </remarks>
+    /// <param name="x">Column relative to the left side of the Viewport.</param>
+    /// <param name="y">Row relative to the top of the Viewport</param>
+    public Point ScreenToViewport (int x, int y)
+    {
+        Point viewportOffset = GetViewportOffset ();
+        Point screen = ScreenToFrame (x, y);
+        screen.Offset (-viewportOffset.X, -viewportOffset.Y);
+
+        return screen;
+    }
+
+    /// <summary>
+    ///     Helper to get the X and Y offset of the Viewport from the Frame. This is the sum of the Left and Top properties
+    ///     of <see cref="Margin"/>, <see cref="Border"/> and <see cref="Padding"/>.
+    /// </summary>
+    public Point GetViewportOffset () { return Padding is null ? Point.Empty : Padding.Thickness.GetInside (Padding.Frame).Location; }
+
+    /// <summary>
+    ///     Scrolls the view vertically by the specified number of rows.
+    /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///     </para>
+    /// </remarks>
+    /// <param name="rows"></param>
+    /// <returns><see langword="true"/> if the <see cref="Viewport"/> was changed.</returns>
+    public bool? ScrollVertical (int rows)
+    {
+        if (ContentSize == Size.Empty || ContentSize == Viewport.Size)
+        {
+            return false;
+        }
+
+        if (!ScrollSettings.HasFlag (ScrollSettings.NoRestrictVertical)
+            && (Viewport.Y + rows > ContentSize.Height - Viewport.Height || Viewport.Y + rows < 0))
+        {
+            return false;
+        }
+
+        Viewport = Viewport with { Y = Viewport.Y + rows };
+
+        return true;
+    }
+
+    /// <summary>
+    ///     Scrolls the view horizontally by the specified number of columns.
+    /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///     </para>
+    /// </remarks>
+    /// <param name="cols"></param>
+    /// <returns><see langword="true"/> if the <see cref="Viewport"/> was changed.</returns>
+    public bool? ScrollHorizontal (int cols)
+    {
+        if (ContentSize == Size.Empty || ContentSize == Viewport.Size)
+        {
+            return false;
+        }
+
+        if (!ScrollSettings.HasFlag (ScrollSettings.NoRestrictHorizontal)
+            && (Viewport.X + cols > ContentSize.Width - Viewport.Width || Viewport.X + cols < 0))
+        {
+            return false;
+        }
+
+        Viewport = Viewport with { X = Viewport.X + cols };
+
+        return true;
+    }
+
+    #endregion Viewport
+}

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

@@ -468,7 +468,7 @@ public partial class View
         {
         {
             return true;
             return true;
         }
         }
-
+        
         return false;
         return false;
     }
     }
 
 

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

@@ -324,7 +324,7 @@ public partial class View
                 return false;
                 return false;
             }
             }
 
 
-            sizeRequired = Viewport.Size;
+            sizeRequired = ContentSize;
 
 
             if (AutoSize || string.IsNullOrEmpty (TextFormatter.Text))
             if (AutoSize || string.IsNullOrEmpty (TextFormatter.Text))
             {
             {
@@ -338,9 +338,9 @@ public partial class View
 
 
                     // TODO: v2 - This uses frame.Width; it should only use Viewport
                     // TODO: v2 - This uses frame.Width; it should only use Viewport
                     if (_frame.Width < colWidth
                     if (_frame.Width < colWidth
-                        && (Width is null || (Viewport.Width >= 0 && Width is Dim.DimAbsolute && Width.Anchor (0) >= 0 && Width.Anchor (0) < colWidth)))
+                        && (Width is null || (ContentSize.Width >= 0 && Width is Dim.DimAbsolute && Width.Anchor (0) >= 0 && Width.Anchor (0) < colWidth)))
                     {
                     {
-                        sizeRequired = new (colWidth, Viewport.Height);
+                        sizeRequired = new (colWidth, ContentSize.Height);
 
 
                         return true;
                         return true;
                     }
                     }
@@ -349,7 +349,7 @@ public partial class View
                 default:
                 default:
                     if (_frame.Height < 1 && (Height is null || (Height is Dim.DimAbsolute && Height.Anchor (0) == 0)))
                     if (_frame.Height < 1 && (Height is null || (Height is Dim.DimAbsolute && Height.Anchor (0) == 0)))
                     {
                     {
-                        sizeRequired = new (Viewport.Width, 1);
+                        sizeRequired = new (ContentSize.Width, 1);
 
 
                         return true;
                         return true;
                     }
                     }

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

@@ -100,7 +100,7 @@ public class ColorPicker : View
 
 
         if (me.X > Viewport.Width || me.Y > Viewport.Height)
         if (me.X > Viewport.Width || me.Y > Viewport.Height)
         {
         {
-            return true;
+            return false;
         }
         }
 
 
         Cursor = new Point (me.X / _boxWidth, me.Y / _boxHeight);
         Cursor = new Point (me.X / _boxWidth, me.Y / _boxHeight);

+ 1 - 2
Terminal.Gui/Views/ScrollView.cs

@@ -194,7 +194,6 @@ public class ScrollView : View
             {
             {
                 // We're not initialized so we can't do anything fancy. Just cache value.
                 // We're not initialized so we can't do anything fancy. Just cache value.
                 _contentOffset = new Point (-Math.Abs (value.X), -Math.Abs (value.Y));
                 _contentOffset = new Point (-Math.Abs (value.X), -Math.Abs (value.Y));
-                ;
 
 
                 return;
                 return;
             }
             }
@@ -205,7 +204,7 @@ public class ScrollView : View
 
 
     /// <summary>Represents the contents of the data shown inside the scrollview</summary>
     /// <summary>Represents the contents of the data shown inside the scrollview</summary>
     /// <value>The size of the content.</value>
     /// <value>The size of the content.</value>
-    public Size ContentSize
+    public new Size ContentSize
     {
     {
         get => _contentSize;
         get => _contentSize;
         set
         set

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

@@ -260,7 +260,7 @@ public partial class Toplevel : View
         {
         {
             //Driver.SetAttribute (GetNormalColor ());
             //Driver.SetAttribute (GetNormalColor ());
             // TODO: It's bad practice for views to always clear. Defeats the purpose of clipping etc...
             // TODO: It's bad practice for views to always clear. Defeats the purpose of clipping etc...
-            Clear ();
+            ClearVisibleContent ();
             LayoutSubviews ();
             LayoutSubviews ();
             PositionToplevels ();
             PositionToplevels ();
 
 

+ 1 - 5
UICatalog/Scenarios/Adornments.cs

@@ -82,8 +82,6 @@ public class Adornments : Scenario
 
 
             //BorderStyle = LineStyle.None,
             //BorderStyle = LineStyle.None,
         };
         };
-        view.X = 36;
-        view.Y = 0;
         view.Width = Dim.Percent (60);
         view.Width = Dim.Percent (60);
         view.Height = Dim.Percent (80);
         view.Height = Dim.Percent (80);
 
 
@@ -452,15 +450,13 @@ public class Adornments : Scenario
                 Add (_diagCheckBox);
                 Add (_diagCheckBox);
                 _viewToEdit.X = Pos.Right (rbBorderStyle);
                 _viewToEdit.X = Pos.Right (rbBorderStyle);
                 _viewToEdit.Y = 0;
                 _viewToEdit.Y = 0;
-                _viewToEdit.Width = Dim.Fill ();
-                _viewToEdit.Height = Dim.Fill ();
                 Add (_viewToEdit);
                 Add (_viewToEdit);
 
 
                 _viewToEdit.LayoutComplete += (s, e) =>
                 _viewToEdit.LayoutComplete += (s, e) =>
                                               {
                                               {
                                                   if (ckbTitle.Checked == true)
                                                   if (ckbTitle.Checked == true)
                                                   {
                                                   {
-                                                      //_viewToEdit.Title = _origTitle;
+                                                      _viewToEdit.Title = _origTitle;
                                                   }
                                                   }
                                                   else
                                                   else
                                                   {
                                                   {

+ 52 - 23
UICatalog/Scenarios/VirtualContentScrolling.cs

@@ -12,18 +12,27 @@ public class VirtualScrolling : Scenario
 {
 {
     private ViewDiagnosticFlags _diagnosticFlags;
     private ViewDiagnosticFlags _diagnosticFlags;
 
 
-    public class VirtualDemoView : Window
+    public class VirtualDemoView : View
     {
     {
         public VirtualDemoView ()
         public VirtualDemoView ()
         {
         {
             Text = "Virtual Demo View Text. This is long text.\nThe second line.\n3\n4\n5th line.";
             Text = "Virtual Demo View Text. This is long text.\nThe second line.\n3\n4\n5th line.";
-            Arrangement = ViewArrangement.Fixed;
-            ContentSize = new Size (100, 50);
+            CanFocus = true;
+            Arrangement = ViewArrangement.Movable;
+            ColorScheme = Colors.ColorSchemes ["Toplevel"];
+            BorderStyle = LineStyle.Rounded;
+
+            // TODO: Add a way to set the scroll settings in the Scenario
+            ContentSize = new Size (100, 60);
+            //ScrollSettings = ScrollSettings.NoRestrict;
 
 
             // Things this view knows how to do
             // Things this view knows how to do
             AddCommand (Command.ScrollDown, () => ScrollVertical (1));
             AddCommand (Command.ScrollDown, () => ScrollVertical (1));
             AddCommand (Command.ScrollUp, () => ScrollVertical (-1));
             AddCommand (Command.ScrollUp, () => ScrollVertical (-1));
 
 
+            AddCommand (Command.ScrollRight, () => ScrollHorizontal (1));
+            AddCommand (Command.ScrollLeft, () => ScrollHorizontal (-1));
+
             //AddCommand (Command.PageUp, () => PageUp ());
             //AddCommand (Command.PageUp, () => PageUp ());
             //AddCommand (Command.PageDown, () => PageDown ());
             //AddCommand (Command.PageDown, () => PageDown ());
             //AddCommand (Command.TopHome, () => Home ());
             //AddCommand (Command.TopHome, () => Home ());
@@ -32,43 +41,58 @@ public class VirtualScrolling : Scenario
             // Default keybindings for all ListViews
             // Default keybindings for all ListViews
             KeyBindings.Add (Key.CursorUp, Command.ScrollUp);
             KeyBindings.Add (Key.CursorUp, Command.ScrollUp);
             KeyBindings.Add (Key.CursorDown, Command.ScrollDown);
             KeyBindings.Add (Key.CursorDown, Command.ScrollDown);
+            KeyBindings.Add (Key.CursorLeft, Command.ScrollLeft);
+            KeyBindings.Add (Key.CursorRight, Command.ScrollRight);
 
 
             //KeyBindings.Add (Key.PageUp, Command.PageUp);
             //KeyBindings.Add (Key.PageUp, Command.PageUp);
             //KeyBindings.Add (Key.PageDown, Command.PageDown);
             //KeyBindings.Add (Key.PageDown, Command.PageDown);
             //KeyBindings.Add (Key.Home, Command.TopHome);
             //KeyBindings.Add (Key.Home, Command.TopHome);
             //KeyBindings.Add (Key.End, Command.BottomEnd);
             //KeyBindings.Add (Key.End, Command.BottomEnd);
 
 
+            Border.Add (new Label () { X = 23 });
             LayoutComplete += VirtualDemoView_LayoutComplete;
             LayoutComplete += VirtualDemoView_LayoutComplete;
-        }
 
 
-        private void VirtualDemoView_LayoutComplete (object sender, LayoutEventArgs e)
-        {
-            Title = Viewport.ToString ();
-            SetNeedsDisplay ();
+            MouseEvent += VirtualDemoView_MouseEvent;
         }
         }
 
 
-        private bool? ScrollVertical (int rows)
+        private void VirtualDemoView_MouseEvent (object sender, MouseEventEventArgs e)
         {
         {
-            if (ContentSize == Size.Empty || ContentSize == Viewport.Size)
+            if (e.MouseEvent.Flags == MouseFlags.WheeledDown)
+            {
+                ScrollVertical (1);
+                return;
+            }
+            if (e.MouseEvent.Flags == MouseFlags.WheeledUp)
             {
             {
-                return true;
+                ScrollVertical (-1);
+
+                return;
             }
             }
 
 
-            if (Viewport.Y + rows < 0)
+            if (e.MouseEvent.Flags == MouseFlags.WheeledRight)
             {
             {
-                return true;
+                ScrollHorizontal (1);
+                return;
             }
             }
+            if (e.MouseEvent.Flags == MouseFlags.WheeledLeft)
+            {
+                ScrollHorizontal (-1);
 
 
-            Viewport = Viewport with { Y = Viewport.Y + rows };
+                return;
+            }
 
 
-            return true;
         }
         }
 
 
-        /// <inheritdoc />
-        public override void OnDrawContent (Rectangle viewport)
+        private void VirtualDemoView_LayoutComplete (object sender, LayoutEventArgs e)
         {
         {
-            base.OnDrawContent (viewport);
+            var status = Border.Subviews.OfType<Label> ().FirstOrDefault ();
+
+            if (status is { })
+            {
+                status.Title = $"Frame: {Frame}\n\nViewport: {Viewport}, ContentSize = {ContentSize}";
+            }
 
 
+            SetNeedsDisplay ();
         }
         }
     }
     }
 
 
@@ -76,7 +100,7 @@ public class VirtualScrolling : Scenario
     {
     {
         Application.Init ();
         Application.Init ();
 
 
-        var view = new VirtualDemoView { Title = "The _Window With Content" };
+        var view = new VirtualDemoView { Title = "Virtual Demo View" };
 
 
         var tf1 = new TextField { X = 20, Y = 7, Width = 10, Text = "TextField" };
         var tf1 = new TextField { X = 20, Y = 7, Width = 10, Text = "TextField" };
         var color = new ColorPicker { Title = "BG", BoxHeight = 1, BoxWidth = 1, X = Pos.AnchorEnd (11) };
         var color = new ColorPicker { Title = "BG", BoxHeight = 1, BoxWidth = 1, X = Pos.AnchorEnd (11) };
@@ -93,7 +117,7 @@ public class VirtualScrolling : Scenario
                                   };
                                   };
                               };
                               };
 
 
-        var button = new Button { X = Pos.Center (), Y = Pos.Center (), Text = "Press me!" };
+        var button = new Button { X = Pos.Center (), Y = Pos.Center (), Text = "Centered Button" };
 
 
         button.Accept += (s, e) =>
         button.Accept += (s, e) =>
                              MessageBox.Query (20, 7, "Hi", $"Am I a {view.GetType ().Name}?", "Yes", "No");
                              MessageBox.Query (20, 7, "Hi", $"Am I a {view.GetType ().Name}?", "Yes", "No");
@@ -101,10 +125,11 @@ public class VirtualScrolling : Scenario
         var label = new TextView
         var label = new TextView
         {
         {
             X = Pos.Center (),
             X = Pos.Center (),
-            Y = Pos.Bottom (button),
+            Y = 10,
             Title = "Title",
             Title = "Title",
             Text = "I have a 3 row top border.\nMy border inherits from the SuperView.",
             Text = "I have a 3 row top border.\nMy border inherits from the SuperView.",
-            Width = 40,
+            AllowsTab = false,
+            Width = 42,
             Height = 6 // TODO: Use Dim.Auto
             Height = 6 // TODO: Use Dim.Auto
         };
         };
         label.Border.Thickness = new (1, 3, 1, 1);
         label.Border.Thickness = new (1, 3, 1, 1);
@@ -121,7 +146,7 @@ public class VirtualScrolling : Scenario
         };
         };
 
 
         view.Margin.Data = "Margin";
         view.Margin.Data = "Margin";
-        view.Margin.Thickness = new (3);
+        view.Margin.Thickness = new (0);
 
 
         view.Border.Data = "Border";
         view.Border.Data = "Border";
         view.Border.Thickness = new (3);
         view.Border.Thickness = new (3);
@@ -143,6 +168,10 @@ public class VirtualScrolling : Scenario
 
 
         editor.Closed += (s, e) => View.Diagnostics = _diagnosticFlags;
         editor.Closed += (s, e) => View.Diagnostics = _diagnosticFlags;
 
 
+        //button.SetFocus ();
+
+        view.Width = Dim.Fill ();
+        view.Height = Dim.Fill ();
         Application.Run (editor);
         Application.Run (editor);
         editor.Dispose ();
         editor.Dispose ();
         Application.Shutdown ();
         Application.Shutdown ();

+ 53 - 88
UnitTests/Dialogs/MessageBoxTests.cs

@@ -242,7 +242,7 @@ public class MessageBoxTests
     {
     {
         int iterations = -1;
         int iterations = -1;
         var top = new Toplevel ();
         var top = new Toplevel ();
-        top.BorderStyle = LineStyle.Double;
+        top.BorderStyle = LineStyle.None;
         ((FakeDriver)Application.Driver).SetBufferSize (20, 10);
         ((FakeDriver)Application.Driver).SetBufferSize (20, 10);
 
 
         var btn =
         var btn =
@@ -273,21 +273,15 @@ public class MessageBoxTests
 
 
                                          TestHelpers.AssertDriverContentsWithFrameAre (
                                          TestHelpers.AssertDriverContentsWithFrameAre (
                                                                                        @$"
                                                                                        @$"
-╔══════════════════╗
-║┌────────────────┐║
-║│ffffffffffffffff│║
-║│ffffffffffffffff│║
-║│ffffffffffffffff│║
-║│       ff       │║
-║│                │║
-║│    {
-    btn
-}   │║
-║└────────────────┘║
-╚══════════════════╝",
+┌──────────────────┐
+│ffffffffffffffffff│
+│ffffffffffffffffff│
+│  ffffffffffffff  │
+│                  │
+│     {btn}    │
+└──────────────────┘",
                                                                                        _output
                                                                                        _output
                                                                                       );
                                                                                       );
-                                         Assert.Equal (new (20 - 2, 10 - 2), Application.Current.Frame.Size);
                                          Application.RequestStop ();
                                          Application.RequestStop ();
 
 
                                          // Really long text
                                          // Really long text
@@ -299,18 +293,16 @@ public class MessageBoxTests
 
 
                                          TestHelpers.AssertDriverContentsWithFrameAre (
                                          TestHelpers.AssertDriverContentsWithFrameAre (
                                                                                        @$"
                                                                                        @$"
-╔┌────────────────┐╗
-║│ffffffffffffffff│║
-║│ffffffffffffffff│║
-║│ffffffffffffffff│║
-║│ffffffffffffffff│║
-║│ffffffffffffffff│║
-║│ffffffffffffffff│║
-║│ffffffffffffffff│║
-║│    {
-    btn
-}   │║
-╚└────────────────┘╝",
+│ffffffffffffffffff│
+│ffffffffffffffffff│
+│ffffffffffffffffff│
+│ffffffffffffffffff│
+│ffffffffffffffffff│
+│ffffffffffffffffff│
+│ffffffffffffffffff│
+│ffffffffffffffffff│
+│ffffffffffffffffff│
+│     {btn}    │",
                                                                                        _output
                                                                                        _output
                                                                                       );
                                                                                       );
                                          Application.RequestStop ();
                                          Application.RequestStop ();
@@ -326,7 +318,7 @@ public class MessageBoxTests
     {
     {
         int iterations = -1;
         int iterations = -1;
         var top = new Toplevel ();
         var top = new Toplevel ();
-        top.BorderStyle = LineStyle.Double;
+        top.BorderStyle = LineStyle.None;
         ((FakeDriver)Application.Driver).SetBufferSize (20, 10);
         ((FakeDriver)Application.Driver).SetBufferSize (20, 10);
 
 
         var btn =
         var btn =
@@ -363,16 +355,12 @@ public class MessageBoxTests
 
 
                                          TestHelpers.AssertDriverContentsWithFrameAre (
                                          TestHelpers.AssertDriverContentsWithFrameAre (
                                                                                        @"
                                                                                        @"
-╔══════════════════╗
-║                  ║
 ────────────────────
 ────────────────────
 ff ff ff ff ff ff ff
 ff ff ff ff ff ff ff
                     
                     
       ⟦► btn ◄⟧     
       ⟦► btn ◄⟧     
 ────────────────────
 ────────────────────
-║                  ║
-║                  ║
-╚══════════════════╝",
+",
                                                                                        _output
                                                                                        _output
                                                                                       );
                                                                                       );
                                          Application.RequestStop ();
                                          Application.RequestStop ();
@@ -386,16 +374,12 @@ ff ff ff ff ff ff ff
 
 
                                          TestHelpers.AssertDriverContentsWithFrameAre (
                                          TestHelpers.AssertDriverContentsWithFrameAre (
                                                                                        @"
                                                                                        @"
-╔══════════════════╗
-║                  ║
 ────────────────────
 ────────────────────
 ffffffffffffffffffff
 ffffffffffffffffffff
                     
                     
       ⟦► btn ◄⟧     
       ⟦► btn ◄⟧     
 ────────────────────
 ────────────────────
-║                  ║
-║                  ║
-╚══════════════════╝",
+",
                                                                                        _output
                                                                                        _output
                                                                                       );
                                                                                       );
                                          Application.RequestStop ();
                                          Application.RequestStop ();
@@ -411,7 +395,7 @@ ffffffffffffffffffff
     {
     {
         int iterations = -1;
         int iterations = -1;
         var top = new Toplevel();
         var top = new Toplevel();
-        top.BorderStyle = LineStyle.Double;
+        top.BorderStyle = LineStyle.None;
         ((FakeDriver)Application.Driver).SetBufferSize (20, 10);
         ((FakeDriver)Application.Driver).SetBufferSize (20, 10);
 
 
         var btn =
         var btn =
@@ -446,20 +430,14 @@ ffffffffffffffffffff
                                      {
                                      {
                                          Application.Refresh ();
                                          Application.Refresh ();
 
 
-                                         TestHelpers.AssertDriverContentsWithFrameAre (
-                                                                                       @$"
-╔══════════════════╗
-║ ┌──────────────┐ ║
-║ │ff ff ff ff ff│ ║
-║ │ff ff ff ff ff│ ║
-║ │ff ff ff ff ff│ ║
-║ │    ff ff     │ ║
-║ │              │ ║
-║ │   {
-    btn
-}  │ ║
-║ └──────────────┘ ║
-╚══════════════════╝",
+                                         TestHelpers.AssertDriverContentsWithFrameAre (@$"
+┌─────────────────┐
+│ff ff ff ff ff ff│
+│ff ff ff ff ff ff│
+│ ff ff ff ff ff  │
+│                 │
+│    {btn}    │
+└─────────────────┘",
                                                                                        _output
                                                                                        _output
                                                                                       );
                                                                                       );
                                          Application.RequestStop ();
                                          Application.RequestStop ();
@@ -471,20 +449,17 @@ ffffffffffffffffffff
                                      {
                                      {
                                          Application.Refresh ();
                                          Application.Refresh ();
 
 
-                                         TestHelpers.AssertDriverContentsWithFrameAre (
-                                                                                       @$"
-╔┌────────────────┐╗
-║│ffffffffffffffff│║
-║│ffffffffffffffff│║
-║│ffffffffffffffff│║
-║│ffffffffffffffff│║
-║│ffffffffffffffff│║
-║│ffffffffffffffff│║
-║│ffffffffffffffff│║
-║│    {
-    btn
-}   │║
-╚└────────────────┘╝",
+                                         TestHelpers.AssertDriverContentsWithFrameAre (@$"
+│ffffffffffffffffff│
+│ffffffffffffffffff│
+│ffffffffffffffffff│
+│ffffffffffffffffff│
+│ffffffffffffffffff│
+│ffffffffffffffffff│
+│ffffffffffffffffff│
+│ffffffffffffffffff│
+│ffffffffffffffffff│
+│     {btn}    │",
                                                                                        _output
                                                                                        _output
                                                                                       );
                                                                                       );
                                          Application.RequestStop ();
                                          Application.RequestStop ();
@@ -492,6 +467,7 @@ ffffffffffffffffffff
                                  };
                                  };
 
 
         Application.Run (top);
         Application.Run (top);
+        top.Dispose ();
     }
     }
 
 
     [Fact]
     [Fact]
@@ -500,7 +476,7 @@ ffffffffffffffffffff
     {
     {
         int iterations = -1;
         int iterations = -1;
         var top = new Toplevel();
         var top = new Toplevel();
-        top.BorderStyle = LineStyle.Double;
+        top.BorderStyle = LineStyle.None;
         ((FakeDriver)Application.Driver).SetBufferSize (20, 10);
         ((FakeDriver)Application.Driver).SetBufferSize (20, 10);
 
 
         var btn =
         var btn =
@@ -530,16 +506,12 @@ ffffffffffffffffffff
 
 
                                          TestHelpers.AssertDriverContentsWithFrameAre (
                                          TestHelpers.AssertDriverContentsWithFrameAre (
                                                                                        @"
                                                                                        @"
-╔══════════════════╗
-║                  ║
 ────────────────────
 ────────────────────
 ffffffffffffffffffff
 ffffffffffffffffffff
                     
                     
       ⟦► btn ◄⟧     
       ⟦► btn ◄⟧     
 ────────────────────
 ────────────────────
-║                  ║
-║                  ║
-╚══════════════════╝",
+",
                                                                                        _output
                                                                                        _output
                                                                                       );
                                                                                       );
 
 
@@ -554,16 +526,12 @@ ffffffffffffffffffff
 
 
                                          TestHelpers.AssertDriverContentsWithFrameAre (
                                          TestHelpers.AssertDriverContentsWithFrameAre (
                                                                                        @"
                                                                                        @"
-╔══════════════════╗
-║                  ║
 ────────────────────
 ────────────────────
 ffffffffffffffffffff
 ffffffffffffffffffff
                     
                     
       ⟦► btn ◄⟧     
       ⟦► btn ◄⟧     
 ────────────────────
 ────────────────────
-║                  ║
-║                  ║
-╚══════════════════╝",
+",
                                                                                        _output
                                                                                        _output
                                                                                       );
                                                                                       );
 
 
@@ -663,7 +631,7 @@ ffffffffffffffffffff
     public void Size_No_With_Button ()
     public void Size_No_With_Button ()
     {
     {
         var top = new Toplevel ();
         var top = new Toplevel ();
-        top.BorderStyle = LineStyle.Double;
+        top.BorderStyle = LineStyle.None;
         int iterations = -1;
         int iterations = -1;
 
 
         var aboutMessage = new StringBuilder ();
         var aboutMessage = new StringBuilder ();
@@ -700,16 +668,12 @@ ffffffffffffffffffff
 
 
                                          TestHelpers.AssertDriverContentsWithFrameAre (
                                          TestHelpers.AssertDriverContentsWithFrameAre (
                                                                                        @$"
                                                                                        @$"
-╔══════════════════════════════════════════╗
-║┌────────────────────────────────────────┐║
-║│0123456789012345678901234567890123456789│║
-║│ https://github.com/gui-cs/Terminal.Gui │║
-║│                                        │║
-║│                {
-    btn
-}                │║
-║└────────────────────────────────────────┘║
-╚══════════════════════════════════════════╝
+ ┌────────────────────────────────────────┐
+ │0123456789012345678901234567890123456789│
+ │ https://github.com/gui-cs/Terminal.Gui │
+ │                                        │
+ │                {btn}                │
+ └────────────────────────────────────────┘
 ",
 ",
                                                                                        _output
                                                                                        _output
                                                                                       );
                                                                                       );
@@ -719,6 +683,7 @@ ffffffffffffffffffff
                                  };
                                  };
 
 
         Application.Run (top);
         Application.Run (top);
+        top.Dispose ();
     }
     }
 
 
     [Fact]
     [Fact]

+ 70 - 4
UnitTests/View/Layout/ScreenToTests.cs

@@ -82,7 +82,38 @@ public class ScreenToTests
         var view = new View { X = viewX, Y = viewY, Width = 5, Height = 5 };
         var view = new View { X = viewX, Y = viewY, Width = 5, Height = 5 };
         super.Add (view);
         super.Add (view);
 
 
-        Point actual = view.ScreenToFrame (x, y);
+        Point actual = view.ScreenToViewport (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 Adornments</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 ScreenToViewport_SuperHasAdornments_Positive_Viewport (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 };
+        view.ContentSize = new (6, 6);
+        super.Add (view);
+
+        view.Viewport = new (1, 1, 5, 5);
+
+        Point actual = view.ScreenToViewport (x, y);
         Assert.Equal (expectedX, actual.X);
         Assert.Equal (expectedX, actual.X);
         Assert.Equal (expectedY, actual.Y);
         Assert.Equal (expectedY, actual.Y);
     }
     }
@@ -108,6 +139,41 @@ public class ScreenToTests
         Assert.Equal (expectedY, actual.Y);
         Assert.Equal (expectedY, actual.Y);
     }
     }
 
 
+    /// <summary>Tests that screen to bounds mapping works correctly when the view has as superview it DOES have Adornments</summary>
+    [Theory]
+    [InlineData (0, 0, 0, 0, -2, -2)] // it's ok for the view to return coordinates outside of its bounds
+    [InlineData (0, 0, 1, 1, -1, -1)]
+    [InlineData (0, 0, 9, 9, 7, 7)]
+    //[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 ScreenToViewport_HasAdornments_Positive_Viewport (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,
+            BorderStyle = LineStyle.Single,
+        };
+        view.ContentSize = new (10, 10);
+        super.Add (view);
+
+        view.Viewport = view.Viewport with { Location = new (1, 1) };
+
+        Point actual = view.ScreenToViewport (x, y);
+        Assert.Equal (expectedX, actual.X);
+        Assert.Equal (expectedY, actual.Y);
+    }
+
     /// <summary>
     /// <summary>
     ///     Tests that screen to view mapping works correctly when the view has no superview and there ARE Adornments on the
     ///     Tests that screen to view mapping works correctly when the view has no superview and there ARE Adornments on the
     ///     view.
     ///     view.
@@ -121,7 +187,7 @@ public class ScreenToTests
     [InlineData (1, 1, 1, 1, 0, 0)]
     [InlineData (1, 1, 1, 1, 0, 0)]
     [InlineData (1, 1, 9, 9, 8, 8)]
     [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
     [InlineData (1, 1, 11, 11, 10, 10)] // it's ok for the view to return coordinates outside of its bounds
-    public void ScreenToView_NoSuper_HasAdornments (int viewX, int viewY, int x, int y, int expectedX, int expectedY)
+    public void ScreenToFrame_NoSuper_HasAdornments (int viewX, int viewY, int x, int y, int expectedX, int expectedY)
     {
     {
         var view = new View
         var view = new View
         {
         {
@@ -150,7 +216,7 @@ public class ScreenToTests
     [InlineData (1, 1, 1, 1, 0, 0)]
     [InlineData (1, 1, 1, 1, 0, 0)]
     [InlineData (1, 1, 9, 9, 8, 8)]
     [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
     [InlineData (1, 1, 11, 11, 10, 10)] // it's ok for the view to return coordinates outside of its bounds
-    public void ScreenToView_NoSuper_NoAdornments (int viewX, int viewY, int x, int y, int expectedX, int expectedY)
+    public void ScreenToFrame_NoSuper_NoAdornments (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 view = new View { X = viewX, Y = viewY, Width = 10, Height = 10 };
 
 
@@ -169,7 +235,7 @@ public class ScreenToTests
     [InlineData (1, 1, 1, 1, -1, -1)]
     [InlineData (1, 1, 1, 1, -1, -1)]
     [InlineData (1, 1, 9, 9, 7, 7)]
     [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
     [InlineData (1, 1, 11, 11, 9, 9)] // it's ok for the view to return coordinates outside of its bounds
-    public void ScreenToView_SuperHasAdornments (int viewX, int viewY, int x, int y, int expectedX, int expectedY)
+    public void ScreenToFrame_SuperHasAdornments (int viewX, int viewY, int x, int y, int expectedX, int expectedY)
     {
     {
         var super = new View
         var super = new View
         {
         {

+ 18 - 18
UnitTests/View/Layout/SetRelativeLayoutTests.cs

@@ -10,7 +10,7 @@ public class SetRelativeLayoutTests
     [Fact]
     [Fact]
     public void AbsolutePosDim_DontChange ()
     public void AbsolutePosDim_DontChange ()
     {
     {
-        var screen = new Rectangle (0, 0, 10, 15);
+        var screen = new Size (10, 15);
 
 
         var view = new View
         var view = new View
         {
         {
@@ -31,7 +31,7 @@ public class SetRelativeLayoutTests
     [Fact]
     [Fact]
     public void ComputedPosDim_StayComputed ()
     public void ComputedPosDim_StayComputed ()
     {
     {
-        var screen = new Rectangle (0, 0, 10, 15);
+        var screen = new Size (10, 15);
         var view = new View { X = 1, Y = 2, Width = Dim.Fill (), Height = Dim.Fill () };
         var view = new View { X = 1, Y = 2, Width = Dim.Fill (), Height = Dim.Fill () };
 
 
         Assert.Equal ("Absolute(1)", view.X.ToString ());
         Assert.Equal ("Absolute(1)", view.X.ToString ());
@@ -48,7 +48,7 @@ public class SetRelativeLayoutTests
     {
     {
         var view = new View { X = 1, Y = 1, Width = Dim.Fill (), Height = Dim.Fill () };
         var view = new View { X = 1, Y = 1, Width = Dim.Fill (), Height = Dim.Fill () };
 
 
-        view.SetRelativeLayout (new Rectangle (0, 0, 80, 25));
+        view.SetRelativeLayout (new Size ( 80, 25));
         Assert.Equal ("Fill(0)", view.Width.ToString ());
         Assert.Equal ("Fill(0)", view.Width.ToString ());
         Assert.Equal (1, view.Frame.X);
         Assert.Equal (1, view.Frame.X);
         Assert.Equal (1, view.Frame.Y);
         Assert.Equal (1, view.Frame.Y);
@@ -63,7 +63,7 @@ public class SetRelativeLayoutTests
         view.Y = 0;
         view.Y = 0;
         Assert.Equal ("Absolute(0)", view.X.ToString ());
         Assert.Equal ("Absolute(0)", view.X.ToString ());
         Assert.Equal ("Fill(0)", view.Width.ToString ());
         Assert.Equal ("Fill(0)", view.Width.ToString ());
-        view.SetRelativeLayout (new Rectangle (0, 0, 80, 25));
+        view.SetRelativeLayout (new Size ( 80, 25));
         Assert.Equal (0, view.Frame.X);
         Assert.Equal (0, view.Frame.X);
         Assert.Equal (0, view.Frame.Y);
         Assert.Equal (0, view.Frame.Y);
         Assert.Equal (80, view.Frame.Width);
         Assert.Equal (80, view.Frame.Width);
@@ -77,7 +77,7 @@ public class SetRelativeLayoutTests
     [Fact]
     [Fact]
     public void Fill_And_PosCenter ()
     public void Fill_And_PosCenter ()
     {
     {
-        var screen = new Rectangle (0, 0, 80, 25);
+        var screen = new Size (80, 25);
         var view = new View { X = Pos.Center (), Y = Pos.Center (), Width = Dim.Fill (), Height = Dim.Fill () };
         var view = new View { X = Pos.Center (), Y = Pos.Center (), Width = Dim.Fill (), Height = Dim.Fill () };
 
 
         view.SetRelativeLayout (screen);
         view.SetRelativeLayout (screen);
@@ -139,7 +139,7 @@ public class SetRelativeLayoutTests
     [Fact]
     [Fact]
     public void Fill_Pos_Outside_Bounds ()
     public void Fill_Pos_Outside_Bounds ()
     {
     {
-        var screen = new Rectangle (0, 0, 80, 25);
+        var screen = new Size (80, 25);
 
 
         var view = new View
         var view = new View
         {
         {
@@ -187,7 +187,7 @@ public class SetRelativeLayoutTests
     [Fact]
     [Fact]
     public void Fill_Pos_Within_Bounds ()
     public void Fill_Pos_Within_Bounds ()
     {
     {
-        var screen = new Rectangle (0, 0, 80, 25);
+        var screen = new Size (80, 25);
         var view = new View { X = 1, Y = 1, Width = 5, Height = 4 };
         var view = new View { X = 1, Y = 1, Width = 5, Height = 4 };
 
 
         view.SetRelativeLayout (screen);
         view.SetRelativeLayout (screen);
@@ -246,7 +246,7 @@ public class SetRelativeLayoutTests
             Height = 1
             Height = 1
         };
         };
         superView.Add (testView);
         superView.Add (testView);
-        testView.SetRelativeLayout (superView.Frame);
+        testView.SetRelativeLayout (superView.Frame.Size);
         Assert.Equal (4, testView.Frame.X);
         Assert.Equal (4, testView.Frame.X);
         Assert.Equal (4, testView.Frame.Y);
         Assert.Equal (4, testView.Frame.Y);
 
 
@@ -259,7 +259,7 @@ public class SetRelativeLayoutTests
             Height = 1
             Height = 1
         };
         };
         superView.Add (testView);
         superView.Add (testView);
-        testView.SetRelativeLayout (superView.Frame);
+        testView.SetRelativeLayout (superView.Frame.Size);
         Assert.Equal (5, testView.Frame.X);
         Assert.Equal (5, testView.Frame.X);
         Assert.Equal (5, testView.Frame.Y);
         Assert.Equal (5, testView.Frame.Y);
 
 
@@ -272,7 +272,7 @@ public class SetRelativeLayoutTests
             Height = 1
             Height = 1
         };
         };
         superView.Add (testView);
         superView.Add (testView);
-        testView.SetRelativeLayout (superView.Frame);
+        testView.SetRelativeLayout (superView.Frame.Size);
         Assert.Equal (5, testView.Frame.X);
         Assert.Equal (5, testView.Frame.X);
         Assert.Equal (5, testView.Frame.Y);
         Assert.Equal (5, testView.Frame.Y);
 
 
@@ -285,7 +285,7 @@ public class SetRelativeLayoutTests
             Height = 1
             Height = 1
         };
         };
         superView.Add (testView);
         superView.Add (testView);
-        testView.SetRelativeLayout (superView.Frame);
+        testView.SetRelativeLayout (superView.Frame.Size);
         Assert.Equal (6, testView.Frame.X);
         Assert.Equal (6, testView.Frame.X);
         Assert.Equal (6, testView.Frame.Y);
         Assert.Equal (6, testView.Frame.Y);
 
 
@@ -298,7 +298,7 @@ public class SetRelativeLayoutTests
             Height = 1
             Height = 1
         };
         };
         superView.Add (testView);
         superView.Add (testView);
-        testView.SetRelativeLayout (superView.Frame);
+        testView.SetRelativeLayout (superView.Frame.Size);
         Assert.Equal (5, testView.Frame.X);
         Assert.Equal (5, testView.Frame.X);
         Assert.Equal (5, testView.Frame.Y);
         Assert.Equal (5, testView.Frame.Y);
 
 
@@ -311,7 +311,7 @@ public class SetRelativeLayoutTests
             Height = 1
             Height = 1
         };
         };
         superView.Add (testView);
         superView.Add (testView);
-        testView.SetRelativeLayout (superView.Frame);
+        testView.SetRelativeLayout (superView.Frame.Size);
         Assert.Equal (5, testView.Frame.X);
         Assert.Equal (5, testView.Frame.X);
         Assert.Equal (5, testView.Frame.Y);
         Assert.Equal (5, testView.Frame.Y);
 
 
@@ -324,7 +324,7 @@ public class SetRelativeLayoutTests
             Height = 1
             Height = 1
         };
         };
         superView.Add (testView);
         superView.Add (testView);
-        testView.SetRelativeLayout (superView.Frame);
+        testView.SetRelativeLayout (superView.Frame.Size);
         Assert.Equal (5, testView.Frame.X);
         Assert.Equal (5, testView.Frame.X);
         Assert.Equal (5, testView.Frame.Y);
         Assert.Equal (5, testView.Frame.Y);
 
 
@@ -337,7 +337,7 @@ public class SetRelativeLayoutTests
             Height = 1
             Height = 1
         };
         };
         superView.Add (testView);
         superView.Add (testView);
-        testView.SetRelativeLayout (superView.Frame);
+        testView.SetRelativeLayout (superView.Frame.Size);
         Assert.Equal (6, testView.Frame.X);
         Assert.Equal (6, testView.Frame.X);
         Assert.Equal (6, testView.Frame.Y);
         Assert.Equal (6, testView.Frame.Y);
 
 
@@ -351,7 +351,7 @@ public class SetRelativeLayoutTests
         // SetRelativeLayout. In addition, the old test was bogus because it was testing the wrong thing (and 
         // SetRelativeLayout. In addition, the old test was bogus because it was testing the wrong thing (and 
         // because in v1 Pos.Center was broken in this regard!
         // because in v1 Pos.Center was broken in this regard!
 
 
-        var screen = new Rectangle (0, 0, 80, 25);
+        var screen = new Size (80, 25);
 
 
         var view = new View
         var view = new View
         {
         {
@@ -385,7 +385,7 @@ public class SetRelativeLayoutTests
     [Fact]
     [Fact]
     public void PosCombine_PosCenter_Plus_Absolute ()
     public void PosCombine_PosCenter_Plus_Absolute ()
     {
     {
-        var screen = new Rectangle (0, 0, 80, 25);
+        var screen = new Size (80, 25);
 
 
         var view = new View
         var view = new View
         {
         {
@@ -403,7 +403,7 @@ public class SetRelativeLayoutTests
     [Fact]
     [Fact]
     public void PosDimFunction ()
     public void PosDimFunction ()
     {
     {
-        var screen = new Rectangle (0, 0, 30, 1);
+        var screen = new Size (30, 1);
         var view = new View { Text = "abc", AutoSize = true }; // BUGBUG: AutoSize or Width must be set
         var view = new View { Text = "abc", AutoSize = true }; // BUGBUG: AutoSize or Width must be set
         view.X = Pos.AnchorEnd () - Pos.Function (GetViewWidth);
         view.X = Pos.AnchorEnd () - Pos.Function (GetViewWidth);
 
 

+ 312 - 15
UnitTests/View/Layout/ToScreenTests.cs

@@ -245,6 +245,303 @@ public class ToScreenTests (ITestOutputHelper output)
         Assert.Equal (expectedX, screen.X);
         Assert.Equal (expectedX, screen.X);
     }
     }
 
 
+    // ContentToScreen tests ----------------------
+
+    [Fact]
+    public void ContentToScreen_With_Positive_Content_Location ()
+    {
+        View view = new ()
+        {
+            X = 1,
+            Y = 1,
+            Width = 10,
+            Height = 10,
+            ContentSize = new (20, 20)
+        };
+
+        Point testPoint = new ( 0, 0);
+        Assert.Equal (new Point (1, 1), view.ContentToScreen (testPoint));
+    }
+
+    [Theory]
+    [InlineData (0, 0, 1)]
+    [InlineData (1, 0, 2)]
+    [InlineData (-1, 0, 0)]
+
+    [InlineData (0, 1, 2)]
+    [InlineData (1, 1, 3)]
+    [InlineData (-1, 1, 1)]
+
+    [InlineData (0, -1, 0)]
+    [InlineData (1, -1, 1)]
+    [InlineData (-1, -1, -1)]
+    public void ContentToScreen_NoSuperView_WithAdornments (int frameX, int contentX, int expectedX)
+    {
+        // We test with only X because Y is equivalent. Height/Width are irrelevant.
+        // Arrange
+        var frame = new Rectangle (frameX, 0, 10, 10);
+
+        var view = new View ();
+        view.Frame = frame;
+        view.ContentSize = new (20, 20);
+        view.BorderStyle = LineStyle.Single;
+
+        // Act
+        var screen = view.ContentToScreen (new (contentX, 0));
+
+        // Assert
+        Assert.Equal (expectedX, screen.X);
+    }
+
+    [Theory]
+    [InlineData (0, 0, 0)]
+    [InlineData (1, 0, 1)]
+    [InlineData (-1, 0, -1)]
+    [InlineData (11, 0, 11)]
+
+    [InlineData (0, 1, 1)]
+    [InlineData (1, 1, 2)]
+    [InlineData (-1, 1, 0)]
+    [InlineData (11, 1, 12)]
+
+    [InlineData (0, -1, -1)]
+    [InlineData (1, -1, 0)]
+    [InlineData (-1, -1, -2)]
+    [InlineData (11, -1, 10)]
+    public void ContentToScreen_SuperView_WithoutAdornments (int frameX, int contentX, int expectedX)
+    {
+        // We test with only X because Y is equivalent. Height/Width are irrelevant.
+        // Arrange
+        var frame = new Rectangle (frameX, 0, 10, 10);
+
+        var superView = new View ()
+        {
+            X = 0,
+            Y = 0,
+            Height = Dim.Fill (),
+            Width = Dim.Fill ()
+        };
+
+        var view = new View ();
+        view.Frame = frame;
+        view.ContentSize = new (20, 20);
+
+        superView.Add (view);
+        superView.LayoutSubviews ();
+
+        // Act
+        var screen = view.ContentToScreen (new (contentX, 0));
+
+        // Assert
+        Assert.Equal (expectedX, screen.X);
+    }
+
+    //[Theory]
+    //[InlineData (0, 0, 1)]
+    //[InlineData (1, 0, 2)]
+    //[InlineData (-1, 0, 0)]
+    //[InlineData (11, 0, 12)]
+
+    //[InlineData (0, 1, 2)]
+    //[InlineData (1, 1, 3)]
+    //[InlineData (-1, 1, 1)]
+    //[InlineData (11, 1, 13)]
+
+    //[InlineData (0, -1, 0)]
+    //[InlineData (1, -1, 1)]
+    //[InlineData (-1, -1, -1)]
+    //[InlineData (11, -1, 11)]
+    //public void ContentToScreen_SuperView_WithAdornments (int frameX, int ContentX, int expectedX)
+    //{
+    //    // We test with only X because Y is equivalent. Height/Width are irrelevant.
+    //    // Arrange
+    //    var frame = new Rectangle (frameX, 0, 10, 10);
+
+    //    var superView = new View ()
+    //    {
+    //        X = 0,
+    //        Y = 0,
+    //        Height = Dim.Fill (),
+    //        Width = Dim.Fill ()
+    //    };
+    //    superView.BorderStyle = LineStyle.Single;
+
+    //    var view = new View ();
+    //    view.Frame = frame;
+
+    //    superView.Add (view);
+    //    superView.LayoutSubviews ();
+
+    //    // Act
+    //    var screen = view.ContentToScreen (new (ContentX, 0, 0, 0));
+
+    //    // Assert
+    //    Assert.Equal (expectedX, screen.X);
+    //}
+
+    //[Theory]
+    //[InlineData (0, 0, 0)]
+    //[InlineData (1, 0, 1)]
+    //[InlineData (-1, 0, -1)]
+    //[InlineData (11, 0, 11)]
+
+    //[InlineData (0, 1, 1)]
+    //[InlineData (1, 1, 2)]
+    //[InlineData (-1, 1, 0)]
+    //[InlineData (11, 1, 12)]
+
+    //[InlineData (0, -1, -1)]
+    //[InlineData (1, -1, 0)]
+    //[InlineData (-1, -1, -2)]
+    //[InlineData (11, -1, 10)]
+    //public void ContentToScreen_NestedSuperView_WithoutAdornments (int frameX, int ContentX, int expectedX)
+    //{
+    //    // We test with only X because Y is equivalent. Height/Width are irrelevant.
+    //    // Arrange
+    //    var frame = new Rectangle (frameX, 0, 10, 10);
+
+    //    var superSuperView = new View ()
+    //    {
+    //        X = 0,
+    //        Y = 0,
+    //        Height = Dim.Fill (),
+    //        Width = Dim.Fill ()
+    //    };
+
+    //    var superView = new View ()
+    //    {
+    //        X = 0,
+    //        Y = 0,
+    //        Height = Dim.Fill (),
+    //        Width = Dim.Fill ()
+    //    };
+
+    //    superSuperView.Add (superView);
+
+    //    var view = new View ();
+    //    view.Frame = frame;
+
+    //    superView.Add (view);
+    //    superView.LayoutSubviews ();
+
+    //    // Act
+    //    var screen = view.ContentToScreen (new (ContentX, 0, 0, 0));
+
+    //    // Assert
+    //    Assert.Equal (expectedX, screen.X);
+    //}
+
+    //[Theory]
+    //[InlineData (0, 0, 2)]
+    //[InlineData (1, 0, 3)]
+    //[InlineData (-1, 0, 1)]
+    //[InlineData (11, 0, 13)]
+
+    //[InlineData (0, 1, 3)]
+    //[InlineData (1, 1, 4)]
+    //[InlineData (-1, 1, 2)]
+    //[InlineData (11, 1, 14)]
+
+    //[InlineData (0, -1, 1)]
+    //[InlineData (1, -1, 2)]
+    //[InlineData (-1, -1, 0)]
+    //[InlineData (11, -1, 12)]
+    //public void ContentToScreen_NestedSuperView_WithAdornments (int frameX, int ContentX, int expectedX)
+    //{
+    //    // We test with only X because Y is equivalent. Height/Width are irrelevant.
+    //    // Arrange
+    //    var frame = new Rectangle (frameX, 0, 10, 10);
+
+    //    var superSuperView = new View ()
+    //    {
+    //        X = 0,
+    //        Y = 0,
+    //        Height = Dim.Fill (),
+    //        Width = Dim.Fill ()
+    //    };
+    //    superSuperView.BorderStyle = LineStyle.Single;
+
+    //    var superView = new View ()
+    //    {
+    //        X = 0,
+    //        Y = 0,
+    //        Height = Dim.Fill (),
+    //        Width = Dim.Fill ()
+    //    };
+
+    //    superSuperView.Add (superView);
+    //    superView.BorderStyle = LineStyle.Single;
+
+    //    var view = new View ();
+    //    view.Frame = frame;
+
+    //    superView.Add (view);
+    //    superView.LayoutSubviews ();
+
+    //    // Act
+    //    var screen = view.ContentToScreen (new (ContentX, 0, 0, 0));
+
+    //    // Assert
+    //    Assert.Equal (expectedX, screen.X);
+    //}
+
+
+    //[Theory]
+    //[InlineData (0, 0, 3)]
+    //[InlineData (1, 0, 4)]
+    //[InlineData (-1, 0, 2)]
+    //[InlineData (11, 0, 14)]
+
+    //[InlineData (0, 1, 4)]
+    //[InlineData (1, 1, 5)]
+    //[InlineData (-1, 1, 3)]
+    //[InlineData (11, 1, 15)]
+
+    //[InlineData (0, -1, 2)]
+    //[InlineData (1, -1, 3)]
+    //[InlineData (-1, -1, 1)]
+    //[InlineData (11, -1, 13)]
+    //public void ContentToScreen_Positive_NestedSuperView_WithAdornments (int frameX, int testX, int expectedX)
+    //{
+    //    // We test with only X because Y is equivalent. Height/Width are irrelevant.
+    //    // Arrange
+    //    var frame = new Rectangle (frameX, 0, 10, 10);
+
+    //    var superSuperView = new View ()
+    //    {
+    //        X = 0,
+    //        Y = 0,
+    //        Height = Dim.Fill (),
+    //        Width = Dim.Fill ()
+    //    };
+    //    superSuperView.BorderStyle = LineStyle.Single;
+
+    //    var superView = new View ()
+    //    {
+    //        X = 0,
+    //        Y = 0,
+    //        Height = Dim.Fill (),
+    //        Width = Dim.Fill ()
+    //    };
+
+    //    superSuperView.Add (superView);
+    //    superView.BorderStyle = LineStyle.Single;
+
+    //    var view = new View ();
+    //    view.Frame = frame;
+    //    view.ContentSize = new (11, 11);
+    //    view.Content = view.Content with { Location = new (1, 1) };
+
+    //    superView.Add (view);
+    //    superView.LayoutSubviews ();
+
+    //    // Act
+    //    var screen = view.ContentToScreen (new (testX, 0, 0, 0));
+
+    //    // Assert
+    //    Assert.Equal (expectedX, screen.X);
+    //}
+
     // ViewportToScreen tests ----------------------
     // ViewportToScreen tests ----------------------
 
 
     [Fact]
     [Fact]
@@ -260,7 +557,7 @@ public class ToScreenTests (ITestOutputHelper output)
         Assert.Equal (new Point (0, 0), view.ViewportToScreen (testRect).Location);
         Assert.Equal (new Point (0, 0), view.ViewportToScreen (testRect).Location);
         view.Viewport = view.Viewport with { Location = new Point (1, 1) };
         view.Viewport = view.Viewport with { Location = new Point (1, 1) };
         Assert.Equal (new Rectangle (1, 1, 10, 10), view.Viewport);
         Assert.Equal (new Rectangle (1, 1, 10, 10), view.Viewport);
-        Assert.Equal (new Point (-1, -1), view.ViewportToScreen (testRect).Location);
+        Assert.Equal (new Point (0, 0), view.ViewportToScreen (testRect).Location);
     }
     }
 
 
     [Theory]
     [Theory]
@@ -509,20 +806,20 @@ public class ToScreenTests (ITestOutputHelper output)
 
 
 
 
     [Theory]
     [Theory]
-    [InlineData (0, 0, 3)]
-    [InlineData (1, 0, 4)]
-    [InlineData (-1, 0, 2)]
-    [InlineData (11, 0, 14)]
-
-    [InlineData (0, 1, 4)]
-    [InlineData (1, 1, 5)]
-    [InlineData (-1, 1, 3)]
-    [InlineData (11, 1, 15)]
-
-    [InlineData (0, -1, 2)]
-    [InlineData (1, -1, 3)]
-    [InlineData (-1, -1, 1)]
-    [InlineData (11, -1, 13)]
+    [InlineData (0, 0, 2)]
+    [InlineData (1, 0, 3)]
+    [InlineData (-1, 0, 1)]
+    [InlineData (11, 0, 13)]
+
+    [InlineData (0, 1, 3)]
+    [InlineData (1, 1, 4)]
+    [InlineData (-1, 1, 2)]
+    [InlineData (11, 1, 14)]
+
+    [InlineData (0, -1, 1)]
+    [InlineData (1, -1, 2)]
+    [InlineData (-1, -1, 0)]
+    [InlineData (11, -1, 12)]
     public void ViewportToScreen_Positive_NestedSuperView_WithAdornments (int frameX, int testX, int expectedX)
     public void ViewportToScreen_Positive_NestedSuperView_WithAdornments (int frameX, int testX, int expectedX)
     {
     {
         // We test with only X because Y is equivalent. Height/Width are irrelevant.
         // We test with only X because Y is equivalent. Height/Width are irrelevant.

+ 2 - 2
UnitTests/View/Layout/ViewportTests.cs

@@ -257,14 +257,14 @@ public class ViewportTests (ITestOutputHelper output)
     }
     }
 
 
     [Fact]
     [Fact]
-    public void ContentSize_Empty_ByDefault ()
+    public void ContentSize_Matches_ViewportSize_If_Not_Set ()
     {
     {
         View view = new ()
         View view = new ()
         {
         {
             Width = 1,
             Width = 1,
             Height = 1
             Height = 1
         };
         };
-        Assert.Equal (Size.Empty, view.ContentSize);
+        Assert.Equal (view.Viewport.Size, view.ContentSize);
     }
     }
 
 
 }
 }

+ 1 - 1
UnitTests/View/Text/AutoSizeFalseTests.cs

@@ -216,7 +216,7 @@ public class AutoSizeFalseTests
     {
     {
         var view = new View { Width = Dim.Fill (), Height = Dim.Fill () };
         var view = new View { Width = Dim.Fill (), Height = Dim.Fill () };
 
 
-        view.SetRelativeLayout (new (0, 0, 10, 4));
+        view.SetRelativeLayout (new (10, 4));
         Assert.Equal (new (0, 0, 10, 4), view.Frame);
         Assert.Equal (new (0, 0, 10, 4), view.Frame);
         Assert.Equal (new (0, 0), view.TextFormatter.Size);
         Assert.Equal (new (0, 0), view.TextFormatter.Size);
         Assert.False (view.AutoSize);
         Assert.False (view.AutoSize);

+ 1 - 1
UnitTests/View/Text/AutoSizeTrueTests.cs

@@ -2742,7 +2742,7 @@ Y
         Assert.Equal ("Absolute(20)", view.Width.ToString ());
         Assert.Equal ("Absolute(20)", view.Width.ToString ());
         Assert.Equal ("Absolute(1)", view.Height.ToString ());
         Assert.Equal ("Absolute(1)", view.Height.ToString ());
 
 
-        view.SetRelativeLayout (new (0, 0, 25, 5));
+        view.SetRelativeLayout (new (25, 5));
 
 
         Assert.True (view.AutoSize);
         Assert.True (view.AutoSize);
         Assert.Equal (LayoutStyle.Absolute, view.LayoutStyle);
         Assert.Equal (LayoutStyle.Absolute, view.LayoutStyle);

+ 1 - 1
UnitTests/Views/TextViewTests.cs

@@ -7675,7 +7675,7 @@ This is the second line.
                                                      );
                                                      );
 
 
         ((FakeDriver)Application.Driver).SetBufferSize (6, 25);
         ((FakeDriver)Application.Driver).SetBufferSize (6, 25);
-        tv.SetRelativeLayout (Application.Driver.Viewport);
+        tv.SetRelativeLayout (Application.Driver.Viewport.Size);
         tv.Draw ();
         tv.Draw ();
         Assert.Equal (new Point (4, 2), tv.CursorPosition);
         Assert.Equal (new Point (4, 2), tv.CursorPosition);
         Assert.Equal (new Point (12, 0), cp);
         Assert.Equal (new Point (12, 0), cp);