瀏覽代碼

Merge branch 'v2_2489-scrollbar' of tig:tig/Terminal.Gui into v2_2489-scrollbar

Tig 8 月之前
父節點
當前提交
0900efc324

+ 10 - 3
Terminal.Gui/View/View.Content.cs

@@ -313,7 +313,7 @@ public partial class View
                 //SetSubViewNeedsDraw();
             }
 
-            OnViewportChanged (new (IsInitialized ? Viewport : Rectangle.Empty, oldViewport));
+            RaiseViewportChangedEvent (oldViewport);
 
             return;
         }
@@ -326,7 +326,7 @@ public partial class View
             Size = newSize
         };
 
-        OnViewportChanged (new (IsInitialized ? Viewport : Rectangle.Empty, oldViewport));
+        // Note, setting the Frame will cause ViewportChanged to be raised.
 
         return;
 
@@ -368,6 +368,13 @@ public partial class View
         }
     }
 
+    private void RaiseViewportChangedEvent (Rectangle oldViewport)
+    {
+        var args = new DrawEventArgs (IsInitialized ? Viewport : Rectangle.Empty, oldViewport);
+        OnViewportChanged (args);
+        ViewportChanged?.Invoke (this, args);
+    }
+
     /// <summary>
     ///     Fired when the <see cref="Viewport"/> changes. This event is fired after the <see cref="Viewport"/> has been
     ///     updated.
@@ -378,7 +385,7 @@ public partial class View
     ///     Called when the <see cref="Viewport"/> changes. Invokes the <see cref="ViewportChanged"/> event.
     /// </summary>
     /// <param name="e"></param>
-    protected virtual void OnViewportChanged (DrawEventArgs e) { ViewportChanged?.Invoke (this, e); }
+    protected virtual void OnViewportChanged (DrawEventArgs e) { }
 
     /// <summary>
     ///     Converts a <see cref="Viewport"/>-relative location and size to a screen-relative location and size.

+ 5 - 0
Terminal.Gui/View/View.Layout.cs

@@ -98,6 +98,11 @@ public partial class View // Layout APIs
         // BUGBUG: When SetFrame is called from Frame_set, this event gets raised BEFORE OnResizeNeeded. Is that OK?
         OnFrameChanged (in frame);
         FrameChanged?.Invoke (this, new (in frame));
+
+        if (oldViewport != Viewport)
+        {
+            RaiseViewportChangedEvent (oldViewport);
+        }
         return true;
     }
 

+ 133 - 128
Terminal.Gui/View/View.ScrollBars.cs

