Browse Source

Suggestions and questions

Tig 1 year ago
parent
commit
d5b98a12ff

+ 11 - 13
Terminal.Gui/View/SuperViewChangedEventArgs.cs

@@ -1,28 +1,26 @@
 namespace Terminal.Gui;
 namespace Terminal.Gui;
 
 
 /// <summary>
 /// <summary>
-///     Args for events where the <see cref="View.SuperView"/> of a <see cref="View"/> is changed (e.g.
+///     EventArgs for events where the state of the <see cref="View.SuperView"/> of a <see cref="View"/> is changing (e.g.
 ///     <see cref="View.Removed"/> / <see cref="View.Added"/> events).
 ///     <see cref="View.Removed"/> / <see cref="View.Added"/> events).
 /// </summary>
 /// </summary>
 public class SuperViewChangedEventArgs : EventArgs
 public class SuperViewChangedEventArgs : EventArgs
 {
 {
     /// <summary>Creates a new instance of the <see cref="SuperViewChangedEventArgs"/> class.</summary>
     /// <summary>Creates a new instance of the <see cref="SuperViewChangedEventArgs"/> class.</summary>
-    /// <param name="parent"></param>
-    /// <param name="child"></param>
-    public SuperViewChangedEventArgs (View parent, View child)
+    /// <param name="superView"></param>
+    /// <param name="subView"></param>
+    public SuperViewChangedEventArgs (View superView, View subView)
     {
     {
-        Parent = parent;
-        Child = child;
+        SuperView = superView;
+        SubView = subView;
     }
     }
 
 
-    // TODO: Child is the wrong name. It should be View.
-    /// <summary>The view that is having it's <see cref="View.SuperView"/> changed</summary>
-    public View Child { get; }
+    /// <summary>The SubView that is either being added or removed from <see cref="Parent"/>.</summary>
+    public View SubView { get; }
 
 
-    // TODO: Parent is the wrong name. It should be SuperView.
     /// <summary>
     /// <summary>
-    ///     The parent.  For <see cref="View.Removed"/> this is the old parent (new parent now being null).  For
-    ///     <see cref="View.Added"/> it is the new parent to whom view now belongs.
+    ///     The SuperView that is changing state. For <see cref="View.Removed"/> this is the SuperView <see cref="SubView"/> is being removed from. For
+    ///     <see cref="View.Added"/> it is the SuperView <see cref="SubView"/> is being added to.
     /// </summary>
     /// </summary>
-    public View Parent { get; }
+    public View SuperView { get; }
 }
 }

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

