From f32af48a09db04039abc98c12122259dcaf92eaf Mon Sep 17 00:00:00 2001 From: BDisp Date: Sat, 18 Jul 2020 21:23:38 +0100 Subject: [PATCH] Fixes #808. Added an automated CanFocus. --- Terminal.Gui/Core/View.cs | 38 ++++++++-- UnitTests/ViewTests.cs | 152 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+), 7 deletions(-) diff --git a/Terminal.Gui/Core/View.cs b/Terminal.Gui/Core/View.cs index 92284c012..e7c9adaea 100644 --- a/Terminal.Gui/Core/View.cs +++ b/Terminal.Gui/Core/View.cs @@ -276,6 +276,9 @@ namespace Terminal.Gui { } } + bool oldCanFocus; + int oldTabIndex; + /// public override bool CanFocus { get => base.CanFocus; @@ -284,11 +287,30 @@ namespace Terminal.Gui { base.CanFocus = value; if (!value && tabIndex > -1) { TabIndex = -1; - } else if (value && tabIndex == -1) { + } + if (value && SuperView != null && !SuperView.CanFocus) { + SuperView.CanFocus = value; + } + if (value && tabIndex == -1) { TabIndex = SuperView != null ? SuperView.tabIndexes.IndexOf (this) : -1; } TabStop = value; } + if (subviews != null && IsInitialized) { + foreach (var view in subviews) { + if (view.CanFocus != value) { + if (!value) { + view.oldCanFocus = view.CanFocus; + view.oldTabIndex = view.tabIndex; + view.CanFocus = value; + view.tabIndex = -1; + } else { + view.CanFocus = view.oldCanFocus; + view.tabIndex = view.oldTabIndex; + } + } + } + } } } @@ -661,13 +683,13 @@ namespace Terminal.Gui { subviews.Add (view); tabIndexes.Add (view); view.container = this; - OnAdded (view); if (view.CanFocus) { CanFocus = true; view.tabIndex = tabIndexes.IndexOf (view); } SetNeedsLayout (); SetNeedsDisplay (); + OnAdded (view); if (IsInitialized) { view.BeginInit (); } @@ -717,15 +739,15 @@ namespace Terminal.Gui { subviews.Remove (view); tabIndexes.Remove (view); view.container = null; - OnRemoved (view); view.tabIndex = -1; - if (subviews.Count < 1) - this.CanFocus = false; - + if (subviews.Count < 1) { + CanFocus = false; + } foreach (var v in subviews) { if (v.Frame.IntersectsWith (touched)) view.SetNeedsDisplay (); } + OnRemoved (view); } void PerformActionForSubview (View subview, Action action) @@ -1869,7 +1891,9 @@ namespace Terminal.Gui { public void BeginInit () { if (!IsInitialized) { - Initialized?.Invoke (this, new EventArgs ()); + oldCanFocus = CanFocus; + oldTabIndex = tabIndex; + Initialized?.Invoke (this, EventArgs.Empty); } if (subviews?.Count > 0) { foreach (var view in subviews) { diff --git a/UnitTests/ViewTests.cs b/UnitTests/ViewTests.cs index 5053b03f0..1e5f5eb70 100644 --- a/UnitTests/ViewTests.cs +++ b/UnitTests/ViewTests.cs @@ -747,5 +747,157 @@ namespace Terminal.Gui { Assert.False (f.CanFocus); Assert.True (v.CanFocus); } + + [Fact] + public void CanFocus_Faced_With_Container_Before_Run () + { + Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true))); + + var t = Application.Top; + + var w = new Window ("w"); + var f = new FrameView ("f"); + var v = new View ("v") { CanFocus = true }; + f.Add (v); + w.Add (f); + t.Add (w); + + Assert.True (t.CanFocus); + Assert.True (w.CanFocus); + Assert.True (f.CanFocus); + Assert.True (v.CanFocus); + + f.CanFocus = false; + Assert.False (f.CanFocus); + Assert.True (v.CanFocus); + + v.CanFocus = false; + Assert.False (f.CanFocus); + Assert.False (v.CanFocus); + + v.CanFocus = true; + Assert.False (f.CanFocus); + Assert.True (v.CanFocus); + + Application.Iteration += () => Application.RequestStop (); + + Application.Run (); + Application.Shutdown (); + } + + [Fact] + public void CanFocus_Faced_With_Container_After_Run () + { + Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true))); + + var t = Application.Top; + + var w = new Window ("w"); + var f = new FrameView ("f"); + var v = new View ("v") { CanFocus = true }; + f.Add (v); + w.Add (f); + t.Add (w); + + t.Ready += () => { + Assert.True (t.CanFocus); + Assert.True (w.CanFocus); + Assert.True (f.CanFocus); + Assert.True (v.CanFocus); + + f.CanFocus = false; + Assert.False (f.CanFocus); + Assert.False (v.CanFocus); + + v.CanFocus = false; + Assert.False (f.CanFocus); + Assert.False (v.CanFocus); + + v.CanFocus = true; + Assert.True (f.CanFocus); + Assert.True (v.CanFocus); + }; + + Application.Iteration += () => Application.RequestStop (); + + Application.Run (); + Application.Shutdown (); + } + + [Fact] + public void CanFocus_Container_ToFalse_Turns_All_Subviews_ToFalse_Too () + { + Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true))); + + var t = Application.Top; + + var w = new Window ("w"); + var f = new FrameView ("f"); + var v1 = new View ("v1") { CanFocus = true }; + var v2 = new View ("v2") { CanFocus = true }; + f.Add (v1, v2); + w.Add (f); + t.Add (w); + + t.Ready += () => { + Assert.True (t.CanFocus); + Assert.True (w.CanFocus); + Assert.True (f.CanFocus); + Assert.True (v1.CanFocus); + Assert.True (v2.CanFocus); + + w.CanFocus = false; + Assert.True (w.CanFocus); + Assert.False (f.CanFocus); + Assert.False (v1.CanFocus); + Assert.False (v2.CanFocus); + }; + + Application.Iteration += () => Application.RequestStop (); + + Application.Run (); + Application.Shutdown (); + } + + [Fact] + public void CanFocus_Container_Toggling_All_Subviews_To_Old_Value_When_Is_True () + { + Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true))); + + var t = Application.Top; + + var w = new Window ("w"); + var f = new FrameView ("f"); + var v1 = new View ("v1"); + var v2 = new View ("v2") { CanFocus = true }; + f.Add (v1, v2); + w.Add (f); + t.Add (w); + + t.Ready += () => { + Assert.True (t.CanFocus); + Assert.True (w.CanFocus); + Assert.True (f.CanFocus); + Assert.False (v1.CanFocus); + Assert.True (v2.CanFocus); + + w.CanFocus = false; + Assert.True (w.CanFocus); + Assert.False (f.CanFocus); + Assert.False (v1.CanFocus); + Assert.False (v2.CanFocus); + + w.CanFocus = true; + Assert.True (w.CanFocus); + Assert.True (f.CanFocus); + Assert.False (v1.CanFocus); + Assert.True (v2.CanFocus); + }; + + Application.Iteration += () => Application.RequestStop (); + + Application.Run (); + Application.Shutdown (); + } } }