#nullable enable
namespace Terminal.Gui;
///
/// A -derived object to be used as a vertically-oriented menu. Each subview is a .
///
public class Menuv2 : Bar
{
///
public Menuv2 () : this ([]) { }
///
public Menuv2 (IEnumerable? menuItems) : this (menuItems?.Cast ()) { }
///
public Menuv2 (IEnumerable? shortcuts) : base (shortcuts)
{
Orientation = Orientation.Vertical;
Width = Dim.Auto ();
Height = Dim.Auto (DimAutoStyle.Content, 1);
Border!.Thickness = new Thickness (1, 1, 1, 1);
Border.LineStyle = LineStyle.Single;
}
///
/// Gets or sets the menu item that opened this menu as a sub-menu.
///
public MenuItemv2? SuperMenuItem { get; set; }
///
protected override void OnVisibleChanged ()
{
if (Visible)
{
SelectedMenuItem = SubViews.Where (mi => mi is MenuItemv2).ElementAtOrDefault (0) as MenuItemv2;
}
}
///
public override void EndInit ()
{
base.EndInit ();
if (Border is { })
{
}
}
///
protected override void OnSubViewAdded (View view)
{
base.OnSubViewAdded (view);
switch (view)
{
case MenuItemv2 menuItem:
{
menuItem.CanFocus = true;
AddCommand (menuItem.Command, RaiseAccepted);
menuItem.Accepted += MenuItemOnAccepted;
break;
void MenuItemOnAccepted (object? sender, CommandEventArgs e)
{
Logging.Trace ($"MenuItemOnAccepted: {e.Context?.Source?.Title}");
RaiseAccepted (e.Context);
}
}
case Line line:
// Grow line so we get auto-join line
line.X = Pos.Func (() => -Border!.Thickness.Left);
line.Width = Dim.Fill ()! + Dim.Func (() => Border!.Thickness.Right);
break;
}
}
///
protected override bool OnAccepting (CommandEventArgs args)
{
Logging.Trace ($"{args.Context}");
if (SuperMenuItem is { })
{
Logging.Trace ($"Invoking Accept on SuperMenuItem: {SuperMenuItem.Title}...");
return SuperMenuItem?.SuperView?.InvokeCommand (Command.Accept, args.Context) is true;
}
return false;
}
// TODO: Consider moving Accepted to Bar?
///
/// Raises the / event indicating an item in this menu (or submenu)
/// was accepted. This is used to determine when to hide the menu.
///
///
///
protected bool? RaiseAccepted (ICommandContext? ctx)
{
//Logging.Trace ($"RaiseAccepted: {ctx}");
CommandEventArgs args = new () { Context = ctx };
OnAccepted (args);
Accepted?.Invoke (this, args);
return true;
}
///
/// 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 OnFocusedChanged (View? previousFocused, View? focused)
{
base.OnFocusedChanged (previousFocused, focused);
SelectedMenuItem = focused as MenuItemv2;
RaiseSelectedMenuItemChanged (SelectedMenuItem);
}
///
/// Gets or set the currently selected menu item. This is a helper that
/// tracks .
///
public MenuItemv2? SelectedMenuItem
{
get => Focused as MenuItemv2;
set
{
if (value == Focused)
{
return;
}
// Note we DO NOT set focus here; This property tracks Focused
}
}
internal void RaiseSelectedMenuItemChanged (MenuItemv2? selected)
{
//Logging.Trace ($"RaiseSelectedMenuItemChanged: {selected?.Title}");
OnSelectedMenuItemChanged (selected);
SelectedMenuItemChanged?.Invoke (this, selected);
}
///
/// Called when the selected menu item has changed.
///
///
protected virtual void OnSelectedMenuItemChanged (MenuItemv2? selected)
{
}
///
/// Raised when the selected menu item has changed.
///
public event EventHandler? SelectedMenuItemChanged;
}