mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-29 17:28:01 +01:00
Moved view navigation out of Toplevel and into Application (via ViewNavigation static class).
This commit is contained in:
@@ -330,7 +330,7 @@ public static partial class Application // Keyboard handling
|
||||
() =>
|
||||
{
|
||||
// TODO: Move this method to Application.Navigation.cs
|
||||
Current.MoveNextView ();
|
||||
ViewNavigation.MoveNextView ();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -341,7 +341,7 @@ public static partial class Application // Keyboard handling
|
||||
() =>
|
||||
{
|
||||
// TODO: Move this method to Application.Navigation.cs
|
||||
Current.MovePreviousView ();
|
||||
ViewNavigation.MovePreviousView ();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -352,7 +352,7 @@ public static partial class Application // Keyboard handling
|
||||
() =>
|
||||
{
|
||||
// TODO: Move this method to Application.Navigation.cs
|
||||
Current.MoveNextViewOrTop ();
|
||||
ViewNavigation.MoveNextViewOrTop ();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -363,7 +363,7 @@ public static partial class Application // Keyboard handling
|
||||
() =>
|
||||
{
|
||||
// TODO: Move this method to Application.Navigation.cs
|
||||
Current.MovePreviousViewOrTop ();
|
||||
ViewNavigation.MovePreviousViewOrTop ();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,169 @@
|
||||
#nullable enable
|
||||
using static Terminal.Gui.View;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Terminal.Gui;
|
||||
|
||||
internal static class ViewNavigation
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the deepest focused subview of the specified <paramref name="view"/>.
|
||||
/// </summary>
|
||||
/// <param name="view"></param>
|
||||
/// <returns></returns>
|
||||
internal static View GetDeepestFocusedSubview (View view)
|
||||
{
|
||||
if (view is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach (View v in view.Subviews)
|
||||
{
|
||||
if (v.HasFocus)
|
||||
{
|
||||
return GetDeepestFocusedSubview (v);
|
||||
}
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the focus to the next view in the <see cref="TabIndexes"/> list. If the last view is focused, the first view is focused.
|
||||
/// </summary>
|
||||
/// <param name="viewsInTabIndexes"></param>
|
||||
/// <param name="direction"></param>
|
||||
internal static void FocusNearestView (IEnumerable<View>? viewsInTabIndexes, NavigationDirection direction)
|
||||
{
|
||||
if (viewsInTabIndexes is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var found = false;
|
||||
var focusProcessed = false;
|
||||
var idx = 0;
|
||||
|
||||
foreach (View v in viewsInTabIndexes)
|
||||
{
|
||||
if (v == Application.Current)
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (found && v != Application.Current)
|
||||
{
|
||||
if (direction == NavigationDirection.Forward)
|
||||
{
|
||||
Application.Current.SuperView?.FocusNext ();
|
||||
}
|
||||
else
|
||||
{
|
||||
Application.Current.SuperView?.FocusPrev ();
|
||||
}
|
||||
|
||||
focusProcessed = true;
|
||||
|
||||
if (Application.Current.SuperView?.Focused is { } && Application.Current.SuperView.Focused != Application.Current)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (found && !focusProcessed && idx == viewsInTabIndexes.Count () - 1)
|
||||
{
|
||||
viewsInTabIndexes.ToList () [0].SetFocus ();
|
||||
}
|
||||
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Moves the focus to
|
||||
/// </summary>
|
||||
internal static void MoveNextView ()
|
||||
{
|
||||
View old = GetDeepestFocusedSubview (Application.Current.Focused);
|
||||
|
||||
if (!Application.Current.FocusNext ())
|
||||
{
|
||||
Application.Current.FocusNext ();
|
||||
}
|
||||
|
||||
if (old != Application.Current.Focused && old != Application.Current.Focused?.Focused)
|
||||
{
|
||||
old?.SetNeedsDisplay ();
|
||||
Application.Current.Focused?.SetNeedsDisplay ();
|
||||
}
|
||||
else
|
||||
{
|
||||
FocusNearestView (Application.Current.SuperView?.TabIndexes, NavigationDirection.Forward);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void MoveNextViewOrTop ()
|
||||
{
|
||||
if (Application.OverlappedTop is null)
|
||||
{
|
||||
Toplevel top = Application.Current.Modal ? Application.Current : Application.Top;
|
||||
top.FocusNext ();
|
||||
|
||||
if (top.Focused is null)
|
||||
{
|
||||
top.FocusNext ();
|
||||
}
|
||||
|
||||
top.SetNeedsDisplay ();
|
||||
Application.BringOverlappedTopToFront ();
|
||||
}
|
||||
else
|
||||
{
|
||||
Application.OverlappedMoveNext ();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void MovePreviousView ()
|
||||
{
|
||||
View old = GetDeepestFocusedSubview (Application.Current.Focused);
|
||||
|
||||
if (!Application.Current.FocusPrev ())
|
||||
{
|
||||
Application.Current.FocusPrev ();
|
||||
}
|
||||
|
||||
if (old != Application.Current.Focused && old != Application.Current.Focused?.Focused)
|
||||
{
|
||||
old?.SetNeedsDisplay ();
|
||||
Application.Current.Focused?.SetNeedsDisplay ();
|
||||
}
|
||||
else
|
||||
{
|
||||
FocusNearestView (Application.Current.SuperView?.TabIndexes?.Reverse (), NavigationDirection.Backward);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void MovePreviousViewOrTop ()
|
||||
{
|
||||
if (Application.OverlappedTop is null)
|
||||
{
|
||||
Toplevel top = Application.Current.Modal ? Application.Current : Application.Top;
|
||||
top.FocusPrev ();
|
||||
|
||||
if (top.Focused is null)
|
||||
{
|
||||
top.FocusPrev ();
|
||||
}
|
||||
|
||||
top.SetNeedsDisplay ();
|
||||
Application.BringOverlappedTopToFront ();
|
||||
}
|
||||
else
|
||||
{
|
||||
Application.OverlappedMovePrevious ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static partial class Application // App-level View Navigation
|
||||
{
|
||||
|
||||
|
||||
@@ -110,6 +110,25 @@ public class KeyBindings
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <para>Adds a new key combination that will trigger the commands in <paramref name="commands"/>.</para>
|
||||
/// <para>
|
||||
/// If the key is already bound to a different array of <see cref="Command"/>s it will be rebound
|
||||
/// <paramref name="commands"/>.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Commands are only ever applied to the current <see cref="View"/> (i.e. this feature cannot be used to switch
|
||||
/// focus to another view and perform multiple commands there).
|
||||
/// </remarks>
|
||||
/// <param name="key">The key to check.</param>
|
||||
/// <param name="scope">The scope for the command.</param>
|
||||
/// <param name="commands">
|
||||
/// The command to invoked on the <see cref="View"/> when <paramref name="key"/> is pressed. When
|
||||
/// multiple commands are provided,they will be applied in sequence. The bound <paramref name="key"/> strike will be
|
||||
/// consumed if any took effect.
|
||||
/// </param>
|
||||
public void Add (Key key, KeyBindingScope scope, params Command [] commands)
|
||||
{
|
||||
if (BoundView is { } && scope.FastHasFlags (KeyBindingScope.Application))
|
||||
|
||||
@@ -411,165 +411,7 @@ public partial class Toplevel : View
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool OnLeave (View view) { return MostFocused?.OnLeave (view) ?? base.OnLeave (view); }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the focus to the next view in the <see cref="TabIndexes"/> list. If the last view is focused, the first view is focused.
|
||||
/// </summary>
|
||||
/// <param name="viewsInTabIndexes"></param>
|
||||
/// <param name="direction"></param>
|
||||
private void FocusNearestView (IEnumerable<View> viewsInTabIndexes, NavigationDirection direction)
|
||||
{
|
||||
if (viewsInTabIndexes is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var found = false;
|
||||
var focusProcessed = false;
|
||||
var idx = 0;
|
||||
|
||||
foreach (View v in viewsInTabIndexes)
|
||||
{
|
||||
if (v == this)
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (found && v != this)
|
||||
{
|
||||
if (direction == NavigationDirection.Forward)
|
||||
{
|
||||
SuperView?.FocusNext ();
|
||||
}
|
||||
else
|
||||
{
|
||||
SuperView?.FocusPrev ();
|
||||
}
|
||||
|
||||
focusProcessed = true;
|
||||
|
||||
if (SuperView.Focused is { } && SuperView.Focused != this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (found && !focusProcessed && idx == viewsInTabIndexes.Count () - 1)
|
||||
{
|
||||
viewsInTabIndexes.ToList () [0].SetFocus ();
|
||||
}
|
||||
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the deepest focused subview of the specified <paramref name="view"/>.
|
||||
/// </summary>
|
||||
/// <param name="view"></param>
|
||||
/// <returns></returns>
|
||||
private View GetDeepestFocusedSubview (View view)
|
||||
{
|
||||
if (view is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach (View v in view.Subviews)
|
||||
{
|
||||
if (v.HasFocus)
|
||||
{
|
||||
return GetDeepestFocusedSubview (v);
|
||||
}
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the focus to
|
||||
/// </summary>
|
||||
internal void MoveNextView ()
|
||||
{
|
||||
View old = GetDeepestFocusedSubview (Focused);
|
||||
|
||||
if (!FocusNext ())
|
||||
{
|
||||
FocusNext ();
|
||||
}
|
||||
|
||||
if (old != Focused && old != Focused?.Focused)
|
||||
{
|
||||
old?.SetNeedsDisplay ();
|
||||
Focused?.SetNeedsDisplay ();
|
||||
}
|
||||
else
|
||||
{
|
||||
FocusNearestView (SuperView?.TabIndexes, NavigationDirection.Forward);
|
||||
}
|
||||
}
|
||||
|
||||
internal void MoveNextViewOrTop ()
|
||||
{
|
||||
if (Application.OverlappedTop is null)
|
||||
{
|
||||
Toplevel top = Modal ? this : Application.Top;
|
||||
top.FocusNext ();
|
||||
|
||||
if (top.Focused is null)
|
||||
{
|
||||
top.FocusNext ();
|
||||
}
|
||||
|
||||
top.SetNeedsDisplay ();
|
||||
Application.BringOverlappedTopToFront ();
|
||||
}
|
||||
else
|
||||
{
|
||||
Application.OverlappedMoveNext ();
|
||||
}
|
||||
}
|
||||
|
||||
internal void MovePreviousView ()
|
||||
{
|
||||
View old = GetDeepestFocusedSubview (Focused);
|
||||
|
||||
if (!FocusPrev ())
|
||||
{
|
||||
FocusPrev ();
|
||||
}
|
||||
|
||||
if (old != Focused && old != Focused?.Focused)
|
||||
{
|
||||
old?.SetNeedsDisplay ();
|
||||
Focused?.SetNeedsDisplay ();
|
||||
}
|
||||
else
|
||||
{
|
||||
FocusNearestView (SuperView?.TabIndexes?.Reverse (), NavigationDirection.Backward);
|
||||
}
|
||||
}
|
||||
|
||||
internal void MovePreviousViewOrTop ()
|
||||
{
|
||||
if (Application.OverlappedTop is null)
|
||||
{
|
||||
Toplevel top = Modal ? this : Application.Top;
|
||||
top.FocusPrev ();
|
||||
|
||||
if (top.Focused is null)
|
||||
{
|
||||
top.FocusPrev ();
|
||||
}
|
||||
|
||||
top.SetNeedsDisplay ();
|
||||
Application.BringOverlappedTopToFront ();
|
||||
}
|
||||
else
|
||||
{
|
||||
Application.OverlappedMovePrevious ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Size / Position Management
|
||||
|
||||
Reference in New Issue
Block a user