From e16205af8546a6bcefe87629ad2195759275342b Mon Sep 17 00:00:00 2001 From: BDisp Date: Tue, 7 Nov 2023 00:49:06 +0000 Subject: [PATCH] Fixes #2954. Modal view is always refreshing only by moving the mouse. (#2958) * Fixes #2954. Modal view is always refreshing only by moving the mouse. * Fixes invisible topLevel to be cleaned up which should be a drawing task. * Forcing Shutdown. --- Terminal.Gui/Application.cs | 7 +- UnitTests/Application/ApplicationTests.cs | 109 +++++++++++++++++++++- UnitTests/Views/OverlappedTests.cs | 73 ++++++++++++++- 3 files changed, 179 insertions(+), 10 deletions(-) diff --git a/Terminal.Gui/Application.cs b/Terminal.Gui/Application.cs index 1521c86f81..3889b51f50 100644 --- a/Terminal.Gui/Application.cs +++ b/Terminal.Gui/Application.cs @@ -665,8 +665,6 @@ public static void RunIteration (ref RunState state, ref bool firstIteration) OverlappedTop?.OnActivate (state.Toplevel); Top.SetSubViewNeedsDisplay (); Refresh (); - } else if (Current.SuperView == null && Current?.Modal == true) { - Refresh (); } } @@ -675,13 +673,11 @@ public static void RunIteration (ref RunState state, ref bool firstIteration) if (state.Toplevel != Top && (Top.NeedsDisplay || Top.SubViewNeedsDisplay || Top.LayoutNeeded)) { state.Toplevel.SetNeedsDisplay (state.Toplevel.Frame); - Top.Clear (); Top.Draw (); foreach (var top in _topLevels.Reverse ()) { if (top != Top && top != state.Toplevel) { top.SetNeedsDisplay (); top.SetSubViewNeedsDisplay (); - top.Clear (); top.Draw (); } } @@ -690,14 +686,13 @@ public static void RunIteration (ref RunState state, ref bool firstIteration) && (Driver.Cols != state.Toplevel.Frame.Width || Driver.Rows != state.Toplevel.Frame.Height) && (state.Toplevel.NeedsDisplay || state.Toplevel.SubViewNeedsDisplay || state.Toplevel.LayoutNeeded)) { - state.Toplevel.Clear (); + state.Toplevel.Clear (new Rect (Point.Empty, new Size (Driver.Cols, Driver.Rows))); } if (state.Toplevel.NeedsDisplay || state.Toplevel.SubViewNeedsDisplay || state.Toplevel.LayoutNeeded || OverlappedChildNeedsDisplay ()) { - state.Toplevel.Clear (); state.Toplevel.Draw (); state.Toplevel.PositionCursor (); Driver.Refresh (); diff --git a/UnitTests/Application/ApplicationTests.cs b/UnitTests/Application/ApplicationTests.cs index d5f5d83d66..585fff8557 100644 --- a/UnitTests/Application/ApplicationTests.cs +++ b/UnitTests/Application/ApplicationTests.cs @@ -1,10 +1,11 @@ -using System; +using System; using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Xunit; +using Xunit.Abstractions; // Alias Console to MockConsole so we don't accidentally use Console using Console = Terminal.Gui.FakeConsole; @@ -12,8 +13,11 @@ namespace Terminal.Gui.ApplicationTests; public class ApplicationTests { - public ApplicationTests () + readonly ITestOutputHelper output; + + public ApplicationTests (ITestOutputHelper output) { + this.output = output; #if DEBUG_IDISPOSABLE Responder.Instances.Clear (); RunState.Instances.Clear (); @@ -416,6 +420,107 @@ public void Run_Loaded_Ready_Unlodaded_Events () Assert.Equal (3, count); } + [Fact] + public void Run_Toplevel_With_Modal_View_Does_Not_Refresh_If_Not_Dirty () + { + Init (); + var count = 0; + Dialog d = null; + var top = Application.Top; + top.DrawContent += (s, a) => count++; + var iteration = -1; + Application.Iteration += (s, a) => { + iteration++; + if (iteration == 0) { + d = new Dialog (); + d.DrawContent += (s, a) => count++; + Application.Run (d); + } else if (iteration < 3) { + Application.OnMouseEvent (new (new () { X = 0, Y = 0, Flags = MouseFlags.ReportMousePosition })); + Assert.False (top.NeedsDisplay); + Assert.False (top.SubViewNeedsDisplay); + Assert.False (top.LayoutNeeded); + Assert.False (d.NeedsDisplay); + Assert.False (d.SubViewNeedsDisplay); + Assert.False (d.LayoutNeeded); + } else { + Application.RequestStop (); + } + }; + Application.Run (); + Application.Shutdown (); + // 1 - First top load, 1 - Dialog load, 1 - Dialog unload, Total - 3. + Assert.Equal (3, count); + } + + [Fact] + public void Run_A_Modal_Toplevel_Refresh_Background_On_Moving () + { + Init (); + var d = new Dialog () { Width = 5, Height = 5 }; + ((FakeDriver)Application.Driver).SetBufferSize (10, 10); + var rs = Application.Begin (d); + TestHelpers.AssertDriverContentsWithFrameAre (@" + ┌───┐ + │ │ + │ │ + │ │ + └───┘", output); + + var attributes = new Attribute [] { + // 0 + new Attribute (ColorName.White, ColorName.Black), + // 1 + Colors.Dialog.Normal + }; + TestHelpers.AssertDriverColorsAre (@" +0000000000 +0000000000 +0011111000 +0011111000 +0011111000 +0011111000 +0011111000 +0000000000 +0000000000 +0000000000 +", null, attributes); + + Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () { X = 2, Y = 2, Flags = MouseFlags.Button1Pressed })); + Assert.Equal (d, Application.MouseGrabView); + + Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () { X = 1, Y = 1, Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition })); + Application.Refresh (); + TestHelpers.AssertDriverContentsWithFrameAre (@" + ┌───┐ + │ │ + │ │ + │ │ + └───┘", output); + + attributes = new Attribute [] { + // 0 + new Attribute (ColorName.White, ColorName.Black), + // 1 + Colors.Dialog.Normal + }; + TestHelpers.AssertDriverColorsAre (@" +0000000000 +0111110000 +0111110000 +0111110000 +0111110000 +0111110000 +0000000000 +0000000000 +0000000000 +0000000000 +", null, attributes); + + Application.End (rs); + Application.Shutdown (); + } + // TODO: Add tests for Run that test errorHandler #endregion diff --git a/UnitTests/Views/OverlappedTests.cs b/UnitTests/Views/OverlappedTests.cs index 7a22adc6ff..005fe4424f 100644 --- a/UnitTests/Views/OverlappedTests.cs +++ b/UnitTests/Views/OverlappedTests.cs @@ -1,21 +1,27 @@ -using System; +using System; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using Terminal.Gui; using Xunit; +using Xunit.Abstractions; // Alias Console to MockConsole so we don't accidentally use Console using Console = Terminal.Gui.FakeConsole; namespace Terminal.Gui.ViewsTests { public class OverlappedTests { - public OverlappedTests () + readonly ITestOutputHelper output; + + public OverlappedTests (ITestOutputHelper output) { + this.output = output; #if DEBUG_IDISPOSABLE Responder.Instances.Clear (); RunState.Instances.Clear (); + this.output = output; + #endif } @@ -674,5 +680,68 @@ public void MoveToOverlappedChild_Throw_NullReferenceException_Passing_Null_Para { Assert.Throws (delegate { Application.MoveToOverlappedChild (null); }); } + + + [Fact, AutoInitShutdown] + public void Visible_False_Does_Not_Clear () + { + var overlapped = new Overlapped (); + var win1 = new Window () { Width = 5, Height = 5, Visible = false }; + var win2 = new Window () { X = 1, Y = 1, Width = 5, Height = 5 }; + ((FakeDriver)Application.Driver).SetBufferSize (10, 10); + var rs = Application.Begin (overlapped); + Application.Begin (win1); + Application.Begin (win2); + Assert.Equal (win2, Application.Current); + var firstIteration = false; + Application.RunIteration (ref rs, ref firstIteration); + TestHelpers.AssertDriverContentsWithFrameAre (@" + ┌───┐ + │ │ + │ │ + │ │ + └───┘", output); + var attributes = new Attribute [] { + // 0 + Colors.TopLevel.Normal, + // 1 + Colors.Base.Normal + }; + TestHelpers.AssertDriverColorsAre (@" +0000000000 +0111110000 +0111110000 +0111110000 +0111110000 +0111110000 +0000000000 +0000000000 +0000000000 +0000000000", null, attributes); + + Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () { X = 1, Y = 1, Flags = MouseFlags.Button1Pressed })); + Assert.Equal (win2, Application.MouseGrabView); + Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () { X = 2, Y = 2, Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition })); + Application.RunIteration (ref rs, ref firstIteration); + TestHelpers.AssertDriverContentsWithFrameAre (@" + ┌───┐ + │ │ + │ │ + │ │ + └───┘", output); + TestHelpers.AssertDriverColorsAre (@" +0000000000 +0000000000 +0011111000 +0011111000 +0011111000 +0011111000 +0011111000 +0000000000 +0000000000 +0000000000", null, attributes); + + Application.Shutdown (); + } } }