diff --git a/Terminal.Gui/Application/Application.Run.cs b/Terminal.Gui/Application/Application.Run.cs
index 296021133..9ebe0c3b8 100644
--- a/Terminal.Gui/Application/Application.Run.cs
+++ b/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);
}
}
diff --git a/Terminal.Gui/Application/ApplicationNavigation.cs b/Terminal.Gui/Application/ApplicationNavigation.cs
index 8e4e5ed94..e83526b73 100644
--- a/Terminal.Gui/Application/ApplicationNavigation.cs
+++ b/Terminal.Gui/Application/ApplicationNavigation.cs
@@ -115,17 +115,17 @@ public class ApplicationNavigation
///
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
///
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);
}
diff --git a/Terminal.Gui/Application/ApplicationOverlapped.cs b/Terminal.Gui/Application/ApplicationOverlapped.cs
index 14a4163ea..cdbdbe22c 100644
--- a/Terminal.Gui/Application/ApplicationOverlapped.cs
+++ b/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;
}
diff --git a/Terminal.Gui/View/View.Hierarchy.cs b/Terminal.Gui/View/View.Hierarchy.cs
index 92baa9c6b..21a84d345 100644
--- a/Terminal.Gui/View/View.Hierarchy.cs
+++ b/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;
}
diff --git a/Terminal.Gui/View/View.Keyboard.cs b/Terminal.Gui/View/View.Keyboard.cs
index 73625417a..517e4d12b 100644
--- a/Terminal.Gui/View/View.Keyboard.cs
+++ b/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;
}
diff --git a/Terminal.Gui/View/View.Navigation.cs b/Terminal.Gui/View/View.Navigation.cs
index 42688e810..b21d9ca6d 100644
--- a/Terminal.Gui/View/View.Navigation.cs
+++ b/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))
+ if (CancelEnterFocus (leavingView))
{
- // The event was cancelled
- return false;
- }
-
- var args = new FocusEventArgs (leavingView, this);
- Enter?.Invoke (this, args);
-
- if (args.Cancel)
- {
- // 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;
+ }
+
/// Virtual method invoked when this view is gaining focus (entering).
/// The view that is leaving focus.
/// , if the event is to be cancelled, otherwise.
@@ -198,25 +217,26 @@ public partial class View // Focus and cross-view navigation management (TabStop
/// The previously focused view. If there is no previously focused view.
/// if was changed.
///
- 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 { };
- }
-
- if (Focused is { })
- {
- if (Focused.AdvanceFocus (direction, behavior))
+ View deepest = FindDeepestFocusableView (behavior, direction);
+ if (deepest is { })
{
- // TODO: Temporary hack to make Application.Navigation.FocusChanged work
- if (Focused.Focused is null)
- {
- Application.Navigation?.SetFocused (Focused);
- }
- return true;
+ return deepest.SetFocus ();
}
}
- var index = GetScopedTabIndexes (behavior, direction);
+ if (focused!.AdvanceFocus (direction, behavior))
+ {
+ return true;
+ }
+
+ 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
///
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;
}
+ ///
+ /// Returns the most focused Subview down the subview-hierarchy.
+ ///
+ /// The most focused Subview, or if no Subview is focused.
+ public View GetMostFocused ()
+ {
+ if (GetFocused () is null)
+ {
+ return null;
+ }
+
+ View most = GetFocused ()!.GetMostFocused ();
+
+ if (most is { })
+ {
+ return most;
+ }
+
+ return GetFocused ();
+ }
+
/////
///// Internal API that causes to enter focus.
///// 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
///
public event EventHandler CanFocusChanged;
- /// Returns the currently focused Subview inside this view, or if nothing is focused.
+ /// Returns the currently focused Subview of this view, or if nothing is focused.
/// The currently focused Subview.
[CanBeNull]
- public View Focused { get; private set; }
+ public View GetFocused ()
+ {
+ return Subviews.FirstOrDefault (v => v.HasFocus);
+ }
///
/// Focuses the deepest focusable view in if one exists. If there are no views in
@@ -691,19 +628,17 @@ public partial class View // Focus and cross-view navigation management (TabStop
///
///
///
- public void FocusDeepest (TabBehavior? behavior, NavigationDirection direction)
+ /// if a subview other than this was focused.
+ 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
/// Returns a value indicating if this View is currently on Top (Active)
public bool IsCurrentTop => Application.Current == this;
- ///
- /// Returns the most focused Subview in the chain of subviews (the leaf view that has the focus), or
- /// if nothing is focused.
- ///
- /// The most focused Subview.
- public View MostFocused
- {
- get
- {
- if (Focused is null)
- {
- return null;
- }
-
- View most = Focused.MostFocused;
-
- if (most is { })
- {
- return most;
- }
-
- return Focused;
- }
- }
/// Invoked when the property from a view is changed.
///
diff --git a/Terminal.Gui/Views/Menu/MenuBar.cs b/Terminal.Gui/Views/Menu/MenuBar.cs
index a900d060e..35f01bdc7 100644
--- a/Terminal.Gui/Views/Menu/MenuBar.cs
+++ b/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))
{
diff --git a/Terminal.Gui/Views/NumericUpDown.cs b/Terminal.Gui/Views/NumericUpDown.cs
index 279cfd6cf..df57bd6b0 100644
--- a/Terminal.Gui/Views/NumericUpDown.cs
+++ b/Terminal.Gui/Views/NumericUpDown.cs
@@ -67,7 +67,7 @@ public class NumericUpDown : 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 ()
diff --git a/Terminal.Gui/Views/TabView.cs b/Terminal.Gui/Views/TabView.cs
index e6959a491..2835820f6 100644
--- a/Terminal.Gui/Views/TabView.cs
+++ b/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;
diff --git a/Terminal.Gui/Views/Toplevel.cs b/Terminal.Gui/Views/Toplevel.cs
index 5afbcb22a..b74cf8ced 100644
--- a/Terminal.Gui/Views/Toplevel.cs
+++ b/Terminal.Gui/Views/Toplevel.cs
@@ -79,7 +79,6 @@ public partial class Toplevel : View
///
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!)
diff --git a/UICatalog/Scenarios/ConfigurationEditor.cs b/UICatalog/Scenarios/ConfigurationEditor.cs
index 1e095a527..d2d80b859 100644
--- a/UICatalog/Scenarios/ConfigurationEditor.cs
+++ b/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 ();
}
diff --git a/UICatalog/Scenarios/KeyBindings.cs b/UICatalog/Scenarios/KeyBindings.cs
index d62444543..1854da2eb 100644
--- a/UICatalog/Scenarios/KeyBindings.cs
+++ b/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]}");
}
diff --git a/UICatalog/Scenarios/MenuBarScenario.cs b/UICatalog/Scenarios/MenuBarScenario.cs
index b9c6bee67..edac4a054 100644
--- a/UICatalog/Scenarios/MenuBarScenario.cs
+++ b/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 (); };
diff --git a/UnitTests/FileServices/FileDialogTests.cs b/UnitTests/FileServices/FileDialogTests.cs
index 1c0954168..873819f7c 100644
--- a/UnitTests/FileServices/FileDialogTests.cs
+++ b/UnitTests/FileServices/FileDialogTests.cs
@@ -107,8 +107,8 @@ public class FileDialogTests (ITestOutputHelper output)
Application.OnKeyDown (Key.Tab);
#endif
- Assert.IsType (dlg.MostFocused);
- var tf = (TextField)dlg.MostFocused;
+ Assert.IsType (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 (dlg.MostFocused);
+ Assert.IsType (dlg.GetMostFocused ());
Send ('v', ConsoleKey.DownArrow);
- Assert.IsType (dlg.MostFocused);
+ Assert.IsType (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 eventMultiSelected = null;
dlg.FilesSelected += (s, e) => { eventMultiSelected = e.Dialog.MultiSelected; };
- Assert.IsType (dlg.MostFocused);
+ Assert.IsType (dlg.GetMostFocused ());
Send ('v', ConsoleKey.DownArrow);
- Assert.IsType (dlg.MostFocused);
+ Assert.IsType (dlg.GetMostFocused ());
// Try to toggle '..'
Send (' ', ConsoleKey.Spacebar);
@@ -236,9 +236,9 @@ public class FileDialogTests (ITestOutputHelper output)
IReadOnlyCollection eventMultiSelected = null;
dlg.FilesSelected += (s, e) => { eventMultiSelected = e.Dialog.MultiSelected; };
- Assert.IsType (dlg.MostFocused);
+ Assert.IsType (dlg.GetMostFocused ());
Send ('v', ConsoleKey.DownArrow);
- Assert.IsType (dlg.MostFocused);
+ Assert.IsType (dlg.GetMostFocused ());
// Move selection to subfolder
Send ('v', ConsoleKey.DownArrow);
@@ -288,9 +288,9 @@ public class FileDialogTests (ITestOutputHelper output)
IReadOnlyCollection eventMultiSelected = null;
dlg.FilesSelected += (s, e) => { eventMultiSelected = e.Dialog.MultiSelected; };
- Assert.IsType (dlg.MostFocused);
+ Assert.IsType (dlg.GetMostFocused ());
Send ('v', ConsoleKey.DownArrow);
- Assert.IsType (dlg.MostFocused);
+ Assert.IsType (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 (dlg.MostFocused);
+ Assert.IsType (dlg.GetMostFocused ());
Send ('v', ConsoleKey.DownArrow);
- Assert.IsType (dlg.MostFocused);
+ Assert.IsType (dlg.GetMostFocused ());
// Should be selecting ..
Send ('v', ConsoleKey.DownArrow);
diff --git a/UnitTests/View/Navigation/AddRemoveTests.cs b/UnitTests/View/Navigation/AddRemoveTests.cs
new file mode 100644
index 000000000..873f38e21
--- /dev/null
+++ b/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);
+ }
+
+}
diff --git a/UnitTests/View/Navigation/AdvanceFocusTests.cs b/UnitTests/View/Navigation/AdvanceFocusTests.cs
new file mode 100644
index 000000000..1910daad0
--- /dev/null
+++ b/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 ();
+ }
+}
diff --git a/UnitTests/View/Navigation/CanFocusTests.cs b/UnitTests/View/Navigation/CanFocusTests.cs
new file mode 100644
index 000000000..04a8e5ca6
--- /dev/null
+++ b/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 (() => 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 ();
+ }
+}
diff --git a/UnitTests/View/Navigation/HasFocusTests.cs b/UnitTests/View/Navigation/HasFocusTests.cs
new file mode 100644
index 000000000..fbfe0c3f7
--- /dev/null
+++ b/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);
+ }
+
+}
diff --git a/UnitTests/View/NavigationTests.cs b/UnitTests/View/Navigation/NavigationTests.cs
similarity index 51%
rename from UnitTests/View/NavigationTests.cs
rename to UnitTests/View/Navigation/NavigationTests.cs
index df4d393ed..22d238429 100644
--- a/UnitTests/View/NavigationTests.cs
+++ b/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 (() => 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.MostFocused); // BUGBUG: Should be view
+ 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.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 ();
- }
}
diff --git a/UnitTests/View/Navigation/SetFocusTests.cs b/UnitTests/View/Navigation/SetFocusTests.cs
new file mode 100644
index 000000000..d02c2b243
--- /dev/null
+++ b/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);
+ }
+}
diff --git a/UnitTests/View/ViewTests.cs b/UnitTests/View/ViewTests.cs
index 9aed13c82..29bf48967 100644
--- a/UnitTests/View/ViewTests.cs
+++ b/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 ();
}
diff --git a/UnitTests/Views/AppendAutocompleteTests.cs b/UnitTests/Views/AppendAutocompleteTests.cs
index eaabc43a6..daed47adb 100644
--- a/UnitTests/Views/AppendAutocompleteTests.cs
+++ b/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;
}
diff --git a/UnitTests/Views/OverlappedTests.cs b/UnitTests/Views/OverlappedTests.cs
index ad747afa4..5c82ca100 100644
--- a/UnitTests/Views/OverlappedTests.cs
+++ b/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);
diff --git a/UnitTests/Views/TabViewTests.cs b/UnitTests/Views/TabViewTests.cs
index f8f255434..630d7ae5c 100644
--- a/UnitTests/Views/TabViewTests.cs
+++ b/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 ();
}
diff --git a/UnitTests/Views/TextFieldTests.cs b/UnitTests/Views/TextFieldTests.cs
index 59c9cdd20..168a46b21 100644
--- a/UnitTests/Views/TextFieldTests.cs
+++ b/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;
}
diff --git a/UnitTests/Views/ToplevelTests.cs b/UnitTests/Views/ToplevelTests.cs
index 4e3f11101..9c630cf19 100644
--- a/UnitTests/Views/ToplevelTests.cs
+++ b/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 ();
}
diff --git a/UnitTests/Views/TreeTableSourceTests.cs b/UnitTests/Views/TreeTableSourceTests.cs
index 4e4ba260e..516187206 100644
--- a/UnitTests/Views/TreeTableSourceTests.cs
+++ b/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;
}
diff --git a/UnitTests/Views/WindowTests.cs b/UnitTests/Views/WindowTests.cs
index a010227f7..8fcfc7dde 100644
--- a/UnitTests/Views/WindowTests.cs
+++ b/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);
}