Переглянути джерело

Fixes #1818. Adds Title change events to Window

Charlie Kindel 3 роки тому
батько
коміт
f8622ce60c
3 змінених файлів з 208 додано та 2 видалено
  1. 59 1
      Terminal.Gui/Core/Window.cs
  2. 148 0
      UnitTests/WindowTests.cs
  3. 1 1
      UnitTests/WizardTests.cs

+ 59 - 1
Terminal.Gui/Core/Window.cs

@@ -9,6 +9,7 @@
 //  - FrameView Does not support IEnumerable
 // Any udpates done here should probably be done in FrameView as well; TODO: Merge these classes
 
+using System;
 using System.Collections;
 using NStack;
 
@@ -31,7 +32,10 @@ namespace Terminal.Gui {
 		public ustring Title {
 			get => title;
 			set {
-				title = value;
+				if (!OnTitleChanging (value)) {
+					title = value;
+					OnTitleChanged (title);
+				}
 				SetNeedsDisplay ();
 			}
 		}
@@ -333,5 +337,59 @@ namespace Terminal.Gui {
 				base.TextAlignment = contentView.TextAlignment = value;
 			}
 		}
+
+		/// <summary>
+		/// An <see cref="EventArgs"/> which allows passing a cancelable new <see cref="Title"/> value event.
+		/// </summary>
+		public class TitleEventArgs : EventArgs {
+			/// <summary>
+			/// The new Window Title.
+			/// </summary>
+			public ustring NewTitle { get; set; }
+
+			/// <summary>
+			/// Flag which allows cancelling changing to the new TItle value.
+			/// </summary>
+			public bool Cancel { get; set; }
+
+			/// <summary>
+			/// Initializes a new instance of <see cref="TitleEventArgs"/>
+			/// </summary>
+			/// <param name="newTitle">The new <see cref="Window.Title"/> to be replaced.</param>
+			public TitleEventArgs (ustring newTitle)
+			{
+				NewTitle = newTitle;
+			}
+		}
+		/// <summary>
+		/// Called before the <see cref="Window.Title"/> changes. Invokes the <see cref="TitleChanging"/> event, which can be cancelled.
+		/// </summary>
+		/// <returns>`true` if an event handler cancelled the Title change.</returns>
+		public virtual bool OnTitleChanging (ustring newTitle)
+		{
+			var args = new TitleEventArgs (newTitle);
+			TitleChanging?.Invoke (args);
+			return args.Cancel;
+		}
+
+		/// <summary>
+		/// Event fired when the <see cref="Window.Title"/> is changing. Set <see cref="TitleEventArgs.Cancel"/> to 
+		/// `true` to cancel the Title change.
+		/// </summary>
+		public event Action<TitleEventArgs> TitleChanging;
+
+		/// <summary>
+		/// Called when the <see cref="Window.Title"/> has been changed. Invokes the <see cref="TitleChanged"/> event.
+		/// </summary>
+		public virtual void OnTitleChanged (ustring newTitle)
+		{
+			var args = new TitleEventArgs (title);
+			TitleChanged?.Invoke (args);
+		}
+
+		/// <summary>
+		/// Event fired after the <see cref="Window.Title"/> has been changed. 
+		/// </summary>
+		public event Action<TitleEventArgs> TitleChanged;
 	}
 }

+ 148 - 0
UnitTests/WindowTests.cs