@@ -182,7 +182,7 @@ public partial class View
     /// <param name="e">Event where <see cref="ViewEventArgs.View"/> is the subview being added.</param>
     /// <param name="e">Event where <see cref="ViewEventArgs.View"/> is the subview being added.</param>
     public virtual void OnAdded (SuperViewChangedEventArgs e)
     public virtual void OnAdded (SuperViewChangedEventArgs e)
     {
     {
-        View view = e.Child;
+        View view = e.SubView;
         view.IsAdded = true;
         view.IsAdded = true;
         view.OnResizeNeeded ();
         view.OnResizeNeeded ();
         view.Added?.Invoke (this, e);
         view.Added?.Invoke (this, e);
@@ -192,7 +192,7 @@ public partial class View
     /// <param name="e">Event args describing the subview being removed.</param>
     /// <param name="e">Event args describing the subview being removed.</param>
     public virtual void OnRemoved (SuperViewChangedEventArgs e)
     public virtual void OnRemoved (SuperViewChangedEventArgs e)
     {
     {
-        View view = e.Child;
+        View view = e.SubView;
         view.IsAdded = false;
         view.IsAdded = false;
         view.Removed?.Invoke (this, e);
         view.Removed?.Invoke (this, e);
     }
     }

+ 77 - 62
Terminal.Gui/Views/Scroll.cs

@@ -1,7 +1,7 @@
 namespace Terminal.Gui;
 namespace Terminal.Gui;
 
 
 /// <summary>
 /// <summary>
-///     Represents the "inside part" of a scroll bar, minus the arrows.
+///     Provides a proportional control for scrolling through content. Used within a <see cref="ScrollBar"/>.
 /// </summary>
 /// </summary>
 public class Scroll : View
 public class Scroll : View
 {
 {
@@ -39,7 +39,7 @@ public class Scroll : View
 
 
     private Orientation _orientation;
     private Orientation _orientation;
     /// <summary>
     /// <summary>
-    ///     Determines the Orientation of the scroll.
+    ///     Gets or sets if the Scroll is oriented vertically or horizontally.
     /// </summary>
     /// </summary>
     public Orientation Orientation
     public Orientation Orientation
     {
     {
@@ -53,7 +53,7 @@ public class Scroll : View
 
 
     private int _position;
     private int _position;
     /// <summary>
     /// <summary>
-    ///     The position, relative to <see cref="Size"/>, to set the scrollbar at.
+    ///     Gets or sets the position of the start of the Scroll slider, relative to <see cref="Size"/>.
     /// </summary>
     /// </summary>
     public int Position
     public int Position
     {
     {
@@ -74,26 +74,39 @@ public class Scroll : View
                 return;
                 return;
             }
             }
 
 
-            int oldPos = _position;
-            _position = value;
-            OnPositionChanged (oldPos);
 
 
             if (!_wasSliderMouse)
             if (!_wasSliderMouse)
             {
             {
                 AdjustSlider ();
                 AdjustSlider ();
             }
             }
+
+            int oldPos = _position;
+            _position = value;
+            OnPositionChanged (oldPos);
         }
         }
     }
     }
 
 
-    /// <summary>This event is raised when the position on the scrollbar has changed.</summary>
+    /// <summary>Raised when the <see cref="Position"/> has changed.</summary>
     public event EventHandler<StateEventArgs<int>> PositionChanged;
     public event EventHandler<StateEventArgs<int>> PositionChanged;
 
 
-    /// <summary>This event is raised when the position on the scrollbar is changing.</summary>
+    /// <summary>Raised when the <see cref="Position"/> is changing. Set <see cref="StateEventArgs{T}.Cancel"/> to <see langword="true"/> to prevent the position from being changed.</summary>
     public event EventHandler<StateEventArgs<int>> PositionChanging;
     public event EventHandler<StateEventArgs<int>> PositionChanging;
 
 
+    /// <summary>Virtual method called when <see cref="Position"/> has changed. Fires <see cref="PositionChanged"/>.</summary>
+    protected virtual void OnPositionChanged (int oldPos) { PositionChanged?.Invoke (this, new (oldPos, Position)); }
+
+    /// <summary>Virtual method called when <see cref="Position"/> is changing. Fires <see cref="PositionChanging"/>, which is cancelable.</summary>
+    protected virtual StateEventArgs<int> OnPositionChanging (int oldPos, int newPos)
+    {
+        StateEventArgs<int> args = new (oldPos, newPos);
+        PositionChanging?.Invoke (this, args);
+
+        return args;
+    }
+
     private int _size;
     private int _size;
     /// <summary>
     /// <summary>
-    ///     The size of content the scroll represents.
+    ///     Gets or sets the size of the Scroll. This is the total size of the content that can be scrolled through.
     /// </summary>
     /// </summary>
     public int Size
     public int Size
     {
     {
@@ -107,35 +120,10 @@ public class Scroll : View
         }
         }
     }
     }
 
 
-    /// <summary>This event is raised when the size of the scroll has changed.</summary>
+    /// <summary>Raised when <see cref="Size"/> has changed.</summary>
     public event EventHandler<StateEventArgs<int>> SizeChanged;
     public event EventHandler<StateEventArgs<int>> SizeChanged;
 
 
