mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
New branch dervied from v2_3037_Bar
This commit is contained in:
@@ -289,6 +289,5 @@ partial class Application
|
||||
/// <remarks>
|
||||
/// This is an internal method used by the <see cref="View"/> class to remove Application key bindings.
|
||||
/// </remarks>
|
||||
/// <param name="view">The view that is bound to the key.</param>
|
||||
internal static void ClearKeyBindings () { _keyBindings.Clear (); }
|
||||
}
|
||||
|
||||
@@ -1,233 +0,0 @@
|
||||
namespace Terminal.Gui;
|
||||
|
||||
/// <summary>
|
||||
/// Provides a horizontally or vertically oriented container for other views to be used as a menu, toolbar, or status bar.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
public class Bar : View
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public Bar ()
|
||||
{
|
||||
SetInitialProperties ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="Orientation"/> for this <see cref="Bar"/>. The default is
|
||||
/// <see cref="Orientation.Horizontal"/>.
|
||||
/// </summary>
|
||||
public Orientation Orientation { get; set; } = Orientation.Horizontal;
|
||||
|
||||
public bool StatusBarStyle { get; set; } = true;
|
||||
|
||||
public override void Add (View view)
|
||||
{
|
||||
if (Orientation == Orientation.Horizontal)
|
||||
{
|
||||
//view.AutoSize = true;
|
||||
}
|
||||
|
||||
//if (StatusBarStyle)
|
||||
//{
|
||||
// // Light up right border
|
||||
// view.BorderStyle = LineStyle.Single;
|
||||
// view.Border.Thickness = new Thickness (0, 0, 1, 0);
|
||||
//}
|
||||
|
||||
//if (view is not Shortcut)
|
||||
//{
|
||||
// if (StatusBarStyle)
|
||||
// {
|
||||
// view.Padding.Thickness = new Thickness (0, 0, 1, 0);
|
||||
// }
|
||||
|
||||
// view.Margin.Thickness = new Thickness (1, 0, 0, 0);
|
||||
//}
|
||||
|
||||
//view.ColorScheme = ColorScheme;
|
||||
|
||||
// Add any HotKey keybindings to our bindings
|
||||
IEnumerable<KeyValuePair<Key, KeyBinding>> bindings = view.KeyBindings.Bindings.Where (b => b.Value.Scope == KeyBindingScope.HotKey);
|
||||
|
||||
foreach (KeyValuePair<Key, KeyBinding> binding in bindings)
|
||||
{
|
||||
AddCommand (
|
||||
binding.Value.Commands [0],
|
||||
() =>
|
||||
{
|
||||
if (view is Shortcut shortcut)
|
||||
{
|
||||
return shortcut.CommandView.InvokeCommands (binding.Value.Commands);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
KeyBindings.Add (binding.Key, binding.Value);
|
||||
}
|
||||
|
||||
base.Add (view);
|
||||
}
|
||||
|
||||
private void Bar_LayoutStarted (object sender, LayoutEventArgs e)
|
||||
{
|
||||
View prevBarItem = null;
|
||||
|
||||
switch (Orientation)
|
||||
{
|
||||
case Orientation.Horizontal:
|
||||
for (var index = 0; index < Subviews.Count; index++)
|
||||
{
|
||||
View barItem = Subviews [index];
|
||||
|
||||
if (!barItem.Visible)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prevBarItem == null)
|
||||
{
|
||||
barItem.X = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make view to right be autosize
|
||||
//Subviews [^1].AutoSize = true;
|
||||
|
||||
// Align the view to the right of the previous view
|
||||
barItem.X = Pos.Right (prevBarItem);
|
||||
}
|
||||
|
||||
barItem.Y = Pos.Center ();
|
||||
barItem.SetRelativeLayout (new Size (int.MaxValue, int.MaxValue));
|
||||
prevBarItem = barItem;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Orientation.Vertical:
|
||||
// CommandView is aligned left, HelpView is aligned right, KeyView is aligned right
|
||||
// All CommandView's are the same width, all HelpView's are the same width,
|
||||
// all KeyView's are the same width
|
||||
|
||||
int maxCommandWidth = 0;
|
||||
int maxHelpWidth = 0;
|
||||
|
||||
List<Shortcut> shortcuts = Subviews.Where (s => s is Shortcut && s.Visible).Cast<Shortcut> ().ToList ();
|
||||
|
||||
foreach (Shortcut shortcut in shortcuts)
|
||||
{
|
||||
// Let AutoSize do its thing to get the minimum width of each CommandView and HelpView
|
||||
shortcut.CommandView.SetRelativeLayout (new Size (int.MaxValue, int.MaxValue));
|
||||
shortcut.KeyView.SetRelativeLayout (new Size (int.MaxValue, int.MaxValue));
|
||||
shortcut.HelpView.SetRelativeLayout (new Size (int.MaxValue, int.MaxValue));
|
||||
}
|
||||
|
||||
maxCommandWidth = shortcuts.Max (s => s.CommandView.Frame.Width);
|
||||
maxHelpWidth = shortcuts.Max (s => s.HelpView.Frame.Width);
|
||||
|
||||
// Set the width of all CommandView's and HelpView's to the max width
|
||||
foreach (Shortcut shortcut in shortcuts)
|
||||
{
|
||||
shortcut.CommandView.Width = Dim.Auto (minimumContentDim: maxCommandWidth);
|
||||
shortcut.KeyView.Width = Dim.Auto ();
|
||||
shortcut.HelpView.Width = Dim.Auto (minimumContentDim: maxHelpWidth);
|
||||
|
||||
// shortcut.LayoutSubviews ();
|
||||
}
|
||||
|
||||
// Set the overall size of the Bar and arrange the views vertically
|
||||
|
||||
var maxBarItemWidth = 0;
|
||||
|
||||
for (var index = 0; index < Subviews.Count; index++)
|
||||
{
|
||||
View barItem = Subviews [index];
|
||||
|
||||
if (!barItem.Visible)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prevBarItem == null)
|
||||
{
|
||||
barItem.Y = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Align the view to the bottom of the previous view
|
||||
barItem.Y = index;
|
||||
}
|
||||
|
||||
prevBarItem = barItem;
|
||||
|
||||
if (barItem is Shortcut shortcut)
|
||||
{
|
||||
//shortcut.SetRelativeLayout (new (int.MaxValue, int.MaxValue));
|
||||
maxBarItemWidth = Math.Max (maxBarItemWidth, shortcut.Frame.Width);
|
||||
}
|
||||
else
|
||||
{
|
||||
maxBarItemWidth = Math.Max (maxBarItemWidth, barItem.Frame.Width);
|
||||
}
|
||||
|
||||
barItem.X = 0;
|
||||
}
|
||||
|
||||
foreach (Shortcut shortcut in shortcuts)
|
||||
{
|
||||
if (Width is DimAuto)
|
||||
{
|
||||
shortcut.Width = Dim.Auto (DimAutoStyle.Content, minimumContentDim: maxBarItemWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
//shortcut._container.Width = Dim.Fill ();
|
||||
// shortcut.Width = Dim.Fill ();
|
||||
}
|
||||
|
||||
shortcut.LayoutSubviews ();
|
||||
}
|
||||
|
||||
|
||||
//for (var index = 0; index < Subviews.Count; index++)
|
||||
//{
|
||||
// var shortcut = Subviews [index] as Shortcut;
|
||||
|
||||
// if (shortcut is { Visible: false })
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// if (Width is DimAuto)
|
||||
// {
|
||||
// shortcut._container.Width = Dim.Auto (DimAutoStyle.Content, minimumContentDim: maxBarItemWidth);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// shortcut._container.Width = Dim.Fill ();
|
||||
// shortcut.Width = Dim.Fill ();
|
||||
// }
|
||||
|
||||
// //shortcut.SetContentSize (new (maxBarItemWidth, 1));
|
||||
// //shortcut.Width = Dim.Auto (DimAutoStyle.Content, minimumContentDim: int.Max(maxBarItemWidth, GetContentSize().Width));
|
||||
|
||||
//}
|
||||
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetInitialProperties ()
|
||||
{
|
||||
ColorScheme = Colors.ColorSchemes ["Menu"];
|
||||
CanFocus = true;
|
||||
|
||||
Width = Dim.Auto ();
|
||||
Height = Dim.Auto ();
|
||||
|
||||
LayoutStarted += Bar_LayoutStarted;
|
||||
}
|
||||
}
|
||||
@@ -1,529 +0,0 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Terminal.Gui;
|
||||
|
||||
// TODO: I don't love the name Shortcut, but I can't think of a better one right now. Shortcut is a bit overloaded.
|
||||
// TODO: It can mean "Application-scoped key binding" or "A key binding that is displayed in a visual way".
|
||||
// TODO: I tried `BarItem` but that's not great either as it implies it can only be used in `Bar`s.
|
||||
|
||||
/// <summary>
|
||||
/// Displays a command, help text, and a key binding. Useful for displaying a command in <see cref="Bar"/> such as a
|
||||
/// menu, toolbar, or status bar.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// When the user clicks on the <see cref="Shortcut"/> or presses the key
|
||||
/// specified by <see cref="Key"/> the <see cref="Command.Accept"/> command is invoked, causing the
|
||||
/// <see cref="Accept"/> event to be fired
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If <see cref="KeyBindingScope"/> is <see cref="KeyBindingScope.Application"/>, the <see cref="Command"/>
|
||||
/// be invoked regardless of what View has focus, enabling an application-wide keyboard shortcut.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Set <see cref="View.Title"/> to change the Command text displayed in the <see cref="Shortcut"/>.
|
||||
/// By default, the <see cref="Command"/> text is the <see cref="View.Title"/> of <see cref="CommandView"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Set <see cref="View.Text"/> to change the Help text displayed in the <see cref="Shortcut"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The text displayed for the <see cref="Key"/> is the string representation of the <see cref="Key"/>.
|
||||
/// If the <see cref="Key"/> is <see cref="Key.Empty"/>, the <see cref="Key"/> text is not displayed.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class Shortcut : View
|
||||
{
|
||||
// Hosts the Command, Help, and Key Views. Needed (IIRC - wrote a long time ago) to allow mouse clicks to be handled by the Shortcut.
|
||||
internal readonly View _container;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="Shortcut"/>.
|
||||
/// </summary>
|
||||
public Shortcut ()
|
||||
{
|
||||
CanFocus = true;
|
||||
Width = Dim.Auto (DimAutoStyle.Content);
|
||||
Height = Dim.Auto (DimAutoStyle.Content);
|
||||
|
||||
//Height = Dim.Auto (minimumContentDim: 1, maximumContentDim: 1);
|
||||
|
||||
AddCommand (Gui.Command.HotKey, () => true);
|
||||
AddCommand (Gui.Command.Accept, OnAccept);
|
||||
KeyBindings.Add (KeyCode.Space, Gui.Command.Accept);
|
||||
KeyBindings.Add (KeyCode.Enter, Gui.Command.Accept);
|
||||
|
||||
_container = new ()
|
||||
{
|
||||
Id = "_container",
|
||||
// Only the Shortcut (_container) should be able to have focus, not any subviews.
|
||||
CanFocus = true,
|
||||
Width = Dim.Auto (DimAutoStyle.Content, 1),
|
||||
Height = Dim.Auto (DimAutoStyle.Content, 1),
|
||||
BorderStyle = LineStyle.Dashed
|
||||
};
|
||||
|
||||
CommandView = new ();
|
||||
|
||||
HelpView = new ()
|
||||
{
|
||||
Id = "_helpView",
|
||||
// Only the Shortcut should be able to have focus, not any subviews
|
||||
CanFocus = false,
|
||||
X = Pos.Align (Alignment.End, AlignmentModes.IgnoreFirstOrLast | AlignmentModes.AddSpaceBetweenItems),
|
||||
Y = Pos.Center (),
|
||||
|
||||
// Helpview is the only subview that doesn't have a min width
|
||||
Width = Dim.Auto (DimAutoStyle.Text),
|
||||
Height = Dim.Auto (DimAutoStyle.Text),
|
||||
ColorScheme = Colors.ColorSchemes ["Error"]
|
||||
};
|
||||
_container.Add (HelpView);
|
||||
|
||||
// HelpView.TextAlignment = Alignment.End;
|
||||
HelpView.MouseClick += Shortcut_MouseClick;
|
||||
|
||||
KeyView = new ()
|
||||
{
|
||||
Id = "_keyView",
|
||||
// Only the Shortcut should be able to have focus, not any subviews
|
||||
CanFocus = false,
|
||||
X = Pos.Align (Alignment.End, AlignmentModes.IgnoreFirstOrLast | AlignmentModes.AddSpaceBetweenItems),
|
||||
Y = Pos.Center (),
|
||||
|
||||
// Bar will set the width of all KeyViews to the width of the widest KeyView.
|
||||
Width = Dim.Auto (DimAutoStyle.Text),
|
||||
Height = Dim.Auto (DimAutoStyle.Text),
|
||||
};
|
||||
_container.Add (KeyView);
|
||||
|
||||
KeyView.MouseClick += Shortcut_MouseClick;
|
||||
|
||||
CommandView.Margin.Thickness = new Thickness (1, 0, 1, 0);
|
||||
HelpView.Margin.Thickness = new Thickness (1, 0, 1, 0);
|
||||
KeyView.Margin.Thickness = new Thickness (1, 0, 1, 0);
|
||||
|
||||
MouseClick += Shortcut_MouseClick;
|
||||
|
||||
TitleChanged += Shortcut_TitleChanged;
|
||||
Initialized += OnInitialized;
|
||||
|
||||
Add (_container);
|
||||
|
||||
return;
|
||||
|
||||
void OnInitialized (object sender, EventArgs e)
|
||||
{
|
||||
if (ColorScheme != null)
|
||||
{
|
||||
var cs = new ColorScheme (ColorScheme)
|
||||
{
|
||||
Normal = ColorScheme.HotNormal,
|
||||
HotNormal = ColorScheme.Normal
|
||||
};
|
||||
KeyView.ColorScheme = cs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Shortcut_MouseClick (object sender, MouseEventEventArgs e)
|
||||
{
|
||||
// When the Shortcut is clicked, we want to invoke the Command and Set focus
|
||||
View view = sender as View;
|
||||
if (!e.Handled && Command.HasValue)
|
||||
{
|
||||
// If the subview (likely CommandView) didn't handle the mouse click, invoke the command.
|
||||
bool? handled = false;
|
||||
handled = InvokeCommand (Command.Value);
|
||||
if (handled.HasValue)
|
||||
{
|
||||
e.Handled = handled.Value;
|
||||
}
|
||||
}
|
||||
if (CanFocus)
|
||||
{
|
||||
SetFocus ();
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override ColorScheme ColorScheme
|
||||
{
|
||||
get
|
||||
{
|
||||
if (base.ColorScheme == null)
|
||||
{
|
||||
return SuperView?.ColorScheme ?? base.ColorScheme;
|
||||
}
|
||||
|
||||
return base.ColorScheme;
|
||||
}
|
||||
set
|
||||
{
|
||||
base.ColorScheme = value;
|
||||
|
||||
if (ColorScheme != null)
|
||||
{
|
||||
var cs = new ColorScheme (ColorScheme)
|
||||
{
|
||||
Normal = ColorScheme.HotNormal,
|
||||
HotNormal = ColorScheme.Normal
|
||||
};
|
||||
KeyView.ColorScheme = cs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Command
|
||||
|
||||
private Command? _command;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="Command"/> that will be invoked when the user clicks on the <see cref="Shortcut"/> or
|
||||
/// presses <see cref="Key"/>.
|
||||
/// </summary>
|
||||
public Command? Command
|
||||
{
|
||||
get => _command;
|
||||
set
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
_command = value.Value;
|
||||
UpdateKeyBinding ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private View _commandView;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the View that displays the command text and hotkey.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// By default, the <see cref="View.Title"/> of the <see cref="CommandView"/> is displayed as the Shortcut's
|
||||
/// command text.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// By default, the CommandView is a <see cref="View"/> with <see cref="View.CanFocus"/> set to
|
||||
/// <see langword="false"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Setting the <see cref="CommandView"/> will add it to the <see cref="Shortcut"/> and remove any existing
|
||||
/// <see cref="CommandView"/>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <para>
|
||||
/// This example illustrates how to add a <see cref="Shortcut"/> to a <see cref="StatusBar"/> that toggles the
|
||||
/// <see cref="Application.Force16Colors"/> property.
|
||||
/// </para>
|
||||
/// <code>
|
||||
/// var force16ColorsShortcut = new Shortcut
|
||||
/// {
|
||||
/// Key = Key.F6,
|
||||
/// KeyBindingScope = KeyBindingScope.HotKey,
|
||||
/// Command = Command.Accept,
|
||||
/// CommandView = new CheckBox { Text = "Force 16 Colors" }
|
||||
/// };
|
||||
/// var cb = force16ColorsShortcut.CommandView as CheckBox;
|
||||
/// cb.Checked = Application.Force16Colors;
|
||||
///
|
||||
/// cb.Toggled += (s, e) =>
|
||||
/// {
|
||||
/// var cb = s as CheckBox;
|
||||
/// Application.Force16Colors = cb!.Checked == true;
|
||||
/// Application.Refresh();
|
||||
/// };
|
||||
/// StatusBar.Add(force16ColorsShortcut);
|
||||
/// </code>
|
||||
/// </example>
|
||||
|
||||
public View CommandView
|
||||
{
|
||||
get => _commandView;
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException ();
|
||||
}
|
||||
|
||||
if (_commandView is { })
|
||||
{
|
||||
_container.Remove (_commandView);
|
||||
_commandView?.Dispose ();
|
||||
}
|
||||
|
||||
|
||||
_commandView = value;
|
||||
_commandView.Id = "_commandView";
|
||||
|
||||
// TODO: Determine if it makes sense to allow the CommandView to be focusable.
|
||||
// Right now, we don't set CanFocus to false here.
|
||||
_commandView.CanFocus = false;
|
||||
|
||||
// Bar will set the width of all CommandViews to the width of the widest CommandViews.
|
||||
_commandView.Width = Dim.Auto (DimAutoStyle.Text);
|
||||
_commandView.Height = Dim.Auto (DimAutoStyle.Text);
|
||||
_commandView.X = X = Pos.Align (Alignment.End, AlignmentModes.IgnoreFirstOrLast | AlignmentModes.AddSpaceBetweenItems);
|
||||
_commandView.Y = Pos.Center ();
|
||||
|
||||
_commandView.MouseClick += Shortcut_MouseClick;
|
||||
_commandView.Accept += CommandView_Accept;
|
||||
|
||||
_commandView.Margin.Thickness = new (1, 0, 1, 0);
|
||||
|
||||
_commandView.HotKeyChanged += (s, e) =>
|
||||
{
|
||||
if (e.NewKey != Key.Empty)
|
||||
{
|
||||
// Add it
|
||||
AddKeyBindingsForHotKey (e.OldKey, e.NewKey);
|
||||
}
|
||||
};
|
||||
|
||||
_commandView.HotKeySpecifier = new ('_');
|
||||
|
||||
_container.Remove (HelpView);
|
||||
_container.Remove (KeyView);
|
||||
_container.Add (_commandView, HelpView, KeyView);
|
||||
|
||||
UpdateKeyBinding();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void _commandView_MouseEvent (object sender, MouseEventEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void Shortcut_TitleChanged (object sender, StateEventArgs<string> e)
|
||||
{
|
||||
// If the Title changes, update the CommandView text. This is a helper to make it easier to set the CommandView text.
|
||||
// CommandView is public and replaceable, but this is a convenience.
|
||||
_commandView.Text = Title;
|
||||
}
|
||||
|
||||
private void CommandView_Accept (object sender, CancelEventArgs e)
|
||||
{
|
||||
// When the CommandView fires its Accept event, we want to act as though the
|
||||
// Shortcut was clicked.
|
||||
var args = new HandledEventArgs ();
|
||||
Accept?.Invoke (this, args);
|
||||
|
||||
if (args.Handled)
|
||||
{
|
||||
e.Cancel = args.Handled;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Command
|
||||
|
||||
#region Help
|
||||
|
||||
/// <summary>
|
||||
/// The subview that displays the help text for the command. Internal for unit testing.
|
||||
/// </summary>
|
||||
internal View HelpView { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the help text displayed in the middle of the Shortcut.
|
||||
/// </summary>
|
||||
public override string Text
|
||||
{
|
||||
get => base.Text;
|
||||
set
|
||||
{
|
||||
//base.Text = value;
|
||||
if (HelpView != null)
|
||||
{
|
||||
HelpView.Text = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Help
|
||||
|
||||
#region Key
|
||||
|
||||
private Key _key;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="Key"/> that will be bound to the <see cref="Command.Accept"/> command.
|
||||
/// </summary>
|
||||
public Key Key
|
||||
{
|
||||
get => _key;
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException ();
|
||||
}
|
||||
|
||||
_key = value;
|
||||
|
||||
if (Command != null)
|
||||
{
|
||||
UpdateKeyBinding ();
|
||||
}
|
||||
|
||||
KeyView.Text = $"{Key}";
|
||||
KeyView.Visible = Key != Key.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private KeyBindingScope _keyBindingScope;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the scope for the key binding for how <see cref="Key"/> is bound to <see cref="Command"/>.
|
||||
/// </summary>
|
||||
public KeyBindingScope KeyBindingScope
|
||||
{
|
||||
get => _keyBindingScope;
|
||||
set
|
||||
{
|
||||
_keyBindingScope = value;
|
||||
|
||||
if (Command != null)
|
||||
{
|
||||
UpdateKeyBinding ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the subview that displays the key. Internal for unit testing.
|
||||
/// </summary>
|
||||
|
||||
internal View KeyView { get; }
|
||||
|
||||
private void UpdateKeyBinding ()
|
||||
{
|
||||
if (KeyBindingScope == KeyBindingScope.Application)
|
||||
{
|
||||
// return;
|
||||
}
|
||||
|
||||
if (Command != null && Key != null && Key != Key.Empty)
|
||||
{
|
||||
// CommandView holds our command/keybinding
|
||||
// Add a key binding for this command to this Shortcut
|
||||
if (CommandView.GetSupportedCommands ().Contains (Command.Value))
|
||||
{
|
||||
CommandView.KeyBindings.Remove (Key);
|
||||
CommandView.KeyBindings.Add (Key, KeyBindingScope, Command.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// throw new InvalidOperationException ($"CommandView does not support the command {Command.Value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Key
|
||||
|
||||
/// <summary>
|
||||
/// The event fired when the <see cref="Command.Accept"/> command is received. This
|
||||
/// occurs if the user clicks on the Shortcut or presses <see cref="Key"/>.
|
||||
/// </summary>
|
||||
public new event EventHandler<HandledEventArgs> Accept;
|
||||
|
||||
/// <summary>
|
||||
/// Called when the <see cref="Command.Accept"/> command is received. This
|
||||
/// occurs if the user clicks on the Bar with the mouse or presses the key bound to
|
||||
/// Command.Accept (Space by default).
|
||||
/// </summary>
|
||||
protected new bool? OnAccept ()
|
||||
{
|
||||
// TODO: This is not completely thought through.
|
||||
|
||||
|
||||
|
||||
if (Key == null || Key == Key.Empty)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var handled = false;
|
||||
var keyCopy = new Key (Key);
|
||||
|
||||
switch (KeyBindingScope)
|
||||
{
|
||||
case KeyBindingScope.Application:
|
||||
// Simulate a key down to invoke the Application scoped key binding
|
||||
handled = Application.OnKeyDown (keyCopy);
|
||||
|
||||
break;
|
||||
case KeyBindingScope.Focused:
|
||||
handled = InvokeCommand (Command.Value) == true;
|
||||
handled = false;
|
||||
|
||||
break;
|
||||
case KeyBindingScope.HotKey:
|
||||
if (Command.HasValue)
|
||||
{
|
||||
//handled = _commandView.InvokeCommand (Gui.Command.HotKey) == true;
|
||||
//handled = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//if (handled == false)
|
||||
{
|
||||
var args = new HandledEventArgs ();
|
||||
Accept?.Invoke (this, args);
|
||||
handled = args.Handled;
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool OnEnter (View view)
|
||||
{
|
||||
// TODO: This is a hack. Need to refine this.
|
||||
var cs = new ColorScheme (ColorScheme)
|
||||
{
|
||||
Normal = ColorScheme.Focus,
|
||||
HotNormal = ColorScheme.HotFocus
|
||||
};
|
||||
|
||||
_container.ColorScheme = cs;
|
||||
|
||||
cs = new (ColorScheme)
|
||||
{
|
||||
Normal = ColorScheme.HotFocus,
|
||||
HotNormal = ColorScheme.Focus
|
||||
};
|
||||
KeyView.ColorScheme = cs;
|
||||
|
||||
return base.OnEnter (view);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool OnLeave (View view)
|
||||
{
|
||||
// TODO: This is a hack. Need to refine this.
|
||||
var cs = new ColorScheme (ColorScheme)
|
||||
{
|
||||
Normal = ColorScheme.Normal,
|
||||
HotNormal = ColorScheme.HotNormal
|
||||
};
|
||||
|
||||
_container.ColorScheme = cs;
|
||||
|
||||
cs = new (ColorScheme)
|
||||
{
|
||||
Normal = ColorScheme.HotNormal,
|
||||
HotNormal = ColorScheme.Normal
|
||||
};
|
||||
KeyView.ColorScheme = cs;
|
||||
|
||||
return base.OnLeave (view);
|
||||
}
|
||||
}
|
||||
@@ -1,489 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Terminal.Gui;
|
||||
|
||||
namespace UICatalog.Scenarios;
|
||||
|
||||
[ScenarioMetadata ("Bars", "Illustrates Bar views (e.g. StatusBar)")]
|
||||
[ScenarioCategory ("Controls")]
|
||||
public class Bars : Scenario
|
||||
{
|
||||
public override void Main ()
|
||||
{
|
||||
Application.Init ();
|
||||
Window app = new ();
|
||||
|
||||
app.Loaded += App_Loaded;
|
||||
|
||||
Application.Run (app);
|
||||
app.Dispose ();
|
||||
Application.Shutdown ();
|
||||
}
|
||||
|
||||
|
||||
// Setting everything up in Loaded handler because we change the
|
||||
// QuitKey and it only sticks if changed after init
|
||||
private void App_Loaded (object sender, EventArgs e)
|
||||
{
|
||||
Application.QuitKey = Key.Z.WithCtrl;
|
||||
Application.Top.Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}";
|
||||
|
||||
List<string> eventSource = new ();
|
||||
ListView eventLog = new ListView ()
|
||||
{
|
||||
X = Pos.AnchorEnd (),
|
||||
Width = 50,
|
||||
Height = Dim.Fill (),
|
||||
ColorScheme = Colors.ColorSchemes ["Toplevel"],
|
||||
Source = new ListWrapper (eventSource)
|
||||
};
|
||||
Application.Top.Add (eventLog);
|
||||
|
||||
var shortcut1 = new Shortcut
|
||||
{
|
||||
Title = "_Zigzag",
|
||||
Key = Key.Z.WithAlt,
|
||||
Text = "Gonna zig zag",
|
||||
KeyBindingScope = KeyBindingScope.HotKey,
|
||||
Command = Command.Accept,
|
||||
};
|
||||
shortcut1.Accept += (s, e) =>
|
||||
{
|
||||
eventSource.Add ($"Accept: {s}");
|
||||
eventLog.MoveDown ();
|
||||
};
|
||||
Application.Top.Add (shortcut1);
|
||||
shortcut1.SetFocus ();
|
||||
|
||||
//var shortcut2 = new Shortcut
|
||||
//{
|
||||
// Title = "Za_G",
|
||||
// Text = "Gonna zag",
|
||||
// Key = Key.G.WithAlt,
|
||||
// KeyBindingScope = KeyBindingScope.HotKey,
|
||||
// Command = Command.Accept,
|
||||
// X = Pos.Left (shortcut1),
|
||||
// Y = Pos.Bottom (shortcut1),
|
||||
// //Width = 50,
|
||||
//};
|
||||
|
||||
|
||||
//var shortcut3 = new Shortcut
|
||||
//{
|
||||
// Title = "Shortcut3",
|
||||
// Key = Key.D3.WithCtrl,
|
||||
// Text = "Number Three",
|
||||
// KeyBindingScope = KeyBindingScope.Application,
|
||||
// Command = Command.Accept,
|
||||
//};
|
||||
|
||||
//shortcut3.Accept += (s, e) =>
|
||||
// {
|
||||
// eventSource.Add ($"Accept: {s}");
|
||||
// eventLog.MoveDown ();
|
||||
// };
|
||||
|
||||
//var shortcut4 = new Shortcut
|
||||
//{
|
||||
// Title = "Shortcut4",
|
||||
// Text = "Number 4",
|
||||
// Key = Key.F4,
|
||||
// KeyBindingScope = KeyBindingScope.Application,
|
||||
// Command = Command.Accept,
|
||||
//};
|
||||
|
||||
//var cb = new CheckBox ()
|
||||
//{
|
||||
// Title = "Hello",// shortcut4.Text
|
||||
//};
|
||||
|
||||
//cb.Toggled += (s, e) =>
|
||||
// {
|
||||
// eventSource.Add ($"Toggled: {s}");
|
||||
// eventLog.MoveDown ();
|
||||
// };
|
||||
|
||||
//shortcut4.CommandView = cb;
|
||||
|
||||
//shortcut4.Accept += (s, e) =>
|
||||
// {
|
||||
// eventSource.Add ($"Accept: {s}");
|
||||
// eventLog.MoveDown ();
|
||||
// };
|
||||
|
||||
//var bar = new Bar
|
||||
//{
|
||||
// X = 2,
|
||||
// Y = Pos.Bottom(shortcut1),
|
||||
// Orientation = Orientation.Vertical,
|
||||
// StatusBarStyle = false,
|
||||
// Width = Dim.Percent(40)
|
||||
//};
|
||||
//bar.Add (shortcut3, shortcut4);
|
||||
|
||||
////CheckBox hello = new ()
|
||||
////{
|
||||
//// Title = "Hello",
|
||||
//// X = 0,
|
||||
//// Y = 1,
|
||||
////};
|
||||
////Application.Top.Add (hello);
|
||||
////hello.Toggled += (s, e) =>
|
||||
//// {
|
||||
//// eventSource.Add ($"Toggled: {s}");
|
||||
//// eventLog.MoveDown ();
|
||||
//// };
|
||||
|
||||
//Application.Top.Add (bar);
|
||||
|
||||
// BUGBUG: This should not be needed
|
||||
//Application.Top.LayoutSubviews ();
|
||||
|
||||
//SetupMenuBar ();
|
||||
//SetupContentMenu ();
|
||||
// SetupStatusBar ();
|
||||
}
|
||||
|
||||
private void Button_Clicked (object sender, EventArgs e) { MessageBox.Query ("Hi", $"You clicked {sender}"); }
|
||||
|
||||
//private void SetupContentMenu ()
|
||||
//{
|
||||
// Application.Top.Add (new Label { Text = "Right Click for Context Menu", X = Pos.Center (), Y = 4 });
|
||||
// Application.Top.MouseClick += ShowContextMenu;
|
||||
//}
|
||||
|
||||
//private void ShowContextMenu (object s, MouseEventEventArgs e)
|
||||
//{
|
||||
// if (e.MouseEvent.Flags != MouseFlags.Button3Clicked)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// var contextMenu = new Bar
|
||||
// {
|
||||
// Id = "contextMenu",
|
||||
// X = e.MouseEvent.Position.X,
|
||||
// Y = e.MouseEvent.Position.Y,
|
||||
// Width = Dim.Auto (DimAutoStyle.Content),
|
||||
// Height = Dim.Auto (DimAutoStyle.Content),
|
||||
// Orientation = Orientation.Vertical,
|
||||
// StatusBarStyle = false,
|
||||
// BorderStyle = LineStyle.Rounded,
|
||||
// Modal = true,
|
||||
// };
|
||||
|
||||
// var newMenu = new Shortcut
|
||||
// {
|
||||
// Title = "_New...",
|
||||
// Text = "Create a new file",
|
||||
// Key = Key.N.WithCtrl,
|
||||
// CanFocus = true
|
||||
// };
|
||||
|
||||
// newMenu.Accept += (s, e) =>
|
||||
// {
|
||||
// contextMenu.RequestStop ();
|
||||
|
||||
// Application.AddTimeout (
|
||||
// new TimeSpan (0),
|
||||
// () =>
|
||||
// {
|
||||
// MessageBox.Query ("File", "New");
|
||||
|
||||
// return false;
|
||||
// });
|
||||
// };
|
||||
|
||||
// var open = new Shortcut
|
||||
// {
|
||||
// Title = "_Open...",
|
||||
// Text = "Show the File Open Dialog",
|
||||
// Key = Key.O.WithCtrl,
|
||||
// CanFocus = true
|
||||
// };
|
||||
|
||||
// open.Accept += (s, e) =>
|
||||
// {
|
||||
// contextMenu.RequestStop ();
|
||||
|
||||
// Application.AddTimeout (
|
||||
// new TimeSpan (0),
|
||||
// () =>
|
||||
// {
|
||||
// MessageBox.Query ("File", "Open");
|
||||
|
||||
// return false;
|
||||
// });
|
||||
// };
|
||||
|
||||
// var save = new Shortcut
|
||||
// {
|
||||
// Title = "_Save...",
|
||||
// Text = "Save",
|
||||
// Key = Key.S.WithCtrl,
|
||||
// CanFocus = true
|
||||
// };
|
||||
|
||||
// save.Accept += (s, e) =>
|
||||
// {
|
||||
// contextMenu.RequestStop ();
|
||||
|
||||
// Application.AddTimeout (
|
||||
// new TimeSpan (0),
|
||||
// () =>
|
||||
// {
|
||||
// MessageBox.Query ("File", "Save");
|
||||
|
||||
// return false;
|
||||
// });
|
||||
// };
|
||||
|
||||
// var saveAs = new Shortcut
|
||||
// {
|
||||
// Title = "Save _As...",
|
||||
// Text = "Save As",
|
||||
// Key = Key.A.WithCtrl,
|
||||
// CanFocus = true
|
||||
// };
|
||||
|
||||
// saveAs.Accept += (s, e) =>
|
||||
// {
|
||||
// contextMenu.RequestStop ();
|
||||
|
||||
// Application.AddTimeout (
|
||||
// new TimeSpan (0),
|
||||
// () =>
|
||||
// {
|
||||
// MessageBox.Query ("File", "Save As");
|
||||
|
||||
// return false;
|
||||
// });
|
||||
// };
|
||||
|
||||
// contextMenu.Add (newMenu, open, save, saveAs);
|
||||
|
||||
// contextMenu.KeyBindings.Add (Key.Esc, Command.QuitToplevel);
|
||||
|
||||
// contextMenu.Initialized += Menu_Initialized;
|
||||
|
||||
// void Application_MouseEvent (object sender, MouseEvent e)
|
||||
// {
|
||||
// // If user clicks outside of the menuWindow, close it
|
||||
// if (!contextMenu.Frame.Contains (e.Position.X, e.Position.Y))
|
||||
// {
|
||||
// if (e.Flags is (MouseFlags.Button1Clicked or MouseFlags.Button3Clicked))
|
||||
// {
|
||||
// contextMenu.RequestStop ();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// Application.MouseEvent += Application_MouseEvent;
|
||||
|
||||
// Application.Run (contextMenu);
|
||||
// contextMenu.Dispose ();
|
||||
|
||||
// Application.MouseEvent -= Application_MouseEvent;
|
||||
//}
|
||||
|
||||
private void Menu_Initialized (object sender, EventArgs e)
|
||||
{
|
||||
// BUGBUG: this should not be needed
|
||||
|
||||
((View)(sender)).LayoutSubviews ();
|
||||
}
|
||||
|
||||
//private void SetupMenuBar ()
|
||||
//{
|
||||
// var menuBar = new Bar
|
||||
// {
|
||||
// Id = "menuBar",
|
||||
|
||||
// X = 0,
|
||||
// Y = 0,
|
||||
// Width = Dim.Fill (),
|
||||
// Height = Dim.Auto (DimAutoStyle.Content),
|
||||
// StatusBarStyle = true
|
||||
// };
|
||||
|
||||
// var fileMenu = new Shortcut
|
||||
// {
|
||||
// Title = "_File",
|
||||
// Key = Key.F.WithAlt,
|
||||
// KeyBindingScope = KeyBindingScope.HotKey,
|
||||
// Command = Command.Accept,
|
||||
// };
|
||||
// fileMenu.HelpView.Visible = false;
|
||||
// fileMenu.KeyView.Visible = false;
|
||||
|
||||
// fileMenu.Accept += (s, e) =>
|
||||
// {
|
||||
// fileMenu.SetFocus ();
|
||||
|
||||
// if (s is View view)
|
||||
// {
|
||||
// var menu = new Bar
|
||||
// {
|
||||
// X = view.Frame.X + 1,
|
||||
// Y = view.Frame.Y + 1,
|
||||
// ColorScheme = view.ColorScheme,
|
||||
// Orientation = Orientation.Vertical,
|
||||
// StatusBarStyle = false,
|
||||
// BorderStyle = LineStyle.Dotted,
|
||||
// Width = Dim.Auto (DimAutoStyle.Content),
|
||||
// Height = Dim.Auto (DimAutoStyle.Content),
|
||||
// };
|
||||
|
||||
// menu.KeyBindings.Add (Key.Esc, Command.QuitToplevel);
|
||||
|
||||
// var newMenu = new Shortcut
|
||||
// {
|
||||
// Title = "_New...",
|
||||
// Text = "Create a new file",
|
||||
// Key = Key.N.WithCtrl
|
||||
// };
|
||||
|
||||
// var open = new Shortcut
|
||||
// {
|
||||
// Title = "_Open...",
|
||||
// Text = "Show the File Open Dialog",
|
||||
// Key = Key.O.WithCtrl
|
||||
// };
|
||||
|
||||
// var save = new Shortcut
|
||||
// {
|
||||
// Title = "_Save...",
|
||||
// Text = "Save",
|
||||
// Key = Key.S.WithCtrl
|
||||
// };
|
||||
|
||||
// menu.Add (newMenu, open, save);
|
||||
|
||||
// // BUGBUG: this is all bad
|
||||
// menu.Initialized += Menu_Initialized;
|
||||
// open.Initialized += Menu_Initialized;
|
||||
// save.Initialized += Menu_Initialized;
|
||||
// newMenu.Initialized += Menu_Initialized;
|
||||
|
||||
// Application.Run (menu);
|
||||
// menu.Dispose ();
|
||||
// Application.Refresh ();
|
||||
// }
|
||||
// };
|
||||
|
||||
// var editMenu = new Shortcut
|
||||
// {
|
||||
// Title = "_Edit",
|
||||
|
||||
// //Key = Key.E.WithAlt,
|
||||
// KeyBindingScope = KeyBindingScope.HotKey,
|
||||
// Command = Command.Accept
|
||||
// };
|
||||
|
||||
// editMenu.Accept += (s, e) => { };
|
||||
// editMenu.HelpView.Visible = false;
|
||||
// editMenu.KeyView.Visible = false;
|
||||
|
||||
// menuBar.Add (fileMenu, editMenu);
|
||||
|
||||
// menuBar.Initialized += Menu_Initialized;
|
||||
|
||||
// Application.Top.Add (menuBar);
|
||||
//}
|
||||
|
||||
private void SetupStatusBar ()
|
||||
{
|
||||
var statusBar = new Bar
|
||||
{
|
||||
Id = "statusBar",
|
||||
X = 0,
|
||||
Y = Pos.AnchorEnd (),
|
||||
Width = Dim.Fill (),
|
||||
};
|
||||
|
||||
var shortcut = new Shortcut
|
||||
{
|
||||
Text = "Quit Application",
|
||||
Title = "Q_uit",
|
||||
Key = Application.QuitKey,
|
||||
KeyBindingScope = KeyBindingScope.Application,
|
||||
Command = Command.QuitToplevel,
|
||||
CanFocus = false
|
||||
};
|
||||
|
||||
statusBar.Add (shortcut);
|
||||
|
||||
shortcut = new Shortcut
|
||||
{
|
||||
Text = "Help Text",
|
||||
Title = "Help",
|
||||
Key = Key.F1,
|
||||
KeyBindingScope = KeyBindingScope.HotKey,
|
||||
Command = Command.Accept,
|
||||
CanFocus = false
|
||||
};
|
||||
|
||||
var labelHelp = new Label
|
||||
{
|
||||
X = Pos.Center (),
|
||||
Y = Pos.Top (statusBar) - 1,
|
||||
Text = "Help"
|
||||
};
|
||||
Application.Top.Add (labelHelp);
|
||||
|
||||
shortcut.Accept += (s, e) =>
|
||||
{
|
||||
labelHelp.Text = labelHelp.Text + "!";
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
statusBar.Add (shortcut);
|
||||
|
||||
shortcut = new Shortcut
|
||||
{
|
||||
Title = "_Show/Hide",
|
||||
Key = Key.F10,
|
||||
KeyBindingScope = KeyBindingScope.HotKey,
|
||||
Command = Command.ToggleExpandCollapse,
|
||||
CommandView = new CheckBox
|
||||
{
|
||||
Text = "_Show/Hide"
|
||||
},
|
||||
CanFocus = false
|
||||
};
|
||||
|
||||
statusBar.Add (shortcut);
|
||||
|
||||
var button1 = new Button
|
||||
{
|
||||
Text = "I'll Hide",
|
||||
Visible = false
|
||||
};
|
||||
button1.Accept += Button_Clicked;
|
||||
statusBar.Add (button1);
|
||||
|
||||
((CheckBox)shortcut.CommandView).Toggled += (s, e) =>
|
||||
{
|
||||
button1.Visible = !button1.Visible;
|
||||
button1.Enabled = button1.Visible;
|
||||
};
|
||||
|
||||
statusBar.Add (new Label { HotKeySpecifier = new Rune ('_'), Text = "Fo_cusLabel", CanFocus = true });
|
||||
|
||||
var button2 = new Button
|
||||
{
|
||||
Text = "Or me!",
|
||||
};
|
||||
button2.Accept += (s, e) => Application.RequestStop ();
|
||||
|
||||
statusBar.Add (button2);
|
||||
|
||||
statusBar.Initialized += Menu_Initialized;
|
||||
|
||||
Application.Top.Add (statusBar);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user