PopoverBaseImpl.cs 3.6 KB

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