Fixed stoopid screen bug

This commit is contained in:
Tig
2024-10-21 22:19:46 -06:00
parent 4d4dbbf8b9
commit a632c238e9
7 changed files with 211 additions and 83 deletions

View File

@@ -3,28 +3,13 @@ namespace Terminal.Gui;
public static partial class Application // Screen related stuff
{
private static Size _screenSize = new (2048, 2048);
/// <summary>
/// INTERNAL API for Unit Tests. Only works if there's no driver.
/// </summary>
/// <param name="size"></param>
internal static void SetScreenSize (Size size)
{
if (Driver is { })
{
throw new InvalidOperationException ("Cannot set the screen size when the ConsoleDriver is already initialized.");
}
_screenSize = size;
}
/// <summary>
/// Gets the size of the screen. This is the size of the screen as reported by the <see cref="ConsoleDriver"/>.
/// </summary>
/// <remarks>
/// If the <see cref="ConsoleDriver"/> has not been initialized, this will return a default size of 2048x2048; useful for unit tests.
/// </remarks>
public static Rectangle Screen => Driver?.Screen ?? new (new (0, 0), _screenSize);
public static Rectangle Screen => Driver?.Screen ?? new (new (0, 0), new (2048, 2048));
/// <summary>Invoked when the terminal's size changed. The new size of the terminal is provided.</summary>
/// <remarks>

View File

@@ -62,7 +62,8 @@ public class Adornment : View
if (current != _thickness)
{
Parent?.SetAdornmentFrames ();
Parent?.SetLayoutNeeded ();
SetLayoutNeeded ();
//Parent?.SetLayoutNeeded ();
OnThicknessChanged ();
}

View File

@@ -167,7 +167,7 @@ public partial class View // Layout APIs
#region Frame
private Rectangle _frame;
private Rectangle? _frame;
/// <summary>Gets or sets the absolute location and dimension of the view.</summary>
/// <value>
@@ -199,7 +199,7 @@ public partial class View // Layout APIs
{
//Debug.WriteLine("Frame_get with _layoutNeeded");
}
return _frame;
return _frame ?? Rectangle.Empty;
}
set
{
@@ -207,10 +207,10 @@ public partial class View // Layout APIs
if (SetFrame (value with { Width = Math.Max (value.Width, 0), Height = Math.Max (value.Height, 0) }))
{
// If Frame gets set, set all Pos/Dim to Absolute values.
_x = _frame.X;
_y = _frame.Y;
_width = _frame.Width;
_height = _frame.Height;
_x = _frame!.Value.X;
_y = _frame!.Value.Y;
_width = _frame!.Value.Width;
_height = _frame!.Value.Height;
// Implicit layout is ok here because we are setting the Frame directly.
Layout ();
@@ -308,6 +308,18 @@ public partial class View // Layout APIs
return frame;
}
// helper for X, Y, Width, Height setters to ensure consistency
private void PosDimSet ()
{
SetLayoutNeeded ();
if (_x is PosAbsolute && _y is PosAbsolute && _width is DimAbsolute && _height is DimAbsolute)
{
// Implicit layout is ok here because all Pos/Dim are Absolute values.
Layout ();
}
}
private Pos _x = Pos.Absolute (0);
/// <summary>Gets or sets the X position for the view (the column).</summary>
@@ -346,22 +358,10 @@ public partial class View // Layout APIs
_x = value ?? throw new ArgumentNullException (nameof (value), @$"{nameof (X)} cannot be null");
SetLayoutNeeded ();
if (IsAbsoluteLayout ())
{
// Implicit layout is ok here because all Pos/Dim are Absolute values.
Layout ();
SetLayoutNeeded ();
}
PosDimSet ();
}
}
private bool IsAbsoluteLayout ()
{
return _x is PosAbsolute && _y is PosAbsolute && _width is DimAbsolute && _height is DimAbsolute;
}
private Pos _y = Pos.Absolute (0);
@@ -400,15 +400,7 @@ public partial class View // Layout APIs
}
_y = value ?? throw new ArgumentNullException (nameof (value), @$"{nameof (Y)} cannot be null");
SetLayoutNeeded ();
if (IsAbsoluteLayout ())
{
// Implicit layout is ok here because all Pos/Dim are Absolute values.
Layout ();
SetLayoutNeeded ();
}
PosDimSet ();
}
}
@@ -459,14 +451,7 @@ public partial class View // Layout APIs
// Reset TextFormatter - Will be recalculated in SetTextFormatterSize
TextFormatter.ConstrainToHeight = null;
SetLayoutNeeded ();
if (IsAbsoluteLayout ())
{
// Implicit layout is ok here because all Pos/Dim are Absolute values.
Layout ();
SetLayoutNeeded ();
}
PosDimSet ();
}
}
@@ -517,15 +502,7 @@ public partial class View // Layout APIs
// Reset TextFormatter - Will be recalculated in SetTextFormatterSize
TextFormatter.ConstrainToWidth = null;
SetLayoutNeeded ();
if (IsAbsoluteLayout ())
{
// Implicit layout is ok here because all Pos/Dim are Absolute values.
Layout ();
SetLayoutNeeded ();
}
PosDimSet ();
}
}

