Răsfoiți Sursa

Merged v2_develop

Tig 1 an în urmă
părinte
comite
4f59a64b2c

+ 2 - 2
Terminal.Gui/Application.cs

@@ -526,7 +526,7 @@ public static partial class Application
         }
         }
 
 
         //if (Toplevel.LayoutStyle == LayoutStyle.Computed) {
         //if (Toplevel.LayoutStyle == LayoutStyle.Computed) {
-        toplevel.SetRelativeLayout (Driver.Viewport);
+        toplevel.SetRelativeLayout (Driver.Viewport.Size);
 
 
         //}
         //}
 
 
@@ -1310,7 +1310,7 @@ public static partial class Application
 
 
         foreach (Toplevel t in _topLevels)
         foreach (Toplevel t in _topLevels)
         {
         {
-            t.SetRelativeLayout (Rectangle.Empty with { Size = args.Size });
+            t.SetRelativeLayout (args.Size);
             t.LayoutSubviews ();
             t.LayoutSubviews ();
             t.PositionToplevels ();
             t.PositionToplevels ();
             t.OnSizeChanging (new (args.Size));
             t.OnSizeChanging (new (args.Size));

+ 35 - 24
Terminal.Gui/View/Layout/ViewLayout.cs

@@ -356,7 +356,13 @@ public partial class View
         // Translate bounds to Frame (our SuperView's Viewport-relative coordinates)
         // Translate bounds to Frame (our SuperView's Viewport-relative coordinates)
         Rectangle screen = FrameToScreen ();
         Rectangle screen = FrameToScreen ();
         Point viewportOffset = GetViewportOffset ();
         Point viewportOffset = GetViewportOffset ();
-        screen.Offset (viewportOffset.X + Viewport.X + viewport.X, viewportOffset.Y + Viewport.Y + viewport.Y);
+        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);
         return new (screen.Location, viewport.Size);
     }
     }
@@ -369,7 +375,7 @@ public partial class View
     {
     {
         Point viewportOffset = GetViewportOffset ();
         Point viewportOffset = GetViewportOffset ();
         Point screen = ScreenToFrame (x, y);
         Point screen = ScreenToFrame (x, y);
-        screen.Offset (-viewportOffset.X, -viewportOffset.Y);
+        screen.Offset (-viewportOffset.X + Viewport.X, -viewportOffset.Y + Viewport.Y);
 
 
         return screen;
         return screen;
     }
     }
@@ -383,13 +389,18 @@ public partial class View
         return Padding is null ? Point.Empty : Padding.Thickness.GetInside (Padding.Frame).Location;
         return Padding is null ? Point.Empty : Padding.Thickness.GetInside (Padding.Frame).Location;
     }
     }
 
 
+    private Size _contentSize;
     /// <summary>
     /// <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
     /// 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>.
     /// 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
     /// If a positive size is provided, <see cref="Viewport"/> describes the portion of the content currently visible
     /// to the view. This enables virtual scrolling.
     /// to the view. This enables virtual scrolling.
     /// </summary>
     /// </summary>
-    public Size ContentSize { get; set; }
+    public Size ContentSize
+    {
+        get => _contentSize == Size.Empty ? Viewport.Size : _contentSize;
+        set => _contentSize = value;
+    }
 
 
     #endregion Viewport
     #endregion Viewport
 
 
@@ -911,8 +922,8 @@ public partial class View
 
 
         LayoutAdornments ();
         LayoutAdornments ();
 
 
-        Rectangle oldBounds = Viewport;
-        OnLayoutStarted (new () { OldBounds = oldBounds });
+        Rectangle oldViewport = Viewport;
+        OnLayoutStarted (new () { OldViewport = oldViewport });
 
 
         SetTextFormatterSize ();
         SetTextFormatterSize ();
 
 
