diff --git a/Example/demo.cs b/Example/demo.cs
index 8b3f3cd6d..2957c8dc2 100644
--- a/Example/demo.cs
+++ b/Example/demo.cs
@@ -651,11 +651,17 @@ static class Demo {
new MenuItem [] { menuItems [0], menuItems [1] }),
menuItems[3],
miUseKeysUpDownAsKeysLeftRight = new MenuItem ("Use_KeysUpDownAsKeysLeftRight", "",
- () => menu.UseKeysUpDownAsKeysLeftRight = miUseKeysUpDownAsKeysLeftRight.Checked = useKeysUpDownAsKeysLeftRight = !useKeysUpDownAsKeysLeftRight) {
+ () => {
+ menu.UseKeysUpDownAsKeysLeftRight = miUseKeysUpDownAsKeysLeftRight.Checked = useKeysUpDownAsKeysLeftRight = !useKeysUpDownAsKeysLeftRight;
+ miUseSubMenusSingleFrame.Checked = useSubMenusSingleFrame = menu.UseSubMenusSingleFrame;
+ }) {
CheckType = MenuItemCheckStyle.Checked, Checked = useKeysUpDownAsKeysLeftRight
},
miUseSubMenusSingleFrame = new MenuItem ("Use_SubMenusSingleFrame", "",
- () => menu.UseSubMenusSingleFrame = miUseSubMenusSingleFrame.Checked = useSubMenusSingleFrame = !useSubMenusSingleFrame) {
+ () => {
+ menu.UseSubMenusSingleFrame = miUseSubMenusSingleFrame.Checked = useSubMenusSingleFrame = !useSubMenusSingleFrame;
+ miUseKeysUpDownAsKeysLeftRight.Checked = useKeysUpDownAsKeysLeftRight = menu.UseKeysUpDownAsKeysLeftRight;
+ }) {
CheckType = MenuItemCheckStyle.Checked, Checked = useSubMenusSingleFrame
},
miHeightAsBuffer = new MenuItem ("_Height As Buffer", "", () => {
diff --git a/Terminal.Gui/Views/Menu.cs b/Terminal.Gui/Views/Menu.cs
index d35ccf15e..a6eed77d2 100644
--- a/Terminal.Gui/Views/Menu.cs
+++ b/Terminal.Gui/Views/Menu.cs
@@ -654,7 +654,7 @@ namespace Terminal.Gui {
if (current >= barItems.Children.Length) {
current = 0;
}
- if (this != host.openCurrentMenu && barItems.Children [current].IsFromSubMenu && host.selectedSub > -1) {
+ if (this != host.openCurrentMenu && barItems.Children [current]?.IsFromSubMenu == true && host.selectedSub > -1) {
host.PreviousMenu (true);
host.SelectEnabledItem (barItems.Children, current, out current);
host.openCurrentMenu = this;
@@ -843,10 +843,21 @@ namespace Terminal.Gui {
/// The menu array.
public MenuBarItem [] Menus { get; set; }
+ private bool useKeysUpDownAsKeysLeftRight = false;
+
///
/// Used for change the navigation key style.
///
- public bool UseKeysUpDownAsKeysLeftRight { get; set; } = false;
+ public bool UseKeysUpDownAsKeysLeftRight {
+ get => useKeysUpDownAsKeysLeftRight;
+ set {
+ useKeysUpDownAsKeysLeftRight = value;
+ if (value && UseSubMenusSingleFrame) {
+ UseSubMenusSingleFrame = false;
+ SetNeedsDisplay ();
+ }
+ }
+ }
static ustring shortcutDelimiter = "+";
///
@@ -866,10 +877,21 @@ namespace Terminal.Gui {
///
new public static Rune HotKeySpecifier => '_';
+ private bool useSubMenusSingleFrame;
+
///
/// Gets or sets if the sub-menus must be displayed in a single or multiple frames.
///
- public bool UseSubMenusSingleFrame { get; set; }
+ public bool UseSubMenusSingleFrame {
+ get => useSubMenusSingleFrame;
+ set {
+ useSubMenusSingleFrame = value;
+ if (value && UseKeysUpDownAsKeysLeftRight) {
+ useKeysUpDownAsKeysLeftRight = false;
+ SetNeedsDisplay ();
+ }
+ }
+ }
///
/// Initializes a new instance of the .
diff --git a/UnitTests/ApplicationTests.cs b/UnitTests/ApplicationTests.cs
index 9f70b66aa..0aa526d68 100644
--- a/UnitTests/ApplicationTests.cs
+++ b/UnitTests/ApplicationTests.cs
@@ -1293,45 +1293,47 @@ namespace Terminal.Gui.Core {
int numberOfTimeoutsPerThread = 100;
- // start lots of threads
- for (int i = 0; i < numberOfThreads; i++) {
-
- var myi = i;
+ lock (Application.Top) {
+ // start lots of threads
+ for (int i = 0; i < numberOfThreads; i++) {
- Task.Run (() => {
- Task.Delay (100).Wait ();
+ var myi = i;
- // each thread registers lots of 1s timeouts
- for(int j=0;j< numberOfTimeoutsPerThread; j++) {
+ Task.Run (() => {
+ Task.Delay (100).Wait ();
- Application.MainLoop.AddTimeout (TimeSpan.FromSeconds(1), (s) => {
+ // each thread registers lots of 1s timeouts
+ for (int j = 0; j < numberOfTimeoutsPerThread; j++) {
- // each timeout delegate increments delegatesRun count by 1 every second
- Interlocked.Increment (ref delegatesRun);
- return true;
- });
- }
-
- // if this is the first Thread created
- if (myi == 0) {
+ Application.MainLoop.AddTimeout (TimeSpan.FromSeconds (1), (s) => {
- // let the timeouts run for a bit
- Task.Delay (5000).Wait ();
+ // each timeout delegate increments delegatesRun count by 1 every second
+ Interlocked.Increment (ref delegatesRun);
+ return true;
+ });
+ }
- // then tell the application to quuit
- Application.MainLoop.Invoke (() => Application.RequestStop ());
- }
- });
+ // if this is the first Thread created
+ if (myi == 0) {
+
+ // let the timeouts run for a bit
+ Task.Delay (5000).Wait ();
+
+ // then tell the application to quit
+ Application.MainLoop.Invoke (() => Application.RequestStop ());
+ }
+ });
+ }
+
+ // blocks here until the RequestStop is processed at the end of the test
+ Application.Run ();
+
+ // undershoot a bit to be on the safe side. The 5000 ms wait allows the timeouts to run
+ // a lot but all those timeout delegates could end up going slowly on a slow machine perhaps
+ // so the final number of delegatesRun might vary by computer. So for this assert we say
+ // that it should have run at least 2 seconds worth of delegates
+ Assert.True (delegatesRun >= numberOfThreads * numberOfTimeoutsPerThread * 2);
}
-
- // blocks here until the RequestStop is processed at the end of the test
- Application.Run ();
-
- // undershoot a bit to be on the safe side. The 5000 ms wait allows the timeouts to run
- // a lot but all those timeout delegates could end up going slowly on a slow machine perhaps
- // so the final number of delegatesRun might vary by computer. So for this assert we say
- // that it should have run at least 2 seconds worth of delegates
- Assert.True (delegatesRun >= numberOfThreads * numberOfTimeoutsPerThread * 2);
}
}
}
diff --git a/UnitTests/AssemblyInfo.cs b/UnitTests/AssemblyInfo.cs
index 1278f5dea..ddf16f7b8 100644
--- a/UnitTests/AssemblyInfo.cs
+++ b/UnitTests/AssemblyInfo.cs
@@ -13,7 +13,7 @@ using Xunit;
// This is necessary because a) Application is a singleton and Init/Shutdown must be called
// as a pair, and b) all unit test functions should be atomic.
[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
-public class AutoInitShutdown : Xunit.Sdk.BeforeAfterTestAttribute {
+public class AutoInitShutdownAttribute : Xunit.Sdk.BeforeAfterTestAttribute {
static bool _init = false;
public override void Before (MethodInfo methodUnderTest)
diff --git a/UnitTests/MenuTests.cs b/UnitTests/MenuTests.cs
index 420f61512..5f84d4304 100644
--- a/UnitTests/MenuTests.cs
+++ b/UnitTests/MenuTests.cs
@@ -188,6 +188,7 @@ Edit
new MenuBarItem ("_New", new MenuItem [] {
new MenuItem ("_New doc", "Creates new doc.", null, () => false)
}),
+ null,
new MenuItem ("_Save", "Saves the file.", null, null)
})
});
@@ -227,6 +228,16 @@ Edit
}));
Assert.True (menu.IsMenuOpen);
Assert.Equal ("_File", miCurrent.Parent.Title);
+ Assert.Equal ("_New", miCurrent.Title);
+
+ Assert.True (mCurrent.MouseEvent (new MouseEvent () {
+ X = 1,
+ Y = 3,
+ Flags = MouseFlags.ReportMousePosition,
+ View = mCurrent
+ }));
+ Assert.True (menu.IsMenuOpen);
+ Assert.Equal ("_File", miCurrent.Parent.Title);
Assert.Equal ("_Save", miCurrent.Title);
// close the menu
@@ -1269,5 +1280,21 @@ Edit
pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
Assert.Equal (new Rect (2, 0, 13, 1), pos);
}
+
+ [Fact]
+ public void UseKeysUpDownAsKeysLeftRight_And_UseSubMenusSingleFrame_Cannot_Be_Both_True ()
+ {
+ var menu = new MenuBar ();
+ Assert.False (menu.UseKeysUpDownAsKeysLeftRight);
+ Assert.False (menu.UseSubMenusSingleFrame);
+
+ menu.UseKeysUpDownAsKeysLeftRight = true;
+ Assert.True (menu.UseKeysUpDownAsKeysLeftRight);
+ Assert.False (menu.UseSubMenusSingleFrame);
+
+ menu.UseSubMenusSingleFrame = true;
+ Assert.False (menu.UseKeysUpDownAsKeysLeftRight);
+ Assert.True (menu.UseSubMenusSingleFrame);
+ }
}
}
diff --git a/UnitTests/ScenarioTests.cs b/UnitTests/ScenarioTests.cs
index b6c032611..f19904d39 100644
--- a/UnitTests/ScenarioTests.cs
+++ b/UnitTests/ScenarioTests.cs
@@ -82,7 +82,9 @@ namespace Terminal.Gui {
};
var token = Application.MainLoop.AddTimeout (TimeSpan.FromMilliseconds (ms), abortCallback);
- var scenario = (Scenario)Activator.CreateInstance (scenarioClass);
+ Scenario scenario = null;
+ var exception = Record.Exception (() => scenario = (Scenario)Activator.CreateInstance (scenarioClass));
+ Assert.Null (exception);
scenario.Init (Application.Top, Colors.Base);
scenario.Setup ();
// There is no need to call Application.Begin because Init already creates the Application.Top