浏览代码

Refactoring... WIP 2

Tig 8 月之前
父节点
当前提交
427f5b1e3d

+ 1 - 1
Terminal.Gui/Drawing/Thickness.cs

@@ -236,7 +236,7 @@ public record struct Thickness
     }
 
     /// <summary>
-    ///     Gets the total width of the left and right sides of the rectangle. Sets the width of the left and rigth sides
+    ///     Gets the total width of the left and right sides of the rectangle. Sets the width of the left and right sides
     ///     of the rectangle to half the specified value.
     /// </summary>
     public int Horizontal

+ 1 - 1
Terminal.Gui/View/View.Drawing.Clipping.cs

@@ -104,7 +104,7 @@ public partial class View
         if (this is Adornment adornment && adornment.Thickness != Thickness.Empty)
         {
             // Ensure adornments can't draw outside their thickness
-            frameRegion.Exclude (adornment.Thickness.GetInside (Frame));
+            frameRegion.Exclude (adornment.Thickness.GetInside (FrameToScreen()));
         }
 
         SetClip (frameRegion);

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

@@ -43,7 +43,7 @@ public partial class View
                                                 Bottom = scrollBar.Visible ? Padding.Thickness.Bottom + 1 : 0
                                             };
 
-                                            scrollBar.PositionChanged += (_, args) =>
+                                            scrollBar.SliderPositionChanged += (_, args) =>
                                             {
                                                 Viewport = Viewport with { X = args.CurrentValue };
                                             };
@@ -96,7 +96,7 @@ public partial class View
                                                   Right = scrollBar.Visible ? Padding.Thickness.Right + 1 : 0
                                               };
 
-                                              scrollBar.PositionChanged += (_, args) =>
+                                              scrollBar.SliderPositionChanged += (_, args) =>
                                                                            {
                                                                                Viewport = Viewport with { Y = args.CurrentValue };
                                                                            };
@@ -120,12 +120,12 @@ public partial class View
         {
             if (_verticalScrollBar.IsValueCreated)
             {
-                _verticalScrollBar.Value.Position = Viewport.Y;
+                _verticalScrollBar.Value.SliderPosition = Viewport.Y;
             }
 
             if (_horizontalScrollBar.IsValueCreated)
             {
-                _horizontalScrollBar.Value.Position = Viewport.X;
+                _horizontalScrollBar.Value.SliderPosition = Viewport.X;
             }
         };
 

+ 137 - 25
Terminal.Gui/Views/Scroll/Scroll.cs

@@ -133,7 +133,7 @@ public class Scroll : View, IOrientation, IDesignable
     /// <summary>Raised when <see cref="Size"/> has changed.</summary>
     public event EventHandler<EventArgs<int>>? SizeChanged;
 
-    private int _position;
+    private int _sliderPosition;
 
     private void OnSliderOnFrameChanged (object? sender, EventArgs<Rectangle> args)
     {
@@ -142,52 +142,93 @@ public class Scroll : View, IOrientation, IDesignable
             return;
         }
         int framePos = Orientation == Orientation.Vertical ? args.CurrentValue.Y : args.CurrentValue.X;
-        double pos = ((double)ViewportDimension * ViewportDimension / (Size)) * framePos;
-        RaisePositionChangeEvents (_position, (int)pos);
+        RaisePositionChangeEvents (_sliderPosition, framePos);
     }
 
     /// <summary>
-    ///     Gets or sets the position of the start of the Scroll slider, relative to <see cref="Size"/>.
+    ///     Gets or sets the position of the start of the Scroll slider, within the Viewport.
     /// </summary>
-    public int Position
+    public int SliderPosition
     {
-        get => _position;
-        set => RaisePositionChangeEvents (_position, value);
+        get => _sliderPosition;
+        set => RaisePositionChangeEvents (_sliderPosition, value);
     }
 
-    private void RaisePositionChangeEvents (int current, int value)
+    /// <summary>
+    ///     Gets or sets the position of the ScrollSlider within the range of 0...<see cref="Size"/>.
+    /// </summary>
+    public int ContentPosition
+    {
+        get
+        {
+            if (ViewportDimension - _slider.Size == 0)
+            {
+                return 0;
+            }
+            return (int)Math.Round (GetCurrentContentPosition ());
+        }
+        set
+        {
+            if (Size - ViewportDimension == 0)
+            {
+                SliderPosition = 0;
+                return;
+            }
+
+            double newContentPos = (double)value / (ViewportDimension - _slider.Size) * (Size - ViewportDimension);
+            double newSliderPos = (double)value / (Size - ViewportDimension) * (ViewportDimension - _slider.Size);
+
+            int newSliderPosition = (int)Math.Ceiling (newSliderPos);
+            if (newContentPos >= GetCurrentContentPosition ())
+            {
+                newSliderPosition = (int)Math.Floor (newSliderPos);
+            }
+
+            if (SliderPosition != newSliderPosition)
+            {
+                SliderPosition = newSliderPosition;
+            }
+        }
+    }
+
+    private double GetCurrentContentPosition ()
     {
-        if (OnPositionChanging (current, value))
+        return (double)SliderPosition / (ViewportDimension - _slider.Size) * (Size - ViewportDimension);
+    }
+
+    private void RaisePositionChangeEvents (int currentSliderPosition, int newSliderPosition)
+    {
+        if (OnPositionChanging (currentSliderPosition, newSliderPosition))
         {
-            _slider.Position = current;
+            _slider.Position = currentSliderPosition;
             return;
         }
 
-        CancelEventArgs<int> args = new (ref current, ref value);
-        PositionChanging?.Invoke (this, args);
+        CancelEventArgs<int> args = new (ref currentSliderPosition, ref newSliderPosition);
+        SliderPositionChanging?.Invoke (this, args);
 
         if (args.Cancel)
         {
-            _slider.Position = current;
+            _slider.Position = currentSliderPosition;
             return;
         }
 
         // This sets the slider position and clamps the value
-        _slider.Position = value;
+        _slider.Position = newSliderPosition;
 
-        if (_slider.Position == _position)
+        if (_slider.Position == _sliderPosition)
         {
             return;
         }
 
-        _position = value;
+        _sliderPosition = newSliderPosition;
 
-        OnPositionChanged (_position);
-        PositionChanged?.Invoke (this, new (in value));
+        OnPositionChanged (_sliderPosition);
+        SliderPositionChanged?.Invoke (this, new (in newSliderPosition));
     }
 
     /// <summary>
-    ///     Called when <see cref="Position"/> is changing. Return true to cancel the change.
+    ///     Called when <see cref="SliderPosition"/> is changing. Return true to cancel the change.
     /// </summary>
     protected virtual bool OnPositionChanging (int currentPos, int newPos)
     {
@@ -195,16 +236,16 @@ public class Scroll : View, IOrientation, IDesignable
     }
 
     /// <summary>
-    ///     Raised when the <see cref="Position"/> is changing. Set <see cref="CancelEventArgs.Cancel"/> to
+    ///     Raised when the <see cref="SliderPosition"/> is changing. Set <see cref="CancelEventArgs.Cancel"/> to
     ///     <see langword="true"/> to prevent the position from being changed.
     /// </summary>
-    public event EventHandler<CancelEventArgs<int>>? PositionChanging;
+    public event EventHandler<CancelEventArgs<int>>? SliderPositionChanging;
 
-    /// <summary>Called when <see cref="Position"/> has changed.</summary>
+    /// <summary>Called when <see cref="SliderPosition"/> has changed.</summary>
     protected virtual void OnPositionChanged (int position) { }
 
-    /// <summary>Raised when the <see cref="Position"/> has changed.</summary>
-    public event EventHandler<EventArgs<int>>? PositionChanged;
+    /// <summary>Raised when the <see cref="SliderPosition"/> has changed.</summary>
+    public event EventHandler<EventArgs<int>>? SliderPositionChanged;
 
 
     /// <inheritdoc/>
@@ -215,6 +256,77 @@ public class Scroll : View, IOrientation, IDesignable
         return true;
     }
 
+    /// <inheritdoc />
+    protected override bool OnMouseClick (MouseEventArgs args)
+    {
+        if (!args.IsSingleClicked)
+        {
+            return false;
+        }
+
+        if (Orientation == Orientation.Vertical)
+        {
+            // If the position is w/in the slider frame ignore
+            if (args.Position.Y >= _slider.Frame.Y && args.Position.Y < _slider.Frame.Y + _slider.Frame.Height)
+            {
+                return false;
+            }
+
+            SliderPosition = args.Position.Y;
+        }
+        else
+        {
+            // If the position is w/in the slider frame ignore
+            if (args.Position.X >= _slider.Frame.X && args.Position.X < _slider.Frame.X + _slider.Frame.Width)
+            {
+                return false;
+            }
+
+            SliderPosition = args.Position.X;
+        }
+
+
+        return true;
+    }
+
+    /// <inheritdoc/>
+    protected override bool OnMouseEvent (MouseEventArgs mouseEvent)
+    {
+        if (SuperView is null)
+        {
+            return false;
+        }
+
+        if (!mouseEvent.IsWheel)
+        {
+            return false;
+        }
+
+        if (Orientation == Orientation.Vertical)
+        {
+            if (mouseEvent.Flags.HasFlag (MouseFlags.WheeledDown))
+            {
+                SliderPosition++;
+            }
+            if (mouseEvent.Flags.HasFlag (MouseFlags.WheeledUp))
+            {
+                SliderPosition--;
+            }
+        }
+        else
+        {
+            if (mouseEvent.Flags.HasFlag (MouseFlags.WheeledRight))
+            {
+                SliderPosition++;
+            }
+            if (mouseEvent.Flags.HasFlag (MouseFlags.WheeledLeft))
+            {
+                SliderPosition--;
+            }
+        }
+
+        return true;
+    }
 
     /// <inheritdoc />
     public bool EnableForDesign ()