@@ -924,7 +935,7 @@ public partial class View
 
 
         foreach (View v in ordered)
         foreach (View v in ordered)
         {
         {
-            LayoutSubview (v, new (GetViewportOffset (), Viewport.Size));
+            LayoutSubview (v, new (GetViewportOffset (), 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.
@@ -939,7 +950,7 @@ public partial class View
 
 
         LayoutNeeded = false;
         LayoutNeeded = false;
 
 
-        OnLayoutComplete (new () { OldBounds = oldBounds });
+        OnLayoutComplete (new () { OldViewport = oldViewport });
     }
     }
 
 
     /// <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>
@@ -973,10 +984,10 @@ public partial class View
         // TODO: Until then leave it `internal` and non-virtual
         // TODO: Until then leave it `internal` and non-virtual
         // 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).
-        Rectangle relativeBounds = SuperView is { IsInitialized: true } ? SuperView.Viewport :
-                                   Application.Top is { } && Application.Top.IsInitialized ? Application.Top.Viewport :
-                                   Application.Driver?.Viewport ?? new Rectangle (0, 0, int.MaxValue, int.MaxValue);
-        SetRelativeLayout (relativeBounds);
+        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);
+        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.
         if (IsInitialized)
         if (IsInitialized)
@@ -1017,14 +1028,14 @@ public partial class View
 
 
     /// <summary>
     /// <summary>
     ///     Applies the view's position (<see cref="X"/>, <see cref="Y"/>) and dimension (<see cref="Width"/>, and
     ///     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 a rectangle describing the SuperView's Viewport (nominally the
-    ///     same as <c>this.SuperView.Viewport</c>).
+    ///     <see cref="Height"/>) to <see cref="Frame"/>, given the SuperView's ContentSize (nominally the
+    ///     same as <c>this.SuperView.ContentSize</c>).
     /// </summary>
     /// </summary>
-    /// <param name="superviewBounds">
-    ///     The rectangle describing the SuperView's Viewport (nominally the same as
-    ///     <c>this.SuperView.Viewport</c>).
+    /// <param name="superviewContentSize">
+    ///     The size of the SuperView's content (nominally the same as
+    ///     <c>this.SuperView.ContentSize</c>).
     /// </param>
     /// </param>
-    internal void SetRelativeLayout (Rectangle superviewBounds)
+    internal void SetRelativeLayout (Size superviewContentSize)
     {
     {
         Debug.Assert (_x is { });
         Debug.Assert (_x is { });
         Debug.Assert (_y is { });
         Debug.Assert (_y is { });
@@ -1052,7 +1063,7 @@ public partial class View
         // This method is called recursively if pos is Pos.PosCombine
         // This method is called recursively if pos is Pos.PosCombine
         (int newLocation, int newDimension) GetNewLocationAndDimension (
         (int newLocation, int newDimension) GetNewLocationAndDimension (
             bool width,
             bool width,
-            Rectangle superviewBounds,
+            Size superviewContentSize,
             Pos pos,
             Pos pos,
             Dim dim,
             Dim dim,
             int autosizeDimension
             int autosizeDimension
@@ -1114,7 +1125,7 @@ public partial class View
             }
             }
 
 
             int newDimension, newLocation;
             int newDimension, newLocation;
-            int superviewDimension = width ? superviewBounds.Width : superviewBounds.Height;
+            int superviewDimension = width ? superviewContentSize.Width : superviewContentSize.Height;
 
 
             // Determine new location
             // Determine new location
             switch (pos)
             switch (pos)
@@ -1138,7 +1149,7 @@ public partial class View
 
 
                     (left, newDimension) = GetNewLocationAndDimension (
                     (left, newDimension) = GetNewLocationAndDimension (
                                                                        width,
                                                                        width,
-                                                                       superviewBounds,
+                                                                       superviewContentSize,
                                                                        combine._left,
                                                                        combine._left,
                                                                        dim,
                                                                        dim,
                                                                        autosizeDimension
                                                                        autosizeDimension
@@ -1146,7 +1157,7 @@ public partial class View
 
 
                     (right, newDimension) = GetNewLocationAndDimension (
                     (right, newDimension) = GetNewLocationAndDimension (
                                                                         width,
                                                                         width,
-                                                                        superviewBounds,
+                                                                        superviewContentSize,
                                                                         combine._right,
                                                                         combine._right,
                                                                         dim,
                                                                         dim,
                                                                         autosizeDimension
                                                                         autosizeDimension
@@ -1188,10 +1199,10 @@ public partial class View
         }
         }
 
 
         // horizontal/width
         // horizontal/width
-        (newX, newW) = GetNewLocationAndDimension (true, superviewBounds, _x, _width, autosize.Width);
+        (newX, newW) = GetNewLocationAndDimension (true, superviewContentSize, _x, _width, autosize.Width);
 
 
         // vertical/height
         // vertical/height
-        (newY, newH) = GetNewLocationAndDimension (false, superviewBounds, _y, _height, autosize.Height);
+        (newY, newH) = GetNewLocationAndDimension (false, superviewContentSize, _y, _height, autosize.Height);
 
 
         Rectangle r = new (newX, newY, newW, newH);
         Rectangle r = new (newX, newY, newW, newH);
 
 
@@ -1415,7 +1426,7 @@ public partial class View
     private void LayoutSubview (View v, Rectangle viewport)
     private void LayoutSubview (View v, Rectangle viewport)
     {
     {
         //if (v.LayoutStyle == LayoutStyle.Computed) {
         //if (v.LayoutStyle == LayoutStyle.Computed) {
-        v.SetRelativeLayout (viewport);
+        v.SetRelativeLayout (viewport.Size);
 
 
         //}
         //}
 
 

+ 3 - 2
Terminal.Gui/View/ViewDrawing.cs

@@ -418,8 +418,9 @@ public partial class View
             }
             }
 
 
             // This should NOT clear 
             // This should NOT clear 
+            // TODO: If the output is not in the Viewport, do nothing
             TextFormatter?.Draw (
             TextFormatter?.Draw (
-                                 ViewportToScreen (viewport),
+                                 ViewportToScreen (new Rectangle(Point.Empty, ContentSize)),
                                  HasFocus ? GetFocusColor () : GetNormalColor (),
                                  HasFocus ? GetFocusColor () : GetNormalColor (),
                                  HasFocus ? ColorScheme.HotFocus : GetHotNormalColor (),
                                  HasFocus ? ColorScheme.HotFocus : GetHotNormalColor (),
                                  Rectangle.Empty
                                  Rectangle.Empty
@@ -447,7 +448,7 @@ public partial class View
                 }
                 }
 
 
                 // Draw the subview
                 // Draw the subview
-                // Use the view's bounds (view-relative; Location will always be (0,0)
+                // Use the view's Viewport (view-relative; Location will always be (0,0)
                 //if (view.Visible && view.Frame.Width > 0 && view.Frame.Height > 0) {
                 //if (view.Visible && view.Frame.Width > 0 && view.Frame.Height > 0) {
                 view.Draw ();
                 view.Draw ();
 
 

+ 2 - 2
Terminal.Gui/View/ViewEventArgs.cs

@@ -18,8 +18,8 @@ public class ViewEventArgs : EventArgs
 /// <summary>Event arguments for the <see cref="View.LayoutComplete"/> event.</summary>
 /// <summary>Event arguments for the <see cref="View.LayoutComplete"/> event.</summary>
 public class LayoutEventArgs : EventArgs
 public class LayoutEventArgs : EventArgs
 {
 {
-    /// <summary>The view-relative bounds of the <see cref="View"/> before it was laid out.</summary>
-    public Rectangle OldBounds { get; set; }
+    /// <summary>The viewport of the <see cref="View"/> before it was laid out.</summary>
+    public Rectangle OldViewport { get; set; }
 }
 }
 
 
 /// <summary>Event args for draw events</summary>
 /// <summary>Event args for draw events</summary>

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

@@ -617,8 +617,8 @@ public class ComboBox : View
         {
         {
             _search.Width = _listview.Width = _autoHide ? Viewport.Width - 1 : Viewport.Width;
             _search.Width = _listview.Width = _autoHide ? Viewport.Width - 1 : Viewport.Width;
             _listview.Height = CalculatetHeight ();
             _listview.Height = CalculatetHeight ();
-            _search.SetRelativeLayout (Viewport);
-            _listview.SetRelativeLayout (Viewport);
+            _search.SetRelativeLayout (ContentSize);
+            _listview.SetRelativeLayout (ContentSize);
         }
         }
     }
     }
 
 

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

@@ -443,7 +443,7 @@ public static class MessageBox
                                                 );
                                                 );
                         }
                         }
 
 