@@ -11,145 +11,145 @@ public partial class View
     /// </summary>
     private void SetupScrollBars ()
     {
-        _horizontalScrollBar = new Lazy<ScrollBar> (
-                                                    () =>
-                                                    {
-                                                        var scrollBar = new ScrollBar
-                                                        {
-                                                            Orientation = Orientation.Horizontal,
-                                                            X = 0,
-                                                            Y = Pos.AnchorEnd (),
-                                                            Width = Dim.Fill (
-                                                                              Dim.Func (
-                                                                                        () =>
-                                                                                        {
-                                                                                            if (_verticalScrollBar.IsValueCreated)
-                                                                                            {
-                                                                                                return _verticalScrollBar.Value.Visible ? 1 : 0;
-                                                                                            }
-
-                                                                                            return 0;
-                                                                                        })),
-                                                            ScrollableContentSize = GetContentSize ().Width,
-                                                            Visible = false
-                                                        };
-
-                                                        Padding?.Add (scrollBar);
-
-                                                        scrollBar.Initialized += (_, _) =>
-                                                                                 {
-                                                                                     Padding!.Thickness = Padding.Thickness with
-                                                                                     {
-                                                                                         Bottom = scrollBar.Visible ? Padding.Thickness.Bottom + 1 : 0
-                                                                                     };
-
-                                                                                     scrollBar.PositionChanged += (_, args) =>
-                                                                                                                  {
-                                                                                                                      Viewport = Viewport with
-                                                                                                                      {
-                                                                                                                          X = Math.Min (
-                                                                                                                                        args.CurrentValue,
-                                                                                                                                        GetContentSize ().Width - (Viewport.Width))
-                                                                                                                      };
-                                                                                                                  };
-
-                                                                                     scrollBar.VisibleChanged += (_, _) =>
-                                                                                                                 {
-                                                                                                                     Padding.Thickness = Padding.Thickness with
-                                                                                                                     {
-                                                                                                                         Bottom = scrollBar.Visible
-                                                                                                                                      ? Padding.Thickness.Bottom + 1
-                                                                                                                                      : Padding.Thickness.Bottom - 1
-                                                                                                                     };
-                                                                                                                 };
-                                                                                 };
-
-                                                        return scrollBar;
-                                                    });
-
-        _verticalScrollBar = new Lazy<ScrollBar> (
+        if (this is Adornment)
+        {
+            return;
+        }
+
+        _verticalScrollBar = new (() => ScrollBarFactory (Orientation.Vertical));
+        _horizontalScrollBar = new (() => ScrollBarFactory (Orientation.Horizontal));
+
+        ViewportChanged += (_, _) =>
+                           {
+                               if (_verticalScrollBar.IsValueCreated)
+                               {
+                                   _verticalScrollBar.Value.VisibleContentSize = Viewport.Height;
+                                   _verticalScrollBar.Value.Position = Viewport.Y;
+                               }
+
+                               if (_horizontalScrollBar.IsValueCreated)
+                               {
+                                   _horizontalScrollBar.Value.VisibleContentSize = Viewport.Width;
+                                   _horizontalScrollBar.Value.Position = Viewport.X;
+                               }
+                           };
+
+        ContentSizeChanged += (_, _) =>
+                              {
+                                  if (_verticalScrollBar.IsValueCreated)
+                                  {
+                                      _verticalScrollBar.Value.ScrollableContentSize = GetContentSize ().Height;
+                                  }
+
+                                  if (_horizontalScrollBar.IsValueCreated)
+                                  {
+                                      _horizontalScrollBar.Value.ScrollableContentSize = GetContentSize ().Width;
+                                  }
+                              };
+    }
+
+    private ScrollBar ScrollBarFactory (Orientation orientation)
+    {
+        var scrollBar = new ScrollBar
+        {
+            Orientation = orientation,
+            AutoHide = true
+        };
+
+        if (orientation == Orientation.Vertical)
+        {
+            scrollBar.X = Pos.AnchorEnd ();
+
+            // Ensure the scrollbar's length accomodates for the opposite scrollbar's visibility
+            scrollBar.Height = Dim.Fill (
+                                         Dim.Func (
+                                                   () =>
+                                                   {
+                                                       if (_horizontalScrollBar.IsValueCreated)
+                                                       {
+                                                           return _horizontalScrollBar.Value.Visible ? 1 : 0;
+                                                       }
+
+                                                       return 0;
+                                                   }));
+            scrollBar.ScrollableContentSize = GetContentSize ().Height;
+        }
+        else
+        {
+            scrollBar.Y = Pos.AnchorEnd ();
+
+            // Ensure the scrollbar's length accomodates for the opposite scrollbar's visibility
+            scrollBar.Width = Dim.Fill (
+                                        Dim.Func (
                                                   () =>
                                                   {
-                                                      var scrollBar = new ScrollBar
+                                                      if (_verticalScrollBar.IsValueCreated)
                                                       {
-                                                          Orientation = Orientation.Vertical,
-                                                          X = Pos.AnchorEnd (),
-                                                          Y = Pos.Func (() => Padding.Thickness.Top),
-                                                          Height = Dim.Fill (
-                                                                             Dim.Func (
-                                                                                       () =>
-                                                                                       {
-                                                                                           if (_horizontalScrollBar.IsValueCreated)
-                                                                                           {
-                                                                                               return _horizontalScrollBar.Value.Visible ? 1 : 0;
-                                                                                           }
-
-                                                                                           return 0;
-                                                                                       })),
-                                                          ScrollableContentSize = GetContentSize ().Height,
-                                                          Visible = false
-                                                      };
-
-                                                      Padding?.Add (scrollBar);
-
-                                                      scrollBar.Initialized += (_, _) =>
-                                                                               {
-                                                                                   if (Padding is { })
-                                                                                   {
-                                                                                       Padding.Thickness = Padding.Thickness with
-                                                                                       {
-                                                                                           Right = scrollBar.Visible ? Padding.Thickness.Right + 1 : 0
-                                                                                       };
-
-                                                                                       scrollBar.PositionChanged += (_, args) =>
-                                                                                                                    {
-                                                                                                                        Viewport = Viewport with
-                                                                                                                        {
-                                                                                                                            Y = Math.Min (args.CurrentValue, GetContentSize ().Height - (Viewport.Height - 1))
-                                                                                                                        };
-                                                                                                                    };
-
-                                                                                       scrollBar.VisibleChanged += (_, _) =>
-                                                                                                                   {
-                                                                                                                       Padding.Thickness = Padding.Thickness with
-                                                                                                                       {
-                                                                                                                           Right = scrollBar.Visible
-                                                                                                                                       ? Padding.Thickness.Right + 1
-                                                                                                                                       : Padding.Thickness.Right - 1
-                                                                                                                       };
-                                                                                                                   };
-                                                                                   }
-                                                                               };
-
-                                                      return scrollBar;
-                                                  });
+                                                          return _verticalScrollBar.Value.Visible ? 1 : 0;
+                                                      }
 
-        ViewportChanged += (_, _) =>
-        {
-            if (_verticalScrollBar.IsValueCreated)
-            {
-                _verticalScrollBar.Value.VisibleContentSize = Viewport.Height;
-                _verticalScrollBar.Value.Position = Viewport.Y;
-            }
+                                                      return 0;
+                                                  }));
+            scrollBar.ScrollableContentSize = GetContentSize ().Width;
+        }
 