-    /// <inheritdoc/>
-    protected override void Dispose (bool disposing)
-    {
-        Added -= Scroll_Added;
-        Initialized -= Scroll_Initialized;
-        DrawContent -= Scroll_DrawContent;
-        MouseEvent -= Scroll_MouseEvent;
-        _slider.DrawContent -= Scroll_DrawContent;
-        _slider.MouseEvent -= Slider_MouseEvent;
-
-        base.Dispose (disposing);
-    }
-
-    /// <summary>Virtual method to invoke the <see cref="PositionChanged"/> event handler.</summary>
-    protected virtual void OnPositionChanged (int oldPos) { PositionChanged?.Invoke (this, new (oldPos, Position)); }
-
-    /// <summary>Virtual method to invoke the cancelable <see cref="PositionChanging"/> event handler.</summary>
-    protected virtual StateEventArgs<int> OnPositionChanging (int oldPos, int newPos)
-    {
-        StateEventArgs<int> args = new (oldPos, newPos);
-        PositionChanging?.Invoke (this, args);
-
-        return args;
-    }
-
-    /// <summary>Virtual method to invoke the <see cref="SizeChanged"/> event handler.</summary>
+    /// <summary>Virtual method called when <see cref="Size"/> has changed. Fires <see cref="SizeChanged"/>.</summary>
     protected void OnSizeChanged (int oldSize) { SizeChanged?.Invoke (this, new (oldSize, Size)); }
     protected void OnSizeChanged (int oldSize) { SizeChanged?.Invoke (this, new (oldSize, Size)); }
 
 
     private int GetPositionFromSliderLocation (int location)
     private int GetPositionFromSliderLocation (int location)
@@ -145,18 +133,20 @@ public class Scroll : View
             return 0;
             return 0;
         }
         }
 
 
-        int barSize = Orientation == Orientation.Vertical ? ContentSize.Height : ContentSize.Width;
+        int scrollSize = Orientation == Orientation.Vertical ? ContentSize.Height : ContentSize.Width;
 
 
         // Ensure the Position is valid if the slider is at end
         // Ensure the Position is valid if the slider is at end
-        if ((Orientation == Orientation.Vertical && location + _slider.Frame.Height == barSize)
-            || (Orientation == Orientation.Horizontal && location + _slider.Frame.Width == barSize))
+        // We use Frame here instead of ContentSize because even if the slider has a margin or border, Frame indicates the actual size
+        if ((Orientation == Orientation.Vertical && location + _slider.Frame.Height == scrollSize)
+            || (Orientation == Orientation.Horizontal && location + _slider.Frame.Width == scrollSize))
         {
         {
-            return Size - barSize;
+            return Size - scrollSize;
         }
         }
 
 
-        return Math.Min (location * Size / barSize, Size - barSize);
+        return Math.Min (location * Size / scrollSize, Size - scrollSize);
     }
     }
 
 
+    // QUESTION: This method is only called from one place. Should it be inlined? Or, should it be made internal and unit tests be provided?
     private (int Location, int Dimension) GetSliderLocationDimensionFromPosition ()
     private (int Location, int Dimension) GetSliderLocationDimensionFromPosition ()
     {
     {
         if (ContentSize.Height == 0 || ContentSize.Width == 0)
         if (ContentSize.Height == 0 || ContentSize.Width == 0)
@@ -164,37 +154,38 @@ public class Scroll : View
             return new (0, 0);
             return new (0, 0);
         }
         }
 
 
-        int barSize = Orientation == Orientation.Vertical ? ContentSize.Height : ContentSize.Width;
+        int scrollSize = Orientation == Orientation.Vertical ? ContentSize.Height : ContentSize.Width;
         int location;
         int location;
         int dimension;
         int dimension;
 
 
         if (Size > 0)
         if (Size > 0)
         {
         {
-            dimension = Math.Min (Math.Max (barSize * barSize / Size, 1), barSize);
+            dimension = Math.Min (Math.Max (scrollSize * scrollSize / Size, 1), scrollSize);
 
 
             // Ensure the Position is valid
             // Ensure the Position is valid
-            if (Position > 0 && Position + barSize > Size)
+            if (Position > 0 && Position + scrollSize > Size)
             {
             {
-                Position = Size - barSize;
+                Position = Size - scrollSize;
             }
             }
 
 
-            location = Math.Min (Position * barSize / Size, barSize - dimension);
+            location = Math.Min (Position * scrollSize / Size, scrollSize - dimension);
 
 
-            if (Position == Size - barSize && location + dimension < barSize)
+            if (Position == Size - scrollSize && location + dimension < scrollSize)
             {
             {
-                location = barSize - dimension;
+                location = scrollSize - dimension;
             }
             }
         }
         }
         else
         else
         {
         {
             location = 0;
             location = 0;
-            dimension = barSize;
+            dimension = scrollSize;
         }
         }
 
 
         return new (location, dimension);
         return new (location, dimension);
     }
     }
 
 