-                        d.SetRelativeLayout (d.SuperView?.Frame ?? Application.Top.Frame);
+                        d.SetRelativeLayout (d.SuperView?.ContentSize ?? Application.Top.ContentSize);
                     };
                     };
 
 
         // Setup actions
         // Setup actions

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

@@ -262,7 +262,7 @@ public class ScrollBarView : View
 
 
             if (IsInitialized)
             if (IsInitialized)
             {
             {
-                SetRelativeLayout (SuperView?.Frame ?? Host.Frame);
+                SetRelativeLayout (SuperView?.Frame.Size ?? Host.Frame.Size);
                 ShowHideScrollBars (false);
                 ShowHideScrollBars (false);
                 SetNeedsDisplay ();
                 SetNeedsDisplay ();
             }
             }
@@ -890,7 +890,7 @@ public class ScrollBarView : View
     private void ScrollBarView_Initialized (object sender, EventArgs e)
     private void ScrollBarView_Initialized (object sender, EventArgs e)
     {
     {
         SetWidthHeight ();
         SetWidthHeight ();
-        SetRelativeLayout (SuperView?.Frame ?? Host?.Frame ?? Frame);
+        SetRelativeLayout (SuperView?.Frame.Size ?? Host?.Frame.Size ?? Frame.Size);
 
 
         if (OtherScrollBarView is null)
         if (OtherScrollBarView is null)
         {
         {
@@ -995,11 +995,11 @@ public class ScrollBarView : View
         }
         }
 
 
         SetWidthHeight ();
         SetWidthHeight ();
-        SetRelativeLayout (SuperView?.Frame ?? Host.Frame);
+        SetRelativeLayout (SuperView?.Frame.Size ?? Host.Frame.Size);
 
 
         if (_otherScrollBarView is { })
         if (_otherScrollBarView is { })
         {
         {
-            OtherScrollBarView.SetRelativeLayout (SuperView?.Frame ?? Host.Frame);
+            OtherScrollBarView.SetRelativeLayout (SuperView?.Frame.Size ?? Host.Frame.Size);
         }
         }
 
 
         if (_showBothScrollIndicator)
         if (_showBothScrollIndicator)

+ 3 - 3
Terminal.Gui/Views/ScrollView.cs

@@ -722,13 +722,13 @@ public class ScrollView : View
 
 
         if (v)
         if (v)
         {
         {
-            _vertical.SetRelativeLayout (Viewport);
+            _vertical.SetRelativeLayout (ContentSize);
             _vertical.Draw ();
             _vertical.Draw ();
         }
         }
 
 
         if (h)
         if (h)
         {
         {
-            _horizontal.SetRelativeLayout (Viewport);
+            _horizontal.SetRelativeLayout (ContentSize);
             _horizontal.Draw ();
             _horizontal.Draw ();
         }
         }
 
 
@@ -736,7 +736,7 @@ public class ScrollView : View
 
 
         if (v && h)
         if (v && h)
         {
         {
-            _contentBottomRightCorner.SetRelativeLayout (Viewport);
+            _contentBottomRightCorner.SetRelativeLayout (ContentSize);
             _contentBottomRightCorner.Draw ();
             _contentBottomRightCorner.Draw ();
         }
         }
     }
     }

