diff --git a/CommunityToolkitExample/LoginView.cs b/CommunityToolkitExample/LoginView.cs index 7f8fbe53d0..726ab009fe 100644 --- a/CommunityToolkitExample/LoginView.cs +++ b/CommunityToolkitExample/LoginView.cs @@ -59,6 +59,7 @@ public void Receive (Message message) } } SetText(); + // BUGBUG: This should not be needed: Application.LayoutAndDraw (); } diff --git a/Terminal.Gui/Application/Application.Keyboard.cs b/Terminal.Gui/Application/Application.Keyboard.cs index 97b566166c..16d167f346 100644 --- a/Terminal.Gui/Application/Application.Keyboard.cs +++ b/Terminal.Gui/Application/Application.Keyboard.cs @@ -205,7 +205,7 @@ internal static void AddApplicationKeyBindings () Command.Refresh, static () => { - LayoutAndDraw (); + LayoutAndDraw (true); return true; } diff --git a/Terminal.Gui/Application/Application.Run.cs b/Terminal.Gui/Application/Application.Run.cs index 7511f82161..2a91ac8dfa 100644 --- a/Terminal.Gui/Application/Application.Run.cs +++ b/Terminal.Gui/Application/Application.Run.cs @@ -505,6 +505,11 @@ public static void LayoutAndDraw (bool forceDraw = false) { bool neededLayout = View.Layout (TopLevels.Reverse (), Screen.Size); + if (ClearScreenNextIteration) + { + forceDraw = true; + ClearScreenNextIteration = false; + } if (forceDraw) { Driver?.ClearContents (); @@ -688,6 +693,6 @@ public static void End (RunState runState) runState.Toplevel = null; runState.Dispose (); - LayoutAndDraw (); + LayoutAndDraw (true); } } diff --git a/Terminal.Gui/Application/Application.Screen.cs b/Terminal.Gui/Application/Application.Screen.cs index c5bf6d6fd0..5bd74fb1a5 100644 --- a/Terminal.Gui/Application/Application.Screen.cs +++ b/Terminal.Gui/Application/Application.Screen.cs @@ -63,8 +63,17 @@ public static bool OnSizeChanging (SizeChangedEventArgs args) t.SetNeedsLayout (); } - LayoutAndDraw (); + LayoutAndDraw (true); return true; } + + /// + /// Gets or sets whether the screen will be cleared, and all Views redrawn, during the next Application iteration. + /// + /// + /// This is typicall set to true when a View's changes and that view has no + /// SuperView (e.g. when is moved or resized. + /// + public static bool ClearScreenNextIteration { get; set; } } diff --git a/Terminal.Gui/Application/Application.cs b/Terminal.Gui/Application/Application.cs index d9e6c68d92..85a234cef7 100644 --- a/Terminal.Gui/Application/Application.cs +++ b/Terminal.Gui/Application/Application.cs @@ -215,6 +215,8 @@ internal static void ResetState (bool ignoreDisposed = false) Navigation = null; + ClearScreenNextIteration = false; + AddApplicationKeyBindings (); // Reset synchronization context to allow the user to run async/await, diff --git a/Terminal.Gui/View/View.Layout.cs b/Terminal.Gui/View/View.Layout.cs index 1b37f9725b..b0991711b0 100644 --- a/Terminal.Gui/View/View.Layout.cs +++ b/Terminal.Gui/View/View.Layout.cs @@ -557,7 +557,14 @@ public bool SetRelativeLayout (Size superviewContentSize) SetTitleTextFormatterSize (); } - SuperView?.SetNeedsDraw (); + if (SuperView is { }) + { + SuperView?.SetNeedsDraw (); + } + else + { + Application.ClearScreenNextIteration = true; + } } if (TextFormatter.ConstrainToWidth is null) diff --git a/Terminal.Gui/View/View.cs b/Terminal.Gui/View/View.cs index 27fcb065af..e1470d7b1f 100644 --- a/Terminal.Gui/View/View.cs +++ b/Terminal.Gui/View/View.cs @@ -369,7 +369,14 @@ public virtual bool Visible SetNeedsLayout (); SuperView?.SetNeedsLayout (); SetNeedsDraw (); - SuperView?.SetNeedsDraw (); + if (SuperView is { }) + { + SuperView?.SetNeedsDraw (); + } + else + { + Application.ClearScreenNextIteration = true; + } } } diff --git a/Terminal.Gui/Views/Menu/Menu.cs b/Terminal.Gui/Views/Menu/Menu.cs index fdfab4d982..ac3d617977 100644 --- a/Terminal.Gui/Views/Menu/Menu.cs +++ b/Terminal.Gui/Views/Menu/Menu.cs @@ -608,8 +608,7 @@ public void Run (Action? action) Application.UngrabMouse (); _host.CloseAllMenus (); - Application.Driver!.ClearContents (); - Application.LayoutAndDraw (); + Application.LayoutAndDraw (true); _host.Run (action); } diff --git a/Terminal.Gui/Views/Menu/MenuBar.cs b/Terminal.Gui/Views/Menu/MenuBar.cs index 7bba8b7143..3816a1a29b 100644 --- a/Terminal.Gui/Views/Menu/MenuBar.cs +++ b/Terminal.Gui/Views/Menu/MenuBar.cs @@ -1117,7 +1117,7 @@ internal bool SelectItem (MenuItem? item) Application.UngrabMouse (); CloseAllMenus (); - Application.LayoutAndDraw (); + Application.LayoutAndDraw (true); _openedByAltKey = true; return Run (item.Action); diff --git a/UnitTests/Application/ApplicationScreenTests.cs b/UnitTests/Application/ApplicationScreenTests.cs new file mode 100644 index 0000000000..c6a220e525 --- /dev/null +++ b/UnitTests/Application/ApplicationScreenTests.cs @@ -0,0 +1,68 @@ +using Xunit.Abstractions; + +namespace Terminal.Gui.ApplicationTests; + +public class ApplicationScreenTests (ITestOutputHelper output) +{ + [Fact] + public void ClearScreenNextIteration_Resets_To_False_After_LayoutAndDraw () + { + // Arrange + Application.Init (); + + // Act + Application.ClearScreenNextIteration = true; + Application.LayoutAndDraw (); + + // Assert + Assert.False (Application.ClearScreenNextIteration); + + // Cleanup + Application.ResetState (true); + } + + [Fact] + public void ClearContents_Called_When_Top_Frame_Changes () + { + // Arrange + Application.Init (new FakeDriver ()); + Application.Top = new Toplevel (); + Application.TopLevels.Push (Application.Top); + + int clearedContentsRaised = 0; + + Application.Driver!.ClearedContents += (e, a) => clearedContentsRaised++; + + // Act + Application.LayoutAndDraw (); + + // Assert + Assert.Equal (1, clearedContentsRaised); + + // Act + Application.Top.SetNeedsLayout (); + Application.LayoutAndDraw (); + + // Assert + Assert.Equal (1, clearedContentsRaised); + + // Act + Application.Top.X = 1; + Application.LayoutAndDraw (); + + // Assert + Assert.Equal (2, clearedContentsRaised); + + // Act + Application.Top.Width = 10; + Application.LayoutAndDraw (); + + // Assert + Assert.Equal (3, clearedContentsRaised); + + // Cleanup + Application.Top.Dispose (); + Application.Top = null; + Application.Shutdown (); + } +} diff --git a/UnitTests/Configuration/ConfigPropertyTests.cs b/UnitTests/Configuration/ConfigPropertyTests.cs index 0bf96dc6e3..f751b3d72b 100644 --- a/UnitTests/Configuration/ConfigPropertyTests.cs +++ b/UnitTests/Configuration/ConfigPropertyTests.cs @@ -5,6 +5,8 @@ using Terminal.Gui; using Xunit; +namespace Terminal.Gui.ConfigurationTests; + public class ConfigPropertyTests { [Fact] diff --git a/UnitTests/Drawing/SixelEncoderTests.cs b/UnitTests/Drawing/SixelEncoderTests.cs index 65d9e423af..f85942e729 100644 --- a/UnitTests/Drawing/SixelEncoderTests.cs +++ b/UnitTests/Drawing/SixelEncoderTests.cs @@ -1,6 +1,6 @@ using Color = Terminal.Gui.Color; -namespace UnitTests.Drawing; +namespace Terminal.Gui.DrawingTests; public class SixelEncoderTests { diff --git a/UnitTests/LocalPackagesTests.cs b/UnitTests/LocalPackagesTests.cs index 5de7b371f3..04e5c7802b 100644 --- a/UnitTests/LocalPackagesTests.cs +++ b/UnitTests/LocalPackagesTests.cs @@ -1,4 +1,5 @@ -namespace Terminal.Gui; + +namespace Terminal.Gui.BuildAndDeployTests; public class LocalPackagesTests { diff --git a/bench.json b/bench.json deleted file mode 100644 index 52a38240e1..0000000000 --- a/bench.json +++ /dev/null @@ -1,52 +0,0 @@ -[ - { - "Scenario": "Adornments Demo", - "Duration": "00:00:00.1805368", - "IterationCount": 501, - "ClearedContentCount": 0, - "RefreshedCount": 503, - "UpdatedCount": 1, - "DrawCompleteCount": 82, - "LaidOutCount": 82 - }, - { - "Scenario": "All Views Tester", - "Duration": "00:00:00.1070009", - "IterationCount": 501, - "ClearedContentCount": 0, - "RefreshedCount": 503, - "UpdatedCount": 1, - "DrawCompleteCount": 103, - "LaidOutCount": 182 - }, - { - "Scenario": "Animation", - "Duration": "00:00:00.0675802", - "IterationCount": 501, - "ClearedContentCount": 0, - "RefreshedCount": 503, - "UpdatedCount": 1, - "DrawCompleteCount": 4, - "LaidOutCount": 4 - }, - { - "Scenario": "Arrangement", - "Duration": "00:00:00.1284709", - "IterationCount": 501, - "ClearedContentCount": 0, - "RefreshedCount": 503, - "UpdatedCount": 1, - "DrawCompleteCount": 123, - "LaidOutCount": 123 - }, - { - "Scenario": "ASCIICustomButtonTest", - "Duration": "00:00:01.0613372", - "IterationCount": 30, - "ClearedContentCount": 0, - "RefreshedCount": 32, - "UpdatedCount": 31, - "DrawCompleteCount": 4185, - "LaidOutCount": 2852 - } -] \ No newline at end of file