#nullable enable
namespace Terminal.Gui;
///
/// Provides a horizontally or vertically oriented container for s to be used as a menu, toolbar, or status
/// bar.
///
///
///
/// Any can be added to a . However, the is designed to work with
/// objects. The class provides a way to display a command, help, and key and
/// align them in a specific order.
///
///
public class Bar : View, IOrientation, IDesignable
{
private readonly OrientationHelper _orientationHelper;
///
public Bar () : this ([]) { }
///
public Bar (IEnumerable? shortcuts)
{
CanFocus = true;
Width = Dim.Auto ();
Height = Dim.Auto ();
_orientationHelper = new (this);
// Initialized += Bar_Initialized;
MouseEvent += OnMouseEvent;
if (shortcuts is { })
{
foreach (Shortcut shortcut in shortcuts)
{
Add (shortcut);
}
}
}
private void OnMouseEvent (object? sender, MouseEventArgs e)
{
NavigationDirection direction = NavigationDirection.Backward;
if (e.Flags == MouseFlags.WheeledDown)
{
e.Handled = true;
}
if (e.Flags == MouseFlags.WheeledUp)
{
direction = NavigationDirection.Forward;
e.Handled = true;
}
if (e.Flags == MouseFlags.WheeledRight)
{
e.Handled = true;
}
if (e.Flags == MouseFlags.WheeledLeft)
{
direction = NavigationDirection.Forward;
e.Handled = true;
}
if (e.Handled)
{
e.Handled = AdvanceFocus (direction, TabBehavior.TabStop);
}
}
///
public override void EndInit ()
{
base.EndInit ();
ColorScheme = Colors.ColorSchemes ["Menu"];
}
///
public override void SetBorderStyle (LineStyle value)
{
if (Border is { })
{
// The default changes the thickness. We don't want that. We just set the style.
Border.LineStyle = value;
}
}
#region IOrientation members
///
/// Gets or sets the for this . The default is
/// .
///
///
///
/// Horizontal orientation arranges the command, help, and key parts of each s from right to left
/// Vertical orientation arranges the command, help, and key parts of each s from left to right.
///
///
public Orientation Orientation
{
get => _orientationHelper.Orientation;
set => _orientationHelper.Orientation = value;
}
#pragma warning disable CS0067 // The event is never used
///
public event EventHandler>? OrientationChanging;
///
public event EventHandler>? OrientationChanged;
#pragma warning restore CS0067 // The event is never used
/// Called when has changed.
///
public void OnOrientationChanged (Orientation newOrientation)
{
// BUGBUG: this should not be SuperView.GetContentSize
LayoutBarItems (SuperView?.GetContentSize () ?? Application.Screen.Size);
}
#endregion
private AlignmentModes _alignmentModes = AlignmentModes.StartToEnd;
///
/// Gets or sets the for this . The default is
/// .
///
public AlignmentModes AlignmentModes
{
get => _alignmentModes;
set
{
_alignmentModes = value;
//SetNeedsDraw ();
SetNeedsLayout ();
}
}
// TODO: Move this to View
/// Inserts a in the specified index of .
/// The zero-based index at which item should be inserted.
/// The item to insert.
public void AddShortcutAt (int index, Shortcut item)
{
List savedSubViewList = SubViews.ToList ();
int count = savedSubViewList.Count;
RemoveAll ();
for (var i = 0; i <= count; i++)
{
if (i == index)
{
Add (item);
}
if (i < count)
{
Add (savedSubViewList [i]);
}
}
//SetNeedsDraw ();
SetNeedsLayout ();
}
// TODO: Move this to View
/// Removes a at specified index of .
/// The zero-based index of the item to remove.
/// The removed.
public Shortcut? RemoveShortcut (int index)
{
View? toRemove = null;
for (var i = 0; i < SubViews.Count; i++)
{
if (i == index)
{
toRemove = SubViews.ElementAt (i);
}
}
if (toRemove is { })
{
Remove (toRemove);
//SetNeedsDraw ();
SetNeedsLayout ();
}
return toRemove as Shortcut;
}
///
protected override void OnSubViewLayout (LayoutEventArgs args)
{
LayoutBarItems (args.OldContentSize);
}
private void LayoutBarItems (Size contentSize)
{
View? prevBarItem = null;
switch (Orientation)
{
case Orientation.Horizontal:
for (var index = 0; index < SubViews.Count; index++)
{
View barItem = SubViews.ElementAt (index);
barItem.ColorScheme = ColorScheme;
barItem.X = Pos.Align (Alignment.Start, AlignmentModes);
barItem.Y = 0; //Pos.Center ();
}
break;
case Orientation.Vertical:
if (Width!.Has (out _))
{
// Set the overall size of the Bar and arrange the views vertically
var minKeyWidth = 0;
List shortcuts = SubViews.Where (s => s is Shortcut && s.Visible).Cast ().ToList ();
foreach (Shortcut shortcut in shortcuts)
{
// Get the largest width of all KeyView's
minKeyWidth = int.Max (minKeyWidth, shortcut.KeyView.Text.GetColumns ());
}
var maxBarItemWidth = 0;
for (var index = 0; index < SubViews.Count; index++)
{
View barItem = SubViews.ElementAt (index);
barItem.ColorScheme = ColorScheme;
if (!barItem.Visible)
{
continue;
}
if (barItem is Shortcut scBarItem)
{
barItem.X = 0;
scBarItem.MinimumKeyTextSize = minKeyWidth;
scBarItem.Width = scBarItem.GetWidthDimAuto ();
barItem.Layout (Application.Screen.Size);
maxBarItemWidth = Math.Max (maxBarItemWidth, barItem.Frame.Width);
}
if (prevBarItem == null)
{
// TODO: Just use Pos.Align!
barItem.Y = 0;
}
else
{
// TODO: Just use Pos.Align!
// Align the view to the bottom of the previous view
barItem.Y = Pos.Bottom (prevBarItem);
}
prevBarItem = barItem;
}
foreach (var subView in SubViews)
{
if (subView is not Line)
{
subView.Width = Dim.Auto (DimAutoStyle.Auto, minimumContentDim: maxBarItemWidth);
}
}
}
else
{
foreach (var subView in SubViews)
{
if (subView is not Line)
{
subView.Width = Dim.Fill ();
}
}
}
break;
}
}
///
public bool EnableForDesign ()
{
var shortcut = new Shortcut
{
Text = "Quit",
Title = "Q_uit",
Key = Key.Z.WithCtrl,
};
Add (shortcut);
shortcut = new Shortcut
{
Text = "Help Text",
Title = "Help",
Key = Key.F1,
};
Add (shortcut);
shortcut = new Shortcut
{
Text = "Czech",
CommandView = new CheckBox ()
{
Title = "_Check"
},
Key = Key.F9,
CanFocus = false
};
Add (shortcut);
return true;
}
}