@@ -0,0 +1,148 @@
+using System;
+using Xunit;
+using Xunit.Abstractions;
+using GraphViewTests = Terminal.Gui.Views.GraphViewTests;
+
+// Alias Console to MockConsole so we don't accidentally use Console
+using Console = Terminal.Gui.FakeConsole;
+
+namespace Terminal.Gui.Core {
+	public class WindowTests {
+		readonly ITestOutputHelper output;
+
+		public WindowTests (ITestOutputHelper output)
+		{
+			this.output = output;
+		}
+
+		[Fact]
+		public void New_Initializes ()
+		{
+			// Parameterless
+			var r = new Window ();
+			Assert.NotNull (r);
+			Assert.Null (r.Title);
+			Assert.Equal (LayoutStyle.Computed, r.LayoutStyle);
+			Assert.Equal ("Window()({X=0,Y=0,Width=0,Height=0})", r.ToString ());
+			Assert.True (r.CanFocus);
+			Assert.False (r.HasFocus);
+			Assert.Equal (new Rect (0, 0, 0, 0), r.Bounds);
+			Assert.Equal (new Rect (0, 0, 0, 0), r.Frame);
+			Assert.Null (r.Focused);
+			Assert.NotNull (r.ColorScheme);
+			Assert.Equal (Dim.Fill (0), r.Width);
+			Assert.Equal (Dim.Fill (0), r.Height);
+			// FIXED: Pos needs equality implemented
+			Assert.Equal (Pos.At (0), r.X);
+			Assert.Equal (Pos.At (0), r.Y);
+			Assert.False (r.IsCurrentTop);
+			Assert.Empty (r.Id);
+			Assert.NotEmpty (r.Subviews);
+			Assert.False (r.WantContinuousButtonPressed);
+			Assert.False (r.WantMousePositionReports);
+			Assert.Null (r.SuperView);
+			Assert.Null (r.MostFocused);
+			Assert.Equal (TextDirection.LeftRight_TopBottom, r.TextDirection);
+
+			// Empty Rect
+			r = new Window (Rect.Empty, "title");
+			Assert.NotNull (r);
+			Assert.Equal ("title", r.Title);
+			Assert.Equal (LayoutStyle.Absolute, r.LayoutStyle);
+			Assert.Equal ("Window()({X=0,Y=0,Width=0,Height=0})", r.ToString ());
+			Assert.True (r.CanFocus);
+			Assert.False (r.HasFocus);
+			Assert.Equal (new Rect (0, 0, 0, 0), r.Bounds);
+			Assert.Equal (new Rect (0, 0, 0, 0), r.Frame);
+			Assert.Null (r.Focused);
+			Assert.NotNull (r.ColorScheme);
+			Assert.NotNull (r.Width);       // All view Dim are initialized now,
+			Assert.NotNull (r.Height);      // avoiding Dim errors.
+			Assert.NotNull (r.X);           // All view Pos are initialized now,
+			Assert.NotNull (r.Y);           // avoiding Pos errors.
+			Assert.False (r.IsCurrentTop);
+			Assert.Empty (r.Id);
+			Assert.NotEmpty (r.Subviews);
+			Assert.False (r.WantContinuousButtonPressed);
+			Assert.False (r.WantMousePositionReports);
+			Assert.Null (r.SuperView);
+			Assert.Null (r.MostFocused);
+			Assert.Equal (TextDirection.LeftRight_TopBottom, r.TextDirection);
+
+			// Rect with values
+			r = new Window (new Rect (1, 2, 3, 4), "title");
+			Assert.Equal ("title", r.Title);
+			Assert.NotNull (r);
+			Assert.Equal (LayoutStyle.Absolute, r.LayoutStyle);
+			Assert.Equal ("Window()({X=1,Y=2,Width=3,Height=4})", r.ToString ());
+			Assert.True (r.CanFocus);
+			Assert.False (r.HasFocus);
+			Assert.Equal (new Rect (0, 0, 3, 4), r.Bounds);
+			Assert.Equal (new Rect (1, 2, 3, 4), r.Frame);
+			Assert.Null (r.Focused);
+			Assert.NotNull (r.ColorScheme);
+			Assert.NotNull (r.Width);
+			Assert.NotNull (r.Height);
+			Assert.NotNull (r.X);
+			Assert.NotNull (r.Y);
+			Assert.False (r.IsCurrentTop);
+			Assert.Empty (r.Id);
+			Assert.NotEmpty (r.Subviews);
+			Assert.False (r.WantContinuousButtonPressed);
+			Assert.False (r.WantMousePositionReports);
+			Assert.Null (r.SuperView);
+			Assert.Null (r.MostFocused);
+			Assert.Equal (TextDirection.LeftRight_TopBottom, r.TextDirection);
+			r.Dispose();
+		}
+
+		[Fact]
+		public void Set_Title_Fires_TitleChanging ()
+		{
+			var r = new Window ();
+			Assert.Null (r.Title);
+
+			string expectedAfter = null;
+			string expectedDuring = null;
+			bool cancel = false;
+			r.TitleChanging += (args) => {
+				Assert.Equal (expectedDuring, args.NewTitle);
+				args.Cancel = cancel;
+			};
+
+			r.Title = expectedDuring = expectedAfter = "title";
+			Assert.Equal (expectedAfter, r.Title.ToString());
+
+			r.Title = expectedDuring = expectedAfter = "a different title";
+			Assert.Equal (expectedAfter, r.Title.ToString ());
+
+			// Now setup cancelling the change and change it back to "title"
+			cancel = true;
+			r.Title = expectedDuring = "title";
+			Assert.Equal (expectedAfter, r.Title.ToString ());
+			r.Dispose ();
+
+		}
+
+		[Fact]
+		public void Set_Title_Fires_TitleChanged ()
+		{
+			var r = new Window ();
+			Assert.Null (r.Title);
+
+			string expected = null;
+			r.TitleChanged += (args) => {
+				Assert.Equal (r.Title, args.NewTitle);
+			};
+
+			expected = "title";
+			r.Title = expected;
+			Assert.Equal (expected, r.Title.ToString ());
+
+			expected = "another title";
+			r.Title = expected;
+			Assert.Equal (expected, r.Title.ToString ());
+			r.Dispose ();
+		}
+	}
+}

+ 1 - 1
UnitTests/WizardTests.cs

@@ -102,7 +102,7 @@ namespace Terminal.Gui.Views {
 			int height = 7;
 			d.SetBufferSize (width, height);
 
-			var btnBackText = "Back";
+			//	var btnBackText = "Back";
 			var btnBack = string.Empty; // $"{d.LeftBracket} {btnBackText} {d.RightBracket}";
 			var btnNextText = "Finish"; // "Next";
 			var btnNext = $"{d.LeftBracket}{d.LeftDefaultIndicator} {btnNextText} {d.RightDefaultIndicator}{d.RightBracket}";