-            if (_horizontalScrollBar.IsValueCreated)
-            {
-                _horizontalScrollBar.Value.VisibleContentSize = Viewport.Width;
-                _horizontalScrollBar.Value.Position = Viewport.X;
-            }
-        };
+        Padding?.Add (scrollBar);
 
-        ContentSizeChanged += (_, _) =>
+        scrollBar.Initialized += OnScrollBarOnInitialized;
+
+        return scrollBar;
+
+        void OnScrollBarOnInitialized (object? o, EventArgs eventArgs)
         {
-            if (_verticalScrollBar.IsValueCreated)
+            if (orientation == Orientation.Vertical)
             {
-                _verticalScrollBar.Value.ScrollableContentSize = GetContentSize ().Height;
+                Padding!.Thickness = Padding.Thickness with { Right = scrollBar.Visible ? Padding.Thickness.Right + 1 : 0 };
+
+                scrollBar.PositionChanged += (_, args) =>
+                                             {
+                                                 Viewport = Viewport with
+                                                 {
+                                                     Y = Math.Min (
+                                                                   args.CurrentValue,
+                                                                   GetContentSize ().Height - Viewport.Height)
+                                                 };
+                                             };
+
+                scrollBar.VisibleChanged += (_, _) =>
+                                            {
+                                                Padding.Thickness = Padding.Thickness with
+                                                {
+                                                    Right = scrollBar.Visible
+                                                                ? Padding.Thickness.Right + 1
+                                                                : Padding.Thickness.Right - 1
+                                                };
+                                            };
             }
-            if (_horizontalScrollBar.IsValueCreated)
+            else
             {
-                _horizontalScrollBar.Value.ScrollableContentSize = GetContentSize ().Width;
+                Padding!.Thickness = Padding.Thickness with { Bottom = scrollBar.Visible ? Padding.Thickness.Bottom + 1 : 0 };
+
+                scrollBar.PositionChanged += (_, args) =>
+                                             {
+                                                 Viewport = Viewport with
+                                                 {
+                                                     X = Math.Min (
+                                                                   args.CurrentValue,
+                                                                   GetContentSize ().Width - Viewport.Width)
+                                                 };
+                                             };
+
+                scrollBar.VisibleChanged += (_, _) =>
+                                            {
+                                                Padding.Thickness = Padding.Thickness with
+                                                {
+                                                    Bottom = scrollBar.Visible
+                                                                 ? Padding.Thickness.Bottom + 1
+                                                                 : Padding.Thickness.Bottom - 1
+                                                };
+                                            };
             }
-        };
+        }
     }
 
     /// <summary>
@@ -165,6 +165,11 @@ public partial class View
     /// </summary>
     private void DisposeScrollBars ()
     {
+        if (this is Adornment)
+        {
+            return;
+        }
+
         if (_horizontalScrollBar.IsValueCreated)
         {
             Padding?.Remove (_horizontalScrollBar.Value);

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

@@ -150,7 +150,6 @@ public partial class View : IDisposable, ISupportInitializeNotification
         //SetupMouse ();
 
         SetupText ();
-
         SetupScrollBars ();
     }
 

+ 3 - 8
Terminal.Gui/Views/ScrollBar/ScrollBar.cs

@@ -4,6 +4,8 @@ using System.ComponentModel;
 
 namespace Terminal.Gui;
 
+// TODO: When scrollbars autohide, reset viewport to 0
+
 /// <summary>
 ///     Indicates the size of scrollable content and controls the position of the visible content, either vertically or
 ///     horizontally.
@@ -91,14 +93,7 @@ public class ScrollBar : View, IOrientation, IDesignable
 
     private void ShowHide ()
     {
-        if (Orientation == Orientation.Vertical)
-        {
-            Visible = VisibleContentSize < ScrollableContentSize;
-        }
-        else
-        {
-            Visible = VisibleContentSize < ScrollableContentSize;
-        }
+        Visible = VisibleContentSize < ScrollableContentSize;
 
         if (!AutoHide)
         {

+ 51 - 0
UnitTests/View/Layout/FrameTests.cs

@@ -259,4 +259,55 @@ public class FrameTests (ITestOutputHelper output)
         Assert.Equal (Dim.Absolute (40), v.Height);
         v.Dispose ();
     }
+
+    private class TestFrameEventsView : View
+    {
+        public int OnFrameChangedCallCount { get; private set; }
+        public int FrameChangedEventCallCount { get; private set; }
+
+        public TestFrameEventsView ()
+        {
+            FrameChanged += (sender, args) => FrameChangedEventCallCount++;
+        }
+
+        protected override void OnFrameChanged (in Rectangle frame)
+        {
+            OnFrameChangedCallCount++;
+            base.OnFrameChanged (frame);
+        }
+    }
+
+    [Fact]
+    public void OnFrameChanged_Called_When_Frame_Changes ()
+    {
+        // Arrange
+        var view = new TestFrameEventsView ();
+        var initialFrame = new Rectangle (0, 0, 10, 10);
+        var newFrame = new Rectangle (0, 0, 20, 20);
+        view.Frame = initialFrame;
+        Assert.Equal (1, view.OnFrameChangedCallCount);
+
+        // Act
+        view.Frame = newFrame;
+
+        // Assert
+        Assert.Equal (2, view.OnFrameChangedCallCount);
+    }
+
+    [Fact]
+    public void FrameChanged_Event_Raised_When_Frame_Changes ()
+    {
+        // Arrange
+        var view = new TestFrameEventsView ();
+        var initialFrame = new Rectangle (0, 0, 10, 10);
+        var newFrame = new Rectangle (0, 0, 20, 20);
+        view.Frame = initialFrame;
+        Assert.Equal (1, view.FrameChangedEventCallCount);
+
+        // Act
+        view.Frame = newFrame;
+
+        // Assert
+        Assert.Equal (2, view.FrameChangedEventCallCount);
+    }
 }

+ 87 - 0
UnitTests/View/Layout/ViewportTests.cs

@@ -387,6 +387,93 @@ public class ViewportTests (ITestOutputHelper output)
         Assert.NotEqual (view.Viewport.Size, view.GetContentSize ());
     }
 
