Menuv2.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #nullable enable
  2. namespace Terminal.Gui;
  3. /// <summary>
  4. /// A <see cref="Bar"/>-derived object to be used as a vertically-oriented menu. Each subview is a <see cref="MenuItemv2"/>.
  5. /// </summary>
  6. public class Menuv2 : Bar
  7. {
  8. /// <inheritdoc/>
  9. public Menuv2 () : this ([]) { }
  10. /// <inheritdoc/>
  11. public Menuv2 (IEnumerable<MenuItemv2>? shortcuts) : this (shortcuts?.Cast<View>()) { }
  12. /// <inheritdoc/>
  13. public Menuv2 (IEnumerable<View>? shortcuts) : base (shortcuts)
  14. {
  15. Orientation = Orientation.Vertical;
  16. Width = Dim.Auto ();
  17. Height = Dim.Auto (DimAutoStyle.Content, 1);
  18. Border!.Thickness = new Thickness (1, 1, 1, 1);
  19. Border.LineStyle = LineStyle.Single;
  20. }
  21. /// <summary>
  22. /// Gets or sets the menu item that opened this menu as a sub-menu.
  23. /// </summary>
  24. public MenuItemv2? SuperMenuItem { get; set; }
  25. /// <inheritdoc />
  26. protected override void OnVisibleChanged ()
  27. {
  28. if (Visible)
  29. {
  30. SelectedMenuItem = SubViews.Where (mi => mi is MenuItemv2).ElementAtOrDefault (0) as MenuItemv2;
  31. }
  32. }
  33. /// <inheritdoc />
  34. public override void EndInit ()
  35. {
  36. base.EndInit ();
  37. if (Border is { })
  38. {
  39. }
  40. }
  41. /// <inheritdoc />
  42. protected override void OnSubViewAdded (View view)
  43. {
  44. base.OnSubViewAdded (view);
  45. switch (view)
  46. {
  47. case MenuItemv2 menuItem:
  48. {
  49. menuItem.CanFocus = true;
  50. AddCommand (menuItem.Command, RaiseAccepted);
  51. menuItem.Accepted += MenuItemOnAccepted;
  52. break;
  53. void MenuItemOnAccepted (object? sender, CommandEventArgs e)
  54. {
  55. //Logging.Trace ($"Accepted: {e.Context?.Source?.Title}");
  56. RaiseAccepted (e.Context);
  57. }
  58. }
  59. case Line line:
  60. // Grow line so we get auto-join line
  61. line.X = Pos.Func (() => -Border!.Thickness.Left);
  62. line.Width = Dim.Fill ()! + Dim.Func (() => Border!.Thickness.Right);
  63. break;
  64. }
  65. }
  66. // TODO: Consider moving Accepted to Bar?
  67. /// <summary>
  68. /// Raises the <see cref="OnAccepted"/>/<see cref="Accepted"/> event indicating an item in this menu (or submenu)
  69. /// was accepted. This is used to determine when to hide the menu.
  70. /// </summary>
  71. /// <param name="ctx"></param>
  72. /// <returns></returns>
  73. protected bool? RaiseAccepted (ICommandContext? ctx)
  74. {
  75. //Logging.Trace ($"RaiseAccepted: {ctx}");
  76. CommandEventArgs args = new () { Context = ctx };
  77. OnAccepted (args);
  78. Accepted?.Invoke (this, args);
  79. return true;
  80. }
  81. /// <summary>
  82. /// Called when the user has accepted an item in this menu (or submenu). This is used to determine when to hide the menu.
  83. /// </summary>
  84. /// <remarks>
  85. /// </remarks>
  86. /// <param name="args"></param>
  87. protected virtual void OnAccepted (CommandEventArgs args) { }
  88. /// <summary>
  89. /// Raised when the user has accepted an item in this menu (or submenu). This is used to determine when to hide the menu.
  90. /// </summary>
  91. /// <remarks>
  92. /// <para>
  93. /// See <see cref="RaiseAccepted"/> for more information.
  94. /// </para>
  95. /// </remarks>
  96. public event EventHandler<CommandEventArgs>? Accepted;
  97. /// <inheritdoc />
  98. protected override void OnFocusedChanged (View? previousFocused, View? focused)
  99. {
  100. base.OnFocusedChanged (previousFocused, focused);
  101. SelectedMenuItem = focused as MenuItemv2;
  102. RaiseSelectedMenuItemChanged (SelectedMenuItem);
  103. }
  104. /// <summary>
  105. /// Gets or set the currently selected menu item. This is a helper that
  106. /// tracks <see cref="View.Focused"/>.
  107. /// </summary>
  108. public MenuItemv2? SelectedMenuItem
  109. {
  110. get => Focused as MenuItemv2;
  111. set
  112. {
  113. if (value == Focused)
  114. {
  115. return;
  116. }
  117. // Note we DO NOT set focus here; This property tracks Focused
  118. }
  119. }
  120. internal void RaiseSelectedMenuItemChanged (MenuItemv2? selected)
  121. {
  122. //Logging.Trace ($"RaiseSelectedMenuItemChanged: {selected?.Title}");
  123. OnSelectedMenuItemChanged (selected);
  124. SelectedMenuItemChanged?.Invoke (this, selected);
  125. }
  126. /// <summary>
  127. /// Called when the selected menu item has changed.
  128. /// </summary>
  129. /// <param name="selected"></param>
  130. protected virtual void OnSelectedMenuItemChanged (MenuItemv2? selected)
  131. {
  132. }
  133. /// <summary>
  134. /// Raised when the selected menu item has changed.
  135. /// </summary>
  136. public event EventHandler<MenuItemv2?>? SelectedMenuItemChanged;
  137. }