Tig 11 mēneši atpakaļ
vecāks
revīzija
2375ee35a9

+ 1 - 2
Terminal.Gui/Application/Application.Run.cs

@@ -222,7 +222,7 @@ public static partial class Application // Run (Begin, Run, End, Stop)
     internal static bool PositionCursor (View view)
     {
         // Find the most focused view and position the cursor there.
-        View? mostFocused = view?.MostFocused;
+        View? mostFocused = view?.GetMostFocused ();
 
         if (mostFocused is null)
         {
@@ -858,7 +858,6 @@ public static partial class Application // Run (Begin, Run, End, Stop)
                 if (Current is { HasFocus: false })
                 {
                     Current.SetFocus ();
-                    Current.RestoreFocus (null);
                 }
             }
 

+ 12 - 12
Terminal.Gui/Application/ApplicationNavigation.cs

@@ -115,17 +115,17 @@ public class ApplicationNavigation
     /// </summary>
     internal static void MoveNextView ()
     {
-        View? old = GetDeepestFocusedSubview (Application.Current!.Focused);
+        View? old = GetDeepestFocusedSubview (Application.Current!.GetFocused ());
 
         if (!Application.Current.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop))
         {
             Application.Current.AdvanceFocus (NavigationDirection.Forward, null);
         }
 
-        if (old != Application.Current.Focused && old != Application.Current.Focused?.Focused)
+        if (old != Application.Current.GetFocused () && old != Application.Current.GetFocused ()?.GetFocused ())
         {
             old?.SetNeedsDisplay ();
-            Application.Current.Focused?.SetNeedsDisplay ();
+            Application.Current.GetFocused ()?.SetNeedsDisplay ();
         }
         else
         {
@@ -147,16 +147,16 @@ public class ApplicationNavigation
             {
                 Application.Current.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
 
-                if (Application.Current.Focused is null)
+                if (Application.Current.GetFocused () is null)
                 {
                     Application.Current.RestoreFocus (TabBehavior.TabGroup);
                 }
             }
 
-            if (top != Application.Current.Focused && top != Application.Current.Focused?.Focused)
+            if (top != Application.Current.GetFocused() && top != Application.Current.GetFocused ()?.GetFocused ())
             {
                 top?.SetNeedsDisplay ();
-                Application.Current.Focused?.SetNeedsDisplay ();
+                Application.Current.GetFocused ()?.SetNeedsDisplay ();
             }
             else
             {
@@ -165,7 +165,7 @@ public class ApplicationNavigation
 
             //top!.AdvanceFocus (NavigationDirection.Forward);
 
-            //if (top.Focused is null)
+            //if (top.GetFocused () is null)
             //{
             //    top.AdvanceFocus (NavigationDirection.Forward);
             //}
@@ -188,17 +188,17 @@ public class ApplicationNavigation
     /// </summary>
     internal static void MovePreviousView ()
     {
-        View? old = GetDeepestFocusedSubview (Application.Current!.Focused);
+        View? old = GetDeepestFocusedSubview (Application.Current!.GetFocused());
 
         if (!Application.Current.AdvanceFocus (NavigationDirection.Backward, TabBehavior.TabStop))
         {
             Application.Current.AdvanceFocus (NavigationDirection.Backward, null);
         }
 
-        if (old != Application.Current.Focused && old != Application.Current.Focused?.Focused)
+        if (old != Application.Current.GetFocused() && old != Application.Current.GetFocused()?.GetFocused())
         {
             old?.SetNeedsDisplay ();
-            Application.Current.Focused?.SetNeedsDisplay ();
+            Application.Current.GetFocused ()?.SetNeedsDisplay ();
         }
         else
         {
@@ -208,12 +208,12 @@ public class ApplicationNavigation
 
     internal static void MovePreviousViewOrTop ()
     {
-        if (ApplicationOverlapped.OverlappedTop is null)
+        if (ApplicationOverlapped.OverlappedTop is null)    
         {
             Toplevel? top = Application.Current!.Modal ? Application.Current : Application.Top;
             top!.AdvanceFocus (NavigationDirection.Backward, TabBehavior.TabGroup);
 
-            if (top.Focused is null)
+            if (top.GetFocused () is null)
             {
                 top.AdvanceFocus (NavigationDirection.Backward, null);
             }

+ 2 - 2
Terminal.Gui/Application/ApplicationOverlapped.cs

@@ -75,7 +75,7 @@ public static class ApplicationOverlapped
             return;
         }
 
-        View? top = FindTopFromView (Application.Top?.MostFocused);
+        View? top = FindTopFromView (Application.Top?.GetMostFocused ());
 
         if (top is Toplevel && Application.Top?.Subviews.Count > 1 && Application.Top.Subviews [^1] != top)
         {
@@ -151,7 +151,7 @@ public static class ApplicationOverlapped
                 // QUESTION: AdvanceFocus returns false AND sets Focused to null if no view was found to advance to. Should't we only set focusProcessed if it returned true?
                 focusSet = true;
 
-                if (Application.Current.SuperView?.Focused != Application.Current)
+                if (Application.Current.SuperView?.GetFocused () != Application.Current)
                 {
                     return;
                 }

+ 20 - 5
Terminal.Gui/View/View.Hierarchy.cs

@@ -64,6 +64,16 @@ public partial class View // SuperView/SubView hierarchy management (SuperView,
 
         if (view.CanFocus)
         {
+            view._tabIndex = _tabIndexes.IndexOf (view);
+        }
+
+        if (view.Enabled && view.Visible && view.CanFocus)
+        {
+            if (HasFocus)
+            {
+                view.SetFocus ();
+            }
+
 #if AUTO_CANFOCUS
             // BUGBUG: This is a poor API design. Automatic behavior like this is non-obvious and should be avoided. Instead, callers to Add should be explicit about what they want.
             _addingViewSoCanFocusAlsoUpdatesSuperView = true;
@@ -79,7 +89,6 @@ public partial class View // SuperView/SubView hierarchy management (SuperView,
             CanFocus = true;
             _addingViewSoCanFocusAlsoUpdatesSuperView = false;
 #endif
-            view._tabIndex = _tabIndexes.IndexOf (view);
         }
 
         if (view.Enabled && !Enabled)
@@ -184,6 +193,12 @@ public partial class View // SuperView/SubView hierarchy management (SuperView,
             return view;
         }
 
+        // If a view being removed is focused, it should lose focus.
+        if (view.HasFocus)
+        {
+            view.LeaveFocus(this, true);
+        }
+
         Rectangle touched = view.Frame;
         _subviews.Remove (view);
         _tabIndexes!.Remove (view);
@@ -200,13 +215,13 @@ public partial class View // SuperView/SubView hierarchy management (SuperView,
             }
         }
 
-        OnRemoved (new (this, view));
-
-        if (Focused == view)
+        if (HasFocus)
         {
-            Focused = null;
+            FocusDeepest (TabStop, NavigationDirection.Forward);
         }
 
+        OnRemoved (new (this, view));
+
         return view;
     }
 

+ 3 - 3
Terminal.Gui/View/View.Keyboard.cs

@@ -286,7 +286,7 @@ public partial class View  // Keyboard APIs
 
         // By default the KeyBindingScope is View
 
-        if (Focused?.NewKeyDownEvent (keyEvent) == true)
+        if (GetFocused ()?.NewKeyDownEvent (keyEvent) == true)
         {
             return true;
         }
@@ -446,7 +446,7 @@ public partial class View  // Keyboard APIs
             return false;
         }
 
-        if (Focused?.NewKeyUpEvent (keyEvent) == true)
+        if (GetFocused ()?.NewKeyUpEvent (keyEvent) == true)
         {
             return true;
         }
@@ -611,7 +611,7 @@ public partial class View  // Keyboard APIs
         // Now, process any key bindings in the subviews that are tagged to KeyBindingScope.HotKey.
         foreach (View subview in Subviews)
         {
-            if (subview == Focused)
+            if (subview == GetFocused ())
             {
                 continue;
             }

+ 117 - 206
Terminal.Gui/View/View.Navigation.cs

@@ -1,4 +1,6 @@
 using System.Diagnostics;
+using System.Reflection.Metadata.Ecma335;
+using Microsoft.CodeAnalysis.Operations;
 using static Terminal.Gui.FakeDriver;
 
 namespace Terminal.Gui;
@@ -43,7 +45,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
             {
                 if (value)
                 {
-                    if (EnterFocus (Application.Navigation?.GetFocused ()))
+                    if (EnterFocus (Application.Navigation!.GetFocused ()))
                     {
                         // The change happened
                         // HasFocus is now true
@@ -82,12 +84,12 @@ public partial class View // Focus and cross-view navigation management (TabStop
         // Pre-conditions
         if (_hasFocus)
         {
-            throw new InvalidOperationException ($"EnterFocus should not be called if the view already has focus.");
+            return false;
         }
 
-        if (CanFocus && SuperView?.CanFocus == false)
+        if (CanFocus && SuperView is { CanFocus: false })
         {
-            throw new InvalidOperationException ($"It is not possible to EnterFocus if the View's SuperView has CanFocus = false.");
+            return false;
         }
 
         if (!CanBeVisible (this) || !Enabled)
@@ -104,19 +106,8 @@ public partial class View // Focus and cross-view navigation management (TabStop
 
         if (!traversingUp)
         {
-            // Call the virtual method
-            if (OnEnter (leavingView))
-            {
-                // The event was cancelled
-                return false;
-            }
-
-            var args = new FocusEventArgs (leavingView, this);
-            Enter?.Invoke (this, args);
-
-            if (args.Cancel)
+            if (CancelEnterFocus (leavingView))
             {
-                // The event was cancelled
                 return false;
             }
 
@@ -140,44 +131,72 @@ public partial class View // Focus and cross-view navigation management (TabStop
         // If we're here, we're the most-focusable view in the application OR we're traversing up the superview hierarchy.
 
         // If we previously had a subview with focus (`Focused = subview`), we need to make sure that all subviews down the `subview`-hierarchy LeaveFocus.
-        if (Focused is { })
-        {
-            // LeaveFocus will recurse down the subview hierarchy and will also set PreviouslyMostFocused
-            Focused.LeaveFocus (this);
-            Focused = null;
-        }
+        // LeaveFocus will recurse down the subview hierarchy and will also set PreviouslyMostFocused
+        View focused = GetFocused ();
+        focused?.LeaveFocus (this, true);
 
         // We need to ensure all superviews up the superview hierarchy have focus.
         // Any of them may cancel gaining focus. In which case we need to back out.
         if (SuperView is { HasFocus: false } sv)
         {
             // Tell EnterFocus that we're traversing up the superview hierarchy
-            if (!sv.EnterFocus (leavingView, traversingUp))
+            if (!sv.EnterFocus (leavingView, true))
             {
                 // The change was cancelled
                 return false;
             }
+
         }
 
-        // If we're here, we're the most-focusable view in the application and all superviews up the superview hierarchy have focus.
+        // If we're here:
+        // - we're the most-focusable view in the application
+        // - all superviews up the superview hierarchy have focus.
+        // - By setting _hasFocus to true we definitively change HasFocus for this view.
+
+        // Get whatever peer has focus, if any
+        View focusedPeer = SuperView?.GetFocused ();
 
-        // By setting _hasFocus to true we definitively change HasFocus for this view.
         _hasFocus = true;
 
+        // Ensure that the peer loses focus
+        focusedPeer?.LeaveFocus (this);
+
         // We're the most focused view in the application, we need to set the focused view to this view.
         Application.Navigation?.SetFocused (this);
 
+        SetNeedsDisplay ();
+
         // Post-conditions - prove correctness
         if (HasFocus == previousValue)
         {
             throw new InvalidOperationException ($"EnterFocus was not cancelled and the HasFocus value did not change.");
         }
 
-        SetNeedsDisplay ();
-
         return true;
     }
 
+
+    private bool CancelEnterFocus (View leavingView)
+    {
+        // Call the virtual method
+        if (OnEnter (leavingView))
+        {
+            // The event was cancelled
+            return true;
+        }
+
+        var args = new FocusEventArgs (leavingView, this);
+        Enter?.Invoke (this, args);
+
+        if (args.Cancel)
+        {
+            // The event was cancelled
+            return true;
+        }
+
+        return false;
+    }
+
     /// <summary>Virtual method invoked when this view is gaining focus (entering).</summary>
     /// <param name="leavingView">The view that is leaving focus.</param>
     /// <returns> <see langword="true"/>, if the event is to be cancelled, <see langword="false"/> otherwise.</returns>
@@ -198,25 +217,26 @@ public partial class View // Focus and cross-view navigation management (TabStop
     /// <param name="enteringView">The previously focused view. If <see langword="null"/> there is no previously focused view.</param>
     /// <returns><see langword="true"/> if <see cref="HasFocus"/> was changed.</returns>
     /// <exception cref="InvalidOperationException"></exception>
-    private void LeaveFocus ([CanBeNull] View enteringView)
+    private void LeaveFocus ([CanBeNull] View enteringView, bool traversingDown = false)
     {
         // Pre-conditions
-        if (_hasFocus)
+        if (!_hasFocus)
         {
             throw new InvalidOperationException ($"LeaveFocus should not be called if the view does not have focus.");
         }
 
         // If enteringView is null, we need to find the view that should get focus, and SetFocus on it.
-        if (enteringView is null)
+        if (enteringView is null && SuperView is { })
         {
-            if (SuperView?.PreviouslyMostFocused != this)
+            if (SuperView?.PreviouslyMostFocused is { } && SuperView?.PreviouslyMostFocused != this)
             {
                 SuperView?.PreviouslyMostFocused?.SetFocus ();
 
                 // The above will cause LeaveFocus, so we can return
                 return;
             }
-            else
+
+            if (Application.Navigation is { })
             {
                 // Temporarily ensure this view can't get focus
                 bool prevCanFocus = _canFocus;
@@ -230,24 +250,24 @@ public partial class View // Focus and cross-view navigation management (TabStop
         }
 
         // Before we can leave focus, we need to make sure that all views down the subview-hierarchy have left focus.
-        if (Application.Navigation?.GetFocused () != this)
+        View mostFocused = GetMostFocused ();
+        if (mostFocused is { })
         {
-            // Save the most focused view in the subview-hierarchy
-            View originalBottom = Application.Navigation?.GetFocused ();
             // Start at the bottom and work our way up to us
-            View bottom = originalBottom;
+            View bottom = mostFocused;
 
             while (bottom is { } && bottom != this)
             {
                 if (bottom.HasFocus)
                 {
-                    bottom.LeaveFocus (enteringView);
-                    return ;
+                    bottom.LeaveFocus (enteringView, true);
+
+                    break;
                 }
                 bottom = bottom.SuperView;
             }
 
-            PreviouslyMostFocused = originalBottom;
+            PreviouslyMostFocused = mostFocused;
         }
 
         bool previousValue = HasFocus;
@@ -258,17 +278,16 @@ public partial class View // Focus and cross-view navigation management (TabStop
         var args = new FocusEventArgs (enteringView, this);
         Leave?.Invoke (this, args);
 
-        Focused = null;
+        // Get whatever peer has focus, if any
+        View focusedPeer = SuperView?.GetFocused ();
         _hasFocus = false;
 
-        if (Application.Navigation?.GetFocused () != this)
+        if (!traversingDown)
         {
-            PreviouslyMostFocused = null;
-
-            if (SuperView is { })
+            // Now ensure all views up the superview-hierarchy are unfocused
+            if (SuperView is { HasFocus: true } && focusedPeer == this)
             {
-                SuperView.Focused = null;
-                SuperView.PreviouslyMostFocused = this;
+                SuperView.LeaveFocus (enteringView);
             }
         }
 
@@ -330,34 +349,29 @@ public partial class View // Focus and cross-view navigation management (TabStop
             return false;
         }
 
-        if (Focused is null)
+        View focused = GetFocused ();
+        if (focused is null)
         {
-            FocusDeepest (behavior, direction);
-
-            return Focused is { };
+            View deepest = FindDeepestFocusableView (behavior, direction);
+            if (deepest is { })
+            {
+                return deepest.SetFocus ();
+            }
         }
 
-        if (Focused is { })
+        if (focused!.AdvanceFocus (direction, behavior))
         {
-            if (Focused.AdvanceFocus (direction, behavior))
-            {
-                // TODO: Temporary hack to make Application.Navigation.FocusChanged work
-                if (Focused.Focused is null)
-                {
-                    Application.Navigation?.SetFocused (Focused);
-                }
-                return true;
-            }
+            return true;
         }
 
-        var index = GetScopedTabIndexes (behavior, direction);
+        View[] index = GetScopedTabIndexes (behavior, direction);
 
         if (index.Length == 0)
         {
             return false;
         }
 
-        var focusedIndex = index.IndexOf (Focused);
+        var focusedIndex = index.IndexOf (GetFocused ());
         int next = 0;
 
         if (focusedIndex < index.Length - 1)
@@ -370,7 +384,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
             {
                 // Go down the subview-hierarchy and leave
                 // BUGBUG: This doesn't seem right
-                Focused.HasFocus = false;
+                GetFocused ().HasFocus = false;
 
                 // TODO: Should we check the return value of SetHasFocus?
 
@@ -382,38 +396,12 @@ public partial class View // Focus and cross-view navigation management (TabStop
 
         if (view.HasFocus)
         {
-            return true;
+            // We could not advance
+            return false;
         }
 
         // 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
-            // BUGBUG: This doesn't seem right
-            Focused.HasFocus = false;
-
-            view.FocusDeepest (TabBehavior.TabStop, direction);
-
-            // TODO: Temporary hack to make Application.Navigation.FocusChanged work
-            if (view.Focused is null)
-            {
-                Application.Navigation?.SetFocused (view);
-            }
-
-            return true;
-        }
-
-        if (Focused is { })
-        {
-            // Leave
-            // BUGBUG: This doesn't seem right
-            Focused.HasFocus = false;
-
-            // Signal that nothing is focused, and callers should try a peer-subview
-            Focused = null;
-        }
-
-        return false;
+        return view.EnterFocus (GetFocused ());
     }
 
 
@@ -425,19 +413,40 @@ public partial class View // Focus and cross-view navigation management (TabStop
     /// </returns>
     internal bool RestoreFocus (TabBehavior? behavior)
     {
-        if (Focused is null && _subviews?.Count > 0)
+        if (GetFocused () is null && _subviews?.Count > 0)
         {
             // TODO: Find the previous focused view and set focus to it
             if (PreviouslyMostFocused is { } && PreviouslyMostFocused.TabStop == behavior)
             {
                 return PreviouslyMostFocused.SetFocus ();
             }
-            return true;
+            return false;
         }
 
         return false;
     }
 
+    /// <summary>
+    ///     Returns the most focused Subview down the subview-hierarchy.
+    /// </summary>
+    /// <returns>The most focused Subview, or <see langword="null"/> if no Subview is focused.</returns>
+    public View GetMostFocused ()
+    {
+        if (GetFocused () is null)
+        {
+            return null;
+        }
+
+        View most = GetFocused ()!.GetMostFocused ();
+
+        if (most is { })
+        {
+            return most;
+        }
+
+        return GetFocused ();
+    }
+
     ///// <summary>
     /////     Internal API that causes <paramref name="viewToEnterFocus"/> to enter focus.
     /////     <paramref name="viewToEnterFocus"/> must be a subview.
@@ -571,13 +580,6 @@ public partial class View // Focus and cross-view navigation management (TabStop
         get => _canFocus;
         set
         {
-#if AUTO_CANFOCUS
-            if (!_addingViewSoCanFocusAlsoUpdatesSuperView && IsInitialized && SuperView?.CanFocus == false && value)
-            {
-                throw new InvalidOperationException ("Cannot set CanFocus to true if the SuperView CanFocus is false!");
-            }
-#endif
-
             if (_canFocus == value)
             {
                 return;
@@ -585,92 +587,24 @@ public partial class View // Focus and cross-view navigation management (TabStop
 
             _canFocus = value;
 
-#if AUTO_CANFOCUS
-            switch (_canFocus)
-            {
-                case false when _tabIndex > -1:
-                    // BUGBUG: This is a poor API design. Automatic behavior like this is non-obvious and should be avoided. Callers should adjust TabIndex explicitly.
-                    //TabIndex = -1;
-
-                    break;
-
-                case true when SuperView?.CanFocus == false && _addingViewSoCanFocusAlsoUpdatesSuperView:
-                    SuperView.CanFocus = true;
-
-                    break;
-            }
-#endif
-
             if (TabStop is null && _canFocus)
             {
                 TabStop = TabBehavior.TabStop;
             }
 
-            if (!_canFocus && SuperView?.Focused == this)
-            {
-                SuperView.Focused = null;
-            }
-
             if (!_canFocus && HasFocus)
             {
+                // If CanFocus is set to false and this view has focus, make it leave focus
                 HasFocus = false;
-                SuperView?.RestoreFocus (null);
-
-                // If EnsureFocus () didn't set focus to a view, focus the next focusable view in the application
-                if (SuperView is { Focused: null })
-                {
-                    SuperView.AdvanceFocus (NavigationDirection.Forward, null);
-
-                    if (SuperView.Focused is null && Application.Current is { })
-                    {
-                        Application.Current.AdvanceFocus (NavigationDirection.Forward, null);
-                    }
-
-                    ApplicationOverlapped.BringOverlappedTopToFront ();
-                }
             }
 
-            if (_subviews is { } && IsInitialized)
+            if (_canFocus && SuperView is { } && SuperView.GetFocused () is null && !HasFocus)
             {
-#if AUTO_CANFOCUS
-                // Change the CanFocus of all subviews to the same value as this view
-                // if the CanFocus of the subview is different from the value being set
-                foreach (View view in _subviews)
-                {
-                    if (view.CanFocus != value)
-                    {
-                        if (!value)
-                        {
-                            // Cache the old CanFocus and TabIndex so that they can be restored when CanFocus is changed back to true
-                            view._oldCanFocus = view.CanFocus;
-                            view._oldTabIndex = view._tabIndex;
-                            view.CanFocus = false;
-
-                            //view._tabIndex = -1;
-                        }
-                        else
-                        {
-                            if (_addingViewSoCanFocusAlsoUpdatesSuperView)
-                            {
-                                view._addingViewSoCanFocusAlsoUpdatesSuperView = true;
-                            }
-
-                            // Restore the old CanFocus and TabIndex to the values they held before CanFocus was set to false
-                            view.CanFocus = view._oldCanFocus;
-                            view._tabIndex = view._oldTabIndex;
-                            view._addingViewSoCanFocusAlsoUpdatesSuperView = false;
-                        }
-                    }
-                }
-#endif
-                if (this is Toplevel && Application.Current!.Focused != this)
-                {
-                    ApplicationOverlapped.BringOverlappedTopToFront ();
-                }
+                // If CanFocus is set to true and this view does not have focus, make it enter focus
+                SetFocus ();
             }
 
             OnCanFocusChanged ();
-            SetNeedsDisplay ();
         }
     }
 
@@ -680,10 +614,13 @@ public partial class View // Focus and cross-view navigation management (TabStop
     /// </remarks>
     public event EventHandler CanFocusChanged;
 
-    /// <summary>Returns the currently focused Subview inside this view, or <see langword="null"/> if nothing is focused.</summary>
+    /// <summary>Returns the currently focused Subview of this view, or <see langword="null"/> if nothing is focused.</summary>
     /// <value>The currently focused Subview.</value>
     [CanBeNull]
-    public View Focused { get; private set; }
+    public View GetFocused ()
+    {
+        return Subviews.FirstOrDefault (v => v.HasFocus);
+    }
 
     /// <summary>
     ///     Focuses the deepest focusable view in <see cref="View.TabIndexes"/> if one exists. If there are no views in
@@ -691,19 +628,17 @@ public partial class View // Focus and cross-view navigation management (TabStop
     /// </summary>
     /// <param name="behavior"></param>
     /// <param name="direction"></param>
-    public void FocusDeepest (TabBehavior? behavior, NavigationDirection direction)
+    /// <returns><see langword="true"/> if a subview other than this was focused.</returns>
+    public bool FocusDeepest (TabBehavior? behavior, NavigationDirection direction)
     {
-        if (!CanBeVisible (this))
-        {
-            return;
-        }
-
         View deepest = FindDeepestFocusableView (behavior, direction);
 
         if (deepest is { })
         {
-            deepest.SetFocus ();
+            return deepest.SetFocus ();
         }
+
+        return SetFocus ();
     }
 
     [CanBeNull]
@@ -727,30 +662,6 @@ public partial class View // Focus and cross-view navigation management (TabStop
     /// <summary>Returns a value indicating if this View is currently on Top (Active)</summary>
     public bool IsCurrentTop => Application.Current == this;
 
-    /// <summary>
-    ///     Returns the most focused Subview in the chain of subviews (the leaf view that has the focus), or
-    ///     <see langword="null"/> if nothing is focused.
-    /// </summary>
-    /// <value>The most focused Subview.</value>
-    public View MostFocused
-    {
-        get
-        {
-            if (Focused is null)
-            {
-                return null;
-            }
-
-            View most = Focused.MostFocused;
-
-            if (most is { })
-            {
-                return most;
-            }
-
-            return Focused;
-        }
-    }
 
     /// <summary>Invoked when the <see cref="CanFocus"/> property from a view is changed.</summary>
     /// <remarks>

+ 3 - 3
Terminal.Gui/Views/Menu/MenuBar.cs

@@ -391,7 +391,7 @@ public class MenuBar : View, IDesignable
         _selected = 0;
         SetNeedsDisplay ();
 
-        _previousFocused = SuperView is null ? Application.Current?.Focused : SuperView.Focused;
+        _previousFocused = SuperView is null ? Application.Current?.GetFocused () : SuperView.GetFocused ();
         OpenMenu (_selected);
 
         if (!SelectEnabledItem (
@@ -452,7 +452,7 @@ public class MenuBar : View, IDesignable
 
         if (_openMenu is null)
         {
-            _previousFocused = SuperView is null ? Application.Current?.Focused ?? null : SuperView.Focused;
+            _previousFocused = SuperView is null ? Application.Current?.GetFocused () ?? null : SuperView.GetFocused ();
         }
 
         OpenMenu (idx, sIdx, subMenu);
@@ -755,7 +755,7 @@ public class MenuBar : View, IDesignable
         {
             case null:
                 // Open a submenu below a MenuBar
-                _lastFocused ??= SuperView is null ? Application.Current?.MostFocused : SuperView.MostFocused;
+                _lastFocused ??= SuperView is null ? Application.Current?.GetMostFocused () : SuperView.GetMostFocused ();
 
                 if (_openSubMenu is { } && !CloseMenu (false, true))
                 {

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

@@ -67,7 +67,7 @@ public class NumericUpDown<T> : View where T : notnull
             Width = Dim.Auto (minimumContentDim: Dim.Func (() => string.Format (Format, Value).Length)),
             Height = 1,
             TextAlignment = Alignment.Center,
-            CanFocus = true
+            CanFocus = true,
         };
 
         _up = new ()

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

@@ -77,7 +77,7 @@ public class TabView : View
                         {
                             _contentView.SetFocus ();
 
-                            return _contentView.Focused is { };
+                            return _contentView.GetFocused () is { };
                         }
 
                         return false;
@@ -94,7 +94,7 @@ public class TabView : View
                                               {
                                                   _contentView.SetFocus ();
 
-                                                  return _contentView.Focused is { };
+                                                  return _contentView.GetFocused () is { };
                                               }
 
                                               return false;
@@ -1300,7 +1300,7 @@ public class TabView : View
                 // if tab is the selected one and focus is inside this control
                 if (toRender.IsSelected && _host.HasFocus)
                 {
-                    if (_host.Focused == this)
+                    if (_host.GetFocused () == this)
                     {
                         // if focus is the tab bar itself then show that they can switch tabs
                         prevAttr = ColorScheme.HotFocus;

+ 2 - 3
Terminal.Gui/Views/Toplevel.cs

@@ -79,7 +79,6 @@ public partial class Toplevel : View
     /// <inheritdoc/>
     public override View Add (View view)
     {
-        CanFocus = true;
         AddMenuStatusBar (view);
 
         return base.Add (view);
@@ -432,7 +431,7 @@ public partial class Toplevel : View
     {
         if (!IsOverlappedContainer)
         {
-            if (Focused is null)
+            if (GetFocused () is null)
             {
                 RestoreFocus (null);
             }
@@ -442,7 +441,7 @@ public partial class Toplevel : View
 
         // This code path only happens when the Toplevel is an Overlapped container
 
-        if (Focused is null)
+        if (GetFocused () is null)
         {
             // TODO: this is an Overlapped hack
             foreach (Toplevel top in ApplicationOverlapped.OverlappedChildren!)

+ 2 - 2
UICatalog/Scenarios/ConfigurationEditor.cs

@@ -101,7 +101,7 @@ public class ConfigurationEditor : Scenario
     }
     public void Save ()
     {
-        if (_tileView.MostFocused is ConfigTextView editor)
+        if (_tileView.GetMostFocused () is ConfigTextView editor)
         {
             editor.Save ();
         }
@@ -172,7 +172,7 @@ public class ConfigurationEditor : Scenario
 
     private void Reload ()
     {
-        if (_tileView.MostFocused is ConfigTextView editor)
+        if (_tileView.GetMostFocused () is ConfigTextView editor)
         {
             editor.Read ();
         }

+ 3 - 3
UICatalog/Scenarios/KeyBindings.cs

@@ -139,10 +139,10 @@ public sealed class KeyBindings : Scenario
 
     private void AppWindow_DrawContent (object sender, DrawEventArgs e)
     {
-        _focusedBindingsListView.Title = $"_Focused ({Application.Top.MostFocused.GetType ().Name}) Bindings";
+        _focusedBindingsListView.Title = $"_Focused ({Application.Top.GetMostFocused ().GetType ().Name}) Bindings";
 
         _focusedBindings.Clear ();
-        foreach (var binding in Application.Top.MostFocused.KeyBindings.Bindings.Where (b => b.Value.Scope == KeyBindingScope.Focused))
+        foreach (var binding in Application.Top.GetMostFocused ().KeyBindings.Bindings.Where (b => b.Value.Scope == KeyBindingScope.Focused))
         {
             _focusedBindings.Add ($"{binding.Key} -> {binding.Value.Commands [0]}");
         }
@@ -150,7 +150,7 @@ public sealed class KeyBindings : Scenario
 
     private void AppWindow_Leave (object sender, FocusEventArgs e)
     {
-        foreach (var binding in Application.Top.MostFocused.KeyBindings.Bindings.Where (b => b.Value.Scope == KeyBindingScope.Focused))
+        foreach (var binding in Application.Top.GetMostFocused ().KeyBindings.Bindings.Where (b => b.Value.Scope == KeyBindingScope.Focused))
         {
             _focusedBindings.Add ($"{binding.Key} -> {binding.Value.Commands [0]}");
         }

+ 1 - 1
UICatalog/Scenarios/MenuBarScenario.cs

@@ -107,7 +107,7 @@ public class MenuBarScenario : Scenario
                                };
 
         // There's no focus change event, so this is a bit of a hack.
-        menuBar.LayoutComplete += (s, e) => { _focusedView.Text = appWindow.MostFocused?.ToString () ?? "None"; };
+        menuBar.LayoutComplete += (s, e) => { _focusedView.Text = appWindow.GetMostFocused ()?.ToString () ?? "None"; };
 
         var openBtn = new Button { X = Pos.Center (), Y = 4, Text = "_Open Menu", IsDefault = true };
         openBtn.Accept += (s, e) => { menuBar.OpenMenu (); };

+ 12 - 12
UnitTests/FileServices/FileDialogTests.cs

@@ -107,8 +107,8 @@ public class FileDialogTests (ITestOutputHelper output)
         Application.OnKeyDown (Key.Tab);
 #endif
 
-        Assert.IsType<TextField> (dlg.MostFocused);
-        var tf = (TextField)dlg.MostFocused;
+        Assert.IsType<TextField> (dlg.GetMostFocused ());
+        var tf = (TextField)dlg.GetMostFocused ();
         Assert.Equal ("Enter Search", tf.Caption);
 
         // Dialog has not yet been confirmed with a choice
@@ -142,9 +142,9 @@ public class FileDialogTests (ITestOutputHelper output)
 
         AssertIsTheStartingDirectory (dlg.Path);
 
-        Assert.IsType<TextField> (dlg.MostFocused);
+        Assert.IsType<TextField> (dlg.GetMostFocused ());
         Send ('v', ConsoleKey.DownArrow);
-        Assert.IsType<TableView> (dlg.MostFocused);
+        Assert.IsType<TableView> (dlg.GetMostFocused ());
 
         // ".." should be the first thing selected
         // ".." should not mess with the displayed path
@@ -181,9 +181,9 @@ public class FileDialogTests (ITestOutputHelper output)
         IReadOnlyCollection<string> eventMultiSelected = null;
         dlg.FilesSelected += (s, e) => { eventMultiSelected = e.Dialog.MultiSelected; };
 
-        Assert.IsType<TextField> (dlg.MostFocused);
+        Assert.IsType<TextField> (dlg.GetMostFocused ());
         Send ('v', ConsoleKey.DownArrow);
-        Assert.IsType<TableView> (dlg.MostFocused);
+        Assert.IsType<TableView> (dlg.GetMostFocused ());
 
         // Try to toggle '..'
         Send (' ', ConsoleKey.Spacebar);
@@ -236,9 +236,9 @@ public class FileDialogTests (ITestOutputHelper output)
         IReadOnlyCollection<string> eventMultiSelected = null;
         dlg.FilesSelected += (s, e) => { eventMultiSelected = e.Dialog.MultiSelected; };
 
-        Assert.IsType<TextField> (dlg.MostFocused);
+        Assert.IsType<TextField> (dlg.GetMostFocused ());
         Send ('v', ConsoleKey.DownArrow);
-        Assert.IsType<TableView> (dlg.MostFocused);
+        Assert.IsType<TableView> (dlg.GetMostFocused ());
 
         // Move selection to subfolder
         Send ('v', ConsoleKey.DownArrow);
@@ -288,9 +288,9 @@ public class FileDialogTests (ITestOutputHelper output)
         IReadOnlyCollection<string> eventMultiSelected = null;
         dlg.FilesSelected += (s, e) => { eventMultiSelected = e.Dialog.MultiSelected; };
 
-        Assert.IsType<TextField> (dlg.MostFocused);
+        Assert.IsType<TextField> (dlg.GetMostFocused ());
         Send ('v', ConsoleKey.DownArrow);
-        Assert.IsType<TableView> (dlg.MostFocused);
+        Assert.IsType<TableView> (dlg.GetMostFocused ());
 
         // Move selection to subfolder
         Send ('v', ConsoleKey.DownArrow);
@@ -331,9 +331,9 @@ public class FileDialogTests (ITestOutputHelper output)
         dlg.OpenMode = openModeMixed ? OpenMode.Mixed : OpenMode.Directory;
         dlg.AllowsMultipleSelection = multiple;
 
-        Assert.IsType<TextField> (dlg.MostFocused);
+        Assert.IsType<TextField> (dlg.GetMostFocused ());
         Send ('v', ConsoleKey.DownArrow);
-        Assert.IsType<TableView> (dlg.MostFocused);
+        Assert.IsType<TableView> (dlg.GetMostFocused ());
 
         // Should be selecting ..
         Send ('v', ConsoleKey.DownArrow);

+ 140 - 0
UnitTests/View/Navigation/AddRemoveTests.cs

@@ -0,0 +1,140 @@
+using Xunit.Abstractions;
+
+namespace Terminal.Gui.ViewTests;
+
+public class AddRemoveNavigationTests (ITestOutputHelper _output) : TestsAllViews
+{
+  [Fact]
+    public void Add_Subview_Gets_Focus ()
+    {
+        View top = new View ()
+        {
+            Id = "top",
+            CanFocus = true
+        };
+
+        top.SetFocus ();
+        Assert.True (top.HasFocus);
+
+        int nEnter = 0;
+        View subView = new View ()
+        {
+            Id = "subView",
+            CanFocus = true
+        };
+        subView.Enter += (s, e) => nEnter++;
+
+        top.Add (subView);
+
+        Assert.True (top.HasFocus);
+        Assert.Equal (subView, top.GetFocused ());
+        Assert.True (subView.HasFocus);
+        Assert.Equal (1, nEnter);
+    }
+
+    [Fact]
+    public void Add_Subview_Deepest_Gets_Focus ()
+    {
+        View top = new View ()
+        {
+            Id = "top",
+            CanFocus = true
+        };
+
+        top.SetFocus ();
+        Assert.True (top.HasFocus);
+
+        View subView = new View ()
+        {
+            Id = "subView",
+            CanFocus = true
+        };
+
+        View subSubView = new View ()
+        {
+            Id = "subSubView",
+            CanFocus = true
+        };
+
+        subView.Add (subSubView);
+
+        top.Add (subView);
+
+        Assert.True (top.HasFocus);
+        Assert.Equal (subView, top.GetFocused ());
+        Assert.True (subView.HasFocus);
+        Assert.True (subSubView.HasFocus);
+    }
+
+    [Fact]
+    public void Remove_Focused_Subview_Keeps_Focus_And_SubView_Looses_Focus ()
+    {
+        View top = new View ()
+        {
+            Id = "top",
+            CanFocus = true
+        };
+
+        int nLeave = 0;
+
+        View subView = new View ()
+        {
+            Id = "subView",
+            CanFocus = true
+        };
+        subView.Leave += (s, e) => nLeave++;
+
+        top.Add (subView);
+
+        top.SetFocus ();
+        Assert.True (top.HasFocus);
+        Assert.Equal (subView, top.GetFocused ());
+        Assert.True (subView.HasFocus);
+
+        top.Remove (subView);
+        Assert.True (top.HasFocus);
+        Assert.Equal (null, top.GetFocused ());
+        Assert.False (subView.HasFocus);
+        Assert.Equal (1, nLeave);
+    }
+
+    [Fact]
+    public void Remove_Focused_Subview_Keeps_Focus_And_SubView_Looses_Focus_And_Next_Gets_Focus ()
+    {
+        View top = new View ()
+        {
+            Id = "top",
+            CanFocus = true
+        };
+
+        int nLeave1 = 0;
+
+        View subView1 = new View ()
+        {
+            Id = "subView1",
+            CanFocus = true
+        };
+        subView1.Leave += (s, e) => nLeave1++;
+
+        View subView2 = new View ()
+        {
+            Id = "subView2",
+            CanFocus = true
+        };
+        top.Add (subView1, subView2);
+
+        top.SetFocus ();
+        Assert.True (top.HasFocus);
+        Assert.Equal (subView1, top.GetFocused ());
+        Assert.True (subView1.HasFocus);
+        Assert.False (subView2.HasFocus);
+
+        top.Remove (subView1);
+        Assert.True (top.HasFocus);
+        Assert.True (subView2.HasFocus);
+        Assert.Equal (subView2, top.GetFocused ());
+        Assert.False (subView1.HasFocus);
+        Assert.Equal (1, nLeave1);
+    }
+
+}

+ 393 - 0
UnitTests/View/Navigation/AdvanceFocusTests.cs

@@ -0,0 +1,393 @@
+using Xunit.Abstractions;
+
+namespace Terminal.Gui.ViewTests;
+
+public class AdvanceFocusTests (ITestOutputHelper _output)
+{
+    [Fact]
+    public void Subviews_TabIndexes_AreEqual ()
+    {
+        var r = new View ();
+        var v1 = new View { CanFocus = true };
+        var v2 = new View { CanFocus = true };
+        var v3 = new View { CanFocus = true };
+
+        r.Add (v1, v2, v3);
+
+        Assert.True (r.Subviews.IndexOf (v1) == 0);
+        Assert.True (r.Subviews.IndexOf (v2) == 1);
+        Assert.True (r.Subviews.IndexOf (v3) == 2);
+
+        Assert.True (r.TabIndexes.IndexOf (v1) == 0);
+        Assert.True (r.TabIndexes.IndexOf (v2) == 1);
+        Assert.True (r.TabIndexes.IndexOf (v3) == 2);
+
+        Assert.Equal (r.Subviews.IndexOf (v1), r.TabIndexes.IndexOf (v1));
+        Assert.Equal (r.Subviews.IndexOf (v2), r.TabIndexes.IndexOf (v2));
+        Assert.Equal (r.Subviews.IndexOf (v3), r.TabIndexes.IndexOf (v3));
+        r.Dispose ();
+    }
+
+    [Fact]
+    public void TabIndex_Invert_Order ()
+    {
+        var r = new View ();
+        var v1 = new View { Id = "1", CanFocus = true };
+        var v2 = new View { Id = "2", CanFocus = true };
+        var v3 = new View { Id = "3", CanFocus = true };
+
+        r.Add (v1, v2, v3);
+
+        v1.TabIndex = 2;
+        v2.TabIndex = 1;
+        v3.TabIndex = 0;
+        Assert.True (r.TabIndexes.IndexOf (v1) == 2);
+        Assert.True (r.TabIndexes.IndexOf (v2) == 1);
+        Assert.True (r.TabIndexes.IndexOf (v3) == 0);
+
+        Assert.True (r.Subviews.IndexOf (v1) == 0);
+        Assert.True (r.Subviews.IndexOf (v2) == 1);
+        Assert.True (r.Subviews.IndexOf (v3) == 2);
+    }
+
+    [Fact]
+    public void TabIndex_Invert_Order_Added_One_By_One_Does_Not_Do_What_Is_Expected ()
+    {
+        var r = new View ();
+        var v1 = new View { Id = "1", CanFocus = true };
+        r.Add (v1);
+        v1.TabIndex = 2;
+        var v2 = new View { Id = "2", CanFocus = true };
+        r.Add (v2);
+        v2.TabIndex = 1;
+        var v3 = new View { Id = "3", CanFocus = true };
+        r.Add (v3);
+        v3.TabIndex = 0;
+
+        Assert.False (r.TabIndexes.IndexOf (v1) == 2);
+        Assert.True (r.TabIndexes.IndexOf (v1) == 1);
+        Assert.False (r.TabIndexes.IndexOf (v2) == 1);
+        Assert.True (r.TabIndexes.IndexOf (v2) == 2);
+
+        // Only the last is in the expected index
+        Assert.True (r.TabIndexes.IndexOf (v3) == 0);
+
+        Assert.True (r.Subviews.IndexOf (v1) == 0);
+        Assert.True (r.Subviews.IndexOf (v2) == 1);
+        Assert.True (r.Subviews.IndexOf (v3) == 2);
+    }
+
+    [Fact]
+    public void TabIndex_Invert_Order_Mixed ()
+    {
+        var r = new View ();
+        var vl1 = new View { Id = "vl1" };
+        var v1 = new View { Id = "v1", CanFocus = true };
+        var vl2 = new View { Id = "vl2" };
+        var v2 = new View { Id = "v2", CanFocus = true };
+        var vl3 = new View { Id = "vl3" };
+        var v3 = new View { Id = "v3", CanFocus = true };
+
+        r.Add (vl1, v1, vl2, v2, vl3, v3);
+
+        v1.TabIndex = 2;
+        v2.TabIndex = 1;
+        v3.TabIndex = 0;
+        Assert.True (r.TabIndexes.IndexOf (v1) == 4);
+        Assert.True (r.TabIndexes.IndexOf (v2) == 2);
+        Assert.True (r.TabIndexes.IndexOf (v3) == 0);
+
+        Assert.True (r.Subviews.IndexOf (v1) == 1);
+        Assert.True (r.Subviews.IndexOf (v2) == 3);
+        Assert.True (r.Subviews.IndexOf (v3) == 5);
+    }
+
+    [Fact]
+    public void TabIndex_Set_CanFocus_False ()
+    {
+        var r = new View ();
+        var v1 = new View { CanFocus = true };
+        var v2 = new View { CanFocus = true };
+        var v3 = new View { CanFocus = true };
+
+        r.Add (v1, v2, v3);
+
+        v1.CanFocus = false;
+        v1.TabIndex = 0;
+        Assert.True (r.Subviews.IndexOf (v1) == 0);
+        Assert.True (r.TabIndexes.IndexOf (v1) == 0);
+        Assert.NotEqual (-1, v1.TabIndex);
+        r.Dispose ();
+    }
+
+    [Fact]
+    public void TabIndex_Set_CanFocus_False_To_True ()
+    {
+        var r = new View ();
+        var v1 = new View ();
+        var v2 = new View { CanFocus = true };
+        var v3 = new View { CanFocus = true };
+
+        r.Add (v1, v2, v3);
+
+        v1.CanFocus = true;
+        v1.TabIndex = 1;
+        Assert.True (r.Subviews.IndexOf (v1) == 0);
+        Assert.True (r.TabIndexes.IndexOf (v1) == 1);
+        r.Dispose ();
+    }
+
+    [Fact]
+    public void TabIndex_Set_CanFocus_HigherValues ()
+    {
+        var r = new View ();
+        var v1 = new View { CanFocus = true };
+        var v2 = new View { CanFocus = true };
+        var v3 = new View { CanFocus = true };
+
+        r.Add (v1, v2, v3);
+
+        v1.TabIndex = 3;
+        Assert.True (r.Subviews.IndexOf (v1) == 0);
+        Assert.True (r.TabIndexes.IndexOf (v1) == 2);
+        r.Dispose ();
+    }
+
+    [Fact]
+    public void TabIndex_Set_CanFocus_LowerValues ()
+    {
+        var r = new View ();
+        var v1 = new View { CanFocus = true };
+        var v2 = new View { CanFocus = true };
+        var v3 = new View { CanFocus = true };
+
+        r.Add (v1, v2, v3);
+
+        //v1.TabIndex = -1;
+        Assert.True (r.Subviews.IndexOf (v1) == 0);
+        Assert.True (r.TabIndexes.IndexOf (v1) == 0);
+        r.Dispose ();
+    }
+
+    [Fact]
+    public void TabIndex_Set_CanFocus_ValidValues ()
+    {
+        var r = new View ();
+        var v1 = new View { CanFocus = true };
+        var v2 = new View { CanFocus = true };
+        var v3 = new View { CanFocus = true };
+
+        r.Add (v1, v2, v3);
+
+        v1.TabIndex = 1;
+        Assert.True (r.Subviews.IndexOf (v1) == 0);
+        Assert.True (r.TabIndexes.IndexOf (v1) == 1);
+
+        v1.TabIndex = 2;
+        Assert.True (r.Subviews.IndexOf (v1) == 0);
+        Assert.True (r.TabIndexes.IndexOf (v1) == 2);
+        r.Dispose ();
+    }
+
+
+    [Theory]
+    [CombinatorialData]
+    public void TabStop_And_CanFocus_Are_Decoupled (bool canFocus, TabBehavior tabStop)
+    {
+        var view = new View { CanFocus = canFocus, TabStop = tabStop };
+
+        Assert.Equal (canFocus, view.CanFocus);
+        Assert.Equal (tabStop, view.TabStop);
+    }
+
+    [Fact]
+    public void AdvanceFocus_With_CanFocus_Are_All_True ()
+    {
+        var top = new View () { Id = "top", CanFocus = true };
+        var v1 = new View { Id = "v1", CanFocus = true };
+        var v2 = new View { Id = "v2", CanFocus = true };
+        var v3 = new View { Id = "v3", CanFocus = true };
+
+        top.Add (v1, v2, v3);
+
+        top.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        Assert.True (v1.HasFocus);
+        Assert.False (v2.HasFocus);
+        Assert.False (v3.HasFocus);
+        top.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        Assert.False (v1.HasFocus);
+        Assert.True (v2.HasFocus);
+        Assert.False (v3.HasFocus);
+        top.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        Assert.False (v1.HasFocus);
+        Assert.False (v2.HasFocus);
+        Assert.True (v3.HasFocus);
+        top.Dispose ();
+    }
+
+    [Fact]
+    public void AdvanceFocus_CanFocus_Mixed ()
+    {
+        var r = new View ();
+        var v1 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
+        var v2 = new View { CanFocus = false, TabStop = TabBehavior.TabStop };
+        var v3 = new View { CanFocus = false, TabStop = TabBehavior.NoStop };
+
+        r.Add (v1, v2, v3);
+
+        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        Assert.False (v1.HasFocus);
+        Assert.False (v2.HasFocus);
+        Assert.False (v3.HasFocus);
+        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        Assert.False (v1.HasFocus);
+        Assert.False (v2.HasFocus);
+        Assert.False (v3.HasFocus);
+        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        Assert.False (v1.HasFocus);
+        Assert.False (v2.HasFocus);
+        Assert.False (v3.HasFocus);
+        r.Dispose ();
+    }
+
+    [Theory]
+    [CombinatorialData]
+    public void AdvanceFocus_Change_CanFocus_Works ([CombinatorialValues (TabBehavior.NoStop, TabBehavior.TabStop, TabBehavior.TabGroup)] TabBehavior behavior)
+    {
+        var r = new View () { CanFocus = true };
+        var v1 = new View ();
+        var v2 = new View ();
+        var v3 = new View ();
+        Assert.True (r.CanFocus);
+        Assert.False (v1.CanFocus);
+        Assert.False (v2.CanFocus);
+        Assert.False (v3.CanFocus);
+
+        r.Add (v1, v2, v3);
+
+        r.AdvanceFocus (NavigationDirection.Forward, behavior);
+        Assert.False (v1.HasFocus);
+        Assert.False (v2.HasFocus);
+        Assert.False (v3.HasFocus);
+
+        v1.CanFocus = true;
+        v1.TabStop = behavior;
+        r.AdvanceFocus (NavigationDirection.Forward, behavior);
+        Assert.True (v1.HasFocus);
+        Assert.False (v2.HasFocus);
+        Assert.False (v3.HasFocus);
+
+        v2.CanFocus = true;
+        v2.TabStop = behavior;
+        r.AdvanceFocus (NavigationDirection.Forward, behavior);
+        Assert.False (v1.HasFocus);
+        Assert.True (v2.HasFocus);
+        Assert.False (v3.HasFocus);
+
+        v3.CanFocus = true;
+        v3.TabStop = behavior;
+        r.AdvanceFocus (NavigationDirection.Forward, behavior);
+        Assert.False (v1.HasFocus);
+        Assert.False (v2.HasFocus);
+        Assert.True (v3.HasFocus);
+        r.Dispose ();
+    }
+
+    [Fact]
+    public void AdvanceFocus_NoStop_And_CanFocus_True_No_Focus ()
+    {
+        var r = new View ();
+        var v1 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
+        var v2 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
+        var v3 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
+
+        r.Add (v1, v2, v3);
+
+        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        Assert.False (v1.HasFocus);
+        Assert.False (v2.HasFocus);
+        Assert.False (v3.HasFocus);
+        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        Assert.False (v1.HasFocus);
+        Assert.False (v2.HasFocus);
+        Assert.False (v3.HasFocus);
+        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        Assert.False (v1.HasFocus);
+        Assert.False (v2.HasFocus);
+        Assert.False (v3.HasFocus);
+        r.Dispose ();
+    }
+
+    [Fact]
+    public void AdvanceFocus_NoStop_Change_Enables_Stop ()
+    {
+        var r = new View { CanFocus = true };
+        var v1 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
+        var v2 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
+        var v3 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
+
+        r.Add (v1, v2, v3);
+
+        v1.TabStop = TabBehavior.TabStop;
+        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        Assert.True (v1.HasFocus);
+        Assert.False (v2.HasFocus);
+        Assert.False (v3.HasFocus);
+
+        v2.TabStop = TabBehavior.TabStop;
+        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        Assert.False (v1.HasFocus);
+        Assert.True (v2.HasFocus);
+        Assert.False (v3.HasFocus);
+
+        v3.TabStop = TabBehavior.TabStop;
+        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        Assert.False (v1.HasFocus);
+        Assert.False (v2.HasFocus);
+        Assert.True (v3.HasFocus);
+        r.Dispose ();
+    }
+
+    [Fact]
+    public void AdvacneFocus_NoStop_Prevents_Stop ()
+    {
+        var r = new View ();
+        var v1 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
+        var v2 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
+        var v3 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
+
+        r.Add (v1, v2, v3);
+
+        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        Assert.False (v1.HasFocus);
+        Assert.False (v2.HasFocus);
+        Assert.False (v3.HasFocus);
+    }
+
+    [Fact]
+    public void AdvanceFocus_Null_And_CanFocus_False_No_Advance ()
+    {
+        var r = new View ();
+        var v1 = new View ();
+        var v2 = new View ();
+        var v3 = new View ();
+        Assert.False (v1.CanFocus);
+        Assert.Null (v1.TabStop);
+
+        r.Add (v1, v2, v3);
+
+        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        Assert.False (v1.HasFocus);
+        Assert.False (v2.HasFocus);
+        Assert.False (v3.HasFocus);
+        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        Assert.False (v1.HasFocus);
+        Assert.False (v2.HasFocus);
+        Assert.False (v3.HasFocus);
+        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        Assert.False (v1.HasFocus);
+        Assert.False (v2.HasFocus);
+        Assert.False (v3.HasFocus);
+        r.Dispose ();
+    }
+}

+ 580 - 0
UnitTests/View/Navigation/CanFocusTests.cs

@@ -0,0 +1,580 @@
+using Xunit.Abstractions;
+
+namespace Terminal.Gui.ViewTests;
+
+public class CanFocusTests (ITestOutputHelper _output) : TestsAllViews
+{
+    [Fact]
+    public void CanFocus_False_Prevents_SubSubView_HasFocus ()
+    {
+        var view = new View { };
+        var subView = new View { };
+        var subSubView = new View { CanFocus = true };
+
+        subView.Add (subSubView);
+        view.Add (subView);
+
+        Assert.False (view.CanFocus);
+        Assert.False (subView.CanFocus);
+        Assert.True (subSubView.CanFocus);
+
+        view.SetFocus ();
+        Assert.False (view.HasFocus);
+
+        subView.SetFocus ();
+        Assert.False (subView.HasFocus);
+
+        subSubView.SetFocus ();
+        Assert.False (subSubView.HasFocus);
+    }
+
+    [Fact]
+    public void CanFocus_False_Prevents_SubView_HasFocus ()
+    {
+        var view = new View { };
+        var subView = new View { CanFocus = true };
+        var subSubView = new View { };
+
+        subView.Add (subSubView);
+        view.Add (subView);
+
+        Assert.False (view.CanFocus);
+        Assert.True (subView.CanFocus);
+        Assert.False (subSubView.CanFocus);
+
+        view.SetFocus ();
+        Assert.False (view.HasFocus);
+
+        subView.SetFocus ();
+        Assert.False (subView.HasFocus);
+
+        subSubView.SetFocus ();
+        Assert.False (subSubView.HasFocus);
+    }
+
+    [Fact]
+    public void CanFocus_Set_True_No_SuperView_Doesnt_Set_HasFocus ()
+    {
+        var view = new View { };
+
+        // Act
+        view.CanFocus = true;
+        Assert.False (view.HasFocus);
+    }
+
+    [Fact]
+    public void CanFocus_Set_True_Sets_HasFocus_To_True ()
+    {
+        var view = new View { };
+        var subView = new View { };
+        view.Add (subView);
+
+        Assert.False (view.CanFocus);
+        Assert.False (subView.CanFocus);
+
+        view.SetFocus ();
+        Assert.False (view.HasFocus);
+        Assert.False (subView.HasFocus);
+
+        view.CanFocus = true;
+        view.SetFocus ();
+        Assert.True (view.HasFocus);
+
+        // Act
+        subView.CanFocus = true;
+        Assert.True (subView.HasFocus);
+    }
+
+    [Fact]
+    public void CanFocus_Set_SubView_True_Sets_HasFocus_To_True ()
+    {
+        var view = new View
+        {
+            CanFocus = true
+        };
+        var subView = new View
+        {
+            CanFocus = false
+        };
+        var subSubView = new View
+        {
+            CanFocus = true
+        };
+
+        subView.Add (subSubView);
+        view.Add (subView);
+
+        view.SetFocus ();
+        Assert.True (view.HasFocus);
+        Assert.False (subView.HasFocus);
+        Assert.False (subSubView.HasFocus);
+
+        // Act
+        subView.CanFocus = true;
+        Assert.True (subView.HasFocus);
+        Assert.True (subSubView.HasFocus);
+    }
+
+
+    [Fact]
+    public void CanFocus_Set_SubView_True_Does_Not_Change_Focus_If_SuperView_Focused_Is_True ()
+    {
+        var top = new View
+        {
+            Id = "top",
+            CanFocus = true
+        };
+        var subView = new View
+        {
+            Id = "subView",
+            CanFocus = true
+        };
+        var subSubView = new View
+        {
+            Id = "subSubView",
+            CanFocus = true
+        };
+
+        subView.Add (subSubView);
+
+        var subView2 = new View
+        {
+            Id = "subView2",
+            CanFocus = false
+        };
+
+        top.Add (subView, subView2);
+
+        top.SetFocus ();
+        Assert.True (top.HasFocus);
+        Assert.Equal (subView, top.GetFocused ());
+        Assert.True (subView.HasFocus);
+        Assert.True (subSubView.HasFocus);
+
+        // Act
+        subView2.CanFocus = true;
+        Assert.False (subView2.HasFocus);
+        Assert.True (subView.HasFocus);
+        Assert.True (subSubView.HasFocus);
+    }
+
+    [Fact]
+    public void CanFocus_Set_False_Sets_HasFocus_To_False ()
+    {
+        var view = new View { CanFocus = true };
+        var view2 = new View { CanFocus = true };
+        view2.Add (view);
+
+        Assert.True (view.CanFocus);
+
+        view.SetFocus ();
+        Assert.True (view.HasFocus);
+
+        view.CanFocus = false;
+        Assert.False (view.CanFocus);
+        Assert.False (view.HasFocus);
+    }
+
+    // TODO: Figure out what this test is supposed to be testing
+    [Fact]
+    public void CanFocus_Faced_With_Container ()
+    {
+        var t = new Toplevel ();
+        var w = new Window ();
+        var f = new FrameView ();
+        var v = new View { CanFocus = true };
+        f.Add (v);
+        w.Add (f);
+        t.Add (w);
+
+        Assert.True (t.CanFocus);
+        Assert.True (w.CanFocus);
+        Assert.True (f.CanFocus);
+        Assert.True (v.CanFocus);
+
+        f.CanFocus = false;
+        Assert.False (f.CanFocus);
+        Assert.True (v.CanFocus);
+
+        v.CanFocus = false;
+        Assert.False (f.CanFocus);
+        Assert.False (v.CanFocus);
+
+        v.CanFocus = true;
+        Assert.False (f.CanFocus);
+        Assert.True (v.CanFocus);
+    }
+
+    // TODO: Figure out what this test is supposed to be testing
+    [Fact]
+    public void CanFocus_Faced_With_Container_Before_Run ()
+    {
+        Application.Init (new FakeDriver ());
+
+        Toplevel t = new ();
+
+        var w = new Window ();
+        var f = new FrameView ();
+        var v = new View { CanFocus = true };
+        f.Add (v);
+        w.Add (f);
+        t.Add (w);
+
+        Assert.True (t.CanFocus);
+        Assert.True (w.CanFocus);
+        Assert.True (f.CanFocus);
+        Assert.True (v.CanFocus);
+
+        f.CanFocus = false;
+        Assert.False (f.CanFocus);
+        Assert.True (v.CanFocus);
+
+        v.CanFocus = false;
+        Assert.False (f.CanFocus);
+        Assert.False (v.CanFocus);
+
+        v.CanFocus = true;
+        Assert.False (f.CanFocus);
+        Assert.True (v.CanFocus);
+
+        Application.Iteration += (s, a) => Application.RequestStop ();
+
+        Application.Run (t);
+        t.Dispose ();
+        Application.Shutdown ();
+    }
+
+    [Fact]
+    public void CanFocus_Set_Changes_TabIndex_And_TabStop ()
+    {
+        var r = new View ();
+        var v1 = new View { Text = "1" };
+        var v2 = new View { Text = "2" };
+        var v3 = new View { Text = "3" };
+
+        r.Add (v1, v2, v3);
+
+        v2.CanFocus = true;
+        Assert.Equal (r.TabIndexes.IndexOf (v2), v2.TabIndex);
+        Assert.Equal (0, v2.TabIndex);
+        Assert.Equal (TabBehavior.TabStop, v2.TabStop);
+
+        v1.CanFocus = true;
+        Assert.Equal (r.TabIndexes.IndexOf (v1), v1.TabIndex);
+        Assert.Equal (1, v1.TabIndex);
+        Assert.Equal (TabBehavior.TabStop, v1.TabStop);
+
+        v1.TabIndex = 2;
+        Assert.Equal (r.TabIndexes.IndexOf (v1), v1.TabIndex);
+        Assert.Equal (1, v1.TabIndex);
+        v3.CanFocus = true;
+        Assert.Equal (r.TabIndexes.IndexOf (v1), v1.TabIndex);
+        Assert.Equal (1, v1.TabIndex);
+        Assert.Equal (r.TabIndexes.IndexOf (v3), v3.TabIndex);
+        Assert.Equal (2, v3.TabIndex);
+        Assert.Equal (TabBehavior.TabStop, v3.TabStop);
+
+        v2.CanFocus = false;
+        Assert.Equal (r.TabIndexes.IndexOf (v1), v1.TabIndex);
+        Assert.Equal (1, v1.TabIndex);
+        Assert.Equal (TabBehavior.TabStop, v1.TabStop);
+        Assert.Equal (r.TabIndexes.IndexOf (v2), v2.TabIndex); // TabIndex is not changed
+        Assert.NotEqual (-1, v2.TabIndex);
+        Assert.Equal (TabBehavior.TabStop, v2.TabStop); // TabStop is not changed
+        Assert.Equal (r.TabIndexes.IndexOf (v3), v3.TabIndex);
+        Assert.Equal (2, v3.TabIndex);
+        Assert.Equal (TabBehavior.TabStop, v3.TabStop);
+        r.Dispose ();
+    }
+
+
+
+#if V2_NEW_FOCUS_IMPL // Bogus test - depends on auto CanFocus behavior
+
+    [Fact]
+    public void CanFocus_Container_ToFalse_Turns_All_Subviews_ToFalse_Too ()
+    {
+        Application.Init (new FakeDriver ());
+
+        Toplevel t = new ();
+
+        var w = new Window ();
+        var f = new FrameView ();
+        var v1 = new View { CanFocus = true };
+        var v2 = new View { CanFocus = true };
+        f.Add (v1, v2);
+        w.Add (f);
+        t.Add (w);
+
+        t.Ready += (s, e) =>
+                   {
+                       Assert.True (t.CanFocus);
+                       Assert.True (w.CanFocus);
+                       Assert.True (f.CanFocus);
+                       Assert.True (v1.CanFocus);
+                       Assert.True (v2.CanFocus);
+
+                       w.CanFocus = false;
+                       Assert.False (w.CanFocus);
+                       Assert.False (f.CanFocus);
+                       Assert.False (v1.CanFocus);
+                       Assert.False (v2.CanFocus);
+                   };
+
+        Application.Iteration += (s, a) => Application.RequestStop ();
+
+        Application.Run (t);
+        t.Dispose ();
+        Application.Shutdown ();
+    }
+#endif
+
+#if V2_NEW_FOCUS_IMPL // Bogus test - depends on auto CanFocus behavior
+
+    [Fact]
+    public void CanFocus_Container_Toggling_All_Subviews_To_Old_Value_When_Is_True ()
+    {
+        Application.Init (new FakeDriver ());
+
+        Toplevel t = new ();
+
+        var w = new Window ();
+        var f = new FrameView ();
+        var v1 = new View ();
+        var v2 = new View { CanFocus = true };
+        f.Add (v1, v2);
+        w.Add (f);
+        t.Add (w);
+
+        t.Ready += (s, e) =>
+                   {
+                       Assert.True (t.CanFocus);
+                       Assert.True (w.CanFocus);
+                       Assert.True (f.CanFocus);
+                       Assert.False (v1.CanFocus);
+                       Assert.True (v2.CanFocus);
+
+                       w.CanFocus = false;
+                       Assert.False (w.CanFocus);
+                       Assert.False (f.CanFocus);
+                       Assert.False (v1.CanFocus);
+                       Assert.False (v2.CanFocus);
+
+                       w.CanFocus = true;
+                       Assert.True (w.CanFocus);
+                       Assert.True (f.CanFocus);
+                       Assert.False (v1.CanFocus);
+                       Assert.True (v2.CanFocus);
+                   };
+
+        Application.Iteration += (s, a) => Application.RequestStop ();
+
+        Application.Run (t);
+        t.Dispose ();
+        Application.Shutdown ();
+    }
+#endif
+#if V2_NEW_FOCUS_IMPL // Bogus test - depends on auto CanFocus behavior
+    [Fact]
+    public void CanFocus_Faced_With_Container_After_Run ()
+    {
+        Application.Init (new FakeDriver ());
+
+        Toplevel t = new ();
+
+        var w = new Window ();
+        var f = new FrameView ();
+        var v = new View { CanFocus = true };
+        f.Add (v);
+        w.Add (f);
+        t.Add (w);
+
+        t.Ready += (s, e) =>
+                   {
+                       Assert.True (t.CanFocus);
+                       Assert.True (w.CanFocus);
+                       Assert.True (f.CanFocus);
+                       Assert.True (v.CanFocus);
+
+                       f.CanFocus = false;
+                       Assert.False (f.CanFocus);
+                       Assert.False (v.CanFocus);
+
+                       v.CanFocus = false;
+                       Assert.False (f.CanFocus);
+                       Assert.False (v.CanFocus);
+
+                       Assert.Throws<InvalidOperationException> (() => v.CanFocus = true);
+                       Assert.False (f.CanFocus);
+                       Assert.False (v.CanFocus);
+
+                       f.CanFocus = true;
+                       Assert.True (f.CanFocus);
+                       Assert.True (v.CanFocus);
+                   };
+
+        Application.Iteration += (s, a) => Application.RequestStop ();
+
+        Application.Run (t);
+        t.Dispose ();
+        Application.Shutdown ();
+    }
+#endif
+#if V2_NEW_FOCUS_IMPL
+
+    [Fact]
+    [AutoInitShutdown]
+    public void CanFocus_Sets_To_False_On_Single_View_Focus_View_On_Another_Toplevel ()
+    {
+        var view1 = new View { Id = "view1", Width = 10, Height = 1, CanFocus = true };
+        var win1 = new Window { Id = "win1", Width = Dim.Percent (50), Height = Dim.Fill () };
+        win1.Add (view1);
+        var view2 = new View { Id = "view2", Width = 20, Height = 2, CanFocus = true };
+        var win2 = new Window { Id = "win2", X = Pos.Right (win1), Width = Dim.Fill (), Height = Dim.Fill () };
+        win2.Add (view2);
+        var top = new Toplevel ();
+        top.Add (win1, win2);
+        Application.Begin (top);
+
+        Assert.True (view1.CanFocus);
+        Assert.True (view1.HasFocus);
+        Assert.True (view2.CanFocus);
+        Assert.False (view2.HasFocus); // Only one of the most focused toplevels view can have focus
+
+        Assert.True (Application.OnKeyDown (Key.F6));
+        Assert.True (view1.CanFocus);
+        Assert.False (view1.HasFocus); // Only one of the most focused toplevels view can have focus
+        Assert.True (view2.CanFocus);
+        Assert.True (view2.HasFocus);
+
+        Assert.True (Application.OnKeyDown (Key.F6));
+        Assert.True (view1.CanFocus);
+        Assert.True (view1.HasFocus);
+        Assert.True (view2.CanFocus);
+        Assert.False (view2.HasFocus); // Only one of the most focused toplevels view can have focus
+
+        view1.CanFocus = false;
+        Assert.False (view1.CanFocus);
+        Assert.False (view1.HasFocus);
+        Assert.True (view2.CanFocus);
+        Assert.True (view2.HasFocus);
+        Assert.Equal (win2, Application.Current.GetFocused ());
+        Assert.Equal (view2, Application.Current.GetMostFocused ());
+        top.Dispose ();
+    }
+
+    [Fact]
+    [AutoInitShutdown]
+    public void CanFocus_Sets_To_False_On_Toplevel_Focus_View_On_Another_Toplevel ()
+    {
+        var view1 = new View { Id = "view1", Width = 10, Height = 1, CanFocus = true };
+        var win1 = new Window { Id = "win1", Width = Dim.Percent (50), Height = Dim.Fill () };
+        win1.Add (view1);
+        var view2 = new View { Id = "view2", Width = 20, Height = 2, CanFocus = true };
+        var win2 = new Window { Id = "win2", X = Pos.Right (win1), Width = Dim.Fill (), Height = Dim.Fill () };
+        win2.Add (view2);
+        var top = new Toplevel ();
+        top.Add (win1, win2);
+        Application.Begin (top);
+
+        Assert.True (view1.CanFocus);
+        Assert.True (view1.HasFocus);
+        Assert.True (view2.CanFocus);
+        Assert.False (view2.HasFocus); // Only one of the most focused toplevels view can have focus
+
+        Assert.True (Application.OnKeyDown (Key.F6));
+        Assert.True (view1.CanFocus);
+        Assert.False (view1.HasFocus); // Only one of the most focused toplevels view can have focus
+        Assert.True (view2.CanFocus);
+        Assert.True (view2.HasFocus);
+
+        Assert.True (Application.OnKeyDown (Key.F6));
+        Assert.True (view1.CanFocus);
+        Assert.True (view1.HasFocus);
+        Assert.True (view2.CanFocus);
+        Assert.False (view2.HasFocus); // Only one of the most focused toplevels view can have focus
+
+        win1.CanFocus = false;
+        Assert.False (view1.CanFocus);
+        Assert.False (view1.HasFocus);
+        Assert.False (win1.CanFocus);
+        Assert.False (win1.HasFocus);
+        Assert.True (view2.CanFocus);
+        Assert.True (view2.HasFocus);
+        Assert.Equal (win2, Application.Current.GetFocused ());
+        Assert.Equal (view2, Application.Current.GetMostFocused ());
+        top.Dispose ();
+    }
+
+    [Fact]
+    [AutoInitShutdown]
+    public void CanFocus_Sets_To_False_With_Two_Views_Focus_Another_View_On_The_Same_Toplevel ()
+    {
+        var view1 = new View { Id = "view1", Width = 10, Height = 1, CanFocus = true };
+
+        var view12 = new View
+        {
+            Id = "view12",
+            Y = 5,
+            Width = 10,
+            Height = 1,
+            CanFocus = true
+        };
+        var win1 = new Window { Id = "win1", Width = Dim.Percent (50), Height = Dim.Fill () };
+        win1.Add (view1, view12);
+        var view2 = new View { Id = "view2", Width = 20, Height = 2, CanFocus = true };
+        var win2 = new Window { Id = "win2", X = Pos.Right (win1), Width = Dim.Fill (), Height = Dim.Fill () };
+        win2.Add (view2);
+        var top = new Toplevel ();
+        top.Add (win1, win2);
+        Application.Begin (top);
+
+        Assert.True (view1.CanFocus);
+        Assert.True (view1.HasFocus);
+        Assert.True (view2.CanFocus);
+        Assert.False (view2.HasFocus); // Only one of the most focused toplevels view can have focus
+
+        Assert.True (Application.OnKeyDown (Key.F6)); // move to win2
+        Assert.True (view1.CanFocus);
+        Assert.False (view1.HasFocus); // Only one of the most focused toplevels view can have focus
+        Assert.True (view2.CanFocus);
+        Assert.True (view2.HasFocus);
+
+        Assert.True (Application.OnKeyDown (Key.F6));
+        Assert.True (view1.CanFocus);
+        Assert.True (view1.HasFocus);
+        Assert.True (view2.CanFocus);
+        Assert.False (view2.HasFocus); // Only one of the most focused toplevels view can have focus
+
+        view1.CanFocus = false;
+        Assert.False (view1.CanFocus);
+        Assert.False (view1.HasFocus);
+        Assert.True (view2.CanFocus);
+        Assert.False (view2.HasFocus);
+        Assert.Equal (win1, Application.Current.GetFocused ());
+        Assert.Equal (view12, Application.Current.GetMostFocused ());
+        top.Dispose ();
+    }
+#endif
+
+    [Fact (Skip = "Causes crash on Ubuntu in Github Action. Bogus test anyway.")]
+    public void WindowDispose_CanFocusProblem ()
+    {
+        // Arrange
+        Application.Init ();
+        using var top = new Toplevel ();
+        using var view = new View { X = 0, Y = 1, Text = nameof (WindowDispose_CanFocusProblem) };
+        using var window = new Window ();
+        top.Add (window);
+        window.Add (view);
+
+        // Act
+        RunState rs = Application.Begin (top);
+        Application.End (rs);
+        top.Dispose ();
+        Application.Shutdown ();
+
+        // Assert does Not throw NullReferenceException
+        top.SetFocus ();
+    }
+}

+ 160 - 0
UnitTests/View/Navigation/HasFocusTests.cs

@@ -0,0 +1,160 @@
+using Xunit.Abstractions;
+
+namespace Terminal.Gui.ViewTests;
+
+public class HasFocusTests (ITestOutputHelper _output) : TestsAllViews
+{
+
+    [Fact]
+    public void HasFocus_False_Leaves ()
+    {
+        var view = new View ()
+        {
+            Id = "view",
+            CanFocus = true
+        };
+
+        view.SetFocus ();
+        Assert.True (view.HasFocus);
+
+        view.HasFocus = false;
+        Assert.False (view.HasFocus);
+    }
+
+    [Fact]
+    public void HasFocus_False_WithSuperView_Leaves_All ()
+    {
+        var view = new View ()
+        {
+            Id = "view",
+            CanFocus = true
+        };
+
+        var subview = new View ()
+        {
+            Id = "subview",
+            CanFocus = true
+        };
+        view.Add (subview);
+
+        view.SetFocus ();
+        Assert.True (view.HasFocus);
+        Assert.True (subview.HasFocus);
+
+        subview.HasFocus = false;
+        Assert.False (view.HasFocus);
+        Assert.False (subview.HasFocus);
+    }
+
+    [Fact]
+    public void HasFocus_False_WithSubview_Leaves_All ()
+    {
+        var view = new View ()
+        {
+            Id = "view",
+            CanFocus = true
+        };
+
+        var subview = new View ()
+        {
+            Id = "subview",
+            CanFocus = true
+        };
+        view.Add (subview);
+
+        view.SetFocus ();
+        Assert.True (view.HasFocus);
+        Assert.True (subview.HasFocus);
+        Assert.Equal (subview, view.GetFocused ());
+
+        view.HasFocus = false;
+        Assert.Null (view.GetFocused ());
+        Assert.False (view.HasFocus);
+        Assert.False (subview.HasFocus);
+    }
+
+
+    [Fact]
+    public void HasFocus_False_Leave_Invoked ()
+    {
+        var view = new View ()
+        {
+            Id = "view",
+            CanFocus = true
+        };
+        Assert.True (view.CanFocus);
+        Assert.False (view.HasFocus);
+
+        int leaveInvoked = 0;
+
+        view.Leave += (s, e) => leaveInvoked++;
+
+        view.SetFocus ();
+        Assert.True (view.HasFocus);
+        Assert.Equal (0, leaveInvoked);
+
+        view.HasFocus = false;
+        Assert.False (view.HasFocus);
+        Assert.Equal (1, leaveInvoked);
+    }
+
+    [Fact]
+    public void HasFocus_False_Leave_Invoked_ForAllSubViews ()
+    {
+        var view = new View ()
+        {
+            Id = "view",
+            CanFocus = true
+        };
+
+        var subview = new View ()
+        {
+            Id = "subview",
+            CanFocus = true
+        };
+        view.Add (subview);
+
+        int leaveInvoked = 0;
+
+        view.Leave += (s, e) => leaveInvoked++;
+        subview.Leave += (s, e) => leaveInvoked++;
+
+        view.SetFocus ();
+        Assert.True (view.HasFocus);
+        Assert.Equal (0, leaveInvoked);
+
+        view.HasFocus = false;
+        Assert.False (view.HasFocus);
+        Assert.False (subview.HasFocus);
+        Assert.Equal (2, leaveInvoked);
+    }
+
+
+    [Fact]
+    public void Enabled_False_Sets_HasFocus_To_False ()
+    {
+        var wasClicked = false;
+        var view = new Button { Text = "Click Me" };
+        view.Accept += (s, e) => wasClicked = !wasClicked;
+
+        view.NewKeyDownEvent (Key.Space);
+        Assert.True (wasClicked);
+        view.NewMouseEvent (new () { Flags = MouseFlags.Button1Clicked });
+        Assert.False (wasClicked);
+        Assert.True (view.Enabled);
+        Assert.True (view.CanFocus);
+        Assert.True (view.HasFocus);
+
+        view.Enabled = false;
+        view.NewKeyDownEvent (Key.Space);
+        Assert.False (wasClicked);
+        view.NewMouseEvent (new () { Flags = MouseFlags.Button1Clicked });
+        Assert.False (wasClicked);
+        Assert.False (view.Enabled);
+        Assert.True (view.CanFocus);
+        Assert.False (view.HasFocus);
+        view.SetFocus ();
+        Assert.False (view.HasFocus);
+    }
+
+}

+ 69 - 944
UnitTests/View/NavigationTests.cs → UnitTests/View/Navigation/NavigationTests.cs

@@ -141,13 +141,18 @@ public class NavigationTests (ITestOutputHelper _output) : TestsAllViews
         view.Leave += (s, e) => nLeave++;
 
         top.Add (view, otherView);
+        Assert.False (view.HasFocus);
+        Assert.False (otherView.HasFocus);
+
         Application.Begin (top);
+        Assert.True (Application.Current!.HasFocus);
+        Assert.True (top.HasFocus);
 
         // Start with the focus on our test view
-        view.SetFocus ();
+        Assert.True (view.HasFocus);
 
-        //Assert.Equal (1, nEnter);
-        //Assert.Equal (0, nLeave);
+        Assert.Equal (1, nEnter);
+        Assert.Equal (0, nLeave);
 
         // Use keyboard to navigate to next view (otherView).
         if (view is TextView)
@@ -189,11 +194,11 @@ public class NavigationTests (ITestOutputHelper _output) : TestsAllViews
             }
         }
 
-        //Assert.Equal (1, nEnter);
-        //Assert.Equal (1, nLeave);
+        Assert.Equal (1, nEnter);
+        Assert.Equal (1, nLeave);
 
-        //Assert.False (view.HasFocus);
-        //Assert.True (otherView.HasFocus);
+        Assert.False (view.HasFocus);
+        Assert.True (otherView.HasFocus);
 
         // Now navigate back to our test view
         switch (view.TabStop)
@@ -218,6 +223,12 @@ public class NavigationTests (ITestOutputHelper _output) : TestsAllViews
                 throw new ArgumentOutOfRangeException ();
         }
 
+        Assert.Equal (2, nEnter);
+        Assert.Equal (1, nLeave);
+
+        Assert.True (view.HasFocus);
+        Assert.False (otherView.HasFocus);
+
         // Cache state because Shutdown has side effects.
         // Also ensures other tests can continue running if there's a fail
         bool otherViewHasFocus = otherView.HasFocus;
@@ -371,421 +382,6 @@ public class NavigationTests (ITestOutputHelper _output) : TestsAllViews
         r.Dispose ();
     }
 
-    [Fact]
-    public void CanFocus_Container_ToFalse_Turns_All_Subviews_ToFalse_Too ()
-    {
-        Application.Init (new FakeDriver ());
-
-        Toplevel t = new ();
-
-        var w = new Window ();
-        var f = new FrameView ();
-        var v1 = new View { CanFocus = true };
-        var v2 = new View { CanFocus = true };
-        f.Add (v1, v2);
-        w.Add (f);
-        t.Add (w);
-
-        t.Ready += (s, e) =>
-                   {
-                       Assert.True (t.CanFocus);
-                       Assert.True (w.CanFocus);
-                       Assert.True (f.CanFocus);
-                       Assert.True (v1.CanFocus);
-                       Assert.True (v2.CanFocus);
-
-                       w.CanFocus = false;
-                       Assert.False (w.CanFocus);
-                       Assert.False (f.CanFocus);
-                       Assert.False (v1.CanFocus);
-                       Assert.False (v2.CanFocus);
-                   };
-
-        Application.Iteration += (s, a) => Application.RequestStop ();
-
-        Application.Run (t);
-        t.Dispose ();
-        Application.Shutdown ();
-    }
-
-    [Fact]
-    public void CanFocus_Container_Toggling_All_Subviews_To_Old_Value_When_Is_True ()
-    {
-        Application.Init (new FakeDriver ());
-
-        Toplevel t = new ();
-
-        var w = new Window ();
-        var f = new FrameView ();
-        var v1 = new View ();
-        var v2 = new View { CanFocus = true };
-        f.Add (v1, v2);
-        w.Add (f);
-        t.Add (w);
-
-        t.Ready += (s, e) =>
-                   {
-                       Assert.True (t.CanFocus);
-                       Assert.True (w.CanFocus);
-                       Assert.True (f.CanFocus);
-                       Assert.False (v1.CanFocus);
-                       Assert.True (v2.CanFocus);
-
-                       w.CanFocus = false;
-                       Assert.False (w.CanFocus);
-                       Assert.False (f.CanFocus);
-                       Assert.False (v1.CanFocus);
-                       Assert.False (v2.CanFocus);
-
-                       w.CanFocus = true;
-                       Assert.True (w.CanFocus);
-                       Assert.True (f.CanFocus);
-                       Assert.False (v1.CanFocus);
-                       Assert.True (v2.CanFocus);
-                   };
-
-        Application.Iteration += (s, a) => Application.RequestStop ();
-
-        Application.Run (t);
-        t.Dispose ();
-        Application.Shutdown ();
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void CanFocus_Faced_With_Container ()
-    {
-        var t = new Toplevel ();
-        var w = new Window ();
-        var f = new FrameView ();
-        var v = new View { CanFocus = true };
-        f.Add (v);
-        w.Add (f);
-        t.Add (w);
-
-        Assert.True (t.CanFocus);
-        Assert.True (w.CanFocus);
-        Assert.True (f.CanFocus);
-        Assert.True (v.CanFocus);
-
-        f.CanFocus = false;
-        Assert.False (f.CanFocus);
-        Assert.True (v.CanFocus);
-
-        v.CanFocus = false;
-        Assert.False (f.CanFocus);
-        Assert.False (v.CanFocus);
-
-        v.CanFocus = true;
-        Assert.False (f.CanFocus);
-        Assert.True (v.CanFocus);
-        t.Dispose ();
-    }
-
-    [Fact]
-    public void CanFocus_Faced_With_Container_After_Run ()
-    {
-        Application.Init (new FakeDriver ());
-
-        Toplevel t = new ();
-
-        var w = new Window ();
-        var f = new FrameView ();
-        var v = new View { CanFocus = true };
-        f.Add (v);
-        w.Add (f);
-        t.Add (w);
-
-        t.Ready += (s, e) =>
-                   {
-                       Assert.True (t.CanFocus);
-                       Assert.True (w.CanFocus);
-                       Assert.True (f.CanFocus);
-                       Assert.True (v.CanFocus);
-
-                       f.CanFocus = false;
-                       Assert.False (f.CanFocus);
-                       Assert.False (v.CanFocus);
-
-                       v.CanFocus = false;
-                       Assert.False (f.CanFocus);
-                       Assert.False (v.CanFocus);
-
-                       Assert.Throws<InvalidOperationException> (() => v.CanFocus = true);
-                       Assert.False (f.CanFocus);
-                       Assert.False (v.CanFocus);
-
-                       f.CanFocus = true;
-                       Assert.True (f.CanFocus);
-                       Assert.True (v.CanFocus);
-                   };
-
-        Application.Iteration += (s, a) => Application.RequestStop ();
-
-        Application.Run (t);
-        t.Dispose ();
-        Application.Shutdown ();
-    }
-
-    [Fact]
-    public void CanFocus_Faced_With_Container_Before_Run ()
-    {
-        Application.Init (new FakeDriver ());
-
-        Toplevel t = new ();
-
-        var w = new Window ();
-        var f = new FrameView ();
-        var v = new View { CanFocus = true };
-        f.Add (v);
-        w.Add (f);
-        t.Add (w);
-
-        Assert.True (t.CanFocus);
-        Assert.True (w.CanFocus);
-        Assert.True (f.CanFocus);
-        Assert.True (v.CanFocus);
-
-        f.CanFocus = false;
-        Assert.False (f.CanFocus);
-        Assert.True (v.CanFocus);
-
-        v.CanFocus = false;
-        Assert.False (f.CanFocus);
-        Assert.False (v.CanFocus);
-
-        v.CanFocus = true;
-        Assert.False (f.CanFocus);
-        Assert.True (v.CanFocus);
-
-        Application.Iteration += (s, a) => Application.RequestStop ();
-
-        Application.Run (t);
-        t.Dispose ();
-        Application.Shutdown ();
-    }
-
-    [Fact]
-    public void CanFocus_False_Set_HasFocus_To_False ()
-    {
-        var view = new View { CanFocus = true };
-        var view2 = new View { CanFocus = true };
-        view2.Add (view);
-
-        Assert.True (view.CanFocus);
-
-        view.SetFocus ();
-        Assert.True (view.HasFocus);
-
-        view.CanFocus = false;
-        Assert.False (view.CanFocus);
-        Assert.False (view.HasFocus);
-    }
-
-    [Fact]
-    public void CanFocus_Set_Changes_TabIndex_And_TabStop ()
-    {
-        var r = new View ();
-        var v1 = new View { Text = "1" };
-        var v2 = new View { Text = "2" };
-        var v3 = new View { Text = "3" };
-
-        r.Add (v1, v2, v3);
-
-        v2.CanFocus = true;
-        Assert.Equal (r.TabIndexes.IndexOf (v2), v2.TabIndex);
-        Assert.Equal (0, v2.TabIndex);
-        Assert.Equal (TabBehavior.TabStop, v2.TabStop);
-
-        v1.CanFocus = true;
-        Assert.Equal (r.TabIndexes.IndexOf (v1), v1.TabIndex);
-        Assert.Equal (1, v1.TabIndex);
-        Assert.Equal (TabBehavior.TabStop, v1.TabStop);
-
-        v1.TabIndex = 2;
-        Assert.Equal (r.TabIndexes.IndexOf (v1), v1.TabIndex);
-        Assert.Equal (1, v1.TabIndex);
-        v3.CanFocus = true;
-        Assert.Equal (r.TabIndexes.IndexOf (v1), v1.TabIndex);
-        Assert.Equal (1, v1.TabIndex);
-        Assert.Equal (r.TabIndexes.IndexOf (v3), v3.TabIndex);
-        Assert.Equal (2, v3.TabIndex);
-        Assert.Equal (TabBehavior.TabStop, v3.TabStop);
-
-        v2.CanFocus = false;
-        Assert.Equal (r.TabIndexes.IndexOf (v1), v1.TabIndex);
-        Assert.Equal (1, v1.TabIndex);
-        Assert.Equal (TabBehavior.TabStop, v1.TabStop);
-        Assert.Equal (r.TabIndexes.IndexOf (v2), v2.TabIndex); // TabIndex is not changed
-        Assert.NotEqual (-1, v2.TabIndex);
-        Assert.Equal (TabBehavior.TabStop, v2.TabStop); // TabStop is not changed
-        Assert.Equal (r.TabIndexes.IndexOf (v3), v3.TabIndex);
-        Assert.Equal (2, v3.TabIndex);
-        Assert.Equal (TabBehavior.TabStop, v3.TabStop);
-        r.Dispose ();
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void CanFocus_Sets_To_False_On_Single_View_Focus_View_On_Another_Toplevel ()
-    {
-        var view1 = new View { Id = "view1", Width = 10, Height = 1, CanFocus = true };
-        var win1 = new Window { Id = "win1", Width = Dim.Percent (50), Height = Dim.Fill () };
-        win1.Add (view1);
-        var view2 = new View { Id = "view2", Width = 20, Height = 2, CanFocus = true };
-        var win2 = new Window { Id = "win2", X = Pos.Right (win1), Width = Dim.Fill (), Height = Dim.Fill () };
-        win2.Add (view2);
-        var top = new Toplevel ();
-        top.Add (win1, win2);
-        Application.Begin (top);
-
-        Assert.True (view1.CanFocus);
-        Assert.True (view1.HasFocus);
-        Assert.True (view2.CanFocus);
-        Assert.False (view2.HasFocus); // Only one of the most focused toplevels view can have focus
-
-        Assert.True (Application.OnKeyDown (Key.F6));
-        Assert.True (view1.CanFocus);
-        Assert.False (view1.HasFocus); // Only one of the most focused toplevels view can have focus
-        Assert.True (view2.CanFocus);
-        Assert.True (view2.HasFocus);
-
-        Assert.True (Application.OnKeyDown (Key.F6));
-        Assert.True (view1.CanFocus);
-        Assert.True (view1.HasFocus);
-        Assert.True (view2.CanFocus);
-        Assert.False (view2.HasFocus); // Only one of the most focused toplevels view can have focus
-
-        view1.CanFocus = false;
-        Assert.False (view1.CanFocus);
-        Assert.False (view1.HasFocus);
-        Assert.True (view2.CanFocus);
-        Assert.True (view2.HasFocus);
-        Assert.Equal (win2, Application.Current.Focused);
-        Assert.Equal (view2, Application.Current.MostFocused);
-        top.Dispose ();
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void CanFocus_Sets_To_False_On_Toplevel_Focus_View_On_Another_Toplevel ()
-    {
-        var view1 = new View { Id = "view1", Width = 10, Height = 1, CanFocus = true };
-        var win1 = new Window { Id = "win1", Width = Dim.Percent (50), Height = Dim.Fill () };
-        win1.Add (view1);
-        var view2 = new View { Id = "view2", Width = 20, Height = 2, CanFocus = true };
-        var win2 = new Window { Id = "win2", X = Pos.Right (win1), Width = Dim.Fill (), Height = Dim.Fill () };
-        win2.Add (view2);
-        var top = new Toplevel ();
-        top.Add (win1, win2);
-        Application.Begin (top);
-
-        Assert.True (view1.CanFocus);
-        Assert.True (view1.HasFocus);
-        Assert.True (view2.CanFocus);
-        Assert.False (view2.HasFocus); // Only one of the most focused toplevels view can have focus
-
-        Assert.True (Application.OnKeyDown (Key.F6));
-        Assert.True (view1.CanFocus);
-        Assert.False (view1.HasFocus); // Only one of the most focused toplevels view can have focus
-        Assert.True (view2.CanFocus);
-        Assert.True (view2.HasFocus);
-
-        Assert.True (Application.OnKeyDown (Key.F6));
-        Assert.True (view1.CanFocus);
-        Assert.True (view1.HasFocus);
-        Assert.True (view2.CanFocus);
-        Assert.False (view2.HasFocus); // Only one of the most focused toplevels view can have focus
-
-        win1.CanFocus = false;
-        Assert.False (view1.CanFocus);
-        Assert.False (view1.HasFocus);
-        Assert.False (win1.CanFocus);
-        Assert.False (win1.HasFocus);
-        Assert.True (view2.CanFocus);
-        Assert.True (view2.HasFocus);
-        Assert.Equal (win2, Application.Current.Focused);
-        Assert.Equal (view2, Application.Current.MostFocused);
-        top.Dispose ();
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void CanFocus_Sets_To_False_With_Two_Views_Focus_Another_View_On_The_Same_Toplevel ()
-    {
-        var view1 = new View { Id = "view1", Width = 10, Height = 1, CanFocus = true };
-
-        var view12 = new View
-        {
-            Id = "view12",
-            Y = 5,
-            Width = 10,
-            Height = 1,
-            CanFocus = true
-        };
-        var win1 = new Window { Id = "win1", Width = Dim.Percent (50), Height = Dim.Fill () };
-        win1.Add (view1, view12);
-        var view2 = new View { Id = "view2", Width = 20, Height = 2, CanFocus = true };
-        var win2 = new Window { Id = "win2", X = Pos.Right (win1), Width = Dim.Fill (), Height = Dim.Fill () };
-        win2.Add (view2);
-        var top = new Toplevel ();
-        top.Add (win1, win2);
-        Application.Begin (top);
-
-        Assert.True (view1.CanFocus);
-        Assert.True (view1.HasFocus);
-        Assert.True (view2.CanFocus);
-        Assert.False (view2.HasFocus); // Only one of the most focused toplevels view can have focus
-
-        Assert.True (Application.OnKeyDown (Key.F6)); // move to win2
-        Assert.True (view1.CanFocus);
-        Assert.False (view1.HasFocus); // Only one of the most focused toplevels view can have focus
-        Assert.True (view2.CanFocus);
-        Assert.True (view2.HasFocus);
-
-        Assert.True (Application.OnKeyDown (Key.F6));
-        Assert.True (view1.CanFocus);
-        Assert.True (view1.HasFocus);
-        Assert.True (view2.CanFocus);
-        Assert.False (view2.HasFocus); // Only one of the most focused toplevels view can have focus
-
-        view1.CanFocus = false;
-        Assert.False (view1.CanFocus);
-        Assert.False (view1.HasFocus);
-        Assert.True (view2.CanFocus);
-        Assert.False (view2.HasFocus);
-        Assert.Equal (win1, Application.Current.Focused);
-        Assert.Equal (view12, Application.Current.MostFocused);
-        top.Dispose ();
-    }
-
-    [Fact]
-    public void Enabled_False_Sets_HasFocus_To_False ()
-    {
-        var wasClicked = false;
-        var view = new Button { Text = "Click Me" };
-        view.Accept += (s, e) => wasClicked = !wasClicked;
-
-        view.NewKeyDownEvent (Key.Space);
-        Assert.True (wasClicked);
-        view.NewMouseEvent (new() { Flags = MouseFlags.Button1Clicked });
-        Assert.False (wasClicked);
-        Assert.True (view.Enabled);
-        Assert.True (view.CanFocus);
-        Assert.True (view.HasFocus);
-
-        view.Enabled = false;
-        view.NewKeyDownEvent (Key.Space);
-        Assert.False (wasClicked);
-        view.NewMouseEvent (new() { Flags = MouseFlags.Button1Clicked });
-        Assert.False (wasClicked);
-        Assert.False (view.Enabled);
-        Assert.True (view.CanFocus);
-        Assert.False (view.HasFocus);
-        view.SetFocus ();
-        Assert.False (view.HasFocus);
-    }
-
     [Fact]
     [AutoInitShutdown]
     public void Enabled_Sets_Also_Sets_Subviews ()
@@ -807,7 +403,7 @@ public class NavigationTests (ITestOutputHelper _output) : TestsAllViews
 
                                      win.NewKeyDownEvent (Key.Enter);
                                      Assert.True (wasClicked);
-                                     button.NewMouseEvent (new() { Flags = MouseFlags.Button1Clicked });
+                                     button.NewMouseEvent (new () { Flags = MouseFlags.Button1Clicked });
                                      Assert.False (wasClicked);
                                      Assert.True (button.Enabled);
                                      Assert.True (button.CanFocus);
@@ -819,7 +415,7 @@ public class NavigationTests (ITestOutputHelper _output) : TestsAllViews
                                      win.Enabled = false;
                                      button.NewKeyDownEvent (Key.Enter);
                                      Assert.False (wasClicked);
-                                     button.NewMouseEvent (new() { Flags = MouseFlags.Button1Clicked });
+                                     button.NewMouseEvent (new () { Flags = MouseFlags.Button1Clicked });
                                      Assert.False (wasClicked);
                                      Assert.False (button.Enabled);
                                      Assert.True (button.CanFocus);
@@ -856,12 +452,12 @@ public class NavigationTests (ITestOutputHelper _output) : TestsAllViews
     public void Focused_NoSubviews ()
     {
         var view = new View ();
-        Assert.Null (view.Focused);
+        Assert.Null (view.GetFocused ());
 
         view.CanFocus = true;
         view.SetFocus ();
         Assert.True (view.HasFocus);
-        Assert.Null (view.Focused); // BUGBUG: Should be view
+        Assert.Null (view.GetFocused ()); // BUGBUG: Should be view
     }
 
     [Fact]
@@ -881,25 +477,25 @@ public class NavigationTests (ITestOutputHelper _output) : TestsAllViews
         top.Add (frm);
 
         Application.Begin (top);
-        Assert.Equal ("WindowSubview", top.MostFocused.Text);
+        Assert.Equal ("WindowSubview", top.GetMostFocused ().Text);
 
         Application.OnKeyDown (Key.Tab);
-        Assert.Equal ("WindowSubview", top.MostFocused.Text);
+        Assert.Equal ("WindowSubview", top.GetMostFocused ().Text);
 
         Application.OnKeyDown (Key.F6);
-        Assert.Equal ("FrameSubview", top.MostFocused.Text);
+        Assert.Equal ("FrameSubview", top.GetMostFocused ().Text);
 
         Application.OnKeyDown (Key.Tab);
-        Assert.Equal ("FrameSubview", top.MostFocused.Text);
+        Assert.Equal ("FrameSubview", top.GetMostFocused ().Text);
 
         Application.OnKeyDown (Key.F6);
-        Assert.Equal ("WindowSubview", top.MostFocused.Text);
+        Assert.Equal ("WindowSubview", top.GetMostFocused ().Text);
 
         Application.OnKeyDown (Key.F6.WithShift);
-        Assert.Equal ("FrameSubview", top.MostFocused.Text);
+        Assert.Equal ("FrameSubview", top.GetMostFocused ().Text);
 
         Application.OnKeyDown (Key.F6.WithShift);
-        Assert.Equal ("WindowSubview", top.MostFocused.Text);
+        Assert.Equal ("WindowSubview", top.GetMostFocused ().Text);
         top.Dispose ();
     }
 
@@ -927,7 +523,7 @@ public class NavigationTests (ITestOutputHelper _output) : TestsAllViews
                            if (!removed)
                            {
                                removed = true;
-                               view3 = new() { Id = "view3", Y = 1, Width = 10, Height = 5 };
+                               view3 = new () { Id = "view3", Y = 1, Width = 10, Height = 5 };
                                Application.Current.Add (view3);
                                Application.Current.BringSubviewToFront (view3);
                                Assert.False (view3.HasFocus);
@@ -964,18 +560,49 @@ public class NavigationTests (ITestOutputHelper _output) : TestsAllViews
         top1.Dispose ();
     }
 
-    // View.MostFocused - No subviews
     [Fact]
-    [Trait ("BUGBUG", "Fix in Issue #3444")]
-    public void Most_Focused_NoSubviews ()
+    public void GetMostFocused_NoSubviews_Returns_Null ()
     {
         var view = new View ();
-        Assert.Null (view.Focused);
+        Assert.Null (view.GetFocused ());
 
         view.CanFocus = true;
+        Assert.False (view.HasFocus);
+        view.SetFocus ();
+        Assert.True (view.HasFocus);
+        Assert.Null (view.GetMostFocused ());
+    }
+
+    [Fact]
+    public void GetMostFocused_Returns_Most ()
+    {
+        var view = new View ()
+        {
+            Id = "view",
+            CanFocus = true
+        };
+
+        var subview = new View ()
+        {
+            Id = "subview",
+            CanFocus = true
+        };
+
+        view.Add (subview);
+
         view.SetFocus ();
         Assert.True (view.HasFocus);
-        Assert.Null (view.MostFocused); // BUGBUG: Should be view
+        Assert.True (subview.HasFocus);
+        Assert.Equal (subview, view.GetMostFocused ());
+
+        var subview2 = new View ()
+        {
+            Id = "subview2",
+            CanFocus = true
+        };
+
+        view.Add (subview2);
+        Assert.Equal (subview2, view.GetMostFocused ());
     }
 
     //    [Fact]
@@ -1115,7 +742,7 @@ public class NavigationTests (ITestOutputHelper _output) : TestsAllViews
         Application.Init (new FakeDriver ());
 
         var top = new Toplevel ();
-        top.Ready += (s, e) => { Assert.Null (top.Focused); };
+        top.Ready += (s, e) => { Assert.Null (top.GetFocused ()); };
 
         // Keyboard navigation with tab
         FakeConsole.MockKeyPresses.Push (new ('\t', ConsoleKey.Tab, false, false, false));
@@ -1127,6 +754,7 @@ public class NavigationTests (ITestOutputHelper _output) : TestsAllViews
         Application.Shutdown ();
     }
 
+#if V2_NEW_FOCUS_IMPL // bogus test - Depends on auto setting of CanFocus
     [Fact]
     [AutoInitShutdown]
     public void Remove_Does_Not_Change_Focus ()
@@ -1167,6 +795,7 @@ public class NavigationTests (ITestOutputHelper _output) : TestsAllViews
         Assert.False (leave);
         top.Dispose ();
     }
+#endif
 
     [Fact]
     [AutoInitShutdown]
@@ -1454,508 +1083,4 @@ public class NavigationTests (ITestOutputHelper _output) : TestsAllViews
         Assert.Null (View.FindDeepestView (top, new (24, 4)));
         top.Dispose ();
     }
-
-    [Fact]
-    public void SendSubviewBackwards_Subviews_vs_TabIndexes ()
-    {
-        var r = new View ();
-        var v1 = new View { CanFocus = true };
-        var v2 = new View { CanFocus = true };
-        var v3 = new View { CanFocus = true };
-
-        r.Add (v1, v2, v3);
-
-        r.SendSubviewBackwards (v3);
-        Assert.True (r.Subviews.IndexOf (v1) == 0);
-        Assert.True (r.Subviews.IndexOf (v2) == 2);
-        Assert.True (r.Subviews.IndexOf (v3) == 1);
-
-        Assert.True (r.TabIndexes.IndexOf (v1) == 0);
-        Assert.True (r.TabIndexes.IndexOf (v2) == 1);
-        Assert.True (r.TabIndexes.IndexOf (v3) == 2);
-        r.Dispose ();
-    }
-
-    [Fact]
-    public void SendSubviewToBack_Subviews_vs_TabIndexes ()
-    {
-        var r = new View ();
-        var v1 = new View { CanFocus = true };
-        var v2 = new View { CanFocus = true };
-        var v3 = new View { CanFocus = true };
-
-        r.Add (v1, v2, v3);
-
-        r.SendSubviewToBack (v3);
-        Assert.True (r.Subviews.IndexOf (v1) == 1);
-        Assert.True (r.Subviews.IndexOf (v2) == 2);
-        Assert.True (r.Subviews.IndexOf (v3) == 0);
-
-        Assert.True (r.TabIndexes.IndexOf (v1) == 0);
-        Assert.True (r.TabIndexes.IndexOf (v2) == 1);
-        Assert.True (r.TabIndexes.IndexOf (v3) == 2);
-        r.Dispose ();
-    }
-
-    [Fact]
-    public void SetFocus_With_Null_Superview_Does_Not_Throw_Exception ()
-    {
-        var view = new View ()
-        {
-            CanFocus = true
-        };
-        Assert.True (view.CanFocus);
-        Assert.False (view.HasFocus);
-
-        Exception exception = Record.Exception (() => view.SetFocus());
-        Assert.Null (exception);
-
-        Assert.True (view.CanFocus);
-        Assert.True (view.HasFocus);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void SetHasFocus_Do_Not_Throws_If_OnLeave_Remove_Focused_Changing_To_Null ()
-    {
-        var view1Leave = false;
-        var subView1Leave = false;
-        var subView1subView1Leave = false;
-        Toplevel top = new ();
-        var view1 = new View { CanFocus = true };
-        var subView1 = new View { CanFocus = true };
-        var subView1subView1 = new View { CanFocus = true };
-        view1.Leave += (s, e) => { view1Leave = true; };
-
-        subView1.Leave += (s, e) =>
-                          {
-                              subView1.Remove (subView1subView1);
-                              subView1Leave = true;
-                          };
-        view1.Add (subView1);
-
-        subView1subView1.Leave += (s, e) =>
-                                  {
-                                      // This is never invoked
-                                      subView1subView1Leave = true;
-                                  };
-        subView1.Add (subView1subView1);
-        var view2 = new View { CanFocus = true };
-        top.Add (view1, view2);
-        RunState rs = Application.Begin (top);
-
-        view2.SetFocus ();
-        Assert.True (view1Leave);
-        Assert.True (subView1Leave);
-        Assert.False (subView1subView1Leave);
-        Application.End (rs);
-        subView1subView1.Dispose ();
-        top.Dispose ();
-    }
-
-    [Fact]
-    public void Subviews_TabIndexes_AreEqual ()
-    {
-        var r = new View ();
-        var v1 = new View { CanFocus = true };
-        var v2 = new View { CanFocus = true };
-        var v3 = new View { CanFocus = true };
-
-        r.Add (v1, v2, v3);
-
-        Assert.True (r.Subviews.IndexOf (v1) == 0);
-        Assert.True (r.Subviews.IndexOf (v2) == 1);
-        Assert.True (r.Subviews.IndexOf (v3) == 2);
-
-        Assert.True (r.TabIndexes.IndexOf (v1) == 0);
-        Assert.True (r.TabIndexes.IndexOf (v2) == 1);
-        Assert.True (r.TabIndexes.IndexOf (v3) == 2);
-
-        Assert.Equal (r.Subviews.IndexOf (v1), r.TabIndexes.IndexOf (v1));
-        Assert.Equal (r.Subviews.IndexOf (v2), r.TabIndexes.IndexOf (v2));
-        Assert.Equal (r.Subviews.IndexOf (v3), r.TabIndexes.IndexOf (v3));
-        r.Dispose ();
-    }
-
-    [Fact]
-    public void TabIndex_Invert_Order ()
-    {
-        var r = new View ();
-        var v1 = new View { Id = "1", CanFocus = true };
-        var v2 = new View { Id = "2", CanFocus = true };
-        var v3 = new View { Id = "3", CanFocus = true };
-
-        r.Add (v1, v2, v3);
-
-        v1.TabIndex = 2;
-        v2.TabIndex = 1;
-        v3.TabIndex = 0;
-        Assert.True (r.TabIndexes.IndexOf (v1) == 2);
-        Assert.True (r.TabIndexes.IndexOf (v2) == 1);
-        Assert.True (r.TabIndexes.IndexOf (v3) == 0);
-
-        Assert.True (r.Subviews.IndexOf (v1) == 0);
-        Assert.True (r.Subviews.IndexOf (v2) == 1);
-        Assert.True (r.Subviews.IndexOf (v3) == 2);
-    }
-
-    [Fact]
-    public void TabIndex_Invert_Order_Added_One_By_One_Does_Not_Do_What_Is_Expected ()
-    {
-        var r = new View ();
-        var v1 = new View { Id = "1", CanFocus = true };
-        r.Add (v1);
-        v1.TabIndex = 2;
-        var v2 = new View { Id = "2", CanFocus = true };
-        r.Add (v2);
-        v2.TabIndex = 1;
-        var v3 = new View { Id = "3", CanFocus = true };
-        r.Add (v3);
-        v3.TabIndex = 0;
-
-        Assert.False (r.TabIndexes.IndexOf (v1) == 2);
-        Assert.True (r.TabIndexes.IndexOf (v1) == 1);
-        Assert.False (r.TabIndexes.IndexOf (v2) == 1);
-        Assert.True (r.TabIndexes.IndexOf (v2) == 2);
-
-        // Only the last is in the expected index
-        Assert.True (r.TabIndexes.IndexOf (v3) == 0);
-
-        Assert.True (r.Subviews.IndexOf (v1) == 0);
-        Assert.True (r.Subviews.IndexOf (v2) == 1);
-        Assert.True (r.Subviews.IndexOf (v3) == 2);
-    }
-
-    [Fact]
-    public void TabIndex_Invert_Order_Mixed ()
-    {
-        var r = new View ();
-        var vl1 = new View { Id = "vl1" };
-        var v1 = new View { Id = "v1", CanFocus = true };
-        var vl2 = new View { Id = "vl2" };
-        var v2 = new View { Id = "v2", CanFocus = true };
-        var vl3 = new View { Id = "vl3" };
-        var v3 = new View { Id = "v3", CanFocus = true };
-
-        r.Add (vl1, v1, vl2, v2, vl3, v3);
-
-        v1.TabIndex = 2;
-        v2.TabIndex = 1;
-        v3.TabIndex = 0;
-        Assert.True (r.TabIndexes.IndexOf (v1) == 4);
-        Assert.True (r.TabIndexes.IndexOf (v2) == 2);
-        Assert.True (r.TabIndexes.IndexOf (v3) == 0);
-
-        Assert.True (r.Subviews.IndexOf (v1) == 1);
-        Assert.True (r.Subviews.IndexOf (v2) == 3);
-        Assert.True (r.Subviews.IndexOf (v3) == 5);
-    }
-
-    [Fact]
-    public void TabIndex_Set_CanFocus_False ()
-    {
-        var r = new View ();
-        var v1 = new View { CanFocus = true };
-        var v2 = new View { CanFocus = true };
-        var v3 = new View { CanFocus = true };
-
-        r.Add (v1, v2, v3);
-
-        v1.CanFocus = false;
-        v1.TabIndex = 0;
-        Assert.True (r.Subviews.IndexOf (v1) == 0);
-        Assert.True (r.TabIndexes.IndexOf (v1) == 0);
-        Assert.NotEqual (-1, v1.TabIndex);
-        r.Dispose ();
-    }
-
-    [Fact]
-    public void TabIndex_Set_CanFocus_False_To_True ()
-    {
-        var r = new View ();
-        var v1 = new View ();
-        var v2 = new View { CanFocus = true };
-        var v3 = new View { CanFocus = true };
-
-        r.Add (v1, v2, v3);
-
-        v1.CanFocus = true;
-        v1.TabIndex = 1;
-        Assert.True (r.Subviews.IndexOf (v1) == 0);
-        Assert.True (r.TabIndexes.IndexOf (v1) == 1);
-        r.Dispose ();
-    }
-
-    [Fact]
-    public void TabIndex_Set_CanFocus_HigherValues ()
-    {
-        var r = new View ();
-        var v1 = new View { CanFocus = true };
-        var v2 = new View { CanFocus = true };
-        var v3 = new View { CanFocus = true };
-
-        r.Add (v1, v2, v3);
-
-        v1.TabIndex = 3;
-        Assert.True (r.Subviews.IndexOf (v1) == 0);
-        Assert.True (r.TabIndexes.IndexOf (v1) == 2);
-        r.Dispose ();
-    }
-
-    [Fact]
-    public void TabIndex_Set_CanFocus_LowerValues ()
-    {
-        var r = new View ();
-        var v1 = new View { CanFocus = true };
-        var v2 = new View { CanFocus = true };
-        var v3 = new View { CanFocus = true };
-
-        r.Add (v1, v2, v3);
-
-        //v1.TabIndex = -1;
-        Assert.True (r.Subviews.IndexOf (v1) == 0);
-        Assert.True (r.TabIndexes.IndexOf (v1) == 0);
-        r.Dispose ();
-    }
-
-    [Fact]
-    public void TabIndex_Set_CanFocus_ValidValues ()
-    {
-        var r = new View ();
-        var v1 = new View { CanFocus = true };
-        var v2 = new View { CanFocus = true };
-        var v3 = new View { CanFocus = true };
-
-        r.Add (v1, v2, v3);
-
-        v1.TabIndex = 1;
-        Assert.True (r.Subviews.IndexOf (v1) == 0);
-        Assert.True (r.TabIndexes.IndexOf (v1) == 1);
-
-        v1.TabIndex = 2;
-        Assert.True (r.Subviews.IndexOf (v1) == 0);
-        Assert.True (r.TabIndexes.IndexOf (v1) == 2);
-        r.Dispose ();
-    }
-
-    [Fact]
-    public void TabStop_And_CanFocus_Are_All_True ()
-    {
-        var r = new View ();
-        var v1 = new View { CanFocus = true };
-        var v2 = new View { CanFocus = true };
-        var v3 = new View { CanFocus = true };
-
-        r.Add (v1, v2, v3);
-
-        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
-        Assert.True (v1.HasFocus);
-        Assert.False (v2.HasFocus);
-        Assert.False (v3.HasFocus);
-        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
-        Assert.False (v1.HasFocus);
-        Assert.True (v2.HasFocus);
-        Assert.False (v3.HasFocus);
-        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
-        Assert.False (v1.HasFocus);
-        Assert.False (v2.HasFocus);
-        Assert.True (v3.HasFocus);
-        r.Dispose ();
-    }
-
-    [Theory]
-    [CombinatorialData]
-    public void TabStop_And_CanFocus_Are_Decoupled (bool canFocus, TabBehavior tabStop)
-    {
-        var view = new View { CanFocus = canFocus, TabStop = tabStop };
-
-        Assert.Equal (canFocus, view.CanFocus);
-        Assert.Equal (tabStop, view.TabStop);
-    }
-
-    [Fact]
-    public void TabStop_And_CanFocus_Mixed ()
-    {
-        var r = new View ();
-        var v1 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
-        var v2 = new View { CanFocus = false, TabStop = TabBehavior.TabStop };
-        var v3 = new View { CanFocus = false, TabStop = TabBehavior.NoStop };
-
-        r.Add (v1, v2, v3);
-
-        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
-        Assert.False (v1.HasFocus);
-        Assert.False (v2.HasFocus);
-        Assert.False (v3.HasFocus);
-        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
-        Assert.False (v1.HasFocus);
-        Assert.False (v2.HasFocus);
-        Assert.False (v3.HasFocus);
-        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
-        Assert.False (v1.HasFocus);
-        Assert.False (v2.HasFocus);
-        Assert.False (v3.HasFocus);
-        r.Dispose ();
-    }
-
-    [Theory]
-    [CombinatorialData]
-    public void TabStop_Change_CanFocus_Works ([CombinatorialValues (TabBehavior.NoStop, TabBehavior.TabStop, TabBehavior.TabGroup)] TabBehavior behavior)
-    {
-        var r = new View ();
-        var v1 = new View ();
-        var v2 = new View ();
-        var v3 = new View ();
-        Assert.False (v1.CanFocus);
-        Assert.False (v2.CanFocus);
-        Assert.False (v3.CanFocus);
-
-        r.Add (v1, v2, v3);
-
-        r.AdvanceFocus (NavigationDirection.Forward, behavior);
-        Assert.False (v1.HasFocus);
-        Assert.False (v2.HasFocus);
-        Assert.False (v3.HasFocus);
-
-        v1.CanFocus = true;
-        v1.TabStop = behavior;
-        r.AdvanceFocus (NavigationDirection.Forward, behavior);
-        Assert.True (v1.HasFocus);
-        Assert.False (v2.HasFocus);
-        Assert.False (v3.HasFocus);
-
-        v2.CanFocus = true;
-        v2.TabStop = behavior;
-        r.AdvanceFocus (NavigationDirection.Forward, behavior);
-        Assert.False (v1.HasFocus);
-        Assert.True (v2.HasFocus);
-        Assert.False (v3.HasFocus);
-
-        v3.CanFocus = true;
-        v3.TabStop = behavior;
-        r.AdvanceFocus (NavigationDirection.Forward, behavior);
-        Assert.False (v1.HasFocus);
-        Assert.False (v2.HasFocus);
-        Assert.True (v3.HasFocus);
-        r.Dispose ();
-    }
-
-    [Fact]
-    public void TabStop_NoStop_And_CanFocus_True_No_Focus ()
-    {
-        var r = new View ();
-        var v1 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
-        var v2 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
-        var v3 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
-
-        r.Add (v1, v2, v3);
-
-        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
-        Assert.False (v1.HasFocus);
-        Assert.False (v2.HasFocus);
-        Assert.False (v3.HasFocus);
-        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
-        Assert.False (v1.HasFocus);
-        Assert.False (v2.HasFocus);
-        Assert.False (v3.HasFocus);
-        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
-        Assert.False (v1.HasFocus);
-        Assert.False (v2.HasFocus);
-        Assert.False (v3.HasFocus);
-        r.Dispose ();
-    }
-
-    [Fact]
-    public void TabStop_NoStop_Change_Enables_Stop ()
-    {
-        var r = new View ();
-        var v1 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
-        var v2 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
-        var v3 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
-
-        r.Add (v1, v2, v3);
-
-        v1.TabStop = TabBehavior.TabStop;
-        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
-        Assert.True (v1.HasFocus);
-        Assert.False (v2.HasFocus);
-        Assert.False (v3.HasFocus);
-
-        v2.TabStop = TabBehavior.TabStop;
-        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
-        Assert.False (v1.HasFocus);
-        Assert.True (v2.HasFocus);
-        Assert.False (v3.HasFocus);
-
-        v3.TabStop = TabBehavior.TabStop;
-        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
-        Assert.False (v1.HasFocus);
-        Assert.False (v2.HasFocus);
-        Assert.True (v3.HasFocus);
-        r.Dispose ();
-    }
-
-    [Fact]
-    public void TabStop_NoStop_Prevents_Stop ()
-    {
-        var r = new View ();
-        var v1 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
-        var v2 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
-        var v3 = new View { CanFocus = true, TabStop = TabBehavior.NoStop };
-
-        r.Add (v1, v2, v3);
-
-        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
-        Assert.False (v1.HasFocus);
-        Assert.False (v2.HasFocus);
-        Assert.False (v3.HasFocus);
-    }
-
-    [Fact]
-    public void TabStop_Null_And_CanFocus_False_No_Advance ()
-    {
-        var r = new View ();
-        var v1 = new View ();
-        var v2 = new View ();
-        var v3 = new View ();
-        Assert.False (v1.CanFocus);
-        Assert.Null (v1.TabStop);
-
-        r.Add (v1, v2, v3);
-
-        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
-        Assert.False (v1.HasFocus);
-        Assert.False (v2.HasFocus);
-        Assert.False (v3.HasFocus);
-        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
-        Assert.False (v1.HasFocus);
-        Assert.False (v2.HasFocus);
-        Assert.False (v3.HasFocus);
-        r.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
-        Assert.False (v1.HasFocus);
-        Assert.False (v2.HasFocus);
-        Assert.False (v3.HasFocus);
-        r.Dispose ();
-    }
-
-    [Fact (Skip = "Causes crash on Ubuntu in Github Action. Bogus test anyway.")]
-    public void WindowDispose_CanFocusProblem ()
-    {
-        // Arrange
-        Application.Init ();
-        using var top = new Toplevel ();
-        using var view = new View { X = 0, Y = 1, Text = nameof (WindowDispose_CanFocusProblem) };
-        using var window = new Window ();
-        top.Add (window);
-        window.Add (view);
-
-        // Act
-        RunState rs = Application.Begin (top);
-        Application.End (rs);
-        top.Dispose ();
-        Application.Shutdown ();
-
-        // Assert does Not throw NullReferenceException
-        top.SetFocus ();
-    }
 }

+ 226 - 0
UnitTests/View/Navigation/SetFocusTests.cs

@@ -0,0 +1,226 @@
+using Xunit.Abstractions;
+
+namespace Terminal.Gui.ViewTests;
+
+public class SetFocusTests (ITestOutputHelper _output) : TestsAllViews
+{
+   
+    [Fact]
+    public void SetFocus_With_Null_Superview_Does_Not_Throw_Exception ()
+    {
+        var view = new View ()
+        {
+            Id = "view",
+            CanFocus = true
+        };
+        Assert.True (view.CanFocus);
+        Assert.False (view.HasFocus);
+
+        Exception exception = Record.Exception (() => view.SetFocus ());
+        Assert.Null (exception);
+
+        Assert.True (view.CanFocus);
+        Assert.True (view.HasFocus);
+    }
+
+    [Fact]
+    public void SetFocus_SetsFocus ()
+    {
+        var view = new View ()
+        {
+            Id = "view",
+            CanFocus = true
+        };
+        Assert.True (view.CanFocus);
+        Assert.False (view.HasFocus);
+
+        view.SetFocus ();
+        Assert.True (view.HasFocus);
+    }
+
+    [Fact]
+    public void SetFocus_NoSubView_Focused_Is_Null ()
+    {
+        var view = new View ()
+        {
+            Id = "view",
+            CanFocus = true
+        };
+        Assert.True (view.CanFocus);
+        Assert.False (view.HasFocus);
+
+        view.SetFocus ();
+        Assert.True (view.HasFocus);
+        Assert.Null (view.GetFocused ());
+    }
+
+    [Fact]
+    public void SetFocus_SubView_Focused_Is_Set ()
+    {
+        var view = new View ()
+        {
+            Id = "view",
+            CanFocus = true
+        };
+
+        var subview = new View ()
+        {
+            Id = "subview",
+            CanFocus = true
+        };
+        view.Add (subview);
+        Assert.True (view.CanFocus);
+        Assert.False (view.HasFocus);
+
+        view.SetFocus ();
+        Assert.True (view.HasFocus);
+        Assert.Equal (subview, view.GetFocused ());
+    }
+
+    [Fact]
+    public void SetFocus_SetsFocus_DeepestSubView ()
+    {
+        var view = new View ()
+        {
+            Id = "view",
+            CanFocus = true
+        };
+
+        var subview = new View ()
+        {
+            Id = "subview",
+            CanFocus = true
+        };
+        view.Add (subview);
+
+        view.SetFocus ();
+        Assert.True (subview.HasFocus);
+        Assert.Equal (subview, view.GetFocused ());
+    }
+
+    [Fact]
+    public void SetFocus_SetsFocus_DeepestSubView_CompoundSubView ()
+    {
+        var view = new View ()
+        {
+            Id = "view",
+            CanFocus = true
+        };
+
+        var subView = new View ()
+        {
+            Id = "subView",
+            CanFocus = true
+        };
+
+        var subViewSubView1 = new View ()
+        {
+            Id = "subViewSubView1",
+            CanFocus = false
+        };
+
+        var subViewSubView2 = new View ()
+        {
+            Id = "subViewSubView2",
+            CanFocus = true
+        };
+        var subViewSubView3 = new View ()
+        {
+            Id = "subViewSubView3",
+            CanFocus = false
+        };
+        subView.Add (subViewSubView1, subViewSubView2, subViewSubView3);
+
+        view.Add (subView);
+
+        view.SetFocus ();
+        Assert.True (subView.HasFocus);
+        Assert.Equal (subView, view.GetFocused ());
+        Assert.Equal (subViewSubView2, subView.GetFocused ());
+    }
+
+    [Fact]
+    public void SetFocus_Peer_LeavesOther ()
+    {
+        var view = new View ()
+        {
+            Id = "view",
+            CanFocus = true
+        };
+
+        var subview1 = new View ()
+        {
+            Id = "subview1",
+            CanFocus = true
+        };
+
+        var subview2 = new View ()
+        {
+            Id = "subview2",
+            CanFocus = true
+        };
+        view.Add (subview1, subview2);
+
+        view.SetFocus ();
+        Assert.Equal (subview1, view.GetFocused ());
+        Assert.True (subview1.HasFocus);
+        Assert.False (subview2.HasFocus);
+
+        subview2.SetFocus ();
+        Assert.Equal (subview2, view.GetFocused ());
+        Assert.True (subview2.HasFocus);
+        Assert.False (subview1.HasFocus);
+    }
+
+    [Fact]
+    public void SetFocus_Peer_LeavesOthers_Subviews ()
+    {
+        var top = new View
+        {
+            Id = "top",
+            CanFocus = true
+        };
+        var view1 = new View
+        {
+            Id = "view1",
+            CanFocus = true
+        };
+
+        var subView1 = new View
+        {
+            Id = "subView1",
+            CanFocus = true
+        };
+
+        view1.Add (subView1);
+
+        var subView1SubView1 = new View
+        {
+            Id = "subView1subView1",
+            CanFocus = true
+        };
+
+        subView1.Add (subView1SubView1);
+
+        var view2 = new View
+        {
+            Id = "view2",
+            CanFocus = true
+        };
+
+        top.Add (view1, view2);
+        Assert.False (view1.HasFocus);
+        Assert.False (view2.HasFocus);
+
+        view1.SetFocus ();
+        Assert.True (view1.HasFocus);
+        Assert.True (subView1.HasFocus);
+        Assert.True (subView1SubView1.HasFocus);
+        Assert.Equal (subView1, view1.GetFocused ());
+        Assert.Equal (subView1SubView1, subView1.GetFocused ());
+
+        view2.SetFocus ();
+        Assert.False (view1.HasFocus);
+        Assert.True (view2.HasFocus);
+    }
+}

+ 8 - 8
UnitTests/View/ViewTests.cs

@@ -765,7 +765,7 @@ At 0,0
         Assert.False (r.HasFocus);
         Assert.Equal (new (0, 0, 0, 0), r.Viewport);
         Assert.Equal (new (0, 0, 0, 0), r.Frame);
-        Assert.Null (r.Focused);
+        Assert.Null (r.GetFocused ());
         Assert.Null (r.ColorScheme);
         Assert.Equal (0, r.Width);
         Assert.Equal (0, r.Height);
@@ -777,7 +777,7 @@ At 0,0
         Assert.False (r.WantContinuousButtonPressed);
         Assert.False (r.WantMousePositionReports);
         Assert.Null (r.SuperView);
-        Assert.Null (r.MostFocused);
+        Assert.Null (r.GetMostFocused ());
         Assert.Equal (TextDirection.LeftRight_TopBottom, r.TextDirection);
         r.Dispose ();
 
@@ -789,7 +789,7 @@ At 0,0
         Assert.False (r.HasFocus);
         Assert.Equal (new (0, 0, 0, 0), r.Viewport);
         Assert.Equal (new (0, 0, 0, 0), r.Frame);
-        Assert.Null (r.Focused);
+        Assert.Null (r.GetFocused ());
         Assert.Null (r.ColorScheme);
         Assert.Equal (0, r.Width);
         Assert.Equal (0, r.Height);
@@ -801,7 +801,7 @@ At 0,0
         Assert.False (r.WantContinuousButtonPressed);
         Assert.False (r.WantMousePositionReports);
         Assert.Null (r.SuperView);
-        Assert.Null (r.MostFocused);
+        Assert.Null (r.GetMostFocused ());
         Assert.Equal (TextDirection.LeftRight_TopBottom, r.TextDirection);
         r.Dispose ();
 
@@ -813,7 +813,7 @@ At 0,0
         Assert.False (r.HasFocus);
         Assert.Equal (new (0, 0, 3, 4), r.Viewport);
         Assert.Equal (new (1, 2, 3, 4), r.Frame);
-        Assert.Null (r.Focused);
+        Assert.Null (r.GetFocused ());
         Assert.Null (r.ColorScheme);
         Assert.Equal (3, r.Width);
         Assert.Equal (4, r.Height);
@@ -825,7 +825,7 @@ At 0,0
         Assert.False (r.WantContinuousButtonPressed);
         Assert.False (r.WantMousePositionReports);
         Assert.Null (r.SuperView);
-        Assert.Null (r.MostFocused);
+        Assert.Null (r.GetMostFocused ());
         Assert.Equal (TextDirection.LeftRight_TopBottom, r.TextDirection);
         r.Dispose ();
 
@@ -846,7 +846,7 @@ At 0,0
         Assert.False (r.HasFocus);
         Assert.Equal (new (0, 0, 1, 13), r.Viewport);
         Assert.Equal (new (0, 0, 1, 13), r.Frame);
-        Assert.Null (r.Focused);
+        Assert.Null (r.GetFocused ());
         Assert.Null (r.ColorScheme);
         Assert.False (r.IsCurrentTop);
 #if DEBUG
@@ -858,7 +858,7 @@ At 0,0
         Assert.False (r.WantContinuousButtonPressed);
         Assert.False (r.WantMousePositionReports);
         Assert.Null (r.SuperView);
-        Assert.Null (r.MostFocused);
+        Assert.Null (r.GetMostFocused ());
         Assert.Equal (TextDirection.TopBottom_LeftRight, r.TextDirection);
         r.Dispose ();
     }

+ 5 - 5
UnitTests/Views/AppendAutocompleteTests.cs

@@ -26,11 +26,11 @@ public class AppendAutocompleteTests (ITestOutputHelper output)
         Assert.Equal ("f", tf.Text);
 
         // Still has focus though
-        Assert.Same (tf, Application.Top.Focused);
+        Assert.Same (tf, Application.Top.GetFocused ());
 
         // But can tab away
         Application.Driver?.SendKeys ('\t', ConsoleKey.Tab, false, false, false);
-        Assert.NotSame (tf, Application.Top.Focused);
+        Assert.NotSame (tf, Application.Top.GetFocused ());
         Application.Top.Dispose ();
     }
 
@@ -201,11 +201,11 @@ public class AppendAutocompleteTests (ITestOutputHelper output)
         Assert.Equal ("fish", tf.Text);
 
         // Tab should autcomplete but not move focus
-        Assert.Same (tf, Application.Top.Focused);
+        Assert.Same (tf, Application.Top.GetFocused ());
 
         // Second tab should move focus (nothing to autocomplete)
         Application.Driver?.SendKeys ('\t', ConsoleKey.Tab, false, false, false);
-        Assert.NotSame (tf, Application.Top.Focused);
+        Assert.NotSame (tf, Application.Top.GetFocused ());
         Application.Top.Dispose ();
     }
 
@@ -238,7 +238,7 @@ public class AppendAutocompleteTests (ITestOutputHelper output)
 
         Application.Begin (top);
 
-        Assert.Same (tf, top.Focused);
+        Assert.Same (tf, top.GetFocused ());
 
         return tf;
     }

+ 28 - 28
UnitTests/Views/OverlappedTests.cs

@@ -1058,7 +1058,7 @@ public class OverlappedTests
         win2.Add (lblTf1W2, tf1W2, lblTvW2, tvW2, lblTf2W2, tf2W2);
 
         win1.Closing += (s, e) => isRunning = false;
-        Assert.Null (top.Focused);
+        Assert.Null (top.GetFocused ());
         Assert.Equal (top, Application.Current);
         Assert.True (top.IsCurrentTop);
         Assert.Equal (top, ApplicationOverlapped.OverlappedTop);
@@ -1071,9 +1071,9 @@ public class OverlappedTests
         Assert.Equal (win1, Application.Current);
         Assert.True (win1.IsCurrentTop);
         Assert.True (ApplicationOverlapped.IsOverlapped(win1));
-        Assert.Null (top.Focused);
-        Assert.Null (top.MostFocused);
-        Assert.Equal (tf1W1, win1.MostFocused);
+        Assert.Null (top.GetFocused ());
+        Assert.Null (top.GetMostFocused ());
+        Assert.Equal (tf1W1, win1.GetMostFocused ());
         Assert.True (ApplicationOverlapped.IsOverlapped(win1));
         Assert.Single (ApplicationOverlapped.OverlappedChildren!);
 
@@ -1085,9 +1085,9 @@ public class OverlappedTests
         Assert.Equal (win2, Application.Current);
         Assert.True (win2.IsCurrentTop);
         Assert.True (ApplicationOverlapped.IsOverlapped(win2));
-        Assert.Null (top.Focused);
-        Assert.Null (top.MostFocused);
-        Assert.Equal (tf1W2, win2.MostFocused);
+        Assert.Null (top.GetFocused ());
+        Assert.Null (top.GetMostFocused ());
+        Assert.Equal (tf1W2, win2.GetMostFocused ());
         Assert.Equal (2, ApplicationOverlapped.OverlappedChildren!.Count);
 
         ApplicationOverlapped.MoveToOverlappedChild (win1);
@@ -1109,7 +1109,7 @@ public class OverlappedTests
         Assert.True (Application.OnKeyDown (Key.F5)); // refresh
 
         Assert.True (win1.IsCurrentTop);
-        Assert.Equal (tvW1, win1.MostFocused);
+        Assert.Equal (tvW1, win1.GetMostFocused ());
         Assert.True (Application.OnKeyDown (Key.Tab));
         Assert.Equal ($"\tFirst line Win1{Environment.NewLine}Second line Win1", tvW1.Text);
 
@@ -1122,22 +1122,22 @@ public class OverlappedTests
         Assert.True (Application.OnKeyDown (Key.F6.WithShift));    // move back to win1
         Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
 
-        Assert.Equal (tvW1, win1.MostFocused);
+        Assert.Equal (tvW1, win1.GetMostFocused ());
         Assert.True (Application.OnKeyDown (Key.Tab));    // text view eats tab
         Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
-        Assert.Equal (tvW1, win1.MostFocused);
+        Assert.Equal (tvW1, win1.GetMostFocused ());
 
         tvW1.AllowsTab = false;
         Assert.True (Application.OnKeyDown (Key.Tab));    // text view eats tab
         Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
-        Assert.Equal (tf2W1, win1.MostFocused);
+        Assert.Equal (tf2W1, win1.GetMostFocused ());
 
         Assert.True (Application.OnKeyDown (Key.CursorRight));
         Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
-        Assert.Equal (tf2W1, win1.MostFocused);
+        Assert.Equal (tf2W1, win1.GetMostFocused ());
         Assert.True (Application.OnKeyDown (Key.CursorDown));
         Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
-        Assert.Equal (tf1W1, win1.MostFocused);
+        Assert.Equal (tf1W1, win1.GetMostFocused ());
 #if UNIX_KEY_BINDINGS
         Assert.True (ApplicationOverlapped.OverlappedChildren [0].ProcessKeyDown (new (Key.I.WithCtrl)));
         Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
@@ -1145,50 +1145,50 @@ public class OverlappedTests
 #endif
         Assert.True (Application.OnKeyDown (Key.Tab));
         Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
-        Assert.Equal (tvW1, win1.MostFocused);
+        Assert.Equal (tvW1, win1.GetMostFocused ());
         Assert.True (Application.OnKeyDown (Key.CursorLeft));  // The view to the left of tvW1 is tf2W1, but tvW1 is still focused and eats cursor keys
         Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
-        Assert.Equal (tvW1, win1.MostFocused);
+        Assert.Equal (tvW1, win1.GetMostFocused ());
         Assert.True (Application.OnKeyDown (Key.CursorUp));
         Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
-        Assert.Equal (tvW1, win1.MostFocused);
+        Assert.Equal (tvW1, win1.GetMostFocused ());
         Assert.True (Application.OnKeyDown (Key.Tab));
         Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
-        Assert.Equal (tf2W1, win1.MostFocused);
+        Assert.Equal (tf2W1, win1.GetMostFocused ());
 
         Assert.True (Application.OnKeyDown (Key.F6)); // Move to win2
         Assert.Equal (win2, ApplicationOverlapped.OverlappedChildren [0]);
-        Assert.Equal (tf1W2, win2.MostFocused);
+        Assert.Equal (tf1W2, win2.GetMostFocused ());
         tf2W2.SetFocus ();
         Assert.True (tf2W2.HasFocus);
 
         Assert.True (Application.OnKeyDown (Key.F6.WithShift));
         Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
-        Assert.Equal (tf2W1, win1.MostFocused);
+        Assert.Equal (tf2W1, win1.GetMostFocused ());
         Assert.True (Application.OnKeyDown (Application.NextTabGroupKey));
         Assert.Equal (win2, ApplicationOverlapped.OverlappedChildren [0]);
-        Assert.Equal (tf2W2, win2.MostFocused);
+        Assert.Equal (tf2W2, win2.GetMostFocused ());
         Assert.True (Application.OnKeyDown (Application.PrevTabGroupKey));
         Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
-        Assert.Equal (tf2W1, win1.MostFocused);
+        Assert.Equal (tf2W1, win1.GetMostFocused ());
         Assert.True (Application.OnKeyDown (Key.CursorDown));
         Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
-        Assert.Equal (tf1W1, win1.MostFocused);
+        Assert.Equal (tf1W1, win1.GetMostFocused ());
 #if UNIX_KEY_BINDINGS
         Assert.True (Application.OnKeyDown (new (Key.B.WithCtrl)));
 #else
         Assert.True (Application.OnKeyDown (Key.CursorLeft));
 #endif
         Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
-        Assert.Equal (tf1W1, win1.MostFocused);
+        Assert.Equal (tf1W1, win1.GetMostFocused ());
         Assert.True (Application.OnKeyDown (Key.CursorDown));
         Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
-        Assert.Equal (tvW1, win1.MostFocused);
+        Assert.Equal (tvW1, win1.GetMostFocused ());
         Assert.Equal (Point.Empty, tvW1.CursorPosition);
 
         Assert.True (Application.OnKeyDown (Key.End.WithCtrl));
         Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
-        Assert.Equal (tvW1, win1.MostFocused);
+        Assert.Equal (tvW1, win1.GetMostFocused ());
         Assert.Equal (new (16, 1), tvW1.CursorPosition); // Last position of the text
 #if UNIX_KEY_BINDINGS
         Assert.True (Application.OnKeyDown (new (Key.F.WithCtrl)));
@@ -1196,7 +1196,7 @@ public class OverlappedTests
         Assert.True (Application.OnKeyDown (Key.CursorRight)); // should move to next view w/ in Group (tf2W1)
 #endif
         Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
-        Assert.Equal (tf2W1, win1.MostFocused);
+        Assert.Equal (tf2W1, win1.GetMostFocused ());
 
 #if UNIX_KEY_BINDINGS
         Assert.True (ApplicationOverlapped.OverlappedChildren [0].ProcessKeyDown (new (Key.L.WithCtrl)));
@@ -1227,8 +1227,8 @@ public class OverlappedTests
 
         Application.Current = current;
         Assert.True (current.HasFocus);
-        Assert.Equal (superView.Focused, current);
-        Assert.Equal (superView.MostFocused, current);
+        Assert.Equal (superView.GetFocused (), current);
+        Assert.Equal (superView.GetMostFocused (), current);
 
         // Act
         ApplicationOverlapped.SetFocusToNextViewWithWrap (Application.Current.SuperView.TabIndexes, NavigationDirection.Forward);

+ 26 - 26
UnitTests/Views/TabViewTests.cs

@@ -393,9 +393,9 @@ public class TabViewTests (ITestOutputHelper output)
 
         // Is the selected tab view hosting focused
         Assert.Equal (tab1, tv.SelectedTab);
-        Assert.Equal (tv, top.Focused);
-        Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
-        Assert.Equal (tv.SelectedTab.View, top.Focused.MostFocused);
+        Assert.Equal (tv, top.GetFocused ());
+        Assert.Equal (tv.GetMostFocused (), top.GetFocused ().GetMostFocused ());
+        Assert.Equal (tv.SelectedTab.View, top.GetFocused ().GetMostFocused ());
 
         // Press the cursor up key to focus the selected tab
         Application.OnKeyDown (Key.CursorUp);
@@ -403,8 +403,8 @@ public class TabViewTests (ITestOutputHelper output)
 
         // Is the selected tab focused
         Assert.Equal (tab1, tv.SelectedTab);
-        Assert.Equal (tv, top.Focused);
-        Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
+        Assert.Equal (tv, top.GetFocused ());
+        Assert.Equal (tv.GetMostFocused (), top.GetFocused ().GetMostFocused ());
 
         Tab oldChanged = null;
         Tab newChanged = null;
@@ -421,13 +421,13 @@ public class TabViewTests (ITestOutputHelper output)
         Assert.Equal (tab1, oldChanged);
         Assert.Equal (tab2, newChanged);
         Assert.Equal (tab2, tv.SelectedTab);
-        Assert.Equal (tv, top.Focused);
-        Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
+        Assert.Equal (tv, top.GetFocused ());
+        Assert.Equal (tv.GetMostFocused (), top.GetFocused ().GetMostFocused ());
 
         // Press the cursor down key. Since the selected tab has no focusable views, the focus should move to the next view in the toplevel
         Application.OnKeyDown (Key.CursorDown);
         Assert.Equal (tab2, tv.SelectedTab);
-        Assert.Equal (btn, top.MostFocused);
+        Assert.Equal (btn, top.GetMostFocused ());
 
         // Add a focusable subview to Selected Tab
         var btnSubView = new View ()
@@ -441,26 +441,26 @@ public class TabViewTests (ITestOutputHelper output)
         // Press cursor up. Should focus the subview in the selected tab.
         Application.OnKeyDown (Key.CursorUp);
         Assert.Equal (tab2, tv.SelectedTab);
-        Assert.Equal (btnSubView, top.MostFocused);
+        Assert.Equal (btnSubView, top.GetMostFocused ());
 
         Application.OnKeyDown (Key.CursorUp);
-        Assert.Equal (tab2, top.MostFocused);
+        Assert.Equal (tab2, top.GetMostFocused ());
 
         // Press the cursor down key twice.
         Application.OnKeyDown (Key.CursorDown);
         Application.OnKeyDown (Key.CursorDown);
-        Assert.Equal (btn, top.MostFocused);
+        Assert.Equal (btn, top.GetMostFocused ());
 
         // Press the cursor down key again will focus next view in the toplevel, whic is the TabView
         Application.OnKeyDown (Key.CursorDown);
         Assert.Equal (tab2, tv.SelectedTab);
-        Assert.Equal (tv, top.Focused);
-        Assert.Equal (tab1, tv.MostFocused);
+        Assert.Equal (tv, top.GetFocused ());
+        Assert.Equal (tab1, tv.GetMostFocused ());
 
         // Press the cursor down key to focus the selected tab view hosting again
         Application.OnKeyDown (Key.CursorDown);
         Assert.Equal (tab2, tv.SelectedTab);
-        Assert.Equal (btnSubView, top.MostFocused);
+        Assert.Equal (btnSubView, top.GetMostFocused ());
 
         // Press the cursor up key to focus the selected tab
         Application.OnKeyDown (Key.CursorUp);
@@ -468,8 +468,8 @@ public class TabViewTests (ITestOutputHelper output)
 
         // Is the selected tab focused
         Assert.Equal (tab2, tv.SelectedTab);
-        Assert.Equal (tv, top.Focused);
-        Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
+        Assert.Equal (tv, top.GetFocused ());
+        Assert.Equal (tv.GetMostFocused (), top.GetFocused ().GetMostFocused ());
 
         // Press the cursor left key to select the previous tab
         Application.OnKeyDown (Key.CursorLeft);
@@ -477,8 +477,8 @@ public class TabViewTests (ITestOutputHelper output)
         Assert.Equal (tab2, oldChanged);
         Assert.Equal (tab1, newChanged);
         Assert.Equal (tab1, tv.SelectedTab);
-        Assert.Equal (tv, top.Focused);
-        Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
+        Assert.Equal (tv, top.GetFocused ());
+        Assert.Equal (tv.GetMostFocused (), top.GetFocused ().GetMostFocused ());
 
         // Press the end key to select the last tab
         Application.OnKeyDown (Key.End);
@@ -486,8 +486,8 @@ public class TabViewTests (ITestOutputHelper output)
         Assert.Equal (tab1, oldChanged);
         Assert.Equal (tab2, newChanged);
         Assert.Equal (tab2, tv.SelectedTab);
-        Assert.Equal (tv, top.Focused);
-        Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
+        Assert.Equal (tv, top.GetFocused ());
+        Assert.Equal (tv.GetMostFocused (), top.GetFocused ().GetMostFocused ());
 
         // Press the home key to select the first tab
         Application.OnKeyDown (Key.Home);
@@ -495,8 +495,8 @@ public class TabViewTests (ITestOutputHelper output)
         Assert.Equal (tab2, oldChanged);
         Assert.Equal (tab1, newChanged);
         Assert.Equal (tab1, tv.SelectedTab);
-        Assert.Equal (tv, top.Focused);
-        Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
+        Assert.Equal (tv, top.GetFocused ());
+        Assert.Equal (tv.GetMostFocused (), top.GetFocused ().GetMostFocused ());
 
         // Press the page down key to select the next set of tabs
         Application.OnKeyDown (Key.PageDown);
@@ -504,8 +504,8 @@ public class TabViewTests (ITestOutputHelper output)
         Assert.Equal (tab1, oldChanged);
         Assert.Equal (tab2, newChanged);
         Assert.Equal (tab2, tv.SelectedTab);
-        Assert.Equal (tv, top.Focused);
-        Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
+        Assert.Equal (tv, top.GetFocused ());
+        Assert.Equal (tv.GetMostFocused (), top.GetFocused ().GetMostFocused ());
 
         // Press the page up key to select the previous set of tabs
         Application.OnKeyDown (Key.PageUp);
@@ -513,8 +513,8 @@ public class TabViewTests (ITestOutputHelper output)
         Assert.Equal (tab2, oldChanged);
         Assert.Equal (tab1, newChanged);
         Assert.Equal (tab1, tv.SelectedTab);
-        Assert.Equal (tv, top.Focused);
-        Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
+        Assert.Equal (tv, top.GetFocused ());
+        Assert.Equal (tv.GetMostFocused (), top.GetFocused ().GetMostFocused ());
         top.Dispose ();
     }
 

+ 1 - 1
UnitTests/Views/TextFieldTests.cs

@@ -1948,7 +1948,7 @@ Les Miśerables",
 
         Application.Begin (top);
 
-        Assert.Same (tf, top.Focused);
+        Assert.Same (tf, top.GetFocused ());
 
         return tf;
     }

+ 34 - 34
UnitTests/Views/ToplevelTests.cs

@@ -466,8 +466,8 @@ public partial class ToplevelTests (ITestOutputHelper output)
 
         Assert.Equal (new (0, 0, 40, 25), win1.Frame);
         Assert.Equal (new (41, 0, 40, 25), win2.Frame);
-        Assert.Equal (win1, top.Focused);
-        Assert.Equal (tf1W1, top.MostFocused);
+        Assert.Equal (win1, top.GetFocused ());
+        Assert.Equal (tf1W1, top.GetMostFocused ());
 
         Assert.True (isRunning);
         Assert.True (Application.OnKeyDown (Application.QuitKey));
@@ -477,71 +477,71 @@ public partial class ToplevelTests (ITestOutputHelper output)
         Assert.True (Application.OnKeyDown (Key.F5)); // refresh
 
         Assert.True (Application.OnKeyDown (Key.Tab));
-        Assert.Equal (win1, top.Focused);
-        Assert.Equal (tvW1, top.MostFocused);
+        Assert.Equal (win1, top.GetFocused ());
+        Assert.Equal (tvW1, top.GetMostFocused ());
         Assert.True (Application.OnKeyDown (Key.Tab));
         Assert.Equal ($"\tFirst line Win1{Environment.NewLine}Second line Win1", tvW1.Text);
         Assert.True (Application.OnKeyDown (Key.Tab.WithShift));
         Assert.Equal ($"First line Win1{Environment.NewLine}Second line Win1", tvW1.Text);
 
-        var prevMostFocusedSubview = top.MostFocused;
+        var prevMostFocusedSubview = top.GetMostFocused ();
 
         Assert.True (Application.OnKeyDown (Key.F6)); // move to next TabGroup (win2)
-        Assert.Equal (win2, top.Focused);
+        Assert.Equal (win2, top.GetFocused ());
 
         Assert.True (Application.OnKeyDown (Key.F6.WithShift)); // move to prev TabGroup (win1)
-        Assert.Equal (win1, top.Focused);
-        Assert.Equal (tf2W1, top.MostFocused);  // BUGBUG: Should be prevMostFocusedSubview - We need to cache the last focused view in the TabGroup somehow
+        Assert.Equal (win1, top.GetFocused ());
+        Assert.Equal (tf2W1, top.GetMostFocused ());  // BUGBUG: Should be prevMostFocusedSubview - We need to cache the last focused view in the TabGroup somehow
 
         prevMostFocusedSubview.SetFocus ();
 
-        Assert.Equal (tvW1, top.MostFocused);
+        Assert.Equal (tvW1, top.GetMostFocused ());
 
         tf2W1.SetFocus ();
         Assert.True (Application.OnKeyDown (Key.Tab)); // tf2W1 is last subview in win1 - tabbing should take us to first subview of win1
-        Assert.Equal (win1, top.Focused);
-        Assert.Equal (tf1W1, top.MostFocused);
+        Assert.Equal (win1, top.GetFocused ());
+        Assert.Equal (tf1W1, top.GetMostFocused ());
         Assert.True (Application.OnKeyDown (Key.CursorRight)); // move char to right in tf1W1. We're at last char so nav to next view
-        Assert.Equal (win1, top.Focused);
-        Assert.Equal (tvW1, top.MostFocused);
+        Assert.Equal (win1, top.GetFocused ());
+        Assert.Equal (tvW1, top.GetMostFocused ());
         Assert.True (Application.OnKeyDown (Key.CursorDown)); // move down to next view (tvW1)
-        Assert.Equal (win1, top.Focused);
-        Assert.Equal (tvW1, top.MostFocused);
+        Assert.Equal (win1, top.GetFocused ());
+        Assert.Equal (tvW1, top.GetMostFocused ());
 #if UNIX_KEY_BINDINGS
         Assert.True (Application.OnKeyDown (new (Key.I.WithCtrl)));
-        Assert.Equal (win1, top.Focused);
+        Assert.Equal (win1, top.GetFocused ());
         Assert.Equal (tf2W1, top.MostFocused);
 #endif
         Assert.True (Application.OnKeyDown (Key.Tab.WithShift)); // Ignored. TextView eats shift-tab by default
-        Assert.Equal (win1, top.Focused);
-        Assert.Equal (tvW1, top.MostFocused);
+        Assert.Equal (win1, top.GetFocused ());
+        Assert.Equal (tvW1, top.GetMostFocused ());
         tvW1.AllowsTab = false;
         Assert.True (Application.OnKeyDown (Key.Tab.WithShift));
-        Assert.Equal (win1, top.Focused);
-        Assert.Equal (tf1W1, top.MostFocused);
+        Assert.Equal (win1, top.GetFocused ());
+        Assert.Equal (tf1W1, top.GetMostFocused ());
         Assert.True (Application.OnKeyDown (Key.CursorLeft));
-        Assert.Equal (win1, top.Focused);
-        Assert.Equal (tf2W1, top.MostFocused);
+        Assert.Equal (win1, top.GetFocused ());
+        Assert.Equal (tf2W1, top.GetMostFocused ());
         Assert.True (Application.OnKeyDown (Key.CursorUp));
-        Assert.Equal (win1, top.Focused);
-        Assert.Equal (tvW1, top.MostFocused);
+        Assert.Equal (win1, top.GetFocused ());
+        Assert.Equal (tvW1, top.GetMostFocused ());
 
         // nav to win2
         Assert.True (Application.OnKeyDown (Key.F6));
-        Assert.Equal (win2, top.Focused);
-        Assert.Equal (tf1W2, top.MostFocused);
+        Assert.Equal (win2, top.GetFocused ());
+        Assert.Equal (tf1W2, top.GetMostFocused ());
         Assert.True (Application.OnKeyDown (Key.F6.WithShift));
-        Assert.Equal (win1, top.Focused);
-        Assert.Equal (tf2W1, top.MostFocused);
+        Assert.Equal (win1, top.GetFocused ());
+        Assert.Equal (tf2W1, top.GetMostFocused ());
         Assert.True (Application.OnKeyDown (Application.NextTabGroupKey));
-        Assert.Equal (win2, top.Focused);
-        Assert.Equal (tf1W2, top.MostFocused);
+        Assert.Equal (win2, top.GetFocused ());
+        Assert.Equal (tf1W2, top.GetMostFocused ());
         Assert.True (Application.OnKeyDown (Application.PrevTabGroupKey));
-        Assert.Equal (win1, top.Focused);
-        Assert.Equal (tf2W1, top.MostFocused);
+        Assert.Equal (win1, top.GetFocused ());
+        Assert.Equal (tf2W1, top.GetMostFocused ());
         Assert.True (Application.OnKeyDown (Key.CursorUp));
-        Assert.Equal (win1, top.Focused);
-        Assert.Equal (tvW1, top.MostFocused);
+        Assert.Equal (win1, top.GetFocused ());
+        Assert.Equal (tvW1, top.GetMostFocused ());
 
         top.Dispose ();
     }

+ 1 - 1
UnitTests/Views/TreeTableSourceTests.cs

@@ -290,7 +290,7 @@ public class TreeTableSourceTests : IDisposable
         var top = new Toplevel ();
         top.Add (tableView);
         top.RestoreFocus (null);
-        Assert.Equal (tableView, top.MostFocused);
+        Assert.Equal (tableView, top.GetMostFocused ());
 
         return tableView;
     }

+ 6 - 6
UnitTests/Views/WindowTests.cs

@@ -132,7 +132,7 @@ public class WindowTests
         Assert.False (defaultWindow.HasFocus);
         Assert.Equal (new Rectangle (0, 0, Application.Screen.Width - 2, Application.Screen.Height - 2), defaultWindow.Viewport);
         Assert.Equal (new Rectangle (0, 0, Application.Screen.Width, Application.Screen.Height), defaultWindow.Frame);
-        Assert.Null (defaultWindow.Focused);
+        Assert.Null (defaultWindow.GetFocused ());
         Assert.NotNull (defaultWindow.ColorScheme);
         Assert.Equal (0, defaultWindow.X);
         Assert.Equal (0, defaultWindow.Y);
@@ -143,7 +143,7 @@ public class WindowTests
         Assert.False (defaultWindow.WantContinuousButtonPressed);
         Assert.False (defaultWindow.WantMousePositionReports);
         Assert.Null (defaultWindow.SuperView);
-        Assert.Null (defaultWindow.MostFocused);
+        Assert.Null (defaultWindow.GetMostFocused ());
         Assert.Equal (TextDirection.LeftRight_TopBottom, defaultWindow.TextDirection);
 
         // Empty Rect
@@ -154,7 +154,7 @@ public class WindowTests
         Assert.False (windowWithFrameRectEmpty.HasFocus);
         Assert.Equal (Rectangle.Empty, windowWithFrameRectEmpty.Viewport);
         Assert.Equal (Rectangle.Empty, windowWithFrameRectEmpty.Frame);
-        Assert.Null (windowWithFrameRectEmpty.Focused);
+        Assert.Null (windowWithFrameRectEmpty.GetFocused ());
         Assert.NotNull (windowWithFrameRectEmpty.ColorScheme);
         Assert.Equal (0, windowWithFrameRectEmpty.X);
         Assert.Equal (0, windowWithFrameRectEmpty.Y);
@@ -167,7 +167,7 @@ public class WindowTests
         Assert.False (windowWithFrameRectEmpty.WantContinuousButtonPressed);
         Assert.False (windowWithFrameRectEmpty.WantMousePositionReports);
         Assert.Null (windowWithFrameRectEmpty.SuperView);
-        Assert.Null (windowWithFrameRectEmpty.MostFocused);
+        Assert.Null (windowWithFrameRectEmpty.GetMostFocused ());
         Assert.Equal (TextDirection.LeftRight_TopBottom, windowWithFrameRectEmpty.TextDirection);
 
         // Rect with values
@@ -185,7 +185,7 @@ public class WindowTests
         Assert.False (windowWithFrame1234.HasFocus);
         Assert.Equal (new (0, 0, 1, 2), windowWithFrame1234.Viewport);
         Assert.Equal (new (1, 2, 3, 4), windowWithFrame1234.Frame);
-        Assert.Null (windowWithFrame1234.Focused);
+        Assert.Null (windowWithFrame1234.GetFocused ());
         Assert.NotNull (windowWithFrame1234.ColorScheme);
         Assert.Equal (1, windowWithFrame1234.X);
         Assert.Equal (2, windowWithFrame1234.Y);
@@ -198,7 +198,7 @@ public class WindowTests
         Assert.False (windowWithFrame1234.WantContinuousButtonPressed);
         Assert.False (windowWithFrame1234.WantMousePositionReports);
         Assert.Null (windowWithFrame1234.SuperView);
-        Assert.Null (windowWithFrame1234.MostFocused);
+        Assert.Null (windowWithFrame1234.GetMostFocused ());
         Assert.Equal (TextDirection.LeftRight_TopBottom, windowWithFrame1234.TextDirection);
     }