Browse Source

Fixes #808. Added an automated CanFocus.

BDisp 5 years ago
parent
commit
f01ddbe9e0
2 changed files with 183 additions and 7 deletions
  1. 31 7
      Terminal.Gui/Core/View.cs
  2. 152 0
      UnitTests/ViewTests.cs

+ 31 - 7
Terminal.Gui/Core/View.cs

@@ -276,6 +276,9 @@ namespace Terminal.Gui {
 			}
 		}
 
+		bool oldCanFocus;
+		int oldTabIndex;
+
 		/// <inheritdoc/>
 		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;
+							}
+						}
+					}
+				}
 			}
 		}
 
@@ -690,13 +712,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 ();
 			}
@@ -746,15 +768,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<View> action)
@@ -1898,7 +1920,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) {

+ 152 - 0
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 ();
+		}
 	}
 }