Application.Toplevel.cs 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. #nullable enable
  2. namespace Terminal.Gui;
  3. public static partial class Application // Toplevel handling
  4. {
  5. // BUGBUG: Technically, this is not the full lst of TopLevels. There be dragons here, e.g. see how Toplevel.Id is used. What
  6. /// <summary>Holds the stack of TopLevel views.</summary>
  7. // about TopLevels that are just a SubView of another View?
  8. internal static readonly Stack<Toplevel> _topLevels = new ();
  9. /// <summary>The <see cref="Toplevel"/> object used for the application on startup (<seealso cref="Top"/>)</summary>
  10. /// <value>The top.</value>
  11. public static Toplevel? Top { get; private set; }
  12. // TODO: Determine why this can't just return _topLevels.Peek()?
  13. /// <summary>
  14. /// The current <see cref="Toplevel"/> object. This is updated in <see cref="Application.Begin"/> enters and leaves to
  15. /// point to the current
  16. /// <see cref="Toplevel"/> .
  17. /// </summary>
  18. /// <remarks>
  19. /// This will only be distinct from <see cref="Application.Top"/> in scenarios where <see cref="Toplevel.IsOverlappedContainer"/> is <see langword="true"/>.
  20. /// </remarks>
  21. /// <value>The current.</value>
  22. public static Toplevel? Current { get; private set; }
  23. /// <summary>
  24. /// If <paramref name="topLevel"/> is not already Current and visible, finds the last Modal Toplevel in the stack and makes it Current.
  25. /// </summary>
  26. private static void EnsureModalOrVisibleAlwaysOnTop (Toplevel topLevel)
  27. {
  28. if (!topLevel.Running
  29. || (topLevel == Current && topLevel.Visible)
  30. || OverlappedTop == null
  31. || _topLevels.Peek ().Modal)
  32. {
  33. return;
  34. }
  35. foreach (Toplevel top in _topLevels.Reverse ())
  36. {
  37. if (top.Modal && top != Current)
  38. {
  39. MoveCurrent (top);
  40. return;
  41. }
  42. }
  43. if (!topLevel.Visible && topLevel == Current)
  44. {
  45. OverlappedMoveNext ();
  46. }
  47. }
  48. /// <summary>Invoked when the terminal's size changed. The new size of the terminal is provided.</summary>
  49. /// <remarks>
  50. /// Event handlers can set <see cref="SizeChangedEventArgs.Cancel"/> to <see langword="true"/> to prevent
  51. /// <see cref="Application"/> from changing it's size to match the new terminal size.
  52. /// </remarks>
  53. public static event EventHandler<SizeChangedEventArgs>? SizeChanging;
  54. /// <summary>
  55. /// Called when the application's size changes. Sets the size of all <see cref="Toplevel"/>s and fires the
  56. /// <see cref="SizeChanging"/> event.
  57. /// </summary>
  58. /// <param name="args">The new size.</param>
  59. /// <returns><see lanword="true"/>if the size was changed.</returns>
  60. public static bool OnSizeChanging (SizeChangedEventArgs args)
  61. {
  62. SizeChanging?.Invoke (null, args);
  63. if (args.Cancel || args.Size is null)
  64. {
  65. return false;
  66. }
  67. foreach (Toplevel t in _topLevels)
  68. {
  69. t.SetRelativeLayout (args.Size.Value);
  70. t.LayoutSubviews ();
  71. t.PositionToplevels ();
  72. t.OnSizeChanging (new (args.Size));
  73. if (PositionCursor (t))
  74. {
  75. Driver?.UpdateCursor ();
  76. }
  77. }
  78. Refresh ();
  79. return true;
  80. }
  81. }