View File

@@ -1,8 +1,4 @@
#nullable enable
using System.Text;
using Microsoft.VisualStudio.TestPlatform.Utilities;
using Xunit.Abstractions;
namespace Terminal.Gui.ViewTests;
[Trait ("Category", "Output")]
@@ -116,7 +112,7 @@ public class NeedsDisplayTests ()
}
[Fact]
public void NeedsDisplay_False_After_SetRelativeLayout ()
public void NeedsDisplay_False_After_SetRelativeLayout_Absolute_Dims ()
{
var view = new View { Width = 2, Height = 2 };
Assert.True (view.NeedsDisplay);
@@ -131,16 +127,22 @@ public class NeedsDisplayTests ()
Assert.False (view.NeedsDisplay);
view.SetLayoutNeeded ();
// SRL won't change anything since the view is Absolute
view.SetRelativeLayout (Application.Screen.Size);
Assert.True (view.NeedsDisplay);
view.NeedsDisplay = false;
// SRL won't change anything since the view is Absolute. However, Layout has not been called
view.SetRelativeLayout (new (10, 10));
Assert.True (view.NeedsDisplay);
}
view = new View { Width = Dim.Percent (50), Height = Dim.Percent (50) };
[Fact]
public void NeedsDisplay_False_After_SetRelativeLayout_Relative_Dims ()
{
var view = new View { Width = Dim.Percent (50), Height = Dim.Percent (50) };
View superView = new ()
{
Id = "superView",
@@ -164,18 +166,25 @@ public class NeedsDisplayTests ()
superView.SetRelativeLayout (Application.Screen.Size);
Assert.True (view.NeedsDisplay);
Assert.True (superView.NeedsDisplay);
}
[Fact]
public void NeedsDisplay_False_After_SetRelativeLayout_10x10 ()
{
View superView = new ()
{
Id = "superView",
Width = Dim.Fill (),
Height = Dim.Fill ()
};
Assert.True (superView.NeedsDisplay);
superView.Layout ();
superView.NeedsDisplay = false;
superView.SetRelativeLayout (new (10, 10));
Assert.True (superView.NeedsDisplay);
Assert.True (view.NeedsDisplay);
superView.Layout ();
view.SetRelativeLayout (new (11, 11));
Assert.True (superView.NeedsDisplay);
Assert.True (view.NeedsDisplay);
}
[Fact]
@@ -258,7 +267,7 @@ public class NeedsDisplayTests ()
view.Frame = new (3, 3, 6, 6); // Grow right/bottom 1
Assert.Equal (new (3, 3, 6, 6), view.Frame);
Assert.Equal (new (0, 0, 6, 6), view.Viewport);
Assert.Equal (new (0, 0, 6, 6), view._needsDisplayRect);
Assert.Equal (new (0, 0, 6, 6), view._needsDisplayRect);
view.Frame = new (3, 3, 5, 5); // Shrink right/bottom 1
Assert.Equal (new (3, 3, 5, 5), view.Frame);
@@ -278,7 +287,7 @@ public class NeedsDisplayTests ()
view.Frame = new (3, 3, 6, 6); // Grow right/bottom 1
Assert.Equal (new (3, 3, 6, 6), view.Frame);
Assert.Equal (new (1, 1, 6, 6), view.Viewport);
Assert.Equal (new (1, 1, 6, 6), view._needsDisplayRect);
Assert.Equal (new (1, 1, 6, 6), view._needsDisplayRect);
view.Frame = new (3, 3, 5, 5);
Assert.Equal (new (3, 3, 5, 5), view.Frame);

View File

@@ -994,9 +994,10 @@ public partial class DimAutoTests (ITestOutputHelper output)
}
[Fact]
[SetupFakeDriver]
public void DimAutoStyle_Content_Pos_AnchorEnd_Locates_Correctly ()
{
Application.SetScreenSize (new Size (10, 10));
(((FakeDriver)Application.Driver)!).SetBufferSize(10,10);
DimAutoTestView view = new (Auto (DimAutoStyle.Content), Auto (DimAutoStyle.Content));

View File

@@ -22,14 +22,171 @@ public class FrameTests (ITestOutputHelper output)
{
Rectangle frame = new (1, 2, 3, 4);
View view = new ();
Assert.False (view.NeedsLayout);
Assert.Equal (Rectangle.Empty, view.Frame);
view.BeginInit ();
view.EndInit ();
view.Frame = frame;
Assert.Equal (frame, view.Frame);
Assert.False (view.NeedsLayout);
Assert.Equal(view.X, frame.X);
Assert.Equal (view.Y, frame.Y);
Assert.Equal (view.Width, frame.Width);
Assert.Equal (view.Height, frame.Height);
}
[Fact]
public void Frame_Initializer_Sets ()
{
Rectangle frame = new (1, 2, 3, 4);
View view = new ()
{
Frame = frame,
};
Assert.Equal (frame, view.Frame);
Assert.False (view.NeedsLayout);
Assert.Equal (frame.Size, view.Viewport.Size);
Assert.Equal (view.X, frame.X);
Assert.Equal (view.Y, frame.Y);
Assert.Equal (view.Width, frame.Width);
Assert.Equal (view.Height, frame.Height);
}
[Fact]
public void Frame_Empty_Initializer_Sets ()
{
Rectangle frame = new (1, 2, 3, 4);
View view = new ()
{
Frame = frame,
};
Assert.Equal (frame, view.Frame);
Assert.False (view.NeedsLayout);
Assert.Equal (frame.Size, view.Viewport.Size);
Assert.Equal (view.X, frame.X);
Assert.Equal (view.Y, frame.Y);
Assert.Equal (view.Width, frame.Width);
Assert.Equal (view.Height, frame.Height);
view.Frame = Rectangle.Empty;
Assert.Equal (Rectangle.Empty, view.Frame);
Assert.False (view.NeedsLayout);
Assert.Equal (Rectangle.Empty.Size, view.Viewport.Size);
Assert.Equal (view.X, Rectangle.Empty.X);
Assert.Equal (view.Y, Rectangle.Empty.Y);
Assert.Equal (view.Width, Rectangle.Empty.Width);
Assert.Equal (view.Height, Rectangle.Empty.Height);
view.Width = Dim.Fill ();
view.Height = Dim.Fill ();
Assert.True (view.NeedsLayout);
view.Layout ();
Assert.False (view.NeedsLayout);
Assert.Equal (Application.Screen, view.Frame);
view.Frame = Rectangle.Empty;
Assert.Equal (Rectangle.Empty, view.Frame);
Assert.False (view.NeedsLayout);
Assert.Equal (Rectangle.Empty.Size, view.Viewport.Size);
Assert.Equal (view.X, Rectangle.Empty.X);
Assert.Equal (view.Y, Rectangle.Empty.Y);
Assert.Equal (view.Width, Rectangle.Empty.Width);
Assert.Equal (view.Height, Rectangle.Empty.Height);
}
[Fact]
public void Frame_Empty_Initializer_Overrides_Base ()
{
// Prove TestView is correct
FrameTestView view = new ();
Assert.True (view.NeedsLayout);
view.Layout ();
Assert.Equal (new Rectangle(10, 20, 30, 40), view.Frame);
Assert.Equal (10, view.X.GetAnchor(0));
Assert.Equal (20, view.Y.GetAnchor(0));
Assert.Equal (30, view.Width!.GetAnchor(0));
Assert.Equal (40, view.Height!.GetAnchor(0));
Assert.Equal (new Rectangle (0, 0, 30, 40), view.Viewport);
// Set Frame via init
Rectangle frame = new (1, 2, 3, 4);
view = new ()
{
Frame = frame,
};
Assert.Equal (frame, view.Frame);
Assert.False (view.NeedsLayout);
Assert.Equal (frame.Size, view.Viewport.Size);
Assert.Equal (view.X, frame.X);
Assert.Equal (view.Y, frame.Y);
Assert.Equal (view.Width, frame.Width);
Assert.Equal (view.Height, frame.Height);
// Set Frame via init to empty
frame = Rectangle.Empty;
view = new ()
{
Frame = frame,
};
Assert.Equal (frame, view.Frame);
Assert.False (view.NeedsLayout);
Assert.Equal (frame.Size, view.Viewport.Size);
Assert.Equal (view.X, frame.X);
Assert.Equal (view.Y, frame.Y);
Assert.Equal (view.Width, frame.Width);
Assert.Equal (view.Height, frame.Height);
// Set back to original state
view.X = Pos.Func (() => 10);
view.Y = Pos.Func (() => 20);
view.Width = Dim.Func (() => 30);
view.Height = Dim.Func (() => 40);
Assert.True (view.NeedsLayout);
view.Layout ();
Assert.Equal (new Rectangle (10, 20, 30, 40), view.Frame);
Assert.Equal (10, view.X.GetAnchor (0));
Assert.Equal (20, view.Y.GetAnchor (0));
Assert.Equal (30, view.Width!.GetAnchor (0));
Assert.Equal (40, view.Height!.GetAnchor (0));
Assert.Equal (new Rectangle (0, 0, 30, 40), view.Viewport);
view.Frame = frame;
Assert.Equal (frame, view.Frame);
Assert.False (view.NeedsLayout);
Assert.Equal (frame.Size, view.Viewport.Size);
Assert.Equal (view.X, frame.X);
Assert.Equal (view.Y, frame.Y);
Assert.Equal (view.Width, frame.Width);
Assert.Equal (view.Height, frame.Height);
}
private class FrameTestView : View
{
public FrameTestView ()
{
X = Pos.Func (() => 10);
Y = Pos.Func (() => 20);
Width = Dim.Func (() => 30);
Height = Dim.Func (() => 40);
}
}
// Moved this test from AbsoluteLayoutTests
// TODO: Refactor as Theory
[Fact]

View File

@@ -154,8 +154,6 @@ public class WindowTests
Assert.Equal ("title", windowWithFrameRectEmpty.Title);
Assert.True (windowWithFrameRectEmpty.CanFocus);
Assert.False (windowWithFrameRectEmpty.HasFocus);
Assert.Equal (Rectangle.Empty, windowWithFrameRectEmpty.Viewport);
Assert.Equal (Rectangle.Empty, windowWithFrameRectEmpty.Frame);
Assert.Null (windowWithFrameRectEmpty.Focused);
Assert.NotNull (windowWithFrameRectEmpty.ColorScheme);
Assert.Equal (0, windowWithFrameRectEmpty.X);