diff --git a/Terminal.Gui/Core/Application.cs b/Terminal.Gui/Core/Application.cs index 233b0c1fa..5d8cc1fdf 100644 --- a/Terminal.Gui/Core/Application.cs +++ b/Terminal.Gui/Core/Application.cs @@ -1053,7 +1053,8 @@ namespace Terminal.Gui { MdiTop.OnAllChildClosed (); } else { SetCurrentAsTop (); - Current.OnEnter (Current); + runState.Toplevel.OnLeave (Current); + Current.OnEnter (runState.Toplevel); } Refresh (); } diff --git a/Terminal.Gui/Core/Border.cs b/Terminal.Gui/Core/Border.cs index abf4438ce..08e4b614c 100644 --- a/Terminal.Gui/Core/Border.cs +++ b/Terminal.Gui/Core/Border.cs @@ -284,7 +284,7 @@ namespace Terminal.Gui { /// public override void OnCanFocusChanged () { - if (Border.Child != null) { + if (Border?.Child != null) { Border.Child.CanFocus = CanFocus; } base.OnCanFocusChanged (); diff --git a/Terminal.Gui/Core/Toplevel.cs b/Terminal.Gui/Core/Toplevel.cs index f06345152..04f8995e8 100644 --- a/Terminal.Gui/Core/Toplevel.cs +++ b/Terminal.Gui/Core/Toplevel.cs @@ -552,6 +552,7 @@ namespace Terminal.Gui { /// public override void Add (View view) { + CanFocus = true; AddMenuStatusBar (view); base.Add (view); } diff --git a/Terminal.Gui/Core/View.cs b/Terminal.Gui/Core/View.cs index ed6439a8b..b2805320b 100644 --- a/Terminal.Gui/Core/View.cs +++ b/Terminal.Gui/Core/View.cs @@ -995,9 +995,6 @@ namespace Terminal.Gui { view.tabIndex = -1; SetNeedsLayout (); SetNeedsDisplay (); - if (subviews.Count < 1) { - CanFocus = false; - } foreach (var v in subviews) { if (v.Frame.IntersectsWith (touched)) view.SetNeedsDisplay (); diff --git a/Terminal.Gui/Core/Window.cs b/Terminal.Gui/Core/Window.cs index 53925f258..febb7517e 100644 --- a/Terminal.Gui/Core/Window.cs +++ b/Terminal.Gui/Core/Window.cs @@ -270,9 +270,6 @@ namespace Terminal.Gui { SetNeedsDisplay (); contentView.Remove (view); - if (contentView.InternalSubviews.Count < 1) { - CanFocus = false; - } RemoveMenuStatusBar (view); if (view != contentView && Focused == null) { FocusFirst (); diff --git a/UnitTests/TopLevels/ToplevelTests.cs b/UnitTests/TopLevels/ToplevelTests.cs index 120ed6b35..89960d5ce 100644 --- a/UnitTests/TopLevels/ToplevelTests.cs +++ b/UnitTests/TopLevels/ToplevelTests.cs @@ -1009,7 +1009,98 @@ namespace Terminal.Gui.TopLevelTests { Application.End (rs); 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] @@ -1031,5 +1122,22 @@ namespace Terminal.Gui.TopLevelTests { Application.Driver.GetCursorVisibility (out 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); + } } } \ No newline at end of file