@@ -236,7 +348,7 @@ public class Scroll : View, IOrientation, IDesignable
         Width = 1;
         Height = Dim.Fill ();
         Size = 1000;
-        Position = 10;
+        SliderPosition = 10;
 
 
 

+ 27 - 17
Terminal.Gui/Views/Scroll/ScrollBar.cs

@@ -12,7 +12,7 @@ namespace Terminal.Gui;
 /// </summary>
 /// <remarks>
 ///     <para>
-///         <see cref="Position"/> indicates the number of rows or columns the Scroll has moved from 0.
+///         <see cref="SliderPosition"/> indicates the number of rows or columns the Scroll has moved from 0.
 ///     </para>
 /// </remarks>
 public class ScrollBar : View, IOrientation, IDesignable
@@ -27,8 +27,8 @@ public class ScrollBar : View, IOrientation, IDesignable
         CanFocus = false;
 
         _scroll = new ();
-        _scroll.PositionChanging += OnScrollOnPositionChanging;
-        _scroll.PositionChanged += OnScrollOnPositionChanged;
+        _scroll.SliderPositionChanging += OnScrollOnSliderPositionChanging;
+        _scroll.SliderPositionChanged += OnScrollOnSliderPositionChanged;
         _scroll.SizeChanged += OnScrollOnSizeChanged;
 
         _decreaseButton = new ()
@@ -64,13 +64,13 @@ public class ScrollBar : View, IOrientation, IDesignable
 
         void OnDecreaseButtonOnAccept (object? s, CommandEventArgs e)
         {
-            _scroll.Position--;
+            _scroll.ContentPosition--;
             e.Cancel = true;
         }
 
         void OnIncreaseButtonOnAccept (object? s, CommandEventArgs e)
         {
-            _scroll.Position++;
+            _scroll.ContentPosition++;
             e.Cancel = true;
         }
     }
@@ -180,25 +180,26 @@ public class ScrollBar : View, IOrientation, IDesignable
         set;
     }
 
-    /// <summary>Gets or sets the position, relative to <see cref="Size"/>, to set the scrollbar at.</summary>
+    /// <summary>Gets or sets the position of the slider within the ScrollBar's Viewport.</summary>
     /// <value>The position.</value>
-    public int Position
+    public int SliderPosition
     {
-        get => _scroll.Position;
-        set => _scroll.Position = value;
+        get => _scroll.SliderPosition;
+        set => _scroll.SliderPosition = value;
     }
 
-    private void OnScrollOnPositionChanged (object? sender, EventArgs<int> e) { PositionChanged?.Invoke (this, e); }
-    private void OnScrollOnPositionChanging (object? sender, CancelEventArgs<int> e) { PositionChanging?.Invoke (this, e); }
-
-    /// <summary>Raised when the <see cref="Position"/> has changed.</summary>
-    public event EventHandler<EventArgs<int>>? PositionChanged;
+    private void OnScrollOnSliderPositionChanged (object? sender, EventArgs<int> e) { SliderPositionChanged?.Invoke (this, e); }
+    private void OnScrollOnSliderPositionChanging (object? sender, CancelEventArgs<int> e) { SliderPositionChanging?.Invoke (this, e); }
 
     /// <summary>
-    ///     Raised when the <see cref="Position"/> is changing. Set <see cref="CancelEventArgs.Cancel"/> to
+    ///     Raised when the <see cref="SliderPosition"/> is changing. Set <see cref="CancelEventArgs.Cancel"/> to
     ///     <see langword="true"/> to prevent the position from being changed.
     /// </summary>
-    public event EventHandler<CancelEventArgs<int>>? PositionChanging;
+    public event EventHandler<CancelEventArgs<int>>? SliderPositionChanging;
+
+    /// <summary>Raised when the <see cref="SliderPosition"/> has changed.</summary>
+    public event EventHandler<EventArgs<int>>? SliderPositionChanged;
+
 
     /// <summary>
     ///     Gets or sets the size of the Scroll. This is the total size of the content that can be scrolled through.
@@ -209,6 +210,15 @@ public class ScrollBar : View, IOrientation, IDesignable
         set => _scroll.Size = value;
     }
 
+    /// <summary>
+    ///     Gets or sets the position of the ScrollSlider within the range of 0...<see cref="Size"/>.
+    /// </summary>
+    public int ContentPosition
+    {
+        get => _scroll.ContentPosition;
+        set => _scroll.ContentPosition = value;
+    }
+
     /// <summary>Raised when <see cref="Size"/> has changed.</summary>
     public event EventHandler<EventArgs<int>>? SizeChanged;
 
@@ -279,7 +289,7 @@ public class ScrollBar : View, IOrientation, IDesignable
         Width = 1;
         Height = Dim.Fill ();
         Size = 200;
-        Position = 10;
+        SliderPosition = 10;
         //ShowPercent = true;
         return true;
     }

+ 16 - 32
Terminal.Gui/Views/Scroll/ScrollSlider.cs

@@ -91,11 +91,21 @@ public class ScrollSlider : View, IOrientation, IDesignable
         return true;
     }
 
+    private bool _showPercent;
+
     /// <summary>
     ///     Gets or sets whether the ScrollSlider will set <see cref="View.Text"/> to show the percentage the slider
     ///     takes up within the <see cref="View.SuperView"/>'s Viewport.
     /// </summary>
-    public bool ShowPercent { get; set; }
+    public bool ShowPercent
+    {
+        get => _showPercent;
+        set
+        {
+            _showPercent = value;
+            SetNeedsDraw();
+        }
+    }
 
     /// <summary>
     ///     Gets or sets the size of the ScrollSlider. This is a helper that simply gets or sets the Width or Height depending on the
@@ -138,7 +148,7 @@ public class ScrollSlider : View, IOrientation, IDesignable
     }
 
     /// <summary>
-    ///     Gets or sets the position of the ScrollSlider. This is a helper that simply gets or sets the X or Y depending on the
+    ///     Gets or sets the position of the ScrollSlider relative to the size of the ScrollSlider's Frame. This is a helper that simply gets or sets the X or Y depending on the
     ///     <see cref="Orientation"/>. The position will be constrained such that the ScrollSlider will not go outside the Viewport of
     ///     the <see cref="View.SuperView"/>.
     /// </summary>
@@ -175,6 +185,8 @@ public class ScrollSlider : View, IOrientation, IDesignable
     {
         if (!ShowPercent)
         {
+            Text = string.Empty;
+
             return false;
         }
 
@@ -246,38 +258,10 @@ public class ScrollSlider : View, IOrientation, IDesignable
                     Application.UngrabMouse ();
                 }
             }
+            return true;
         }
+        return false;
 
-        if (mouseEvent.IsWheel)
-        {
-            if (mouseEvent.Flags.HasFlag (MouseFlags.WheeledDown) || mouseEvent.Flags.HasFlag (MouseFlags.WheeledRight))
-            {
-                offset = 1;
-            }
-            else if (mouseEvent.Flags.HasFlag (MouseFlags.WheeledDown) || mouseEvent.Flags.HasFlag (MouseFlags.WheeledLeft))
-            {
-                offset = -1;
-            }
-
-            if (Orientation == Orientation.Vertical)
-            {
-                Y = Frame.Y + offset < 0
-                        ? 0
-                        : Frame.Y + offset + Frame.Height > superViewDimension
-                            ? Math.Max (superViewDimension - Frame.Height, 0)
-                            : Frame.Y + offset;
-            }
-            else
-            {
-                X = Frame.X + offset < 0
-                        ? 0
-                        : Frame.X + offset + Frame.Width > superViewDimension
-                            ? Math.Max (superViewDimension - Frame.Width, 0)
-                            : Frame.X + offset;
-            }
-        }
-
-        return true;
     }
 
     /// <inheritdoc />

+ 94 - 119
UICatalog/Scenarios/CharacterMap.cs

@@ -10,7 +10,9 @@ using System.Text;
 using System.Text.Json;
 using System.Text.Unicode;
 using System.Threading.Tasks;
+using JetBrains.Annotations;
 using Terminal.Gui;
+using static System.Runtime.InteropServices.JavaScript.JSType;
 using static Terminal.Gui.SpinnerStyle;
 
 namespace UICatalog.Scenarios;
@@ -335,84 +337,50 @@ internal class CharMap : View, IDesignable
     private int _selected;
     private int _start;
 
