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}";