PopoverBaseImpl.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. namespace Terminal.Gui.App;
  2. /// <summary>
  3. /// Abstract base class for popover views in Terminal.Gui.
  4. /// </summary>
  5. /// <remarks>
  6. /// <para>
  7. /// <b>Popover Lifecycle:</b><br/>
  8. /// To display a popover, use <see cref="ApplicationPopover.Show"/>. To hide a popover, either call
  9. /// <see cref="ApplicationPopover.Hide"/>,
  10. /// set <see cref="View.Visible"/> to <see langword="false"/>, or show another popover.
  11. /// </para>
  12. /// <para>
  13. /// <b>Focus and Input:</b><br/>
  14. /// When visible, a popover receives focus and input events. If the user clicks outside the popover (and not on a
  15. /// subview),
  16. /// presses <see cref="Application.QuitKey"/>, or another popover is shown, the popover will be hidden
  17. /// automatically.
  18. /// </para>
  19. /// <para>
  20. /// <b>Layout:</b><br/>
  21. /// When the popover becomes visible, it is automatically laid out to fill the screen by default. You can override
  22. /// this behavior
  23. /// by setting <see cref="View.Width"/> and <see cref="View.Height"/> in your derived class.
  24. /// </para>
  25. /// <para>
  26. /// <b>Mouse:</b><br/>
  27. /// Popovers are transparent to mouse events (see <see cref="ViewportSettingsFlags.TransparentMouse"/>),
  28. /// meaning mouse events in a popover that are not also within a subview of the popover will not be captured.
  29. /// </para>
  30. /// <para>
  31. /// <b>Custom Popovers:</b><br/>
  32. /// To create a custom popover, inherit from <see cref="PopoverBaseImpl"/> and add your own content and logic.
  33. /// </para>
  34. /// </remarks>
  35. public abstract class PopoverBaseImpl : View, IPopover
  36. {
  37. /// <summary>
  38. /// Initializes a new instance of the <see cref="PopoverBaseImpl"/> class.
  39. /// </summary>
  40. /// <remarks>
  41. /// By default, the popover fills the available screen area and is focusable.
  42. /// </remarks>
  43. protected PopoverBaseImpl ()
  44. {
  45. Id = "popoverBaseImpl";
  46. CanFocus = true;
  47. Width = Dim.Fill ();
  48. Height = Dim.Fill ();
  49. ViewportSettings = ViewportSettingsFlags.Transparent | ViewportSettingsFlags.TransparentMouse;
  50. // TODO: Add a diagnostic setting for this?
  51. //TextFormatter.VerticalAlignment = Alignment.End;
  52. //TextFormatter.Alignment = Alignment.End;
  53. //base.Text = "popover";
  54. AddCommand (Command.Quit, Quit);
  55. KeyBindings.Add (Application.QuitKey, Command.Quit);
  56. return;
  57. bool? Quit (ICommandContext? ctx)
  58. {
  59. if (!Visible)
  60. {
  61. return false;
  62. }
  63. Visible = false;
  64. return true;
  65. }
  66. }
  67. private IRunnable? _current;
  68. /// <inheritdoc/>
  69. public IRunnable? Current
  70. {
  71. get => _current;
  72. set
  73. {
  74. _current = value;
  75. App ??= (_current as View)?.App;
  76. }
  77. }
  78. /// <summary>
  79. /// Called when the <see cref="View.Visible"/> property is changing.
  80. /// </summary>
  81. /// <remarks>
  82. /// When becoming visible, the popover is laid out to fit the screen.
  83. /// When becoming hidden, focus is restored to the previous view.
  84. /// </remarks>
  85. /// <returns>
  86. /// <see langword="true"/> to cancel the visibility change; otherwise, <see langword="false"/>.
  87. /// </returns>
  88. protected override bool OnVisibleChanging ()
  89. {
  90. bool ret = base.OnVisibleChanging ();
  91. if (ret)
  92. {
  93. return ret;
  94. }
  95. if (!Visible)
  96. {
  97. // Whenever visible is changing to true, we need to resize;
  98. // it's our only chance because we don't get laid out until we're visible
  99. if (App is { })
  100. {
  101. Layout (App.Screen.Size);
  102. }
  103. }
  104. else
  105. {
  106. // Whenever visible is changing to false, we need to reset the focus
  107. if (ApplicationNavigation.IsInHierarchy (this, App?.Navigation?.GetFocused ()))
  108. {
  109. App?.Navigation?.SetFocused (App?.TopRunnableView?.MostFocused);
  110. }
  111. }
  112. return ret;
  113. }
  114. }