Made Shortcut opinionated based on Orientation

This commit is contained in:
Tig
2024-06-17 11:59:18 -07:00
parent b6d9e6c14d
commit 434a2d453d
5 changed files with 219 additions and 287 deletions

View File

@@ -74,6 +74,7 @@ public partial class View
SuperView._addingView = false;
}
// QUESTION: This automatic behavior of setting CanFocus to true on the SuperView is not documented, and is annoying.
CanFocus = true;
view._tabIndex = _tabIndexes.IndexOf (view);
_addingView = false;

View File

@@ -138,18 +138,10 @@ public class Shortcut : View
/// <summary>
/// Gets or sets the <see cref="Orientation"/> for this <see cref="Shortcut"/>. The default is
/// <see cref="Orientation.Horizontal"/>, which is ideal for status bars and toolbars. If set to
/// <see cref="Orientation.Horizontal"/>, which is ideal for status bar, menu bar, and tool bar items If set to
/// <see cref="Orientation.Vertical"/>,
/// the Shortcut will be configured for vertical layout, which is ideal for menus.
/// the Shortcut will be configured for vertical layout, which is ideal for menu items.
/// </summary>
/// <remarks>
/// <para>
/// When Horizontal, Key is first, then Help, then Command. When Vertical, Command is first, then Help, then Key.
/// </para>
/// <para>
/// Set <see cref="AlignmentModes"/> to override the default layout.
/// </para>
/// </remarks>
public Orientation Orientation
{
get => _orientation;
@@ -157,26 +149,19 @@ public class Shortcut : View
{
_orientation = value;
if (value == Orientation.Vertical)
{
AlignmentModes = AlignmentModes.StartToEnd | AlignmentModes.IgnoreFirstOrLast;
}
else
{
AlignmentModes = AlignmentModes.EndToStart | AlignmentModes.IgnoreFirstOrLast;
}
// TODO: Determine what, if anything, is opinionated about the orientation.
}
}
// The default Orientation is Horizontal thus set this to EndToStart
private AlignmentModes _alignmentModes = AlignmentModes.EndToStart | AlignmentModes.IgnoreFirstOrLast;
private AlignmentModes _alignmentModes = AlignmentModes.StartToEnd | AlignmentModes.IgnoreFirstOrLast;
/// <summary>
/// Gets or sets the <see cref="AlignmentModes"/> for this <see cref="Shortcut"/>.
/// </summary>
/// <remarks>
/// <para>
/// Setting <see cref="Orientation"/> will set the <see cref="AlignmentModes"/> to the appropriate value.
/// The default is <see cref="AlignmentModes.StartToEnd"/>. This means that the CommandView will be on the left,
/// HelpView in the middle, and KeyView on the right.
/// </para>
/// </remarks>
public AlignmentModes AlignmentModes
@@ -661,7 +646,12 @@ public class Shortcut : View
{
Action?.Invoke ();
return true;
if (CanFocus)
{
SetFocus ();
}
return false;
}
}

View File

@@ -55,17 +55,23 @@ public class StatusBar : Bar
}
}
/// <inheritdoc/>
public override View Add (View view)
{
// Call base first, because otherwise it resets CanFocus to true
base.Add (view);
view.CanFocus = false;
if (view is Shortcut shortcut)
{
shortcut.KeyBindingScope = KeyBindingScope.Application;
// TODO: not happy about using AlignmentModes for this. Too implied.
// TODO: instead, add a property (a style enum?) to Shortcut to control this
shortcut.AlignmentModes = AlignmentModes.EndToStart;
}
return base.Add (view);
return view;
}
}

View File

