Menuv2.cs 5.0 KB

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