Browse Source

Merge pull request #2811 from BDisp/v1_alt-key-on-toplevel-with-menubar-fix_2810

Fixes #2810. Pressing Alt key on a Toplevel with only a MenuBar throws System.InvalidOperationException.
Tig 1 year ago
parent
commit
0d27fcce8a

+ 2 - 1
Terminal.Gui/Core/Application.cs

@@ -1053,7 +1053,8 @@ namespace Terminal.Gui {
 					MdiTop.OnAllChildClosed ();
 					MdiTop.OnAllChildClosed ();
 				} else {
 				} else {
 					SetCurrentAsTop ();
 					SetCurrentAsTop ();
-					Current.OnEnter (Current);
+					runState.Toplevel.OnLeave (Current);
+					Current.OnEnter (runState.Toplevel);
 				}
 				}
 				Refresh ();
 				Refresh ();
 			}
 			}

+ 1 - 1
Terminal.Gui/Core/Border.cs

@@ -284,7 +284,7 @@ namespace Terminal.Gui {
 			/// <inheritdoc/>
 			/// <inheritdoc/>
 			public override void OnCanFocusChanged ()
 			public override void OnCanFocusChanged ()
 			{
 			{
-				if (Border.Child != null) {
+				if (Border?.Child != null) {
 					Border.Child.CanFocus = CanFocus;
 					Border.Child.CanFocus = CanFocus;
 				}
 				}
 				base.OnCanFocusChanged ();
 				base.OnCanFocusChanged ();

+ 1 - 0
Terminal.Gui/Core/Toplevel.cs

@@ -552,6 +552,7 @@ namespace Terminal.Gui {
 		///<inheritdoc/>
 		///<inheritdoc/>
 		public override void Add (View view)
 		public override void Add (View view)
 		{
 		{
+			CanFocus = true;
 			AddMenuStatusBar (view);
 			AddMenuStatusBar (view);
 			base.Add (view);
 			base.Add (view);
 		}
 		}

+ 0 - 3
Terminal.Gui/Core/View.cs

@@ -995,9 +995,6 @@ namespace Terminal.Gui {
 			view.tabIndex = -1;
 			view.tabIndex = -1;
 			SetNeedsLayout ();
 			SetNeedsLayout ();
 			SetNeedsDisplay ();
 			SetNeedsDisplay ();
-			if (subviews.Count < 1) {
-				CanFocus = false;
-			}
 			foreach (var v in subviews) {
 			foreach (var v in subviews) {
 				if (v.Frame.IntersectsWith (touched))
 				if (v.Frame.IntersectsWith (touched))
 					view.SetNeedsDisplay ();
 					view.SetNeedsDisplay ();

+ 0 - 3
Terminal.Gui/Core/Window.cs

@@ -270,9 +270,6 @@ namespace Terminal.Gui {
 			SetNeedsDisplay ();
 			SetNeedsDisplay ();
 			contentView.Remove (view);
 			contentView.Remove (view);
 
 
-			if (contentView.InternalSubviews.Count < 1) {
-				CanFocus = false;
-			}
 			RemoveMenuStatusBar (view);
 			RemoveMenuStatusBar (view);
 			if (view != contentView && Focused == null) {
 			if (view != contentView && Focused == null) {
 				FocusFirst ();
 				FocusFirst ();

+ 109 - 1
UnitTests/TopLevels/ToplevelTests.cs

@@ -1009,7 +1009,98 @@ namespace Terminal.Gui.TopLevelTests {
 			Application.End (rs);
 			Application.End (rs);
 
 
 			Assert.True (isEnter);
 			Assert.True (isEnter);
-			Assert.True (isLeave);  // Leave event is now also invoked on Application.End allowing preform same output action
+			Assert.False (isLeave);  // Leave event cannot be trigger because it v.Enter was performed and v is focused
+			Assert.True (v.HasFocus);
+		}
+
+		[Fact, AutoInitShutdown]
+		public void OnEnter_OnLeave_Triggered_On_Application_Begin_End_With_More_Toplevels ()
+		{
+			var iterations = 0;
+			var steps = new int [5];
+			var isEnterTop = false;
+			var isLeaveTop = false;
+			var vt = new View ();
+			var top = Application.Top;
+			var diag = new Dialog ();
+
+			vt.Enter += (e) => {
+				iterations++;
+				isEnterTop = true;
+				if (iterations == 1) {
+					steps [0] = iterations;
+					Assert.Null (e.View);
+				} else {
+					steps [4] = iterations;
+					Assert.Equal (diag, e.View);
+				}
+			};
+			vt.Leave += (e) => {
+				iterations++;
+				steps [1] = iterations;
+				isLeaveTop = true;
+				Assert.Equal (diag, e.View);
+			};
+			top.Add (vt);
+
+			Assert.False (vt.CanFocus);
+			var exception = Record.Exception (() => top.OnEnter (top));
+			Assert.Null (exception);
+			exception = Record.Exception (() => top.OnLeave (top));
+			Assert.Null (exception);
+
+			vt.CanFocus = true;
+			Application.Begin (top);
+
+			Assert.True (isEnterTop);
+			Assert.False (isLeaveTop);
+
+			isEnterTop = false;
+			var isEnterDiag = false;
+			var isLeaveDiag = false;
+			var vd = new View ();
+			vd.Enter += (e) => {
+				iterations++;
+				steps [2] = iterations;
+				isEnterDiag = true;
+				Assert.Null (e.View);
+			};
+			vd.Leave += (e) => {
+				iterations++;
+				steps [3] = iterations;
+				isLeaveDiag = true;
+				Assert.Equal (top, e.View);
+			};
+			diag.Add (vd);
+
+			Assert.False (vd.CanFocus);
+			exception = Record.Exception (() => diag.OnEnter (diag));
+			Assert.Null (exception);
+			exception = Record.Exception (() => diag.OnLeave (diag));
+			Assert.Null (exception);
+
+			vd.CanFocus = true;
+			var rs = Application.Begin (diag);
+
+			Assert.True (isEnterDiag);
+			Assert.False (isLeaveDiag);
+			Assert.False (isEnterTop);
+			Assert.True (isLeaveTop);
+
+			isEnterDiag = false;
+			isLeaveTop = false;
+			Application.End (rs);
+
+			Assert.False (isEnterDiag);
+			Assert.True (isLeaveDiag);
+			Assert.True (isEnterTop);
+			Assert.False (isLeaveTop);  // Leave event cannot be trigger because it v.Enter was performed and v is focused
+			Assert.True (vt.HasFocus);
+			Assert.Equal (1, steps [0]);
+			Assert.Equal (2, steps [1]);
+			Assert.Equal (3, steps [2]);
+			Assert.Equal (4, steps [3]);
+			Assert.Equal (5, steps [^1]);
 		}
 		}
 
 
 		[Fact, AutoInitShutdown]
 		[Fact, AutoInitShutdown]
@@ -1031,5 +1122,22 @@ namespace Terminal.Gui.TopLevelTests {
 			Application.Driver.GetCursorVisibility (out cursor);
 			Application.Driver.GetCursorVisibility (out cursor);
 			Assert.Equal (CursorVisibility.Invisible, cursor);
 			Assert.Equal (CursorVisibility.Invisible, cursor);
 		}
 		}
+
+		[Fact, AutoInitShutdown]
+		public void Activating_MenuBar_By_Alt_Key_Does_Not_Throw ()
+		{
+			var menu = new MenuBar (new MenuBarItem [] {
+				new MenuBarItem ("Child", new MenuItem [] {
+					new MenuItem ("_Create Child", "", null)
+				})
+			});
+			var topChild = new Toplevel ();
+			topChild.Add (menu);
+			Application.Top.Add (topChild);
+			Application.Begin (Application.Top);
+
+			var exception = Record.Exception (() => topChild.ProcessHotKey (new KeyEvent (Key.AltMask, new KeyModifiers { Alt = true })));
+			Assert.Null (exception);
+		}
 	}
 	}
 }
 }