MenuItemv2.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. #nullable enable
  2. using System.ComponentModel;
  3. using Terminal.Gui.Resources;
  4. namespace Terminal.Gui;
  5. /// <summary>
  6. /// A <see cref="Shortcut"/>-dervied object to be used as a menu item in a <see cref="Menuv2"/>. Has title, an
  7. /// associated help text, and an action to execute on activation.
  8. /// </summary>
  9. public class MenuItemv2 : Shortcut
  10. {
  11. /// <summary>
  12. /// Creates a new instance of <see cref="MenuItemv2"/>.
  13. /// </summary>
  14. public MenuItemv2 () : base (Key.Empty, null, null) { }
  15. /// <summary>
  16. /// Creates a new instance of <see cref="MenuItemv2"/>, binding it to <paramref name="targetView"/> and
  17. /// <paramref name="command"/>. The Key <paramref name="targetView"/>
  18. /// has bound to <paramref name="command"/> will be used as <see cref="Key"/>.
  19. /// </summary>
  20. /// <remarks>
  21. /// </remarks>
  22. /// <param name="targetView">
  23. /// The View that <paramref name="command"/> will be invoked on when user does something that causes the Shortcut's
  24. /// Accept
  25. /// event to be raised.
  26. /// </param>
  27. /// <param name="command">
  28. /// The Command to invoke on <paramref name="targetView"/>. The Key <paramref name="targetView"/>
  29. /// has bound to <paramref name="command"/> will be used as <see cref="Key"/>
  30. /// </param>
  31. /// <param name="commandText">The text to display for the command.</param>
  32. /// <param name="helpText">The help text to display.</param>
  33. /// <param name="subMenu">The submenu to display when the user selects this menu item.</param>
  34. public MenuItemv2 (View? targetView, Command command, string? commandText = null, string? helpText = null, Menuv2? subMenu = null)
  35. : base (
  36. targetView?.HotKeyBindings.GetFirstFromCommands (command)!,
  37. string.IsNullOrEmpty (commandText) ? GlobalResources.GetString ($"cmd.{command}") : commandText,
  38. null,
  39. string.IsNullOrEmpty (helpText) ? GlobalResources.GetString ($"cmd.{command}.Help") : helpText
  40. )
  41. {
  42. TargetView = targetView;
  43. Command = command;
  44. SubMenu = subMenu;
  45. }
  46. // TODO: Consider moving TargetView and Command to Shortcut?
  47. /// <summary>
  48. /// Gets the target <see cref="View"/> that the <see cref="Command"/> will be invoked on.
  49. /// </summary>
  50. public View? TargetView { get; set; }
  51. private Command _command;
  52. /// <summary>
  53. /// Gets the <see cref="Command"/> that will be invoked on <see cref="TargetView"/> when the MenuItem is selected.
  54. /// </summary>
  55. public Command Command
  56. {
  57. get => _command;
  58. set
  59. {
  60. if (_command == value)
  61. {
  62. return;
  63. }
  64. _command = value;
  65. if (string.IsNullOrEmpty (Title))
  66. {
  67. Title = GlobalResources.GetString ($"cmd.{_command}") ?? string.Empty;
  68. }
  69. if (string.IsNullOrEmpty (HelpText))
  70. {
  71. HelpText = GlobalResources.GetString ($"cmd.{_command}.Help") ?? string.Empty;
  72. }
  73. }
  74. }
  75. internal override bool? DispatchCommand (ICommandContext? commandContext)
  76. {
  77. bool? ret = null;
  78. if (commandContext is { Command: not Command.HotKey })
  79. {
  80. if (TargetView is { })
  81. {
  82. commandContext.Command = Command;
  83. ret = TargetView.InvokeCommand (Command, commandContext);
  84. }
  85. else
  86. {
  87. // Is this an Application-bound command?
  88. ret = Application.InvokeCommandsBoundToKey (Key);
  89. }
  90. }
  91. if (ret is not true)
  92. {
  93. ret = base.DispatchCommand (commandContext);
  94. }
  95. Logging.Trace ($"{commandContext?.Source?.Title}");
  96. RaiseAccepted (commandContext);
  97. return ret;
  98. }
  99. private Menuv2? _subMenu;
  100. /// <summary>
  101. /// The submenu to display when the user selects this menu item.
  102. /// </summary>
  103. public Menuv2? SubMenu
  104. {
  105. get => _subMenu;
  106. set
  107. {
  108. _subMenu = value;
  109. if (_subMenu is { })
  110. {
  111. // TODO: This is a temporary hack - add a flag or something instead
  112. KeyView.Text = $"{Glyphs.RightArrow}";
  113. _subMenu.SuperMenuItem = this;
  114. }
  115. }
  116. }
  117. /// <inheritdoc/>
  118. protected override bool OnMouseEnter (CancelEventArgs eventArgs)
  119. {
  120. // When the mouse enters a menuitem, we set focus to it automatically.
  121. // Logging.Trace($"OnEnter {Title}");
  122. SetFocus ();
  123. return base.OnMouseEnter (eventArgs);
  124. }
  125. // TODO: Consider moving Accepted to Shortcut?
  126. /// <summary>
  127. /// Riases the <see cref="OnAccepted"/>/<see cref="Accepted"/> event indicating this item (or submenu)
  128. /// was accepted. This is used to determine when to hide the menu.
  129. /// </summary>
  130. /// <param name="ctx"></param>
  131. /// <returns></returns>
  132. protected bool? RaiseAccepted (ICommandContext? ctx)
  133. {
  134. Logging.Trace ($"RaiseAccepted: {ctx}");
  135. CommandEventArgs args = new () { Context = ctx };
  136. OnAccepted (args);
  137. Accepted?.Invoke (this, args);
  138. return true;
  139. }
  140. /// <summary>
  141. /// Called when the user has accepted an item in this menu (or submenu. This is used to determine when to hide the
  142. /// menu.
  143. /// </summary>
  144. /// <remarks>
  145. /// </remarks>
  146. /// <param name="args"></param>
  147. protected virtual void OnAccepted (CommandEventArgs args) { }
  148. /// <summary>
  149. /// Raised when the user has accepted an item in this menu (or submenu. This is used to determine when to hide the
  150. /// menu.
  151. /// </summary>
  152. /// <remarks>
  153. /// <para>
  154. /// See <see cref="RaiseAccepted"/> for more information.
  155. /// </para>
  156. /// </remarks>
  157. public event EventHandler<CommandEventArgs>? Accepted;
  158. /// <inheritdoc/>
  159. protected override void Dispose (bool disposing)
  160. {
  161. if (disposing)
  162. {
  163. SubMenu?.Dispose ();
  164. SubMenu = null;
  165. }
  166. base.Dispose (disposing);
  167. }
  168. }