+ 16 - 12
UICatalog/Scenarios/Adornments.cs

@@ -91,7 +91,7 @@ public class Adornments : Scenario
 
 
         view.Initialized += (s, e) =>
         view.Initialized += (s, e) =>
                             {
                             {
-                                var labelInPadding = new Label () {  X = 1, Y = 0, Title = "_Text:" };
+                                var labelInPadding = new Label () { X = 1, Y = 0, Title = "_Text:" };
                                 view.Padding.Add (labelInPadding);
                                 view.Padding.Add (labelInPadding);
 
 
                                 var textFieldInPadding = new TextField () { X = Pos.Right (labelInPadding) + 1, Y = Pos.Top (labelInPadding), Width = 15, Text = "some text" };
                                 var textFieldInPadding = new TextField () { X = Pos.Right (labelInPadding) + 1, Y = Pos.Top (labelInPadding), Width = 15, Text = "some text" };
@@ -101,7 +101,7 @@ public class Adornments : Scenario
                                 var btnButtonInPadding = new Button { X = Pos.Center (), Y = 0, Text = "_Button in Padding" };
                                 var btnButtonInPadding = new Button { X = Pos.Center (), Y = 0, Text = "_Button in Padding" };
                                 btnButtonInPadding.Accept += (s, e) => MessageBox.Query (20, 7, "Hi", "Button in Padding Pressed!", "Ok");
                                 btnButtonInPadding.Accept += (s, e) => MessageBox.Query (20, 7, "Hi", "Button in Padding Pressed!", "Ok");
                                 btnButtonInPadding.BorderStyle = LineStyle.Dashed;
                                 btnButtonInPadding.BorderStyle = LineStyle.Dashed;
-                                btnButtonInPadding.Border.Thickness = new (1,1,1,1);
+                                btnButtonInPadding.Border.Thickness = new (1, 1, 1, 1);
                                 view.Padding.Add (btnButtonInPadding);
                                 view.Padding.Add (btnButtonInPadding);
 
 
 #if SUBVIEW_BASED_BORDER
 #if SUBVIEW_BASED_BORDER
@@ -183,7 +183,7 @@ public class Adornments : Scenario
                 }
                 }
 
 
                 _thickness = value;
                 _thickness = value;