+    private readonly ScrollBar _vScrollBar;
+    private readonly ScrollBar _hScrollBar;
+
     public CharMap ()
     {
         ColorScheme = Colors.ColorSchemes ["Dialog"];
         CanFocus = true;
         CursorVisibility = CursorVisibility.Default;
+        //ViewportSettings = ViewportSettings.AllowLocationGreaterThanContentSize;
 
-        SetContentSize (new (RowWidth, (_maxCodePoint / 16 + 1) * _rowHeight));
+        SetContentSize (new (COLUMN_WIDTH * 16, (_maxCodePoint / 16) * _rowHeight)); // +1 for Header
 
         AddCommand (
-                    Command.ScrollUp,
+                    Command.Up,
                     () =>
                     {
-                        if (SelectedCodePoint >= 16)
-                        {
-                            SelectedCodePoint -= 16;
-                        }
-
-                        ScrollVertical (-_rowHeight);
-
+                        SelectedCodePoint -= 16;
                         return true;
                     }
                    );
 
         AddCommand (
-                    Command.ScrollDown,
+                    Command.Down,
                     () =>
                     {
-                        if (SelectedCodePoint <= _maxCodePoint - 16)
-                        {
-                            SelectedCodePoint += 16;
-                        }
-
-                        if (Cursor.Y >= Viewport.Height)
-                        {
-                            ScrollVertical (_rowHeight);
-                        }
-
+                        SelectedCodePoint += 16;
                         return true;
                     }
                    );
 
         AddCommand (
-                    Command.ScrollLeft,
+                    Command.Left,
                     () =>
                     {
-                        if (SelectedCodePoint > 0)
-                        {
-                            SelectedCodePoint--;
-                        }
-
-                        if (Cursor.X > RowLabelWidth + 1)
-                        {
-                            ScrollHorizontal (-COLUMN_WIDTH);
-                        }
-
-                        if (Cursor.X >= Viewport.Width)
-                        {
-                            ScrollHorizontal (Cursor.X - Viewport.Width + 1);
-                        }
-
+                        SelectedCodePoint--;
                         return true;
                     }
                    );
 
         AddCommand (
-                    Command.ScrollRight,
+                    Command.Right,
                     () =>
                     {
-                        if (SelectedCodePoint < _maxCodePoint)
-                        {
-                            SelectedCodePoint++;
-                        }
-
-                        if (Cursor.X >= Viewport.Width)
-                        {
-                            ScrollHorizontal (COLUMN_WIDTH);
-                        }
-
+                       SelectedCodePoint++;
                         return true;
                     }
                    );
@@ -422,8 +390,7 @@ internal class CharMap : View, IDesignable
                     () =>
                     {
                         int page = (Viewport.Height - 1 / _rowHeight) * 16;
-                        SelectedCodePoint -= Math.Min (page, SelectedCodePoint);
-                        Viewport = Viewport with { Y = SelectedCodePoint / 16 * _rowHeight };
+                        SelectedCodePoint -= page;
 
                         return true;
                     }
@@ -434,8 +401,7 @@ internal class CharMap : View, IDesignable
                     () =>
                     {
                         int page = (Viewport.Height - 1 / _rowHeight) * 16;
-                        SelectedCodePoint += Math.Min (page, _maxCodePoint - SelectedCodePoint);
-                        Viewport = Viewport with { Y = SelectedCodePoint / 16 * _rowHeight };
+                        SelectedCodePoint += page;
 
                         return true;
                     }
@@ -456,7 +422,6 @@ internal class CharMap : View, IDesignable
                     () =>
                     {
                         SelectedCodePoint = _maxCodePoint;
-                        Viewport = Viewport with { Y = SelectedCodePoint / 16 * _rowHeight };
 
                         return true;
                     }
@@ -472,10 +437,10 @@ internal class CharMap : View, IDesignable
                     }
                    );
 
-        KeyBindings.Add (Key.CursorUp, Command.ScrollUp);
-        KeyBindings.Add (Key.CursorDown, Command.ScrollDown);
-        KeyBindings.Add (Key.CursorLeft, Command.ScrollLeft);
-        KeyBindings.Add (Key.CursorRight, Command.ScrollRight);
+        KeyBindings.Add (Key.CursorUp, Command.Up);
+        KeyBindings.Add (Key.CursorDown, Command.Down);
+        KeyBindings.Add (Key.CursorLeft, Command.Left);
+        KeyBindings.Add (Key.CursorRight, Command.Right);
         KeyBindings.Add (Key.PageUp, Command.PageUp);
         KeyBindings.Add (Key.PageDown, Command.PageDown);
         KeyBindings.Add (Key.Home, Command.Start);
@@ -487,17 +452,17 @@ internal class CharMap : View, IDesignable
         // Add scrollbars
         Padding.Thickness = new (0, 0, 1, 0);
 
-        ScrollBar hScrollBar = new ()
+        _hScrollBar = new ()
         {
             AutoHide = false,
             X = RowLabelWidth + 1,
             Y = Pos.AnchorEnd (),
             Orientation = Orientation.Horizontal,
             Width = Dim.Fill (1),
-            Size = COLUMN_WIDTH * 15
+            Size = GetContentSize ().Width
         };
 
-        ScrollBar vScrollBar = new ()
+        _vScrollBar = new ()
         {
             AutoHide = false,
             X = Pos.AnchorEnd (),
@@ -506,42 +471,37 @@ internal class CharMap : View, IDesignable
             Size = GetContentSize ().Height
         };
 
-        Padding.Add (vScrollBar, hScrollBar);
+        Padding.Add (_vScrollBar, _hScrollBar);
 
-        vScrollBar.PositionChanged += (sender, args) =>
+        _vScrollBar.SliderPositionChanged += (sender, args) =>
                                       {
                                           if (Viewport.Height > 0)
                                           {
-                                              Viewport = Viewport with { Y = args.CurrentValue };
+                                              Viewport = Viewport with { Y = _vScrollBar.ContentPosition };
                                           }
                                       };
 
-        hScrollBar.PositionChanged += (sender, args) =>
-                                      {
-                                          if (Viewport.Width > 0)
-                                          {
-                                              Viewport = Viewport with { X = args.CurrentValue };
-                                          }
-                                      };
+        _hScrollBar.SliderPositionChanged += (sender, args) =>
+                                             {
+                                                 if (Viewport.Width > 0)
+                                                 {
+                                                     Viewport = Viewport with { X = _hScrollBar.ContentPosition };
+                                                 }
+                                             };
 
-        ViewportChanged += (sender, args) =>
+        FrameChanged += (sender, args) =>
                         {
-                            if (Viewport.Width < GetContentSize ().Width)
+                            int width = Viewport.Width / COLUMN_WIDTH * COLUMN_WIDTH - RowLabelWidth;
+                            if (width < GetContentSize ().Width)
                             {
                                 Padding.Thickness = Padding.Thickness with { Bottom = 1 };
-                                hScrollBar.Visible = true;
                             }
                             else
                             {
                                 Padding.Thickness = Padding.Thickness with { Bottom = 0 };
-                                hScrollBar.Visible = false;
                             }
-
-                            hScrollBar.Size = COLUMN_WIDTH * 15;
-                            hScrollBar.Position = Viewport.X;
-
-                            vScrollBar.Size = GetContentSize ().Height;
-                            vScrollBar.Position = Viewport.Y;
+                            _hScrollBar.ContentPosition = Viewport.X;
+                            _vScrollBar.ContentPosition = Viewport.Y;
                         };
     }
 
