diff --git a/Terminal.Gui/Core/Window.cs b/Terminal.Gui/Core/Window.cs
index 341eca004..20230e49d 100644
--- a/Terminal.Gui/Core/Window.cs
+++ b/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;
}
}
+
+ ///
+ /// An which allows passing a cancelable new value event.
+ ///
+ public class TitleEventArgs : EventArgs {
+ ///
+ /// The new Window Title.
+ ///
+ public ustring NewTitle { get; set; }
+
+ ///
+ /// Flag which allows cancelling changing to the new TItle value.
+ ///
+ public bool Cancel { get; set; }
+
+ ///
+ /// Initializes a new instance of
+ ///
+ /// The new to be replaced.
+ public TitleEventArgs (ustring newTitle)
+ {
+ NewTitle = newTitle;
+ }
+ }
+ ///
+ /// Called before the changes. Invokes the event, which can be cancelled.
+ ///
+ /// `true` if an event handler cancelled the Title change.
+ public virtual bool OnTitleChanging (ustring newTitle)
+ {
+ var args = new TitleEventArgs (newTitle);
+ TitleChanging?.Invoke (args);
+ return args.Cancel;
+ }
+
+ ///
+ /// Event fired when the is changing. Set to
+ /// `true` to cancel the Title change.
+ ///
+ public event Action TitleChanging;
+
+ ///
+ /// Called when the has been changed. Invokes the event.
+ ///
+ public virtual void OnTitleChanged (ustring newTitle)
+ {
+ var args = new TitleEventArgs (title);
+ TitleChanged?.Invoke (args);
+ }
+
+ ///
+ /// Event fired after the has been changed.
+ ///
+ public event Action TitleChanged;
}
}
diff --git a/UnitTests/WindowTests.cs b/UnitTests/WindowTests.cs
new file mode 100644
index 000000000..ae75a1e42
--- /dev/null
+++ b/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 ();
+ }
+ }
+}
diff --git a/UnitTests/WizardTests.cs b/UnitTests/WizardTests.cs
index b676ebb62..839e66a29 100644
--- a/UnitTests/WizardTests.cs
+++ b/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}";