Application.Overlapped.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. #nullable enable
  2. using static Terminal.Gui.View;
  3. using System.Reflection;
  4. namespace Terminal.Gui;
  5. internal static class ViewNavigation
  6. {
  7. /// <summary>
  8. /// Gets the deepest focused subview of the specified <paramref name="view"/>.
  9. /// </summary>
  10. /// <param name="view"></param>
  11. /// <returns></returns>
  12. internal static View? GetDeepestFocusedSubview (View? view)
  13. {
  14. if (view is null)
  15. {
  16. return null;
  17. }
  18. foreach (View v in view.Subviews)
  19. {
  20. if (v.HasFocus)
  21. {
  22. return GetDeepestFocusedSubview (v);
  23. }
  24. }
  25. return view;
  26. }
  27. /// <summary>
  28. /// Sets the focus to the next view in the <see cref="View.TabIndexes"/> list. If the last view is focused, the first view is focused.
  29. /// </summary>
  30. /// <param name="viewsInTabIndexes"></param>
  31. /// <param name="direction"></param>
  32. internal static void FocusNearestView (IEnumerable<View>? viewsInTabIndexes, NavigationDirection direction)
  33. {
  34. if (viewsInTabIndexes is null)
  35. {
  36. return;
  37. }
  38. var found = false;
  39. var focusProcessed = false;
  40. var idx = 0;
  41. foreach (View v in viewsInTabIndexes)
  42. {
  43. if (v == Application.Current)
  44. {
  45. found = true;
  46. }
  47. if (found && v != Application.Current)
  48. {
  49. if (direction == NavigationDirection.Forward)
  50. {
  51. Application.Current!.SuperView?.FocusNext ();
  52. }
  53. else
  54. {
  55. Application.Current!.SuperView?.FocusPrev ();
  56. }
  57. focusProcessed = true;
  58. if (Application.Current.SuperView?.Focused is { } && Application.Current.SuperView.Focused != Application.Current)
  59. {
  60. return;
  61. }
  62. }
  63. else if (found && !focusProcessed && idx == viewsInTabIndexes.Count () - 1)
  64. {
  65. viewsInTabIndexes.ToList () [0].SetFocus ();
  66. }
  67. idx++;
  68. }
  69. }
  70. /// <summary>
  71. /// Moves the focus to
  72. /// </summary>
  73. internal static void MoveNextView ()
  74. {
  75. View? old = GetDeepestFocusedSubview (Application.Current!.Focused);
  76. if (!Application.Current.FocusNext ())
  77. {
  78. Application.Current.FocusNext ();
  79. }
  80. if (old != Application.Current.Focused && old != Application.Current.Focused?.Focused)
  81. {
  82. old?.SetNeedsDisplay ();
  83. Application.Current.Focused?.SetNeedsDisplay ();
  84. }
  85. else
  86. {
  87. FocusNearestView (Application.Current.SuperView?.TabIndexes, NavigationDirection.Forward);
  88. }
  89. }
  90. internal static void MoveNextViewOrTop ()
  91. {
  92. if (Application.OverlappedTop is null)
  93. {
  94. Toplevel? top = Application.Current!.Modal ? Application.Current : Application.Top;
  95. top!.FocusNext ();
  96. if (top.Focused is null)
  97. {
  98. top.FocusNext ();
  99. }
  100. top.SetNeedsDisplay ();
  101. Application.BringOverlappedTopToFront ();
  102. }
  103. else
  104. {
  105. Application.OverlappedMoveNext ();
  106. }
  107. }
  108. internal static void MovePreviousView ()
  109. {
  110. View? old = GetDeepestFocusedSubview (Application.Current!.Focused);
  111. if (!Application.Current.FocusPrev ())
  112. {
  113. Application.Current.FocusPrev ();
  114. }
  115. if (old != Application.Current.Focused && old != Application.Current.Focused?.Focused)
  116. {
  117. old?.SetNeedsDisplay ();
  118. Application.Current.Focused?.SetNeedsDisplay ();
  119. }
  120. else
  121. {
  122. FocusNearestView (Application.Current.SuperView?.TabIndexes?.Reverse (), NavigationDirection.Backward);
  123. }
  124. }
  125. internal static void MovePreviousViewOrTop ()
  126. {
  127. if (Application.OverlappedTop is null)
  128. {
  129. Toplevel? top = Application.Current!.Modal ? Application.Current : Application.Top;
  130. top!.FocusPrev ();
  131. if (top.Focused is null)
  132. {
  133. top.FocusPrev ();
  134. }
  135. top.SetNeedsDisplay ();
  136. Application.BringOverlappedTopToFront ();
  137. }
  138. else
  139. {
  140. Application.OverlappedMovePrevious ();
  141. }
  142. }
  143. }
  144. public static partial class Application // App-level View Navigation
  145. {
  146. }