@@ -550,6 +510,7 @@ internal class CharMap : View, IDesignable
         if (e.Flags == MouseFlags.WheeledDown)
         {
             ScrollVertical (1);
+            _vScrollBar.ContentPosition = Viewport.Y;
             e.Handled = true;
 
             return;
@@ -558,6 +519,7 @@ internal class CharMap : View, IDesignable
         if (e.Flags == MouseFlags.WheeledUp)
         {
             ScrollVertical (-1);
+            _vScrollBar.ContentPosition = Viewport.Y;
             e.Handled = true;
 
             return;
@@ -565,7 +527,7 @@ internal class CharMap : View, IDesignable
 
         if (e.Flags == MouseFlags.WheeledRight)
         {
-            ScrollHorizontal (1);
+            _hScrollBar.SliderPosition++;
             e.Handled = true;
 
             return;
@@ -573,18 +535,17 @@ internal class CharMap : View, IDesignable
 
         if (e.Flags == MouseFlags.WheeledLeft)
         {
-            ScrollHorizontal (-1);
+            _hScrollBar.SliderPosition--;
             e.Handled = true;
         }
     }
 
-    /// <summary>Gets the coordinates of the Cursor based on the SelectedCodePoint in screen coordinates</summary>
+    /// <summary>Gets or sets the coordinates of the Cursor based on the SelectedCodePoint in Viewport-relative coordinates</summary>
     public Point Cursor
     {
         get
         {
-            int row = SelectedCodePoint / 16 * _rowHeight - Viewport.Y + 1;
-
+            int row = SelectedCodePoint / 16 * _rowHeight - Viewport.Y + 1; // + 1 for header
             int col = SelectedCodePoint % 16 * COLUMN_WIDTH - Viewport.X + RowLabelWidth + 1; // + 1 for padding between label and first column
 
             return new (col, row);
@@ -595,8 +556,7 @@ internal class CharMap : View, IDesignable
     public static int _maxCodePoint = UnicodeRange.Ranges.Max (r => r.End);
 
     /// <summary>
-    ///     Specifies the starting offset for the character map. The default is 0x2500 which is the Box Drawing
-    ///     characters.
+    ///     Gets or sets the currently selected codepoint. Causes the Viewport to scroll to make the selected code point visible.
     /// </summary>
     public int SelectedCodePoint
     {
@@ -608,43 +568,61 @@ internal class CharMap : View, IDesignable
                 return;
             }
 
-            _selected = value;
+            Point prevCursor = Cursor;
+            int newSelectedCodePoint = Math.Clamp (value, 0, _maxCodePoint);
+
+            ScrollToMakeRowVisible (newSelectedCodePoint / 16 * _rowHeight, prevCursor.Y);
+            ScrollToMakeColumnVisible (newSelectedCodePoint % 16 * COLUMN_WIDTH, prevCursor.X);
 
-            if (IsInitialized)
+            if (_selected != newSelectedCodePoint)
             {
-                int row = SelectedCodePoint / 16 * _rowHeight;
-                int col = SelectedCodePoint % 16 * COLUMN_WIDTH;
+                _selected = newSelectedCodePoint;
+                SetNeedsDraw ();
+                SelectedCodePointChanged?.Invoke (this, new (SelectedCodePoint, null));
+            }
+        }
+    }
 
-                if (row - Viewport.Y < 0)
-                {
-                    // Moving up.
-                    Viewport = Viewport with { Y = row };
-                }
-                else if (row - Viewport.Y >= Viewport.Height)
-                {
-                    // Moving down.
-                    Viewport = Viewport with { Y = row - Viewport.Height };
-                }
+    private void ScrollToMakeRowVisible (int row, int prevCursorY)
+    {
+        int height = Viewport.Height - 1; // Header
+        int delta = row - (Viewport.Y + height);
+        int scroll = Viewport.Height - (prevCursorY - delta);
 
-                int width = Viewport.Width / COLUMN_WIDTH * COLUMN_WIDTH - RowLabelWidth;
+        if (row - Viewport.Y < 0)
+        {
+            // Moving up.
+            Viewport = Viewport with { Y = Viewport.Y + (row - Viewport.Y) };
+        }
+        else if (row - Viewport.Y >= height)
+        {
+            // Moving down.
+            Viewport = Viewport with { Y = Math.Min (Viewport.Y + scroll, GetContentSize ().Height - height ) };
+        }
+        _vScrollBar.ContentPosition = row;
+    }
 
-                if (col - Viewport.X < 0)
-                {
-                    // Moving left.
-                    Viewport = Viewport with { X = col };
-                }
-                else if (col - Viewport.X >= width)
-                {
-                    // Moving right.
-                    Viewport = Viewport with { X = col - width };
-                }
-            }
+    private void ScrollToMakeColumnVisible (int col, int prevCursorX)
+    {
+        int width = Viewport.Width - RowLabelWidth;
+        int delta = col - (Viewport.X + width);
+        int scroll = Viewport.Width - (prevCursorX - delta);
 
-            SetNeedsDraw ();
-            SelectedCodePointChanged?.Invoke (this, new (SelectedCodePoint, null));
+        if (col - Viewport.X < 0)
+        {
+            // Moving left.
+            Viewport = Viewport with { X = Viewport.X + (col - Viewport.X) };
+            _hScrollBar.ContentPosition = col;
+        }
+        else if (col  - Viewport.X >= width)
+        {
+            // Moving right.
+            Viewport = Viewport with { X = Math.Min (Viewport.X + scroll, GetContentSize ().Width - width) };
+            _hScrollBar.ContentPosition = col;
         }
     }
 
+
     public bool ShowGlyphWidths
     {
         get => _rowHeight == 2;
@@ -682,8 +660,6 @@ internal class CharMap : View, IDesignable
             return true;
         }
 
-        ClearViewport ();
-
         int cursorCol = Cursor.X + Viewport.X - RowLabelWidth - 1;
         int cursorRow = Cursor.Y + Viewport.Y - 1;
 
@@ -710,8 +686,7 @@ internal class CharMap : View, IDesignable
             }
         }
 
-        // Even though the Clip is set to prevent us from drawing on the row potentially occupied by the horizontal
-        // scroll bar, we do the smart thing and not actually draw that row if not necessary.
+        // Start at 1 because Header.
         for (var y = 1; y < Viewport.Height; y++)
         {
             // What row is this?
@@ -1022,7 +997,7 @@ internal class CharMap : View, IDesignable
                                                         document.RootElement,
                                                         new
                                                             JsonSerializerOptions
-                                                            { WriteIndented = true }
+                                                        { WriteIndented = true }
                                                        );
             }
 

+ 19 - 15
UICatalog/Scenarios/Editors/EventLog.cs

@@ -22,7 +22,14 @@ public class EventLog : ListView
 
         X = Pos.AnchorEnd ();
         Y = 0;
-        Width = Dim.Func (() => Math.Min (SuperView!.Viewport.Width / 3, MaxLength + GetAdornmentsThickness ().Horizontal));
+        Width = Dim.Func (() =>
+                          {
+                              if (!IsInitialized)
+                              {
+                                  return 0;
+                              }
+                              return Math.Min (SuperView!.Viewport.Width / 3, MaxLength + GetAdornmentsThickness ().Horizontal);
+                          });
         Height = Dim.Fill ();
 
         ExpandButton = new ()
@@ -55,39 +62,36 @@ public class EventLog : ListView
                 _viewToLog.Initialized += (s, args) =>
                                              {
                                                  View? sender = s as View;
-                                                 _eventSource.Add ($"Initialized: {GetIdentifyingString (sender)}");
-                                                 MoveEnd ();
+                                                 Log ($"Initialized: {GetIdentifyingString (sender)}");
                                              };
 
                 _viewToLog.MouseClick += (s, args) =>
                 {
-                    View? sender = s as View;
-                    _eventSource.Add ($"MouseClick: {args}");
-                    MoveEnd ();
+                    Log ($"MouseClick: {args}");
                 };
 
                 _viewToLog.HandlingHotKey += (s, args) =>
                                         {
-                                            View? sender = s as View;
-                                            _eventSource.Add ($"HandlingHotKey: {args.Context.Command} {args.Context.Data}");
-                                            MoveEnd ();
+                                            Log ($"HandlingHotKey: {args.Context.Command} {args.Context.Data}");
                                         };
                 _viewToLog.Selecting += (s, args) =>
                                         {
-                                            View? sender = s as View;
-                                            _eventSource.Add ($"Selecting: {args.Context.Command} {args.Context.Data}");
-                                            MoveEnd ();
+                                            Log ($"Selecting: {args.Context.Command} {args.Context.Data}");
                                         };
                 _viewToLog.Accepting += (s, args) =>
                                         {
-                                            View? sender = s as View;
-                                            _eventSource.Add ($"Accepting: {args.Context.Command} {args.Context.Data}");
-                                            MoveEnd ();
+                                            Log ($"Accepting: {args.Context.Command} {args.Context.Data}");
                                         };
             }
         }
     }
 
+    public void Log (string text)
+    {
+        _eventSource.Add (text);
+        MoveEnd ();
+    }
+
     private void EventLog_Initialized (object? _, EventArgs e)
     {
 

+ 188 - 93
UICatalog/Scenarios/ScrollBarDemo.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Linq;
 using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
@@ -22,7 +23,7 @@ public class ScrollBarDemo : Scenario
         var editor = new AdornmentsEditor ();
         app.Add (editor);
 
-        var view = new FrameView
+        var frameView = new FrameView
         {
             Title = "Demo View",
             X = Pos.Right (editor),
@@ -30,25 +31,43 @@ public class ScrollBarDemo : Scenario
             Height = Dim.Fill (),
             ColorScheme = Colors.ColorSchemes ["Base"]
         };
-        app.Add (view);
+        app.Add (frameView);
 
         var scrollBar = new ScrollBar
         {
             X = Pos.AnchorEnd (),
+            AutoHide = false
             //ShowPercent = true
         };
-        view.Add (scrollBar);
+        frameView.Add (scrollBar);
 
         app.Loaded += (s, e) =>
                       {
                           scrollBar.Size = scrollBar.Viewport.Height;
                       };
 
+        int GetMaxLabelWidth (int groupId)
+        {
+            return frameView.Subviews.Max (
+                                           v =>
+                                           {
+                                               if (v.Y.Has<PosAlign> (out var pos) && pos.GroupId == groupId)
+                                               {
+                                                   return v.Text.GetColumns ();
+                                               }
+
+                                               return 0;
+                                           });
+        }
+
         var lblWidthHeight = new Label
         {
-            Text = "Width/Height:"
+            Text = "_Width/Height:",
+            TextAlignment = Alignment.End,
+            Y = Pos.Align (Alignment.Start, AlignmentModes.StartToEnd, groupId: 1),
+            Width = Dim.Func (() => GetMaxLabelWidth (1))
         };
-        view.Add (lblWidthHeight);
+        frameView.Add (lblWidthHeight);
 
         NumericUpDown<int> scrollWidthHeight = new ()
         {
@@ -56,7 +75,7 @@ public class ScrollBarDemo : Scenario
             X = Pos.Right (lblWidthHeight) + 1,
             Y = Pos.Top (lblWidthHeight)
         };
-        view.Add (scrollWidthHeight);
+        frameView.Add (scrollWidthHeight);
 
         scrollWidthHeight.ValueChanging += (s, e) =>
                                            {
@@ -82,13 +101,24 @@ public class ScrollBarDemo : Scenario
                                                }
                                            };
 