-                ThicknessChanged?.Invoke (this, new() { Thickness = Thickness });
+                ThicknessChanged?.Invoke (this, new () { Thickness = Thickness });
 
 
                 if (IsInitialized)
                 if (IsInitialized)
                 {
                 {
@@ -221,12 +221,12 @@ public class Adornments : Scenario
         {
         {
             var editWidth = 3;
             var editWidth = 3;
 
 
-            _topEdit = new() { X = Pos.Center (), Y = 0, Width = editWidth };
+            _topEdit = new () { X = Pos.Center (), Y = 0, Width = editWidth };
 
 
             _topEdit.Accept += Edit_Accept;
             _topEdit.Accept += Edit_Accept;
             Add (_topEdit);
             Add (_topEdit);
 
 
-            _leftEdit = new()
+            _leftEdit = new ()
             {
             {
                 X = Pos.Left (_topEdit) - editWidth, Y = Pos.Bottom (_topEdit), Width = editWidth
                 X = Pos.Left (_topEdit) - editWidth, Y = Pos.Bottom (_topEdit), Width = editWidth
             };
             };
@@ -234,12 +234,12 @@ public class Adornments : Scenario
             _leftEdit.Accept += Edit_Accept;
             _leftEdit.Accept += Edit_Accept;
             Add (_leftEdit);
             Add (_leftEdit);
 
 
-            _rightEdit = new() { X = Pos.Right (_topEdit), Y = Pos.Bottom (_topEdit), Width = editWidth };
+            _rightEdit = new () { X = Pos.Right (_topEdit), Y = Pos.Bottom (_topEdit), Width = editWidth };
 
 
             _rightEdit.Accept += Edit_Accept;
             _rightEdit.Accept += Edit_Accept;
             Add (_rightEdit);
             Add (_rightEdit);
 
 
-            _bottomEdit = new() { X = Pos.Center (), Y = Pos.Bottom (_leftEdit), Width = editWidth };
+            _bottomEdit = new () { X = Pos.Center (), Y = Pos.Bottom (_leftEdit), Width = editWidth };
 
 
             _bottomEdit.Accept += Edit_Accept;
             _bottomEdit.Accept += Edit_Accept;
             Add (_bottomEdit);
             Add (_bottomEdit);
@@ -328,7 +328,7 @@ public class Adornments : Scenario
                 _origTitle = value.Title;
                 _origTitle = value.Title;
                 _viewToEdit = value;
                 _viewToEdit = value;
 
 
-                _marginEditor = new()
+                _marginEditor = new ()
                 {
                 {
                     X = 0,
                     X = 0,
                     Y = 0,
                     Y = 0,
@@ -341,7 +341,7 @@ public class Adornments : Scenario
                 _marginEditor.AttributeChanged += Editor_AttributeChanged;
                 _marginEditor.AttributeChanged += Editor_AttributeChanged;
                 Add (_marginEditor);
                 Add (_marginEditor);
 
 
-                _borderEditor = new()
+                _borderEditor = new ()
                 {
                 {
                     X = Pos.Left (_marginEditor),
                     X = Pos.Left (_marginEditor),
                     Y = Pos.Bottom (_marginEditor),
                     Y = Pos.Bottom (_marginEditor),
@@ -411,7 +411,7 @@ public class Adornments : Scenario
                                     {
                                     {
                                         if (ckbTitle.Checked == true)
                                         if (ckbTitle.Checked == true)
                                         {
                                         {
-                                            _viewToEdit.Title = _origTitle;
+                                            //_viewToEdit.Title = _origTitle;
                                         }
                                         }
                                         else
                                         else
                                         {
                                         {
@@ -420,7 +420,7 @@ public class Adornments : Scenario
                                     };
                                     };
                 Add (ckbTitle);
                 Add (ckbTitle);
 
 
-                _paddingEditor = new()
+                _paddingEditor = new ()
                 {
                 {
                     X = Pos.Left (_borderEditor),
                     X = Pos.Left (_borderEditor),
                     Y = Pos.Bottom (rbBorderStyle),
                     Y = Pos.Bottom (rbBorderStyle),
@@ -450,13 +450,17 @@ public class Adornments : Scenario
                                          };
                                          };
 
 
                 Add (_diagCheckBox);
                 Add (_diagCheckBox);
+                _viewToEdit.X = Pos.Right (rbBorderStyle);
+                _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
                                                   {
                                                   {

+ 150 - 0
UICatalog/Scenarios/VirtualContentScrolling.cs

@@ -0,0 +1,150 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using Terminal.Gui;
+
+namespace UICatalog.Scenarios;
+
+[ScenarioMetadata ("_Virtual Content Scrolling Demo", "Demonstrates scrolling built-into View")]
+[ScenarioCategory ("Layout")]
+public class VirtualScrolling : Scenario
+{
+    private ViewDiagnosticFlags _diagnosticFlags;
+
+    public class VirtualDemoView : Window
+    {
+        public VirtualDemoView ()
+        {
+            Text = "Virtual Demo View Text. This is long text.\nThe second line.\n3\n4\n5th line.";
+            Arrangement = ViewArrangement.Fixed;
+            ContentSize = new Size (100, 50);
+
+            // Things this view knows how to do
+            AddCommand (Command.ScrollDown, () => ScrollVertical (1));
+            AddCommand (Command.ScrollUp, () => ScrollVertical (-1));
+
+            //AddCommand (Command.PageUp, () => PageUp ());
+            //AddCommand (Command.PageDown, () => PageDown ());
+            //AddCommand (Command.TopHome, () => Home ());
+            //AddCommand (Command.BottomEnd, () => End ());
+
+            // Default keybindings for all ListViews
+            KeyBindings.Add (Key.CursorUp, Command.ScrollUp);
+            KeyBindings.Add (Key.CursorDown, Command.ScrollDown);
+
+            //KeyBindings.Add (Key.PageUp, Command.PageUp);
+            //KeyBindings.Add (Key.PageDown, Command.PageDown);
+            //KeyBindings.Add (Key.Home, Command.TopHome);
+            //KeyBindings.Add (Key.End, Command.BottomEnd);
+
+            LayoutComplete += VirtualDemoView_LayoutComplete;
+        }
+
+        private void VirtualDemoView_LayoutComplete (object sender, LayoutEventArgs e)
+        {
+            Title = Viewport.ToString ();
+            SetNeedsDisplay ();
+        }
+
+        private bool? ScrollVertical (int rows)
+        {
+            if (ContentSize == Size.Empty || ContentSize == Viewport.Size)
+            {
+                return true;
+            }
+
+            if (Viewport.Y + rows < 0)
+            {
+                return true;
+            }
+
+            Viewport = Viewport with { Y = Viewport.Y + rows };
+
+            return true;
+        }
+
+        /// <inheritdoc />
+        public override void OnDrawContent (Rectangle viewport)
+        {
+            base.OnDrawContent (viewport);
+
+        }
+    }
+
+    public override void Main ()
+    {
+        Application.Init ();
+
+        var view = new VirtualDemoView { Title = "The _Window With Content" };
+
+        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) };
+        color.BorderStyle = LineStyle.RoundedDotted;
+
+        color.ColorChanged += (s, e) =>
+                              {
+                                  color.SuperView.ColorScheme = new (color.SuperView.ColorScheme)
+                                  {
+                                      Normal = new (
+                                                    color.SuperView.ColorScheme.Normal.Foreground,
+                                                    e.Color
+                                                   )
+                                  };
+                              };
+
+        var button = new Button { X = Pos.Center (), Y = Pos.Center (), Text = "Press me!" };
+
+        button.Accept += (s, e) =>
+                             MessageBox.Query (20, 7, "Hi", $"Am I a {view.GetType ().Name}?", "Yes", "No");
+
+        var label = new TextView
+        {
+            X = Pos.Center (),
+            Y = Pos.Bottom (button),
+            Title = "Title",
+            Text = "I have a 3 row top border.\nMy border inherits from the SuperView.",
+            Width = 40,
+            Height = 6 // TODO: Use Dim.Auto
+        };
+        label.Border.Thickness = new (1, 3, 1, 1);
+
+        var btnButtonInWindow = new Button { X = Pos.AnchorEnd (10), Y = Pos.AnchorEnd (1), Text = "Button" };
+
+        var tv = new Label
+        {
+            AutoSize = false,
+            Y = Pos.AnchorEnd (3),
+            Width = 25,
+            Height = Dim.Fill (),
+            Text = "Label\nY=AnchorEnd(3),Height=Dim.Fill()"
+        };
+
+        view.Margin.Data = "Margin";
+        view.Margin.Thickness = new (3);
+
+        view.Border.Data = "Border";
+        view.Border.Thickness = new (3);
+
+        view.Padding.Data = "Padding";
+        view.Padding.Thickness = new (3);
+
+        view.Add (tf1, color, button, label, btnButtonInWindow, tv);
+
+        var editor = new Adornments.AdornmentsEditor
+        {
+            Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}",
+            ColorScheme = Colors.ColorSchemes [TopLevelColorScheme]
+
+            //BorderStyle = LineStyle.None,
+        };
+
+        editor.Initialized += (s, e) => { editor.ViewToEdit = view; };
+
+        editor.Closed += (s, e) => View.Diagnostics = _diagnosticFlags;
+
+        Application.Run (editor);
+        editor.Dispose ();
+        Application.Shutdown ();
+    }
+}

+ 5 - 5
UnitTests/View/DrawTests.cs

@@ -340,7 +340,7 @@ public class DrawTests (ITestOutputHelper output)
         var view = new View { Width = 2, Height = 2, BorderStyle = LineStyle.Single };
         var view = new View { Width = 2, Height = 2, BorderStyle = LineStyle.Single };
         view.BeginInit ();
         view.BeginInit ();
         view.EndInit ();
         view.EndInit ();
-        view.SetRelativeLayout (Application.Driver.Viewport);
+        view.SetRelativeLayout (Application.Driver.Viewport.Size);
 
 
         Assert.Equal (new (0, 0, 2, 2), view.Frame);
         Assert.Equal (new (0, 0, 2, 2), view.Frame);
         Assert.Equal (Rectangle.Empty, view.Viewport);
         Assert.Equal (Rectangle.Empty, view.Viewport);
@@ -365,7 +365,7 @@ public class DrawTests (ITestOutputHelper output)
         view.Border.Thickness = new Thickness (1, 1, 1, 0);
         view.Border.Thickness = new Thickness (1, 1, 1, 0);
         view.BeginInit ();
         view.BeginInit ();
         view.EndInit ();
         view.EndInit ();
-        view.SetRelativeLayout (Application.Driver.Viewport);
+        view.SetRelativeLayout (Application.Driver.Viewport.Size);
 
 
         Assert.Equal (new (0, 0, 2, 1), view.Frame);
         Assert.Equal (new (0, 0, 2, 1), view.Frame);
         Assert.Equal (Rectangle.Empty, view.Viewport);
         Assert.Equal (Rectangle.Empty, view.Viewport);
@@ -383,7 +383,7 @@ public class DrawTests (ITestOutputHelper output)
         view.Border.Thickness = new Thickness (0, 1, 1, 1);
         view.Border.Thickness = new Thickness (0, 1, 1, 1);
         view.BeginInit ();
         view.BeginInit ();
         view.EndInit ();
         view.EndInit ();
-        view.SetRelativeLayout (Application.Driver.Viewport);
+        view.SetRelativeLayout (Application.Driver.Viewport.Size);
 
 
         Assert.Equal (new (0, 0, 1, 2), view.Frame);
         Assert.Equal (new (0, 0, 1, 2), view.Frame);
         Assert.Equal (Rectangle.Empty, view.Viewport);
         Assert.Equal (Rectangle.Empty, view.Viewport);
@@ -408,7 +408,7 @@ public class DrawTests (ITestOutputHelper output)
         view.Border.Thickness = new Thickness (1, 1, 0, 1);
         view.Border.Thickness = new Thickness (1, 1, 0, 1);
         view.BeginInit ();
         view.BeginInit ();
         view.EndInit ();
         view.EndInit ();
-        view.SetRelativeLayout (Application.Driver.Viewport);
+        view.SetRelativeLayout (Application.Driver.Viewport.Size);
 
 
         Assert.Equal (new (0, 0, 1, 2), view.Frame);
         Assert.Equal (new (0, 0, 1, 2), view.Frame);
         Assert.Equal (Rectangle.Empty, view.Viewport);
         Assert.Equal (Rectangle.Empty, view.Viewport);
@@ -434,7 +434,7 @@ public class DrawTests (ITestOutputHelper output)
 
 
         view.BeginInit ();
         view.BeginInit ();
         view.EndInit ();
         view.EndInit ();
-        view.SetRelativeLayout (Application.Driver.Viewport);
+        view.SetRelativeLayout (Application.Driver.Viewport.Size);
 
 
         Assert.Equal (new (0, 0, 2, 1), view.Frame);
         Assert.Equal (new (0, 0, 2, 1), view.Frame);
         Assert.Equal (Rectangle.Empty, view.Viewport);
         Assert.Equal (Rectangle.Empty, view.Viewport);

+ 1 - 1
UnitTests/View/Layout/ToScreenTests.cs

@@ -260,7 +260,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 (-1, -1), view.ViewportToScreen (testRect).Location);
     }
     }
 
 
     [Theory]
     [Theory]