@@ -14,7 +14,7 @@ public class Bars : Scenario
public override void Main ()
{
Application.Init ();
Window app = new ();
Toplevel app = new ();
app.Loaded += App_Loaded;
@@ -28,31 +28,87 @@ public class Bars : Scenario
// 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 ()}";
ObservableCollection<string> eventSource = new ();
ListView eventLog = new ListView ()
{
Title = "Event Log",
X = Pos.AnchorEnd (),
Width = 50,
Height = Dim.Fill (6),
Width = Dim.Auto(),
Height = Dim.Fill (), // Make room for some wide things
ColorScheme = Colors.ColorSchemes ["Toplevel"],
Source = new ListWrapper<string> (eventSource)
};
eventLog.Border.Thickness = new (0, 1, 0, 0);
Application.Top.Add (eventLog);
FrameView menuBarLikeExamples = new ()
{
Title = "MenuBar-Like Examples",
X = 0,
Y = 0,
Width = Dim.Fill () - Dim.Width (eventLog),
Height = 10,
};
Application.Top.Add (menuBarLikeExamples);
Label label = new Label ()
{
Title = " Bar:",
X = 0,
Y = Pos.AnchorEnd () - 6
};
menuBarLikeExamples.Add (label);
Bar bar = new Bar
{
Id = "menuBar-like",
X = Pos.Right (label),
Y = Pos.Top (label),
Width = Dim.Fill (),
Height = 1,//Dim.Auto (DimAutoStyle.Content),
Orientation = Orientation.Horizontal,
};
ConfigMenuBar (bar);
menuBarLikeExamples.Add (bar);
label = new Label ()
{
Title = " MenuBar:",
X = 0,
Y = Pos.Bottom(bar)
};
menuBarLikeExamples.Add (label);
//bar = new MenuBarv2
//{
// Id = "menuBar",
// Width = Dim.Fill (),
// Height = 1,//Dim.Auto (DimAutoStyle.Content),
// Orientation = Orientation.Horizontal,
//};
//ConfigMenuBar (bar);
//menuBarLikeExamples.Add (bar);
FrameView menuLikeExamples = new ()
{
Title = "Menu-Like Examples",
X = 0,
Y = Pos.Bottom (menuBarLikeExamples),
Width = Dim.Fill () - Dim.Width (eventLog),
Height = 10,
};
Application.Top.Add (menuLikeExamples);
var shortcut1 = new Shortcut
{
Title = "_Zigzag",
Key = Key.G.WithCtrl,
Text = "Gonna zig zag",
};
shortcut1.Accept += (s, e) =>
{
eventSource.Add ($"Accept: {s}");
eventLog.MoveDown ();
};
var shortcut2 = new Shortcut
{
@@ -61,49 +117,6 @@ public class Bars : Scenario
Key = Key.G.WithAlt,
};
//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 vBar = new Bar
{
X = 2,
@@ -113,44 +126,41 @@ public class Bars : Scenario
};
vBar.Add (shortcut1, shortcut2);
////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 (vBar);
menuLikeExamples.Add (vBar);
// BUGBUG: This should not be needed
Application.Top.LayoutSubviews ();
menuLikeExamples.LayoutSubviews ();
// SetupMenuBar ();
//SetupContentMenu ();
Label label = new Label ()
FrameView statusBarLikeExamples = new ()
{
Title = "StatusBar-Like Examples",
X = 0,
Y = Pos.AnchorEnd (),
Width = Dim.Width (menuLikeExamples),
Height = 10,
};
Application.Top.Add (statusBarLikeExamples);
label = new Label ()
{
Title = " Bar:",
X = 0,
Y = Pos.AnchorEnd () - 6
};
Application.Top.Add (label);
var bar = new Bar
{
Id = "bar",
X = Pos.Right (label),
Y = Pos.Top (label),
Width = Dim.Fill (),
Orientation = Orientation.Horizontal,
};
ConfigStatusBar (bar);
Application.Top.Add (bar);
statusBarLikeExamples.Add (label);
//bar = new Bar
//{
// Id = "statusBar-like",
// X = Pos.Right (label),
// Y = Pos.Top (label),
// Width = Dim.Fill (),
// Orientation = Orientation.Horizontal,
//};
//ConfigStatusBar (bar);
//statusBarLikeExamples.Add (bar);
label = new Label ()
{
@@ -158,8 +168,8 @@ public class Bars : Scenario
X = 0,
Y = Pos.AnchorEnd () - 3
};
Application.Top.Add (label);
bar = new StatusBar()
statusBarLikeExamples.Add (label);
bar = new StatusBar ()
{
Id = "statusBar",
X = Pos.Right (label),
@@ -168,17 +178,20 @@ public class Bars : Scenario
Orientation = Orientation.Horizontal,
};
ConfigStatusBar (bar);
Application.Top.Add (bar);
statusBarLikeExamples.Add (bar);
foreach (Bar barView in Application.Top.Subviews.Where (b => b is Bar)!)
foreach (FrameView frameView in Application.Top.Subviews.Where (f => f is FrameView)!)
{
foreach (Shortcut sh in barView.Subviews.Where (s => s is Shortcut)!)
foreach (Bar barView in frameView.Subviews.Where (b => b is Bar)!)
{
sh.Accept += (o, args) =>
{
eventSource.Add ($"Accept: {sh!.SuperView.Id} {sh!.CommandView.Text}");
eventLog.MoveDown ();
};
foreach (Shortcut sh in barView.Subviews.Where (s => s is Shortcut)!)
{
sh.Accept += (o, args) =>
{
eventSource.Add ($"Accept: {sh!.SuperView.Id} {sh!.CommandView.Text}");
eventLog.MoveDown ();
};
}
}
}
}
@@ -331,108 +344,20 @@ public class Bars : Scenario
((View)(sender)).LayoutSubviews ();
}
private void SetupMenuBar ()
private void ConfigMenuBar (Bar bar)
{
var menuBar = new Bar
{
Id = "menuBar",
Width = Dim.Fill (),
Height = 1,//Dim.Auto (DimAutoStyle.Content),
Orientation = Orientation.Horizontal,
};
var fileMenuBarItem = new Shortcut
{
Title = "_File",
KeyBindingScope = KeyBindingScope.Application,
Key = Key.F.WithAlt,
};
fileMenuBarItem.KeyView.Visible = false;
var editMenuBarItem = new Shortcut
{
Title = "_Edit",
KeyBindingScope = KeyBindingScope.HotKey,
};
editMenuBarItem.Accept += (s, e) => { };
//editMenu.HelpView.Visible = false;
//editMenu.KeyView.Visible = false;
menuBar.Add (fileMenuBarItem, editMenuBarItem);
menuBar.Initialized += Menu_Initialized;
Application.Top.Add (menuBar);
var fileMenu = new Bar
{
X = 1,
Y = 1,
Orientation = Orientation.Vertical,
// Modal = true,
Visible = false,
};
var newShortcut = new Shortcut
{
Title = "_New...",
Text = "Create a new file",
Key = Key.N.WithCtrl
};
newShortcut.Border.Thickness = new Thickness (0, 1, 0, 0);
var openShortcut = new Shortcut
{
Title = "_Open...",
Text = "Show the File Open Dialog",
Key = Key.O.WithCtrl
};
var saveShortcut = new Shortcut
{
Title = "_Save...",
Text = "Save",
Key = Key.S.WithCtrl,
Enabled = false
};
var exitShortcut = new Shortcut
{
Title = "E_xit",
Text = "Exit",
Key = Key.X.WithCtrl,
};
exitShortcut.Border.Thickness = new Thickness (0, 1, 0, 1);
fileMenu.Add (newShortcut, openShortcut, saveShortcut, exitShortcut);
View prevFocus = null;
fileMenuBarItem.Accept += (s, e) =>
{
if (fileMenu.Visible)
{
// fileMenu.RequestStop ();
prevFocus?.SetFocus ();
return;
}
//fileMenu.Visible = !fileMenu.Visible;
var sender = s as Shortcut;
var screen = sender.FrameToScreen ();
fileMenu.X = screen.X;
fileMenu.Y = screen.Y + 1;
fileMenu.Visible = true;
prevFocus = Application.Top.Focused;
fileMenuBarItem.SetFocus ();
//Application.Run (fileMenu);
fileMenu.Visible = false;
};
Application.Top.Closed += (s, e) =>
{
fileMenu.Dispose ();
};
bar.Add (fileMenuBarItem, editMenuBarItem);
}
private void ConfigStatusBar (Bar bar)
@@ -442,8 +367,7 @@ public class Bars : Scenario
Height = Dim.Auto (DimAutoStyle.Content, 3),
Text = "Quit",
Title = "Q_uit",
Key = Application.QuitKey,
KeyBindingScope = KeyBindingScope.Application,
Key = Key.Z.WithCtrl,
};
bar.Add (shortcut);
@@ -453,7 +377,6 @@ public class Bars : Scenario
Text = "Help Text",
Title = "Help",
Key = Key.F1,
KeyBindingScope = KeyBindingScope.HotKey,
};
bar.Add (shortcut);
@@ -462,9 +385,9 @@ public class Bars : Scenario
{
Title = "_Show/Hide",
Key = Key.F10,
KeyBindingScope = KeyBindingScope.Application,
CommandView = new CheckBox
{
CanFocus = false,
Text = "_Show/Hide"
},
};