+
+        var lblOrientationabel = new Label
+        {
+            Text = "_Orientation:",
+            TextAlignment = Alignment.End,
+            Y = Pos.Align (Alignment.Start, groupId: 1),
+            Width = Dim.Func (() => GetMaxLabelWidth (1))
+        };
+        frameView.Add (lblOrientationabel);
+
         var rgOrientation = new RadioGroup
         {
-            Y = Pos.Bottom (lblWidthHeight),
+            X = Pos.Right (lblOrientationabel) + 1,
+            Y = Pos.Top (lblOrientationabel),
             RadioLabels = ["Vertical", "Horizontal"],
             Orientation = Orientation.Horizontal
         };
-        view.Add (rgOrientation);
+        frameView.Add (rgOrientation);
 
         rgOrientation.SelectedItemChanged += (s, e) =>
                                              {
@@ -104,7 +134,6 @@ public class ScrollBarDemo : Scenario
                                                      scrollBar.Y = 0;
                                                      scrollWidthHeight.Value = Math.Min (scrollWidthHeight.Value, scrollBar.SuperView.GetContentSize ().Width);
                                                      scrollBar.Width = scrollWidthHeight.Value;
-                                                     scrollBar.Height = Dim.Fill ();
                                                      scrollBar.Size /= 3;
                                                  }
                                                  else
@@ -112,8 +141,6 @@ public class ScrollBarDemo : Scenario
                                                      scrollBar.Orientation = Orientation.Horizontal;
                                                      scrollBar.X = 0;
                                                      scrollBar.Y = Pos.AnchorEnd ();
-                                                     scrollBar.Width = Dim.Fill ();
-
                                                      scrollWidthHeight.Value = Math.Min (scrollWidthHeight.Value, scrollBar.SuperView.GetContentSize ().Height);
                                                      scrollBar.Height = scrollWidthHeight.Value;
                                                      scrollBar.Size *= 3;
@@ -122,10 +149,12 @@ public class ScrollBarDemo : Scenario
 
         var lblSize = new Label
         {
-            Y = Pos.Bottom (rgOrientation),
-            Text = "Size:"
+            Text = "_Size:",
+            TextAlignment = Alignment.End,
+            Y = Pos.Align (Alignment.Start, groupId: 1),
+            Width = Dim.Func (() => GetMaxLabelWidth (1))
         };
-        view.Add (lblSize);
+        frameView.Add (lblSize);
 
         NumericUpDown<int> scrollSize = new ()
         {
@@ -133,7 +162,7 @@ public class ScrollBarDemo : Scenario
             X = Pos.Right (lblSize) + 1,
             Y = Pos.Top (lblSize)
         };
-        view.Add (scrollSize);
+        frameView.Add (scrollSize);
 
         scrollSize.ValueChanging += (s, e) =>
                                     {
@@ -150,123 +179,189 @@ public class ScrollBarDemo : Scenario
                                         }
                                     };
 
-        var lblPosition = new Label
+        var lblSliderPosition = new Label
         {
-            Y = Pos.Bottom (lblSize),
-            Text = "Position:"
+            Text = "_SliderPosition:",
+            TextAlignment = Alignment.End,
+            Y = Pos.Align (Alignment.Start, groupId: 1),
+            Width = Dim.Func (() => GetMaxLabelWidth (1))
+
         };
-        view.Add (lblPosition);
+        frameView.Add (lblSliderPosition);
 
-        NumericUpDown<int> scrollPosition = new ()
+        NumericUpDown<int> scrollSliderPosition = new ()
         {
-            Value = scrollBar.Position,
-            X = Pos.Right (lblPosition) + 1,
-            Y = Pos.Top (lblPosition)
+            Value = scrollBar.SliderPosition,
+            X = Pos.Right (lblSliderPosition) + 1,
+            Y = Pos.Top (lblSliderPosition)
         };
-        view.Add (scrollPosition);
+        frameView.Add (scrollSliderPosition);
 
-        scrollPosition.ValueChanging += (s, e) =>
-                                        {
-                                            if (e.NewValue < 0)
-                                            {
-                                                e.Cancel = true;
+        scrollSliderPosition.ValueChanging += (s, e) =>
+                                              {
+                                                  if (e.NewValue < 0)
+                                                  {
+                                                      e.Cancel = true;
 
-                                                return;
-                                            }
+                                                      return;
+                                                  }
 
-                                            if (scrollBar.Position != e.NewValue)
-                                            {
-                                                scrollBar.Position = e.NewValue;
-                                            }
+                                                  if (scrollBar.SliderPosition != e.NewValue)
+                                                  {
+                                                      scrollBar.SliderPosition = e.NewValue;
+                                                  }
 
-                                            if (scrollBar.Position != e.NewValue)
-                                            {
-                                                e.Cancel = true;
-                                            }
-                                        };
+                                                  if (scrollBar.SliderPosition != e.NewValue)
+                                                  {
+                                                      e.Cancel = true;
+                                                  }
+                                              };
 
-        var ckbAutoHide = new CheckBox
-            { Y = Pos.Bottom (scrollPosition), Text = "AutoHideScrollBar", CheckedState = scrollBar.AutoHide ? CheckState.Checked : CheckState.UnChecked };
-        ckbAutoHide.CheckedStateChanging += (s, e) => scrollBar.AutoHide = e.NewValue == CheckState.Checked;
-        view.Add (ckbAutoHide);
+        var lblContentPosition = new Label
+        {
+            Text = "_ContentPosition:",
+            TextAlignment = Alignment.End,
+            Y = Pos.Align (Alignment.Start, groupId: 1),
+            Width = Dim.Func (() => GetMaxLabelWidth (1))
 
-        //var ckbKeepContentInAllViewport = new CheckBox
-        //{
-        //    X = Pos.Right (ckbShowScrollIndicator) + 1, Y = Pos.Bottom (scrollPosition), Text = "KeepContentInAllViewport",
-        //    CheckedState = scrollBar.KeepContentInAllViewport ? CheckState.Checked : CheckState.UnChecked
-        //};
-        //ckbKeepContentInAllViewport.CheckedStateChanging += (s, e) => scrollBar.KeepContentInAllViewport = e.NewValue == CheckState.Checked;
-        //view.Add (ckbKeepContentInAllViewport);
+        };
+        frameView.Add (lblContentPosition);
 
-        var lblSizeChanged = new Label
+        NumericUpDown<int> scrollContentPosition = new ()
         {
-            Y = Pos.Bottom (ckbAutoHide) + 1
+            Value = scrollBar.SliderPosition,
+            X = Pos.Right (lblContentPosition) + 1,
+            Y = Pos.Top (lblContentPosition)
         };
-        view.Add (lblSizeChanged);
+        frameView.Add (scrollContentPosition);
 
-        scrollBar.SizeChanged += (s, e) =>
-                              {
-                                  lblSizeChanged.Text = $"SizeChanged event - CurrentValue: {e.CurrentValue}";
+        scrollContentPosition.ValueChanging += (s, e) =>
+                                               {
+                                                   if (e.NewValue < 0)
+                                                   {
+                                                       e.Cancel = true;
 
-                                  if (scrollSize.Value != e.CurrentValue)
-                                  {
-                                      scrollSize.Value = e.CurrentValue;
-                                  }
-                              };
+                                                       return;
+                                                   }
+
+                                                   if (scrollBar.ContentPosition != e.NewValue)
+                                                   {
+                                                       scrollBar.ContentPosition = e.NewValue;
+                                                   }
 
-        var lblPosChanging = new Label
+                                                   if (scrollBar.ContentPosition != e.NewValue)
+                                                   {
+                                                       e.Cancel = true;
+                                                   }
+                                               };
+
+        var lblOptions = new Label
         {
-            Y = Pos.Bottom (lblSizeChanged)
+            Text = "_Options:",
+            TextAlignment = Alignment.End,
+            Y = Pos.Align (Alignment.Start, groupId: 1),
+            Width = Dim.Func (() => GetMaxLabelWidth (1))
         };
-        view.Add (lblPosChanging);
-
-        scrollBar.PositionChanging += (s, e) => { lblPosChanging.Text = $"PositionChanging event - CurrentValue: {e.CurrentValue}; NewValue: {e.NewValue}"; };
+        frameView.Add (lblOptions);
+        var ckbAutoHide = new CheckBox
+        {
+            Y = Pos.Top (lblOptions),
+            X = Pos.Right (lblOptions) + 1,
+            Text = "Auto_HideScrollBar",
+            CheckedState = scrollBar.AutoHide ? CheckState.Checked : CheckState.UnChecked
+        };
+        ckbAutoHide.CheckedStateChanging += (s, e) => scrollBar.AutoHide = e.NewValue == CheckState.Checked;
+        frameView.Add (ckbAutoHide);
 
-        var lblPositionChanged = new Label
+        var ckbShowPercent = new CheckBox
         {
-            Y = Pos.Bottom (lblPosChanging)
+            Y = Pos.Top (lblOptions),
+            X = Pos.Right (ckbAutoHide) + 1,
+            Text = "Sho_wPercent",
+            CheckedState = scrollBar.ShowPercent ? CheckState.Checked : CheckState.UnChecked
         };
-        view.Add (lblPositionChanged);
+        ckbShowPercent.CheckedStateChanging += (s, e) => scrollBar.ShowPercent = e.NewValue == CheckState.Checked;
+        frameView.Add (ckbShowPercent);
 
