ApplicationNavigation.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. #nullable enable
  2. namespace Terminal.Gui;
  3. /// <summary>
  4. /// Helper class for <see cref="Application"/> navigation. Held by <see cref="Application.Navigation"/>
  5. /// </summary>
  6. public class ApplicationNavigation
  7. {
  8. /// <summary>
  9. /// Initializes a new instance of the <see cref="ApplicationNavigation"/> class.
  10. /// </summary>
  11. public ApplicationNavigation ()
  12. {
  13. // TODO: Move navigation key bindings here from AddApplicationKeyBindings
  14. }
  15. /// <summary>
  16. /// Gets the deepest focused subview of the specified <paramref name="view"/>.
  17. /// </summary>
  18. /// <param name="view"></param>
  19. /// <returns></returns>
  20. internal static View? GetDeepestFocusedSubview (View? view)
  21. {
  22. if (view is null)
  23. {
  24. return null;
  25. }
  26. foreach (View v in view.Subviews)
  27. {
  28. if (v.HasFocus)
  29. {
  30. return GetDeepestFocusedSubview (v);
  31. }
  32. }
  33. return view;
  34. }
  35. /// <summary>
  36. /// Moves the focus to the next focusable view.
  37. /// Honors <see cref="ViewArrangement.Overlapped"/> and will only move to the next subview
  38. /// if the current and next subviews are not overlapped.
  39. /// </summary>
  40. internal static void MoveNextView ()
  41. {
  42. View? old = GetDeepestFocusedSubview (Application.Current!.Focused);
  43. if (!Application.Current.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop))
  44. {
  45. Application.Current.AdvanceFocus (NavigationDirection.Forward, null);
  46. }
  47. if (old != Application.Current.Focused && old != Application.Current.Focused?.Focused)
  48. {
  49. old?.SetNeedsDisplay ();
  50. Application.Current.Focused?.SetNeedsDisplay ();
  51. }
  52. else
  53. {
  54. ApplicationOverlapped.SetFocusToNextViewWithWrap (Application.Current.SuperView?.TabIndexes, NavigationDirection.Forward);
  55. }
  56. }
  57. /// <summary>
  58. /// Moves the focus to the next <see cref="Toplevel"/> subview or the next subview that has
  59. /// <see cref="ApplicationOverlapped.OverlappedTop"/> set.
  60. /// </summary>
  61. internal static void MoveNextViewOrTop ()
  62. {
  63. if (ApplicationOverlapped.OverlappedTop is null)
  64. {
  65. Toplevel? top = Application.Current!.Modal ? Application.Current : Application.Top;
  66. if (!Application.Current.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabGroup))
  67. {
  68. Application.Current.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
  69. if (Application.Current.Focused is null)
  70. {
  71. Application.Current.RestoreFocus ();
  72. }
  73. }
  74. if (top != Application.Current.Focused && top != Application.Current.Focused?.Focused)
  75. {
  76. top?.SetNeedsDisplay ();
  77. Application.Current.Focused?.SetNeedsDisplay ();
  78. }
  79. else
  80. {
  81. ApplicationOverlapped.SetFocusToNextViewWithWrap (Application.Current.SuperView?.TabIndexes, NavigationDirection.Forward);
  82. }
  83. //top!.AdvanceFocus (NavigationDirection.Forward);
  84. //if (top.Focused is null)
  85. //{
  86. // top.AdvanceFocus (NavigationDirection.Forward);
  87. //}
  88. //top.SetNeedsDisplay ();
  89. ApplicationOverlapped.BringOverlappedTopToFront ();
  90. }
  91. else
  92. {
  93. ApplicationOverlapped.OverlappedMoveNext ();
  94. }
  95. }
  96. // TODO: These methods should return bool to indicate if the focus was moved or not.
  97. /// <summary>
  98. /// Moves the focus to the next view. Honors <see cref="ViewArrangement.Overlapped"/> and will only move to the next
  99. /// subview
  100. /// if the current and next subviews are not overlapped.
  101. /// </summary>
  102. internal static void MovePreviousView ()
  103. {
  104. View? old = GetDeepestFocusedSubview (Application.Current!.Focused);
  105. if (!Application.Current.AdvanceFocus (NavigationDirection.Backward, TabBehavior.TabStop))
  106. {
  107. Application.Current.AdvanceFocus (NavigationDirection.Backward, null);
  108. }
  109. if (old != Application.Current.Focused && old != Application.Current.Focused?.Focused)
  110. {
  111. old?.SetNeedsDisplay ();
  112. Application.Current.Focused?.SetNeedsDisplay ();
  113. }
  114. else
  115. {
  116. ApplicationOverlapped.SetFocusToNextViewWithWrap (Application.Current.SuperView?.TabIndexes?.Reverse (), NavigationDirection.Backward);
  117. }
  118. }
  119. internal static void MovePreviousViewOrTop ()
  120. {
  121. if (ApplicationOverlapped.OverlappedTop is null)
  122. {
  123. Toplevel? top = Application.Current!.Modal ? Application.Current : Application.Top;
  124. top!.AdvanceFocus (NavigationDirection.Backward, TabBehavior.TabGroup);
  125. if (top.Focused is null)
  126. {
  127. top.AdvanceFocus (NavigationDirection.Backward, null);
  128. }
  129. top.SetNeedsDisplay ();
  130. ApplicationOverlapped.BringOverlappedTopToFront ();
  131. }
  132. else
  133. {
  134. ApplicationOverlapped.OverlappedMovePrevious ();
  135. }
  136. }
  137. }