+    private class TestViewportEventsView : View
+    {
+        public int OnViewportChangedCallCount { get; private set; }
+        public int ViewportChangedEventCallCount { get; private set; }
+
+        public TestViewportEventsView ()
+        {
+            ViewportChanged += (sender, args) => ViewportChangedEventCallCount++;
+        }
+
+        protected override void OnViewportChanged (DrawEventArgs e)
+        {
+            OnViewportChangedCallCount++;
+            base.OnViewportChanged (e);
+        }
+    }
+
+    [Fact]
+    public void OnViewportChanged_Called_When_Viewport_Changes ()
+    {
+        // Arrange
+        var view = new TestViewportEventsView ();
+        var initialViewport = new Rectangle (0, 0, 10, 10);
+        var newViewport = new Rectangle (0, 0, 20, 20);
+        Assert.Equal (0, view.OnViewportChangedCallCount);
+        view.Viewport = initialViewport;
+        Assert.Equal (1, view.OnViewportChangedCallCount);
+
+        // Act
+        view.Viewport = newViewport;
+
+        // Assert
+        Assert.Equal (2, view.OnViewportChangedCallCount);
+    }
+
+    [Fact]
+    public void ViewportChanged_Event_Raised_When_Viewport_Changes ()
+    {
+        // Arrange
+        var view = new TestViewportEventsView ();
+        var initialViewport = new Rectangle (0, 0, 10, 10);
+        var newViewport = new Rectangle (0, 0, 20, 20);
+        view.Viewport = initialViewport;
+        Assert.Equal (1, view.ViewportChangedEventCallCount);
+
+        // Act
+        view.Viewport = newViewport;
+
+        // Assert
+        Assert.Equal (2, view.ViewportChangedEventCallCount);
+    }
+
+    [Fact]
+    public void OnViewportChanged_Called_When_Frame_Changes ()
+    {
+        // Arrange
+        var view = new TestViewportEventsView ();
+        var initialFrame = new Rectangle (0, 0, 10, 10);
+        var newFrame = new Rectangle (0, 0, 20, 20);
+        Assert.Equal (0, view.OnViewportChangedCallCount);
+        view.Frame = initialFrame;
+        Assert.Equal (1, view.OnViewportChangedCallCount);
+
+        // Act
+        view.Frame = newFrame;
+
+        // Assert
+        Assert.Equal (2, view.OnViewportChangedCallCount);
+    }
+
+    [Fact]
+    public void ViewportChanged_Event_Raised_When_Frame_Changes ()
+    {
+        // Arrange
+        var view = new TestViewportEventsView ();
+        var initialFrame = new Rectangle (0, 0, 10, 10);
+        var newFrame = new Rectangle (0, 0, 20, 20);
+        view.Frame = initialFrame;
+        Assert.Equal (1, view.ViewportChangedEventCallCount);
+
+        // Act
+        view.Frame = newFrame;
+
+        // Assert
+        Assert.Equal (2, view.ViewportChangedEventCallCount);
+    }
+
     //[Theory]
     //[InlineData (0, 0, true)]
     //[InlineData (-1, 0, true)]