-        scrollBar.PositionChanged += (s, e) =>
-                                  {
-                                      lblPositionChanged.Text = $"PositionChanged event - CurrentValue: {e.CurrentValue}";
-                                      scrollPosition.Value = e.CurrentValue;
-                                  };
+        //var ckbKeepContentInAllViewport = new CheckBox
+        //{
+        //    X = Pos.Right (ckbShowScrollIndicator) + 1, Y = Pos.Bottom (scrollPosition), Text = "KeepContentInAllViewport",
+        //    CheckedState = scrollBar.KeepContentInAllViewport ? CheckState.Checked : CheckState.UnChecked
+        //};
+        //ckbKeepContentInAllViewport.CheckedStateChanging += (s, e) => scrollBar.KeepContentInAllViewport = e.NewValue == CheckState.Checked;
+        //view.Add (ckbKeepContentInAllViewport);
 
         var lblScrollFrame = new Label
         {
-            Y = Pos.Bottom (lblPositionChanged) + 1
+            Y = Pos.Bottom (lblOptions) + 1
         };
-        view.Add (lblScrollFrame);
+        frameView.Add (lblScrollFrame);
 
         var lblScrollViewport = new Label
         {
             Y = Pos.Bottom (lblScrollFrame)
         };
-        view.Add (lblScrollViewport);
+        frameView.Add (lblScrollViewport);
 
         var lblScrollContentSize = new Label
         {
             Y = Pos.Bottom (lblScrollViewport)
         };
-        view.Add (lblScrollContentSize);
-
+        frameView.Add (lblScrollContentSize);
 
         scrollBar.SubviewsLaidOut += (s, e) =>
-                                 {
-                                     lblScrollFrame.Text = $"ScrollBar Frame: {scrollBar.Frame.ToString ()}";
-                                     lblScrollViewport.Text = $"ScrollBar Viewport: {scrollBar.Viewport.ToString ()}";
-                                     lblScrollContentSize.Text = $"ScrollBar ContentSize: {scrollBar.GetContentSize ().ToString ()}";
-                                 };
-
-        editor.Initialized += (s, e) =>
-                              {
-                                  scrollBar.Size = int.Max (app.GetContentSize ().Height * 2, app.GetContentSize ().Width * 2);
-                                  editor.ViewToEdit = scrollBar;
-                              };
-
-        app.Closed += (s, e) => View.Diagnostics = _diagnosticFlags;
+                                     {
+                                         lblScrollFrame.Text = $"Scroll Frame: {scrollBar.Frame.ToString ()}";
+                                         lblScrollViewport.Text = $"Scroll Viewport: {scrollBar.Viewport.ToString ()}";
+                                         lblScrollContentSize.Text = $"Scroll ContentSize: {scrollBar.GetContentSize ().ToString ()}";
+                                     };
+
+        EventLog eventLog = new ()
+        {
+            X = Pos.AnchorEnd () - 1,
+            Y = 0,
+            Height = Dim.Height (frameView),
+            BorderStyle = LineStyle.Single,
+            ViewToLog = scrollBar
+        };
+        app.Add (eventLog);
+        frameView.Width = Dim.Fill (Dim.Func (() => Math.Max (28, eventLog.Frame.Width + 1)));
+
+        app.Initialized += AppOnInitialized;
+
+
+        void AppOnInitialized (object sender, EventArgs e)
+        {
+            scrollBar.SizeChanged += (s, e) =>
+                                     {
+                                         eventLog.Log ($"SizeChanged: {e.CurrentValue}");
+
+                                         if (scrollSize.Value != e.CurrentValue)
+                                         {
+                                             scrollSize.Value = e.CurrentValue;
+                                         }
+                                     };
+
+            scrollBar.SliderPositionChanging += (s, e) =>
+                                          {
+                                              eventLog.Log ($"SliderPositionChanging: {e.CurrentValue}");
+                                              eventLog.Log ($"  NewValue: {e.NewValue}");
+                                          };
+
+            scrollBar.SliderPositionChanged += (s, e) =>
+                                         {
+                                             eventLog.Log ($"SliderPositionChanged: {e.CurrentValue}");
+                                             eventLog.Log ($"  ContentPosition: {scrollBar.ContentPosition}");
+                                             scrollSliderPosition.Value = e.CurrentValue;
+                                         };
+
+            editor.Initialized += (s, e) =>
+                                  {
+                                      scrollBar.Size = int.Max (app.GetContentSize ().Height * 2, app.GetContentSize ().Width * 2);
+                                      editor.ViewToEdit = scrollBar;
+                                  };
+
+        }
 
         Application.Run (app);
         app.Dispose ();

+ 6 - 6
UICatalog/Scenarios/ScrollDemo.cs

@@ -160,7 +160,7 @@ public class ScrollDemo : Scenario
 
         NumericUpDown<int> scrollPosition = new ()
         {
-            Value = scroll.Position,
+            Value = scroll.SliderPosition,
             X = Pos.Right (lblPosition) + 1,
             Y = Pos.Top (lblPosition)
         };
@@ -175,12 +175,12 @@ public class ScrollDemo : Scenario
                                                 return;
                                             }
 
-                                            if (scroll.Position != e.NewValue)
+                                            if (scroll.SliderPosition != e.NewValue)
                                             {
-                                                scroll.Position = e.NewValue;
+                                                scroll.SliderPosition = e.NewValue;
                                             }
 
-                                            if (scroll.Position != e.NewValue)
+                                            if (scroll.SliderPosition != e.NewValue)
                                             {
                                                 e.Cancel = true;
                                             }
@@ -216,7 +216,7 @@ public class ScrollDemo : Scenario
         };
         frameView.Add (lblPosChanging);
 
-        scroll.PositionChanging += (s, e) => { lblPosChanging.Text = $"PositionChanging event - CurrentValue: {e.CurrentValue}; NewValue: {e.NewValue}"; };
+        scroll.SliderPositionChanging += (s, e) => { lblPosChanging.Text = $"PositionChanging event - CurrentValue: {e.CurrentValue}; NewValue: {e.NewValue}"; };
 
         var lblPositionChanged = new Label
         {
@@ -224,7 +224,7 @@ public class ScrollDemo : Scenario
         };
         frameView.Add (lblPositionChanged);
 
-        scroll.PositionChanged += (s, e) =>
+        scroll.SliderPositionChanged += (s, e) =>
                                   {
                                       lblPositionChanged.Text = $"PositionChanged event - CurrentValue: {e.CurrentValue}";
                                       scrollPosition.Value = e.CurrentValue;

+ 55 - 55
UnitTests/Views/ScrollBarTests.cs

@@ -179,12 +179,12 @@ public class ScrollBarTests
 
         _ = TestHelpers.AssertDriverContentsWithFrameAre (firstVertExpected, _output);
 
-        scrollBar.Position = 4;
+        scrollBar.SliderPosition = 4;
         Application.RunIteration (ref rs);
 
         _ = TestHelpers.AssertDriverContentsWithFrameAre (middleVertExpected, _output);
 
-        scrollBar.Position = 10;
+        scrollBar.SliderPosition = 10;
         Application.RunIteration (ref rs);
 
         _ = TestHelpers.AssertDriverContentsWithFrameAre (endVertExpected, _output);
@@ -197,18 +197,18 @@ public class ScrollBarTests
         scrollBar.Orientation = Orientation.Horizontal;
         scrollBar.Width = 10;
         scrollBar.Height = 1;
-        scrollBar.Position = 0;
+        scrollBar.SliderPosition = 0;
         scrollBar.Size = size;
         Application.RunIteration (ref rs);
 
         _ = TestHelpers.AssertDriverContentsWithFrameAre (firstHoriExpected, _output);
 
-        scrollBar.Position = 4;
+        scrollBar.SliderPosition = 4;
         Application.RunIteration (ref rs);
 
         _ = TestHelpers.AssertDriverContentsWithFrameAre (middleHoriExpected, _output);
 
-        scrollBar.Position = 10;
+        scrollBar.SliderPosition = 10;
         Application.RunIteration (ref rs);
 
         _ = TestHelpers.AssertDriverContentsWithFrameAre (endHoriExpected, _output);
@@ -226,7 +226,7 @@ public class ScrollBarTests
         Assert.False (scrollBar.CanFocus);
         Assert.Equal (Orientation.Vertical, scrollBar.Orientation);
         Assert.Equal (0, scrollBar.Size);
-        Assert.Equal (0, scrollBar.Position);
+        Assert.Equal (0, scrollBar.SliderPosition);
         Assert.Equal ("Auto(Content,Absolute(1),)", scrollBar.Width!.ToString ());
         Assert.Equal ("Auto(Content,Absolute(1),)", scrollBar.Height!.ToString ());
         //Assert.True (scrollBar.ShowScrollIndicator);
@@ -241,7 +241,7 @@ public class ScrollBarTests
         view.Padding.Thickness = new (0, 0, 2, 0);
         view.SetContentSize (new (view.Viewport.Width, 30));
         var scrollBar = new ScrollBar { Width = 2, Height = Dim.Fill (), Size = view.GetContentSize ().Height };
-        scrollBar.PositionChanged += (_, e) => view.Viewport = view.Viewport with { Y = e.CurrentValue };
+        scrollBar.SliderPositionChanged += (_, e) => view.Viewport = view.Viewport with { Y = e.CurrentValue };
         view.Padding.Add (scrollBar);
         var top = new Toplevel ();
         top.Add (view);
@@ -256,10 +256,10 @@ public class ScrollBarTests
         Assert.Equal (30, scrollBar.Size);
 
         scrollBar.KeepContentInAllViewport = false;
-        scrollBar.Position = 50;
-        Assert.Equal (scrollBar.Position, scrollBar.Size - 1);
-        Assert.Equal (scrollBar.Position, view.Viewport.Y);
-        Assert.Equal (29, scrollBar.Position);
+        scrollBar.SliderPosition = 50;
+        Assert.Equal (scrollBar.SliderPosition, scrollBar.Size - 1);
+        Assert.Equal (scrollBar.SliderPosition, view.Viewport.Y);
+        Assert.Equal (29, scrollBar.SliderPosition);
         Assert.Equal (29, view.Viewport.Y);
 
         top.Dispose ();
@@ -350,7 +350,7 @@ public class ScrollBarTests
             Width = orientation == Orientation.Vertical ? 1 : 10,
             Height = orientation == Orientation.Vertical ? 10 : 1,
             Orientation = orientation, Size = size,
-            Position = position,
+            SliderPosition = position,
             KeepContentInAllViewport = true
         };
         var top = new Toplevel ();