-    private void Parent_LayoutComplete (object sender, LayoutEventArgs e)
+    // TODO: This is unnecessary. If Scroll.Width/Height is Dim.Auto, the Superview will get resized automatically.
+    private void SuperView_LayoutComplete (object sender, LayoutEventArgs e)
     {
     {
         if (!_wasSliderMouse)
         if (!_wasSliderMouse)
         {
         {
@@ -206,19 +197,23 @@ public class Scroll : View
         }
         }
     }
     }
 
 
-    private void Parent_MouseEnter (object sender, MouseEventEventArgs e) { OnMouseEnter (e.MouseEvent); }
+    private void SuperView_MouseEnter (object sender, MouseEventEventArgs e) { OnMouseEnter (e.MouseEvent); }
 
 
-    private void Parent_MouseLeave (object sender, MouseEventEventArgs e) { OnMouseLeave (e.MouseEvent); }
+    private void SuperView_MouseLeave (object sender, MouseEventEventArgs e) { OnMouseLeave (e.MouseEvent); }
 
 
     private void Scroll_Added (object sender, SuperViewChangedEventArgs e)
     private void Scroll_Added (object sender, SuperViewChangedEventArgs e)
     {
     {
-        View parent = e.Parent is Adornment adornment ? adornment.Parent : e.Parent;
+        View parent = e.SuperView is Adornment adornment ? adornment.Parent : e.SuperView;
+
+        parent.LayoutComplete += SuperView_LayoutComplete;
 
 
-        parent.LayoutComplete += Parent_LayoutComplete;
-        parent.MouseEnter += Parent_MouseEnter;
-        parent.MouseLeave += Parent_MouseLeave;
+        // QUESTION: I really don't like this. It feels like a hack that a subview needs to track its parent's mouse events.
+        // QUESTION: Can we figure out a way to do this without tracking the parent's mouse events?
+        parent.MouseEnter += SuperView_MouseEnter;
+        parent.MouseLeave += SuperView_MouseLeave;
     }
     }
 
 
+    // TODO: Just override GetNormalColor instead of having this method (make Slider a View sub-class that overrides GetNormalColor)
     private void Scroll_DrawContent (object sender, DrawEventArgs e) { SetColorSchemeWithSuperview (sender as View); }
     private void Scroll_DrawContent (object sender, DrawEventArgs e) { SetColorSchemeWithSuperview (sender as View); }
 
 
     private void Scroll_Initialized (object sender, EventArgs e)
     private void Scroll_Initialized (object sender, EventArgs e)
@@ -226,6 +221,9 @@ public class Scroll : View
         AdjustSlider ();
         AdjustSlider ();
     }
     }
 
 
