Prechádzať zdrojové kódy

WIP: Refining TabStop and GroupStop

Tig 1 rok pred
rodič
commit
65592b4135

+ 81 - 82
Terminal.Gui/View/View.Navigation.cs

@@ -29,12 +29,12 @@ public partial class View // Focus and cross-view navigation management (TabStop
     ///     </para>
     /// </remarks>
     /// <param name="direction"></param>
-    /// <param name="acrossGroupOrOverlapped">If <see langword="true"/> will advance into ...</param>
+    /// <param name="groupOnly">If <see langword="true"/> will advance into ...</param>
     /// <returns>
     ///     <see langword="true"/> if focus was changed to another subview (or stayed on this one), <see langword="false"/>
     ///     otherwise.
     /// </returns>
-    public bool AdvanceFocus (NavigationDirection direction, bool acrossGroupOrOverlapped = false)
+    public bool AdvanceFocus (NavigationDirection direction, bool groupOnly = false)
     {
         if (!CanBeVisible (this))
         {
@@ -53,11 +53,11 @@ public partial class View // Focus and cross-view navigation management (TabStop
             switch (direction)
             {
                 case NavigationDirection.Forward:
-                    FocusFirst ();
+                    FocusFirst (groupOnly);
 
                     break;
                 case NavigationDirection.Backward:
-                    FocusLast ();
+                    FocusLast (groupOnly);
 
                     break;
                 default:
@@ -67,78 +67,71 @@ public partial class View // Focus and cross-view navigation management (TabStop
             return Focused is { };
         }
 
-        var focusedFound = false;
+        if (Focused is { })
+        {
+            if (Focused.AdvanceFocus (direction, groupOnly))
+            {
+                return true;
+            }
+        }
 
-        foreach (View w in direction == NavigationDirection.Forward
-                               ? TabIndexes.ToArray ()
-                               : TabIndexes.ToArray ().Reverse ())
+        var index = GetScopedTabIndexes (groupOnly ? TabBehavior.TabGroup : TabBehavior.TabStop, direction);
+        if (index.Length == 0)
         {
-            if (w.HasFocus)
+            return false;
+        }
+        var focusedIndex = index.IndexOf (Focused);
+        int next = 0;
+
+        if (focusedIndex < index.Length - 1)
+        {
+            next = focusedIndex + 1;
+        }
+        else
+        {
+            // Wrap around
+            if (SuperView is {})
             {
-                // A subview has focus, tell *it* to FocusNext
-                if (w.AdvanceFocus (direction, acrossGroupOrOverlapped))
+                if (direction == NavigationDirection.Forward)
                 {
-                    // The subview changed which of it's subviews had focus
-                    return true;
+                    return false;
                 }
-
-                if (acrossGroupOrOverlapped && Arrangement.HasFlag (ViewArrangement.Overlapped))
+                else
                 {
                     return false;
-                }
-
-                //Debug.Assert (w.HasFocus);
 
-                if (w.Focused is null)
-                {
-                    // No next focusable view was found. 
-                    if (w.Arrangement.HasFlag (ViewArrangement.Overlapped))
-                    {
-                        // Keep focus w/in w
-                        return false;
-                    }
+                    //SuperView.FocusFirst (groupOnly);
                 }
-
-                // The subview has no subviews that can be next. Cache that we found a focused subview.
-                focusedFound = true;
-
-                continue;
+                return true;
             }
+            //next = index.Length - 1;
 
-            // The subview does not have focus, but at least one other that can. Can this one be focused?
-            if (focusedFound && w.CanFocus && w.TabStop == TabBehavior.TabStop && w.Visible && w.Enabled)
-            {
-                // Make Focused Leave
-                Focused.SetHasFocus (false, w);
+        }
 
-                // If the focused view is overlapped don't focus on the next if it's not overlapped.
-                //if (acrossGroupOrOverlapped && Focused.Arrangement.HasFlag (ViewArrangement.Overlapped)/* && !w.Arrangement.HasFlag (ViewArrangement.Overlapped)*/)
-                //{
-                //    return false;
-                //}
+        View view = index [next];
 
-                // If the focused view is not overlapped and the next is, skip it
-                if (!acrossGroupOrOverlapped && !Focused.Arrangement.HasFlag (ViewArrangement.Overlapped) && w.Arrangement.HasFlag (ViewArrangement.Overlapped))
-                {
-                    continue;
-                }
-
-                switch (direction)
-                {
-                    case NavigationDirection.Forward:
-                        w.FocusFirst ();
 
-                        break;
-                    case NavigationDirection.Backward:
-                        w.FocusLast ();
+        // The subview does not have focus, but at least one other that can. Can this one be focused?
+        if (view.CanFocus && view.Visible && view.Enabled)
+        {
+            // Make Focused Leave
+            Focused.SetHasFocus (false, view);
 
-                        break;
-                }
+            switch (direction)
+            {
+                case NavigationDirection.Forward:
+                    view.FocusFirst (false);
 
-                SetFocus (w);
+                    break;
+                case NavigationDirection.Backward:
+                    view.FocusLast (false);
 
-                return true;
+                    break;
             }
+
+            SetFocus (view);
+
+            return true;
         }
 
         if (Focused is { })
@@ -297,12 +290,12 @@ public partial class View // Focus and cross-view navigation management (TabStop
     ///     Focuses the first focusable view in <see cref="View.TabIndexes"/> if one exists. If there are no views in
     ///     <see cref="View.TabIndexes"/> then the focus is set to the view itself.
     /// </summary>
-    /// <param name="overlappedOnly">
-    ///     If <see langword="true"/>, only subviews where <see cref="Arrangement"/> has
-    ///     <see cref="ViewArrangement.Overlapped"/> set
+    /// <param name="groupOnly">
+    ///     If <see langword="true"/>, only subviews where <see cref="TabStop"/> is
+    ///     <see cref="TabBehavior.TabGroup"/> set
     ///     will be considered.
     /// </param>
-    public void FocusFirst (bool overlappedOnly = false)
+    public void FocusFirst (bool groupOnly = false)
     {
         if (!CanBeVisible (this))
         {
@@ -316,14 +309,10 @@ public partial class View // Focus and cross-view navigation management (TabStop
             return;
         }
 
-        foreach (View view in _tabIndexes.Where (v => !overlappedOnly || v.Arrangement.HasFlag (ViewArrangement.Overlapped)))
+        var indicies = GetScopedTabIndexes (groupOnly ? TabBehavior.TabGroup : TabBehavior.TabStop, NavigationDirection.Forward);
+        if (indicies.Length > 0)
         {
-            if (view.CanFocus && view.TabStop == TabBehavior.TabStop && view.Visible && view.Enabled)
-            {
-                SetFocus (view);
-
-                return;
-            }
+            SetFocus (indicies [0]);
         }
     }
 
@@ -331,12 +320,12 @@ public partial class View // Focus and cross-view navigation management (TabStop
     ///     Focuses the last focusable view in <see cref="View.TabIndexes"/> if one exists. If there are no views in
     ///     <see cref="View.TabIndexes"/> then the focus is set to the view itself.
     /// </summary>
-    /// <param name="overlappedOnly">
-    ///     If <see langword="true"/>, only subviews where <see cref="Arrangement"/> has
-    ///     <see cref="ViewArrangement.Overlapped"/> set
+    /// <param name="groupOnly">
+    ///     If <see langword="true"/>, only subviews where <see cref="TabStop"/> is
+    ///     <see cref="TabBehavior.TabGroup"/> set
     ///     will be considered.
     /// </param>
-    public void FocusLast (bool overlappedOnly = false)
+    public void FocusLast (bool groupOnly = false)
     {
         if (!CanBeVisible (this))
         {
@@ -350,14 +339,10 @@ public partial class View // Focus and cross-view navigation management (TabStop
             return;
         }
 
-        foreach (View view in _tabIndexes.Where (v => !overlappedOnly || v.Arrangement.HasFlag (ViewArrangement.Overlapped)).Reverse ())
+        var indicies = GetScopedTabIndexes (groupOnly ? TabBehavior.TabGroup : TabBehavior.TabStop, NavigationDirection.Forward);
+        if (indicies.Length > 0)
         {
-            if (view.CanFocus && view.TabStop == TabBehavior.TabStop && view.Visible && view.Enabled)
-            {
-                SetFocus (view);
-
-                return;
-            }
+            SetFocus (indicies [^1]);
         }
     }
 
@@ -596,6 +581,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
         Focused.SetHasFocus (true, f);
 
         // Ensure on either the first or last focusable subview of Focused
+        // BUGBUG: With Groups, this means the previous focus is lost
         Focused.FocusFirstOrLast ();
 
         // Recursively set focus upwards in the view hierarchy
@@ -665,6 +651,19 @@ public partial class View // Focus and cross-view navigation management (TabStop
     /// <value>The tabIndexes.</value>
     public IList<View> TabIndexes => _tabIndexes?.AsReadOnly () ?? _empty;
 
+    private View [] GetScopedTabIndexes (TabBehavior behavior, NavigationDirection direction)
+    {
+        var indicies = _tabIndexes.Where (v => v.TabStop == behavior && v is { CanFocus: true, Visible: true, Enabled: true });
+
+        if (direction == NavigationDirection.Backward)
+        {
+            indicies = indicies.Reverse ();
+        }
+
+        return indicies.ToArray ();
+
+    }
+
     private int? _tabIndex; // null indicates the view has not yet been added to TabIndexes
     private int? _oldTabIndex;
 
@@ -695,7 +694,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
         {
             // Once a view is in the tab order, it should not be removed from the tab order; set TabStop to NoStop instead.
             Debug.Assert (value >= 0);
-            Debug.Assert (value is {});
+            Debug.Assert (value is { });
 
             if (SuperView?._tabIndexes is null || SuperView?._tabIndexes.Count == 1)
             {
@@ -814,7 +813,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
             if (_tabStop is null && TabIndex is null)
             {
                 // This view has not yet been added to TabIndexes (TabStop has not been set previously).
-                TabIndex = GetGreatestTabIndexInSuperView(SuperView is { } ? SuperView._tabIndexes.Count : 0);
+                TabIndex = GetGreatestTabIndexInSuperView (SuperView is { } ? SuperView._tabIndexes.Count : 0);
             }
 
             _tabStop = value;

+ 1 - 2
UICatalog/Scenarios/AdornmentEditor.cs

@@ -91,8 +91,7 @@ public class AdornmentEditor : View
         BorderStyle = LineStyle.Dashed;
         Initialized += AdornmentEditor_Initialized;
 
-        //Arrangement = ViewArrangement.Group;
-
+        TabStop = TabBehavior.TabGroup;
     }
 
     private void AdornmentEditor_Initialized (object sender, EventArgs e)

+ 2 - 0
UICatalog/Scenarios/AdornmentsEditor.cs

@@ -32,6 +32,8 @@ public class AdornmentsEditor : View
 
         //SuperViewRendersLineCanvas = true;
 
+        TabStop = TabBehavior.TabGroup;
+
         Application.MouseEvent += Application_MouseEvent;
         Initialized += AdornmentsEditor_Initialized;
     }

+ 2 - 0
UICatalog/Scenarios/ViewExperiments.cs

@@ -31,6 +31,7 @@ public class ViewExperiments : Scenario
             ShadowStyle = ShadowStyle.Transparent,
             BorderStyle = LineStyle.Double,
             CanFocus = true, // Can't drag without this? BUGBUG
+            TabStop = TabBehavior.TabGroup,
             Arrangement = ViewArrangement.Movable | ViewArrangement.Overlapped
         };
 
@@ -63,6 +64,7 @@ public class ViewExperiments : Scenario
             ShadowStyle = ShadowStyle.Transparent,
             BorderStyle = LineStyle.Double,
             CanFocus = true, // Can't drag without this? BUGBUG
+            TabStop = TabBehavior.TabGroup,
             Arrangement = ViewArrangement.Movable | ViewArrangement.Overlapped
         };
 

+ 6 - 2
UICatalog/UICatalog.cs

@@ -466,7 +466,8 @@ public class UICatalogApp
             StatusBar = new ()
             {
                 Visible = ShowStatusBar,
-                AlignmentModes = AlignmentModes.IgnoreFirstOrLast
+                AlignmentModes = AlignmentModes.IgnoreFirstOrLast,
+                CanFocus = false
             };
 
             if (StatusBar is { })
@@ -480,12 +481,14 @@ public class UICatalogApp
                 var statusBarShortcut = new Shortcut
                 {
                     Key = Key.F10,
-                    Title = "Show/Hide Status Bar"
+                    Title = "Show/Hide Status Bar",
+                    CanFocus = false,
                 };
                 statusBarShortcut.Accept += (sender, args) => { StatusBar.Visible = !StatusBar.Visible; };
 
                 ShForce16Colors = new ()
                 {
+                    CanFocus = false,
                     CommandView = new CheckBox
                     {
                         Title = "16 color mode",
@@ -518,6 +521,7 @@ public class UICatalogApp
                 StatusBar.Add (
                                new Shortcut
                                {
+                                   CanFocus = false,
                                    Title = "Quit",
                                    Key = Application.QuitKey
                                },