@@ -366,7 +366,7 @@ public class ScrollBarTests
                                       ScreenPosition = orientation == Orientation.Vertical ? new (0, location) : new Point (location, 0),
                                       Flags = MouseFlags.Button1Pressed
                                   });
-        Assert.Equal (expectedPos, scrollBar.Position);
+        Assert.Equal (expectedPos, scrollBar.SliderPosition);
 
         Application.RunIteration (ref rs);
         _ = TestHelpers.AssertDriverContentsWithFrameAre (expectedOut, _output);
@@ -727,7 +727,7 @@ public class ScrollBarTests
             Width = orientation == Orientation.Vertical ? 1 : 10,
             Height = orientation == Orientation.Vertical ? 10 : 1,
             Orientation = orientation,
-            Size = size, Position = position,
+            Size = size, SliderPosition = position,
             KeepContentInAllViewport = true
         };
         var top = new Toplevel ();
@@ -774,7 +774,7 @@ public class ScrollBarTests
 
         Assert.Equal ("scrollSlider", Application.MouseGrabView?.Id);
         Assert.IsType<ScrollSlider> (Application.MouseGrabView);
-        Assert.Equal (expectedPos, scrollBar.Position);
+        Assert.Equal (expectedPos, scrollBar.SliderPosition);
 
         Application.RunIteration (ref rs);
         _ = TestHelpers.AssertDriverContentsWithFrameAre (expectedOut, _output);
@@ -806,7 +806,7 @@ public class ScrollBarTests
         var scroll = (Scroll)scrollBar.Subviews.FirstOrDefault (x => x is Scroll);
         Rectangle scrollSliderFrame = scroll!.Subviews.FirstOrDefault (x => x is ScrollSlider)!.Frame;
         Assert.Equal (scrollSliderFrame, orientation == Orientation.Vertical ? new (0, 0, 1, 4) : new (0, 0, 4, 1));
-        Assert.Equal (0, scrollBar.Position);
+        Assert.Equal (0, scrollBar.SliderPosition);
 
         Application.RunIteration (ref rs);
 
@@ -822,11 +822,11 @@ public class ScrollBarTests
 
             if (i < 10)
             {
-                Assert.Equal (i + 1, scrollBar.Position);
+                Assert.Equal (i + 1, scrollBar.SliderPosition);
             }
             else
             {
-                Assert.Equal (i, scrollBar.Position);
+                Assert.Equal (i, scrollBar.SliderPosition);
 
                 Assert.Equal (
                               orientation == Orientation.Vertical ? new (0, 4) : new (4, 0),
@@ -842,11 +842,11 @@ public class ScrollBarTests
 
             if (i > 0)
             {
-                Assert.Equal (i - 1, scrollBar.Position);
+                Assert.Equal (i - 1, scrollBar.SliderPosition);
             }
             else
             {
-                Assert.Equal (0, scrollBar.Position);
+                Assert.Equal (0, scrollBar.SliderPosition);
                 Assert.Equal (new (0, 0), scroll.Subviews.FirstOrDefault (x => x is ScrollSlider)!.Frame.Location);
             }
         }
@@ -861,7 +861,7 @@ public class ScrollBarTests
         var scrollBar = new ScrollBar
         {
             X = 10, Y = 10, Width = orientation == Orientation.Vertical ? 1 : 10, Height = orientation == Orientation.Vertical ? 10 : 1, Size = 20,
-            Position = 5, Orientation = orientation, KeepContentInAllViewport = true
+            SliderPosition = 5, Orientation = orientation, KeepContentInAllViewport = true
         };
         var top = new Toplevel ();
         top.Add (scrollBar);
@@ -902,19 +902,19 @@ public class ScrollBarTests
     public void Position_Cannot_Be_Negative_Nor_Greater_Than_Size_Minus_Frame_Length_KeepContentInAllViewport_True (Orientation orientation, int size, int expectedPos1, int expectedPos2)
     {
         var scrollBar = new ScrollBar { Orientation = orientation, Height = 10, Size = size, KeepContentInAllViewport = true };
-        Assert.Equal (0, scrollBar.Position);
+        Assert.Equal (0, scrollBar.SliderPosition);
 
-        scrollBar.Position = -1;
+        scrollBar.SliderPosition = -1;
         scrollBar.Layout ();
-        Assert.Equal (0, scrollBar.Position);
+        Assert.Equal (0, scrollBar.SliderPosition);
 
-        scrollBar.Position = size;
+        scrollBar.SliderPosition = size;
         scrollBar.Layout ();
-        Assert.Equal (expectedPos1, scrollBar.Position);
+        Assert.Equal (expectedPos1, scrollBar.SliderPosition);
 
-        scrollBar.Position = expectedPos2;
+        scrollBar.SliderPosition = expectedPos2;
         scrollBar.Layout ();
-        Assert.Equal (expectedPos2, scrollBar.Position);
+        Assert.Equal (expectedPos2, scrollBar.SliderPosition);
     }
 
     [Fact]
@@ -924,7 +924,7 @@ public class ScrollBarTests
         var changedCount = 0;
         var scrollBar = new ScrollBar { Size = 10 };
 
-        scrollBar.PositionChanging += (s, e) =>
+        scrollBar.SliderPositionChanging += (s, e) =>
                                       {
                                           if (changingCount == 0)
                                           {
@@ -933,16 +933,16 @@ public class ScrollBarTests
 
                                           changingCount++;
                                       };
-        scrollBar.PositionChanged += (s, e) => changedCount++;
+        scrollBar.SliderPositionChanged += (s, e) => changedCount++;
 
-        scrollBar.Position = 1;
-        Assert.Equal (0, scrollBar.Position);
+        scrollBar.SliderPosition = 1;
+        Assert.Equal (0, scrollBar.SliderPosition);
         Assert.Equal (1, changingCount);
         Assert.Equal (0, changedCount);
 
-        scrollBar.Position = 1;
+        scrollBar.SliderPosition = 1;
         scrollBar.Layout ();
-        Assert.Equal (1, scrollBar.Position);
+        Assert.Equal (1, scrollBar.SliderPosition);
         Assert.Equal (2, changingCount);
         Assert.Equal (1, changedCount);
     }
@@ -954,73 +954,73 @@ public class ScrollBarTests
         var cancel = false;
         var changed = 0;
         var scrollBar = new ScrollBar { Height = 10, Size = 20, KeepContentInAllViewport = true };
-        scrollBar.PositionChanging += Scroll_PositionChanging;
-        scrollBar.PositionChanged += Scroll_PositionChanged;
+        scrollBar.SliderPositionChanging += Scroll_PositionChanging;
+        scrollBar.SliderPositionChanged += Scroll_PositionChanged;
 
         Assert.Equal (Orientation.Vertical, scrollBar.Orientation);
         scrollBar.Layout ();
         Assert.Equal (new (0, 0, 1, 10), scrollBar.Viewport);
-        Assert.Equal (0, scrollBar.Position);
+        Assert.Equal (0, scrollBar.SliderPosition);
         Assert.Equal (0, changing);
         Assert.Equal (0, changed);
 
-        scrollBar.Position = 0;
+        scrollBar.SliderPosition = 0;
         scrollBar.Layout ();
-        Assert.Equal (0, scrollBar.Position);
+        Assert.Equal (0, scrollBar.SliderPosition);
         Assert.Equal (0, changing);
         Assert.Equal (0, changed);
 
-        scrollBar.Position = 1;
+        scrollBar.SliderPosition = 1;
         scrollBar.Layout ();
-        Assert.Equal (1, scrollBar.Position);
+        Assert.Equal (1, scrollBar.SliderPosition);
         Assert.Equal (1, changing);
         Assert.Equal (1, changed);
 
         Reset ();
         cancel = true;
-        scrollBar.Position = 2;
+        scrollBar.SliderPosition = 2;
         scrollBar.Layout ();
-        Assert.Equal (1, scrollBar.Position);
+        Assert.Equal (1, scrollBar.SliderPosition);
         Assert.Equal (1, changing);
         Assert.Equal (0, changed);
 
         Reset ();
-        scrollBar.Position = 10;
+        scrollBar.SliderPosition = 10;
         scrollBar.Layout ();
-        Assert.Equal (10, scrollBar.Position);
+        Assert.Equal (10, scrollBar.SliderPosition);
         Assert.Equal (1, changing);
         Assert.Equal (1, changed);
 
         Reset ();
-        scrollBar.Position = 11;
+        scrollBar.SliderPosition = 11;
         scrollBar.Layout ();
-        Assert.Equal (10, scrollBar.Position);
+        Assert.Equal (10, scrollBar.SliderPosition);
         Assert.Equal (0, changing);
         Assert.Equal (0, changed);
 
         Reset ();
-        scrollBar.Position = 12;
+        scrollBar.SliderPosition = 12;
         scrollBar.Layout ();
-        Assert.Equal (10, scrollBar.Position);
+        Assert.Equal (10, scrollBar.SliderPosition);
         Assert.Equal (0, changing);
         Assert.Equal (0, changed);
 
         Reset ();
-        scrollBar.Position = 13;
+        scrollBar.SliderPosition = 13;
         scrollBar.Layout ();
-        Assert.Equal (10, scrollBar.Position);
+        Assert.Equal (10, scrollBar.SliderPosition);
         Assert.Equal (0, changing);
         Assert.Equal (0, changed);
 
         Reset ();
-        scrollBar.Position = 0;
+        scrollBar.SliderPosition = 0;
         scrollBar.Layout ();
-        Assert.Equal (0, scrollBar.Position);
+        Assert.Equal (0, scrollBar.SliderPosition);
         Assert.Equal (1, changing);
         Assert.Equal (1, changed);
 
-        scrollBar.PositionChanging -= Scroll_PositionChanging;
-        scrollBar.PositionChanged -= Scroll_PositionChanged;
+        scrollBar.SliderPositionChanging -= Scroll_PositionChanging;
+        scrollBar.SliderPositionChanged -= Scroll_PositionChanged;
 
         void Scroll_PositionChanging (object sender, CancelEventArgs<int> e)
         {

+ 34 - 34
UnitTests/Views/ScrollTests.cs

@@ -34,10 +34,10 @@ public class ScrollTests
         };
         super.Add (scroll);
         scroll.Layout ();
-        scroll.Position = 1;
+        scroll.SliderPosition = 1;
         scroll.Orientation = Orientation.Horizontal;
 
-        Assert.Equal (0, scroll.Position);
+        Assert.Equal (0, scroll.SliderPosition);
     }
 
 
