#nullable enable
using System.ComponentModel;
using Terminal.Gui.Resources;
namespace Terminal.Gui;
///
/// A -derived object to be used as a menu item in a . Has title, an
/// A -derived object to be used as a menu item in a . Has title, an
/// associated help text, and an action to execute on activation.
///
public class MenuItemv2 : Shortcut
{
///
/// Creates a new instance of .
///
public MenuItemv2 () : base (Key.Empty, null, null) { }
///
/// Creates a new instance of , binding it to and
/// . The Key
/// has bound to will be used as .
///
///
///
///
/// The View that will be invoked on when user does something that causes the Shortcut's
/// Accept
/// event to be raised.
///
///
/// The Command to invoke on . The Key
/// has bound to will be used as
///
/// The text to display for the command.
/// The help text to display.
/// The submenu to display when the user selects this menu item.
public MenuItemv2 (View? targetView, Command command, string? commandText = null, string? helpText = null, Menuv2? subMenu = null)
: base (
targetView?.HotKeyBindings.GetFirstFromCommands (command)!,
string.IsNullOrEmpty (commandText) ? GlobalResources.GetString ($"cmd.{command}") : commandText,
null,
string.IsNullOrEmpty (helpText) ? GlobalResources.GetString ($"cmd.{command}.Help") : helpText
)
{
TargetView = targetView;
Command = command;
SubMenu = subMenu;
}
///
public MenuItemv2 (string? commandText = null, string? helpText = null, Action? action = null, Key? key = null)
: base (key ?? Key.Empty, commandText, action, helpText)
{ }
///
public MenuItemv2 (string commandText, Key key, Action? action = null)
: base (key ?? Key.Empty, commandText, action, null)
{ }
///
public MenuItemv2 (string? commandText = null, string? helpText = null, Menuv2? subMenu = null)
: base (Key.Empty, commandText, null, helpText)
{
SubMenu = subMenu;
}
// TODO: Consider moving TargetView and Command to Shortcut?
///
/// Gets the target that the will be invoked on.
///
public View? TargetView { get; set; }
private Command _command;
///
/// Gets the that will be invoked on when the MenuItem is selected.
///
public Command Command
{
get => _command;
set
{
if (_command == value)
{
return;
}
_command = value;
if (string.IsNullOrEmpty (Title))
{
Title = GlobalResources.GetString ($"cmd.{_command}") ?? string.Empty;
}
if (string.IsNullOrEmpty (HelpText))
{
HelpText = GlobalResources.GetString ($"cmd.{_command}.Help") ?? string.Empty;
}
}
}
internal override bool? DispatchCommand (ICommandContext? commandContext)
{
Logging.Debug ($"{Title} - {commandContext?.Source?.Title} Command: {commandContext?.Command}");
bool? ret = null;
bool quit = false;
if (commandContext is CommandContext keyCommandContext)
{
if (keyCommandContext.Binding.Key is { } && keyCommandContext.Binding.Key == Application.QuitKey && SuperView is { Visible: true })
{
// This supports a MenuItem with Key = Application.QuitKey/Command = Command.Quit
Logging.Debug ($"{Title} - Ignoring Key = Application.QuitKey/Command = Command.Quit");
quit = true;
//ret = true;
}
}
// Translate the incoming command to Command
if (Command != Command.NotBound && commandContext is { })
{
commandContext.Command = Command;
}
if (!quit)
{
if (TargetView is { })
{
Logging.Debug ($"{Title} - InvokeCommand on TargetView ({TargetView.Title})...");
ret = TargetView.InvokeCommand (Command, commandContext);
}
else
{
// Is this an Application-bound command?
Logging.Debug ($"{Title} - Application.InvokeCommandsBoundToKey ({Key})...");
ret = Application.InvokeCommandsBoundToKey (Key);
}
}
if (ret is not true)
{
Logging.Debug ($"{Title} - calling base.DispatchCommand...");
// Base will Raise Selected, then Accepting, then invoke the Action, if any
ret = base.DispatchCommand (commandContext);
}
if (ret is true)
{
Logging.Debug ($"{Title} - Calling RaiseAccepted");
RaiseAccepted (commandContext);
}
return ret;
}
/////
//protected override bool OnAccepting (CommandEventArgs e)
//{
// Logging.Debug ($"{Title} - calling base.OnAccepting: {e.Context?.Command}");
// bool? ret = base.OnAccepting (e);
// if (ret is true || e.Cancel)
// {
// return true;
// }
// //RaiseAccepted (e.Context);
// return ret is true;
//}
private Menuv2? _subMenu;
///
/// The submenu to display when the user selects this menu item.
///
public Menuv2? SubMenu
{
get => _subMenu;
set
{
_subMenu = value;
if (_subMenu is { })
{
SubMenu!.Visible = false;
// TODO: This is a temporary hack - add a flag or something instead
KeyView.Text = $"{Glyphs.RightArrow}";
_subMenu.SuperMenuItem = this;
}
}
}
///
protected override bool OnMouseEnter (CancelEventArgs eventArgs)
{
// When the mouse enters a menuitem, we set focus to it automatically.
// Logging.Trace($"OnEnter {Title}");
SetFocus ();
return base.OnMouseEnter (eventArgs);
}
// TODO: Consider moving Accepted to Shortcut?
///
/// Raises the / event indicating this item (or submenu)
/// was accepted. This is used to determine when to hide the menu.
///
///
///
protected void RaiseAccepted (ICommandContext? ctx)
{
//Logging.Trace ($"RaiseAccepted: {ctx}");
CommandEventArgs args = new () { Context = ctx };
OnAccepted (args);
Accepted?.Invoke (this, args);
}
///
/// Called when the user has accepted an item in this menu (or submenu). This is used to determine when to hide the
/// menu.
///
///
///
///
protected virtual void OnAccepted (CommandEventArgs args) { }
///
/// Raised when the user has accepted an item in this menu (or submenu). This is used to determine when to hide the
/// menu.
///
///
///
/// See for more information.
///
///
public event EventHandler? Accepted;
///
protected override void Dispose (bool disposing)
{
if (disposing)
{
SubMenu?.Dispose ();
SubMenu = null;
}
base.Dispose (disposing);
}
}