+    // TODO: I think you should create a new `internal` view named "ScrollSlider" with an `Orientation` property. It should inherit from View and override GetNormalColor and the mouse events
+    // that can be moved within it's Superview, constrained to move only horizontally or vertically depending on Orientation.
+    // This will really simplify a lot of this.
     private void Scroll_MouseEvent (object sender, MouseEventEventArgs e)
     private void Scroll_MouseEvent (object sender, MouseEventEventArgs e)
     {
     {
         MouseEvent me = e.MouseEvent;
         MouseEvent me = e.MouseEvent;
@@ -258,13 +256,13 @@ public class Scroll : View
 
 
     private void Scroll_Removed (object sender, SuperViewChangedEventArgs e)
     private void Scroll_Removed (object sender, SuperViewChangedEventArgs e)
     {
     {
-        if (e.Parent is { })
+        if (e.SuperView is { })
         {
         {
-            View parent = e.Parent is Adornment adornment ? adornment.Parent : e.Parent;
+            View parent = e.SuperView is Adornment adornment ? adornment.Parent : e.SuperView;
 
 
-            parent.LayoutComplete -= Parent_LayoutComplete;
-            parent.MouseEnter -= Parent_MouseEnter;
-            parent.MouseLeave -= Parent_MouseLeave;
+            parent.LayoutComplete -= SuperView_LayoutComplete;
+            parent.MouseEnter -= SuperView_MouseEnter;
+            parent.MouseLeave -= SuperView_MouseLeave;
         }
         }
     }
     }
 
 
@@ -290,6 +288,7 @@ public class Scroll : View
     {
     {
         TextDirection = Orientation == Orientation.Vertical ? TextDirection.TopBottom_LeftRight : TextDirection.LeftRight_TopBottom;
         TextDirection = Orientation == Orientation.Vertical ? TextDirection.TopBottom_LeftRight : TextDirection.LeftRight_TopBottom;
 
 
+        // QUESTION: Should these Glyphs be configurable via CM?
         Text = string.Concat (
         Text = string.Concat (
                               Enumerable.Repeat (
                               Enumerable.Repeat (
                                                  Glyphs.Stipple.ToString (),
                                                  Glyphs.Stipple.ToString (),
@@ -318,10 +317,12 @@ public class Scroll : View
                                      Orientation == Orientation.Vertical ? ContentSize.Width : slider.Dimension,
                                      Orientation == Orientation.Vertical ? ContentSize.Width : slider.Dimension,
                                      Orientation == Orientation.Vertical ? slider.Dimension : ContentSize.Height
                                      Orientation == Orientation.Vertical ? slider.Dimension : ContentSize.Height
                                     ));
                                     ));
-
         SetSliderText ();
         SetSliderText ();
     }
     }
 
 
+    // TODO: Move this into "ScrollSlider" and override it there. Scroll can then subscribe to _slider.LayoutComplete and call AdjustSlider.
+    // QUESTION: I've been meaning to add a "View.FrameChanged" event (fired from LayoutComplete only if Frame has changed). Should we do that as part of this PR?
+    // QUESTION: Note I *did* add "View.ViewportChanged" in a previous PR.
     private void Slider_MouseEvent (object sender, MouseEventEventArgs e)
     private void Slider_MouseEvent (object sender, MouseEventEventArgs e)
     {
     {
         MouseEvent me = e.MouseEvent;
         MouseEvent me = e.MouseEvent;
@@ -384,4 +385,18 @@ public class Scroll : View
 
 
         e.Handled = true;
         e.Handled = true;
     }
     }
+
+    /// <inheritdoc/>
+    protected override void Dispose (bool disposing)
+    {
+        Added -= Scroll_Added;
+        Initialized -= Scroll_Initialized;
+        DrawContent -= Scroll_DrawContent;
+        MouseEvent -= Scroll_MouseEvent;
+        _slider.DrawContent -= Scroll_DrawContent;
+        _slider.MouseEvent -= Slider_MouseEvent;
+
+        base.Dispose (disposing);
+    }
+
 }
 }

+ 1 - 1
UICatalog/KeyBindingsDialog.cs

@@ -208,7 +208,7 @@ internal class KeyBindingsDialog : Dialog
             // (and always was wrong). Parents don't get to be told when new views are added
             // (and always was wrong). Parents don't get to be told when new views are added
             // to them
             // to them
 
 
-            view.Added += (s, e) => RecordView (e.Child);
+            view.Added += (s, e) => RecordView (e.SubView);
         }
         }
     }
     }
 }
 }

+ 2 - 2
UnitTests/View/SubviewTests.cs

@@ -19,13 +19,13 @@ public class SubviewTests
                    {
                    {
                        Assert.Same (v.SuperView, e.Parent);
                        Assert.Same (v.SuperView, e.Parent);
                        Assert.Same (t, e.Parent);
                        Assert.Same (t, e.Parent);
-                       Assert.Same (v, e.Child);
+                       Assert.Same (v, e.SubView);
                    };
                    };
 
 
         v.Removed += (s, e) =>
         v.Removed += (s, e) =>
                      {
                      {
                          Assert.Same (t, e.Parent);
                          Assert.Same (t, e.Parent);
-                         Assert.Same (v, e.Child);
+                         Assert.Same (v, e.SubView);
                          Assert.True (v.SuperView == null);
                          Assert.True (v.SuperView == null);
                      };
                      };