@@ -224,7 +224,7 @@ public class ScrollTests
         Assert.False (scroll.CanFocus);
         Assert.Equal (Orientation.Vertical, scroll.Orientation);
         Assert.Equal (0, scroll.Size);
-        Assert.Equal (0, scroll.Position);
+        Assert.Equal (0, scroll.SliderPosition);
     }
 
     //[Fact]
@@ -343,7 +343,7 @@ public class ScrollTests
             Width = orientation == Orientation.Vertical ? 1 : 10,
             Height = orientation == Orientation.Vertical ? 10 : 1,
             Orientation = orientation, Size = size,
-            Position = position,
+            SliderPosition = position,
         };
         var top = new Toplevel ();
         top.Add (scroll);
@@ -358,7 +358,7 @@ public class ScrollTests
                                       ScreenPosition = orientation == Orientation.Vertical ? new (0, location) : new Point (location, 0),
                                       Flags = MouseFlags.Button1Pressed
                                   });
-        Assert.Equal (expectedPos, scroll.Position);
+        Assert.Equal (expectedPos, scroll.SliderPosition);
 
         Application.RunIteration (ref rs);
         _ = TestHelpers.AssertDriverContentsWithFrameAre (expectedOut, _output);
@@ -719,7 +719,7 @@ public class ScrollTests
             Width = orientation == Orientation.Vertical ? 1 : 10,
             Height = orientation == Orientation.Vertical ? 10 : 1,
             Orientation = orientation,
-            Size = size, Position = position,
+            Size = size, SliderPosition = position,
         };
         var top = new Toplevel ();
         top.Add (scroll);
@@ -765,7 +765,7 @@ public class ScrollTests
         }
 
         Assert.Equal ("scrollSlider", Application.MouseGrabView?.Id);
-        Assert.Equal (expectedPos, scroll.Position);
+        Assert.Equal (expectedPos, scroll.SliderPosition);
 
         Application.RunIteration (ref rs);
         _ = TestHelpers.AssertDriverContentsWithFrameAre (expectedOut, _output);
@@ -788,7 +788,7 @@ public class ScrollTests
         var scroll = new Scroll
         {
             X = 10, Y = 10, Width = orientation == Orientation.Vertical ? 1 : 10, Height = orientation == Orientation.Vertical ? 10 : 1, Size = 20,
-            Position = 5, Orientation = orientation
+            SliderPosition = 5, Orientation = orientation
         };
         var top = new Toplevel ();
         top.Add (scroll);
@@ -847,10 +847,10 @@ public class ScrollTests
         scroll.Size = scrollSize;
         super.Layout ();
 
-        scroll.Position = scrollPosition;
+        scroll.SliderPosition = scrollPosition;
         super.Layout ();
 
-        Assert.True (scroll.Position <= scrollSize);
+        Assert.True (scroll.SliderPosition <= scrollSize);
     }
 
     [Fact]
@@ -861,7 +861,7 @@ public class ScrollTests
         var scroll = new Scroll { Size = 10 };
         scroll.Layout ();
 
-        scroll.PositionChanging += (s, e) =>
+        scroll.SliderPositionChanging += (s, e) =>
                                    {
                                        if (changingCount == 0)
                                        {
@@ -870,15 +870,15 @@ public class ScrollTests
 
                                        changingCount++;
                                    };
-        scroll.PositionChanged += (s, e) => changedCount++;
+        scroll.SliderPositionChanged += (s, e) => changedCount++;
 
-        scroll.Position = 1;
-        Assert.Equal (0, scroll.Position);
+        scroll.SliderPosition = 1;
+        Assert.Equal (0, scroll.SliderPosition);
         Assert.Equal (1, changingCount);
         Assert.Equal (0, changedCount);
 
-        scroll.Position = 1;
-        Assert.Equal (1, scroll.Position);
+        scroll.SliderPosition = 1;
+        Assert.Equal (1, scroll.SliderPosition);
         Assert.Equal (2, changingCount);
         Assert.Equal (1, changedCount);
     }
@@ -890,53 +890,53 @@ public class ScrollTests
         var cancel = false;
         var changed = 0;
         var scroll = new Scroll { Height = 10, Size = 20 };
-        scroll.PositionChanging += Scroll_PositionChanging;
-        scroll.PositionChanged += Scroll_PositionChanged;
+        scroll.SliderPositionChanging += Scroll_PositionChanging;
+        scroll.SliderPositionChanged += Scroll_PositionChanged;
 
         Assert.Equal (Orientation.Vertical, scroll.Orientation);
         scroll.Layout ();
         Assert.Equal (new (0, 0, 1, 10), scroll.Viewport);
-        Assert.Equal (0, scroll.Position);
+        Assert.Equal (0, scroll.SliderPosition);
         Assert.Equal (0, changing);
         Assert.Equal (0, changed);
 
-        scroll.Position = 0;
-        Assert.Equal (0, scroll.Position);
+        scroll.SliderPosition = 0;
+        Assert.Equal (0, scroll.SliderPosition);
         Assert.Equal (0, changing);
         Assert.Equal (0, changed);
 
-        scroll.Position = 1;
-        Assert.Equal (1, scroll.Position);
+        scroll.SliderPosition = 1;
+        Assert.Equal (1, scroll.SliderPosition);
         Assert.Equal (1, changing);
         Assert.Equal (1, changed);
 
         Reset ();
         cancel = true;
-        scroll.Position = 2;
-        Assert.Equal (1, scroll.Position);
+        scroll.SliderPosition = 2;
+        Assert.Equal (1, scroll.SliderPosition);
         Assert.Equal (1, changing);
         Assert.Equal (0, changed);
 
         Reset ();
-        scroll.Position = 10;
-        Assert.Equal (10, scroll.Position);
+        scroll.SliderPosition = 10;
+        Assert.Equal (10, scroll.SliderPosition);
         Assert.Equal (1, changing);
         Assert.Equal (1, changed);
 
         Reset ();
-        scroll.Position = 11;
-        Assert.Equal (10, scroll.Position);
+        scroll.SliderPosition = 11;
+        Assert.Equal (10, scroll.SliderPosition);
         Assert.Equal (0, changing);
         Assert.Equal (0, changed);
 
         Reset ();
-        scroll.Position = 0;
-        Assert.Equal (0, scroll.Position);
+        scroll.SliderPosition = 0;
+        Assert.Equal (0, scroll.SliderPosition);
         Assert.Equal (1, changing);
         Assert.Equal (1, changed);
 
-        scroll.PositionChanging -= Scroll_PositionChanging;
-        scroll.PositionChanged -= Scroll_PositionChanged;
+        scroll.SliderPositionChanging -= Scroll_PositionChanging;
+        scroll.SliderPositionChanged -= Scroll_PositionChanged;
 
         void Scroll_PositionChanging (object sender, CancelEventArgs<int> e)
         {
@@ -1301,7 +1301,7 @@ public class ScrollTests
 
         scroll.Size = sliderSize;
         scroll.Layout ();
-        scroll.Position = sliderPosition;
+        scroll.SliderPosition = sliderPosition;
 
         super.BeginInit ();
         super.EndInit ();