#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);
_orientationHelper.OrientationChanging += (sender, e) => OrientationChanging?.Invoke (this, e);
_orientationHelper.OrientationChanged += (sender, e) => OrientationChanged?.Invoke (this, e);
// Initialized += Bar_Initialized;
MouseEvent += OnMouseEvent;
if (shortcuts is null)
{
return;
}
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)
{
// 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;
}
///
public event EventHandler>? OrientationChanging;
///
public event EventHandler>? OrientationChanged;
/// 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 [i];
}
}
if (toRemove is { })
{
Remove (toRemove);
SetNeedsDraw ();
SetNeedsLayout ();
}
return toRemove as Shortcut;
}
///
protected override void OnSubviewLayout (LayoutEventArgs args)
{
LayoutBarItems (args.OldContentSize);
}
// This is used to calculate the minimum width of the Bar when the width is NOT Dim.Auto
private int? _minimumDimAutoWidth;
private void LayoutBarItems (Size contentSize)
{
View? prevBarItem = null;
switch (Orientation)
{
case Orientation.Horizontal:
for (var index = 0; index < Subviews.Count; index++)
{
View barItem = Subviews [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 [index];
barItem.X = 0;
barItem.ColorScheme = ColorScheme;
if (!barItem.Visible)
{
continue;
}
if (barItem is Shortcut scBarItem)
{
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)
{
subView.Width = Dim.Auto (DimAutoStyle.Auto, minimumContentDim: _maxBarItemWidth);
}
}
else
{
foreach (var subView in Subviews)
{
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;
}
}