ToplevelOverlapped.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Linq;
  5. namespace Terminal.Gui {
  6. public partial class Toplevel {
  7. /// <summary>
  8. /// Gets or sets if this Toplevel is a container for overlapped children.
  9. /// </summary>
  10. public bool IsOverlappedContainer { get; set; }
  11. /// <summary>
  12. /// Gets or sets if this Toplevel is in overlapped mode within a Toplevel container.
  13. /// </summary>
  14. public bool IsOverlapped {
  15. get {
  16. return Application.OverlappedTop != null && Application.OverlappedTop != this && !Modal;
  17. }
  18. }
  19. }
  20. public static partial class Application {
  21. /// <summary>
  22. /// Gets the list of the Overlapped children which are not modal <see cref="Toplevel"/> from the <see cref="OverlappedTop"/>.
  23. /// </summary>
  24. public static List<Toplevel> OverlappedChildren {
  25. get {
  26. if (OverlappedTop != null) {
  27. List<Toplevel> _overlappedChildren = new List<Toplevel> ();
  28. foreach (var top in _toplevels) {
  29. if (top != OverlappedTop && !top.Modal) {
  30. _overlappedChildren.Add (top);
  31. }
  32. }
  33. return _overlappedChildren;
  34. }
  35. return null;
  36. }
  37. }
  38. /// <summary>
  39. /// The <see cref="Toplevel"/> object used for the application on startup which <see cref="Toplevel.IsOverlappedContainer"/> is true.
  40. /// </summary>
  41. public static Toplevel OverlappedTop {
  42. get {
  43. if (Top.IsOverlappedContainer) {
  44. return Top;
  45. }
  46. return null;
  47. }
  48. }
  49. static View FindDeepestOverlappedView (View start, int x, int y, out int resx, out int resy)
  50. {
  51. if (start.GetType ().BaseType != typeof (Toplevel)
  52. && !((Toplevel)start).IsOverlappedContainer) {
  53. resx = 0;
  54. resy = 0;
  55. return null;
  56. }
  57. var startFrame = start.Frame;
  58. if (!startFrame.Contains (x, y)) {
  59. resx = 0;
  60. resy = 0;
  61. return null;
  62. }
  63. int count = _toplevels.Count;
  64. for (int i = count - 1; i >= 0; i--) {
  65. foreach (var top in _toplevels) {
  66. var rx = x - startFrame.X;
  67. var ry = y - startFrame.Y;
  68. if (top.Visible && top.Frame.Contains (rx, ry)) {
  69. var deep = View.FindDeepestView (top, rx, ry, out resx, out resy);
  70. if (deep == null)
  71. return FindDeepestOverlappedView (top, rx, ry, out resx, out resy);
  72. if (deep != OverlappedTop)
  73. return deep;
  74. }
  75. }
  76. }
  77. resx = x - startFrame.X;
  78. resy = y - startFrame.Y;
  79. return start;
  80. }
  81. static bool OverlappedChildNeedsDisplay ()
  82. {
  83. if (OverlappedTop == null) {
  84. return false;
  85. }
  86. foreach (var top in _toplevels) {
  87. if (top != Current && top.Visible && (top.NeedsDisplay || top.SubViewNeedsDisplay || top.LayoutNeeded)) {
  88. OverlappedTop.SetSubViewNeedsDisplay ();
  89. return true;
  90. }
  91. }
  92. return false;
  93. }
  94. static bool SetCurrentOverlappedAsTop ()
  95. {
  96. if (OverlappedTop == null && Current != Top && Current?.SuperView == null && Current?.Modal == false) {
  97. if (Current.Frame != new Rect (0, 0, Driver.Cols, Driver.Rows)) {
  98. Current.Frame = new Rect (0, 0, Driver.Cols, Driver.Rows);
  99. }
  100. Top = Current;
  101. return true;
  102. }
  103. return false;
  104. }
  105. /// <summary>
  106. /// Move to the next Overlapped child from the <see cref="OverlappedTop"/>.
  107. /// </summary>
  108. public static void OverlappedMoveNext ()
  109. {
  110. if (OverlappedTop != null && !Current.Modal) {
  111. lock (_toplevels) {
  112. _toplevels.MoveNext ();
  113. var isOverlapped = false;
  114. while (_toplevels.Peek () == OverlappedTop || !_toplevels.Peek ().Visible) {
  115. if (!isOverlapped && _toplevels.Peek () == OverlappedTop) {
  116. isOverlapped = true;
  117. } else if (isOverlapped && _toplevels.Peek () == OverlappedTop) {
  118. MoveCurrent (Top);
  119. break;
  120. }
  121. _toplevels.MoveNext ();
  122. }
  123. Current = _toplevels.Peek ();
  124. }
  125. }
  126. }
  127. /// <summary>
  128. /// Move to the previous Overlapped child from the <see cref="OverlappedTop"/>.
  129. /// </summary>
  130. public static void OverlappedMovePrevious ()
  131. {
  132. if (OverlappedTop != null && !Current.Modal) {
  133. lock (_toplevels) {
  134. _toplevels.MovePrevious ();
  135. var isOverlapped = false;
  136. while (_toplevels.Peek () == OverlappedTop || !_toplevels.Peek ().Visible) {
  137. if (!isOverlapped && _toplevels.Peek () == OverlappedTop) {
  138. isOverlapped = true;
  139. } else if (isOverlapped && _toplevels.Peek () == OverlappedTop) {
  140. MoveCurrent (Top);
  141. break;
  142. }
  143. _toplevels.MovePrevious ();
  144. }
  145. Current = _toplevels.Peek ();
  146. }
  147. }
  148. }
  149. /// <summary>
  150. /// Move to the next Overlapped child from the <see cref="OverlappedTop"/> and set it as the <see cref="Top"/> if it is not already.
  151. /// </summary>
  152. /// <param name="top"></param>
  153. /// <returns></returns>
  154. public static bool MoveToOverlappedChild (Toplevel top)
  155. {
  156. if (top.Visible && OverlappedTop != null && Current?.Modal == false) {
  157. lock (_toplevels) {
  158. _toplevels.MoveTo (top, 0, new ToplevelEqualityComparer ());
  159. Current = top;
  160. }
  161. return true;
  162. }
  163. return false;
  164. }
  165. /// <summary>
  166. /// Brings the superview of the most focused overlapped view is on front.
  167. /// </summary>
  168. public static void BringOverlappedTopToFront ()
  169. {
  170. if (OverlappedTop != null) {
  171. return;
  172. }
  173. var top = FindTopFromView (Top?.MostFocused);
  174. if (top != null && Top.Subviews.Count > 1 && Top.Subviews [Top.Subviews.Count - 1] != top) {
  175. Top.BringSubviewToFront (top);
  176. }
  177. }
  178. /// <summary>
  179. /// Gets the current visible Toplevel overlapped child that matches the arguments pattern.
  180. /// </summary>
  181. /// <param name="type">The type.</param>
  182. /// <param name="exclude">The strings to exclude.</param>
  183. /// <returns>The matched view.</returns>
  184. public static Toplevel GetTopOverlappedChild (Type type = null, string [] exclude = null)
  185. {
  186. if (Application.OverlappedTop == null) {
  187. return null;
  188. }
  189. foreach (var top in Application.OverlappedChildren) {
  190. if (type != null && top.GetType () == type
  191. && exclude?.Contains (top.Data.ToString ()) == false) {
  192. return top;
  193. } else if ((type != null && top.GetType () != type)
  194. || (exclude?.Contains (top.Data.ToString ()) == true)) {
  195. continue;
  196. }
  197. return top;
  198. }
  199. return null;
  200. }
  201. }
  202. }