diff --git a/Terminal.Gui/View/View.Content.cs b/Terminal.Gui/View/View.Content.cs index d1bfafc79..968558ca6 100644 --- a/Terminal.Gui/View/View.Content.cs +++ b/Terminal.Gui/View/View.Content.cs @@ -313,7 +313,7 @@ public partial class View //SetSubViewNeedsDraw(); } - OnViewportChanged (new (IsInitialized ? Viewport : Rectangle.Empty, oldViewport)); + RaiseViewportChangedEvent (oldViewport); return; } @@ -326,7 +326,7 @@ public partial class View Size = newSize }; - OnViewportChanged (new (IsInitialized ? Viewport : Rectangle.Empty, oldViewport)); + // Note, setting the Frame will cause ViewportChanged to be raised. return; @@ -368,6 +368,13 @@ public partial class View } } + private void RaiseViewportChangedEvent (Rectangle oldViewport) + { + var args = new DrawEventArgs (IsInitialized ? Viewport : Rectangle.Empty, oldViewport); + OnViewportChanged (args); + ViewportChanged?.Invoke (this, args); + } + /// /// Fired when the changes. This event is fired after the has been /// updated. @@ -378,7 +385,7 @@ public partial class View /// Called when the changes. Invokes the event. /// /// - protected virtual void OnViewportChanged (DrawEventArgs e) { ViewportChanged?.Invoke (this, e); } + protected virtual void OnViewportChanged (DrawEventArgs e) { } /// /// Converts a -relative location and size to a screen-relative location and size. diff --git a/Terminal.Gui/View/View.Layout.cs b/Terminal.Gui/View/View.Layout.cs index 67e18955e..1b37f9725 100644 --- a/Terminal.Gui/View/View.Layout.cs +++ b/Terminal.Gui/View/View.Layout.cs @@ -98,6 +98,11 @@ public partial class View // Layout APIs // BUGBUG: When SetFrame is called from Frame_set, this event gets raised BEFORE OnResizeNeeded. Is that OK? OnFrameChanged (in frame); FrameChanged?.Invoke (this, new (in frame)); + + if (oldViewport != Viewport) + { + RaiseViewportChangedEvent (oldViewport); + } return true; } diff --git a/UnitTests/View/Layout/FrameTests.cs b/UnitTests/View/Layout/FrameTests.cs index 173409a0f..cc9ba8608 100644 --- a/UnitTests/View/Layout/FrameTests.cs +++ b/UnitTests/View/Layout/FrameTests.cs @@ -259,4 +259,55 @@ public class FrameTests (ITestOutputHelper output) Assert.Equal (Dim.Absolute (40), v.Height); v.Dispose (); } + + private class TestFrameEventsView : View + { + public int OnFrameChangedCallCount { get; private set; } + public int FrameChangedEventCallCount { get; private set; } + + public TestFrameEventsView () + { + FrameChanged += (sender, args) => FrameChangedEventCallCount++; + } + + protected override void OnFrameChanged (in Rectangle frame) + { + OnFrameChangedCallCount++; + base.OnFrameChanged (frame); + } + } + + [Fact] + public void OnFrameChanged_Called_When_Frame_Changes () + { + // Arrange + var view = new TestFrameEventsView (); + var initialFrame = new Rectangle (0, 0, 10, 10); + var newFrame = new Rectangle (0, 0, 20, 20); + view.Frame = initialFrame; + Assert.Equal (1, view.OnFrameChangedCallCount); + + // Act + view.Frame = newFrame; + + // Assert + Assert.Equal (2, view.OnFrameChangedCallCount); + } + + [Fact] + public void FrameChanged_Event_Raised_When_Frame_Changes () + { + // Arrange + var view = new TestFrameEventsView (); + var initialFrame = new Rectangle (0, 0, 10, 10); + var newFrame = new Rectangle (0, 0, 20, 20); + view.Frame = initialFrame; + Assert.Equal (1, view.FrameChangedEventCallCount); + + // Act + view.Frame = newFrame; + + // Assert + Assert.Equal (2, view.FrameChangedEventCallCount); + } } diff --git a/UnitTests/View/Layout/ViewportTests.cs b/UnitTests/View/Layout/ViewportTests.cs index c210d8215..f6ab2d394 100644 --- a/UnitTests/View/Layout/ViewportTests.cs +++ b/UnitTests/View/Layout/ViewportTests.cs @@ -387,6 +387,93 @@ public class ViewportTests (ITestOutputHelper output) Assert.NotEqual (view.Viewport.Size, view.GetContentSize ()); } + private class TestViewportEventsView : View + { + public int OnViewportChangedCallCount { get; private set; } + public int ViewportChangedEventCallCount { get; private set; } + + public TestViewportEventsView () + { + ViewportChanged += (sender, args) => ViewportChangedEventCallCount++; + } + + protected override void OnViewportChanged (DrawEventArgs e) + { + OnViewportChangedCallCount++; + base.OnViewportChanged (e); + } + } + + [Fact] + public void OnViewportChanged_Called_When_Viewport_Changes () + { + // Arrange + var view = new TestViewportEventsView (); + var initialViewport = new Rectangle (0, 0, 10, 10); + var newViewport = new Rectangle (0, 0, 20, 20); + Assert.Equal (0, view.OnViewportChangedCallCount); + view.Viewport = initialViewport; + Assert.Equal (1, view.OnViewportChangedCallCount); + + // Act + view.Viewport = newViewport; + + // Assert + Assert.Equal (2, view.OnViewportChangedCallCount); + } + + [Fact] + public void ViewportChanged_Event_Raised_When_Viewport_Changes () + { + // Arrange + var view = new TestViewportEventsView (); + var initialViewport = new Rectangle (0, 0, 10, 10); + var newViewport = new Rectangle (0, 0, 20, 20); + view.Viewport = initialViewport; + Assert.Equal (1, view.ViewportChangedEventCallCount); + + // Act + view.Viewport = newViewport; + + // Assert + Assert.Equal (2, view.ViewportChangedEventCallCount); + } + + [Fact] + public void OnViewportChanged_Called_When_Frame_Changes () + { + // Arrange + var view = new TestViewportEventsView (); + var initialFrame = new Rectangle (0, 0, 10, 10); + var newFrame = new Rectangle (0, 0, 20, 20); + Assert.Equal (0, view.OnViewportChangedCallCount); + view.Frame = initialFrame; + Assert.Equal (1, view.OnViewportChangedCallCount); + + // Act + view.Frame = newFrame; + + // Assert + Assert.Equal (2, view.OnViewportChangedCallCount); + } + + [Fact] + public void ViewportChanged_Event_Raised_When_Frame_Changes () + { + // Arrange + var view = new TestViewportEventsView (); + var initialFrame = new Rectangle (0, 0, 10, 10); + var newFrame = new Rectangle (0, 0, 20, 20); + view.Frame = initialFrame; + Assert.Equal (1, view.ViewportChangedEventCallCount); + + // Act + view.Frame = newFrame; + + // Assert + Assert.Equal (2, view.ViewportChangedEventCallCount); + } + //[Theory] //[InlineData (0, 0, true)] //[InlineData (-1, 0, true)]