View File

@@ -447,70 +447,73 @@ internal class UICatalogApp
]
};
ShVersion = new ()
{
Title = "Version Info",
CanFocus = false,
};
StatusBar = new ()
{
Visible = ShowStatusBar,
};
StatusBar.AlignmentModes = AlignmentModes.StartToEnd | AlignmentModes.IgnoreFirstOrLast;
Shortcut statusBarShortcut = new Shortcut ()
{
Key = Key.F10,
Title = "Show/Hide Status Bar",
};
statusBarShortcut.Accept += (sender, args) =>
{
StatusBar.Visible = !StatusBar.Visible;
};
ShForce16Colors = new Shortcut ()
{
CommandView = new CheckBox ()
{
Title = "16 color mode",
Checked = Application.Force16Colors,
CanFocus = false,
}, HelpText = "",
Key = Key.F6,
};
ShForce16Colors.Accept += (sender, args) =>
{
((CheckBox)ShForce16Colors.CommandView).Checked = Application.Force16Colors = (bool)!((CheckBox)ShForce16Colors.CommandView).Checked!;
MiForce16Colors.Checked = Application.Force16Colors;
Application.Refresh ();
};
//ShDiagnostics = new Shortcut ()
//StatusBar = new ()
//{
// HelpText = "Diagnostic flags",
// CommandView = new RadioGroup()
// {
// RadioLabels = ["Off", "Ruler", "Padding", "MouseEnter"],
// CanFocus = false,
// Orientation = Orientation.Vertical,
// }
// Visible = ShowStatusBar,
//};
StatusBar.Add (
new Shortcut ()
if (StatusBar is { })
{
ShVersion = new ()
{
Title = "Quit",
Key = Application.QuitKey,
},
statusBarShortcut,
ShForce16Colors,
//ShDiagnostics,
ShVersion
);
Title = "Version Info",
CanFocus = false,
};
Shortcut statusBarShortcut = new Shortcut ()
{
Key = Key.F10,
Title = "Show/Hide Status Bar",
};
statusBarShortcut.Accept += (sender, args) => { StatusBar.Visible = !StatusBar.Visible; };
ShForce16Colors = new Shortcut ()
{
CommandView = new CheckBox ()
{
Title = "16 color mode",
Checked = Application.Force16Colors,
CanFocus = false,
},
HelpText = "",
Key = Key.F6,
};
ShForce16Colors.Accept += (sender, args) =>
{
((CheckBox)ShForce16Colors.CommandView).Checked =
Application.Force16Colors = (bool)!((CheckBox)ShForce16Colors.CommandView).Checked!;
MiForce16Colors.Checked = Application.Force16Colors;
Application.Refresh ();
};
//ShDiagnostics = new Shortcut ()
//{
// HelpText = "Diagnostic flags",
// CommandView = new RadioGroup()
// {
// RadioLabels = ["Off", "Ruler", "Padding", "MouseEnter"],
// CanFocus = false,
// Orientation = Orientation.Vertical,
// }
//};
StatusBar.Add (
new Shortcut ()
{
Title = "Quit",
Key = Application.QuitKey,
},
statusBarShortcut,
ShForce16Colors,
//ShDiagnostics,
ShVersion
);
}
// Create the Category list view. This list never changes.
CategoryList = new ()
@@ -615,7 +618,11 @@ internal class UICatalogApp
Add (ScenarioList);
Add (MenuBar);
Add (StatusBar);
if (StatusBar is { })
{
Add (StatusBar);
}
Loaded += LoadedHandler;
Unloaded += UnloadedHandler;
@@ -651,16 +658,14 @@ internal class UICatalogApp
MenuBar.Menus [0].Children [0].Shortcut = (KeyCode)Application.QuitKey;
((Shortcut)StatusBar.Subviews [0]).Key = Application.QuitKey;
if (StatusBar is { })
{
((Shortcut)StatusBar.Subviews [0]).Key = Application.QuitKey;
StatusBar.Visible = ShowStatusBar;
}
MiIsMouseDisabled!.Checked = Application.IsMouseDisabled;
int height = ShowStatusBar ? 1 : 0; // + (MenuBar.Visible ? 1 : 0);
//ContentPane.Height = Dim.Fill (height);
StatusBar.Visible = ShowStatusBar;
Application.Top.SetNeedsDisplay ();
}
@@ -1032,7 +1037,11 @@ internal class UICatalogApp
ConfigChanged ();
MiIsMouseDisabled!.Checked = Application.IsMouseDisabled;
ShVersion.Title = $"{RuntimeEnvironment.OperatingSystem} {RuntimeEnvironment.OperatingSystemVersion}, {Driver.GetVersionInfo ()}";
if (ShVersion is { })
{
ShVersion.Title = $"{RuntimeEnvironment.OperatingSystem} {RuntimeEnvironment.OperatingSystemVersion}, {Driver.GetVersionInfo ()}";
}
if (_selectedScenario != null)
{
@@ -1045,18 +1054,21 @@ internal class UICatalogApp
ScenarioList.SetFocus ();
}
StatusBar.VisibleChanged += (s, e) =>
{
ShowStatusBar = StatusBar.Visible;
if (StatusBar is { })
{
StatusBar.VisibleChanged += (s, e) =>
{
ShowStatusBar = StatusBar.Visible;
int height = StatusBar.Visible ? 1 : 0;
CategoryList.Height = Dim.Fill (height);
ScenarioList.Height = Dim.Fill (height);
int height = StatusBar.Visible ? 1 : 0;
CategoryList.Height = Dim.Fill (height);
ScenarioList.Height = Dim.Fill (height);
// ContentPane.Height = Dim.Fill (height);
LayoutSubviews ();
SetSubViewNeedsDisplay ();
};
// ContentPane.Height = Dim.Fill (height);
LayoutSubviews ();
SetSubViewNeedsDisplay ();
};
}
Loaded -= LoadedHandler;
CategoryList.EnsureSelectedItemVisible ();