Improves robustness of Dim, Pos, and SetRelativeLayout (#3077)

* Updated overview docs

* Updated toc

* Updated docs more

* Updated yml via dependabot

* Initial work in progress

* Fixed some autosize things

* Revamped Pos / Dim API docs

* Removed margin

* horiz->width

* Updated MessageBoxes and Dialogs Scenarios to use AutoSize

* AutoSize->Auxo

* Adds validation

* prep for Dialog to use Dim.Auto - Simplify unit tests to not depend on things not important to the unit test (like Dialog)

* prep for Dialog to use Dim.Auto - Simplify unit tests

* prep for Dialog to use Dim.Auto - Simplify unit tests

* prep for Dialog to use Dim.Auto - Make Dialog tests not depend on MessageBox

* Started on DimAuto unit tests

* started impl on min/max.

* started impl on min/max.

* Added DimAutoStyle

* Added arg checking for not implemented features

* Temporarily made DimAutoStyle.Subviews default

* Removed unneeded override of Anchor

* Fixed GethashCode warning

* Implemented DimAuto(min)

* Fixed unit tests

* renamed scenario

* WIP

* Moved ViewLayout.cs into Layout folder

* Clean up cocde formatting

* Renamed and moved SetFrameToFitText

* Fixed API docs for SetRelativeLayout

* Factored out SetRelativeLayout tests

* Better documented existing SetRelativeLayout behavior + unit tess

* Debugging Pos.Center + x in SetRelativeLayout - WIP

* Progress on low level unit tess

* Initial commit

* Restored unmodified scenarios

* Bump deps
This commit is contained in:
Tig
2023-12-26 09:28:43 -07:00
committed by GitHub
parent 3f35352561
commit a7209bcd88
27 changed files with 6252 additions and 5871 deletions

View File

@@ -36,14 +36,14 @@ jobs:
- name: Upload artifact
if: github.ref_name == 'main' || github.ref_name == 'develop'
uses: actions/upload-pages-artifact@v2
uses: actions/upload-pages-artifact@v3
with:
path: docfx/_site
- name: Deploy to GitHub Pages
if: github.ref_name == 'main' || github.ref_name == 'develop'
id: deployment
uses: actions/deploy-pages@v3
uses: actions/deploy-pages@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -317,6 +317,8 @@ public static partial class Application {
} else if (Top != null && Toplevel != Top && _topLevels.Contains (Top)) {
Top.OnLeave (Toplevel);
}
// BUGBUG: We should not depend on `Id` internally.
// BUGBUG: It is super unclear what this code does anyway.
if (string.IsNullOrEmpty (Toplevel.Id)) {
int count = 1;
string id = (_topLevels.Count + count).ToString ();
@@ -836,6 +838,12 @@ public static partial class Application {
#endregion Run (Begin, Run, End)
#region Toplevel handling
/// <summary>
/// Holds the stack of TopLevel views.
/// </summary>
// BUGBUG: Techncally, this is not the full lst of TopLevels. THere be dragons hwre. E.g. see how Toplevel.Id is used. What
// about TopLevels that are just a SubView of another View?
static readonly Stack<Toplevel> _topLevels = new ();
/// <summary>

View File

@@ -1077,7 +1077,7 @@ internal class WindowsDriver : ConsoleDriver {
inputEvent.KeyEvent = FromVKPacketToKeyEventRecord (inputEvent.KeyEvent);
}
var keyInfo = ToConsoleKeyInfoEx (inputEvent.KeyEvent);
Debug.WriteLine ($"event: {inputEvent.ToString ()} {keyInfo.ToString (keyInfo)}");
//Debug.WriteLine ($"event: {inputEvent.ToString ()} {keyInfo.ToString (keyInfo)}");
var map = MapKey (keyInfo);

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,8 @@
//
// PosDim.cs: Pos and Dim objects for view dimensions.
//
// Authors:
// Miguel de Icaza (miguel@gnome.org)
//
using System;
using static Terminal.Gui.Dim;
namespace Terminal.Gui;
using System;
namespace Terminal.Gui {
/// <summary>
/// Describes the position of a <see cref="View"/> which can be an absolute value, a percentage, centered, or
/// relative to the ending dimension. Integer values are implicitly convertible to
@@ -25,72 +21,123 @@ namespace Terminal.Gui {
/// of the <see cref="View"/> 3 characters to the left after centering for example.
/// </para>
/// <para>
/// It is possible to reference coordinates of another view by using the methods
/// Left(View), Right(View), Bottom(View), Top(View). The X(View) and Y(View) are
/// Reference coordinates of another view by using the methods Left(View), Right(View), Bottom(View), Top(View). The X(View) and Y(View) are
/// aliases to Left(View) and Top(View) respectively.
/// </para>
/// <para>
/// <list type="table">
/// <listheader>
/// <term>Pos Object</term>
/// <description>Description</description>
/// </listheader>
/// <item>
/// <term><see cref="Pos.Function(Func{int})"/></term>
/// <description>
/// Creates a <see cref="Pos"/> object that computes the position by executing the provided function. The function will be called every time the position is needed.
/// </description>
/// </item>
/// <item>
/// <term><see cref="Pos.Percent(float)"/></term>
/// <description>
/// Creates a <see cref="Pos"/> object that is a percentage of the width or height of the SuperView.
/// </description>
/// </item>
/// <item>
/// <term><see cref="Pos.Anchor(int)"/></term>
/// <description>
/// Creates a <see cref="Pos"/> object that is anchored to the end (right side or bottom) of the dimension,
/// useful to flush the layout from the right or bottom.
/// </description>
/// </item>
/// <item>
/// <term><see cref="Pos.Center"/></term>
/// <description>
/// Creates a <see cref="Pos"/> object that can be used to center the <see cref="View"/>.
/// </description>
/// </item>
/// <item>
/// <term><see cref="Pos.At(int)"/></term>
/// <description>
/// Creates a <see cref="Pos"/> object that is an absolute position based on the specified integer value.
/// </description>
/// </item>
/// <item>
/// <term><see cref="Pos.Left"/></term>
/// <description>
/// Creates a <see cref="Pos"/> object that tracks the Left (X) position of the specified <see cref="View"/>.
/// </description>
/// </item>
/// <item>
/// <term><see cref="Pos.X(View)"/></term>
/// <description>
/// Creates a <see cref="Pos"/> object that tracks the Left (X) position of the specified <see cref="View"/>.
/// </description>
/// </item>
/// <item>
/// <term><see cref="Pos.Top(View)"/></term>
/// <description>
/// Creates a <see cref="Pos"/> object that tracks the Top (Y) position of the specified <see cref="View"/>.
/// </description>
/// </item>
/// <item>
/// <term><see cref="Pos.Y(View)"/></term>
/// <description>
/// Creates a <see cref="Pos"/> object that tracks the Top (Y) position of the specified <see cref="View"/>.
/// </description>
/// </item>
/// <item>
/// <term><see cref="Pos.Right(View)"/></term>
/// <description>
/// Creates a <see cref="Pos"/> object that tracks the Right (X+Width) coordinate of the specified <see cref="View"/>.
/// </description>
/// </item>
/// <item>
/// <term><see cref="Pos.Bottom(View)"/></term>
/// <description>
/// Creates a <see cref="Pos"/> object that tracks the Bottom (Y+Height) coordinate of the specified <see cref="View"/>
/// </description>
/// </item>
///
/// </list>
/// </para>
/// </remarks>
public class Pos {
internal virtual int Anchor (int width)
{
return 0;
internal virtual int Anchor (int width) => 0;
/// <summary>
/// Creates a <see cref="Pos"/> object that computes the position by executing the provided function. The function will be called every time the position is needed.
/// </summary>
/// <param name="function">The function to be executed.</param>
/// <returns>The <see cref="Pos"/> returned from the function.</returns>
public static Pos Function (Func<int> function) => new PosFunc (function);
internal class PosFactor : Pos {
readonly float _factor;
public PosFactor (float n) => _factor = n;
internal override int Anchor (int width) => (int)(width * _factor);
public override string ToString () => $"Factor({_factor})";
public override int GetHashCode () => _factor.GetHashCode ();
public override bool Equals (object other) => other is PosFactor f && f._factor == _factor;
}
// Helper class to provide dynamic value by the execution of a function that returns an integer.
internal class PosFunc : Pos {
Func<int> function;
readonly Func<int> _function;
public PosFunc (Func<int> n)
{
this.function = n;
}
public PosFunc (Func<int> n) => _function = n;
internal override int Anchor (int width)
{
return function ();
}
internal override int Anchor (int width) => _function ();
public override string ToString ()
{
return $"PosFunc({function ()})";
}
public override string ToString () => $"PosFunc({_function ()})";
public override int GetHashCode () => function.GetHashCode ();
public override int GetHashCode () => _function.GetHashCode ();
public override bool Equals (object other) => other is PosFunc f && f.function () == function ();
}
/// <summary>
/// Creates a "PosFunc" from the specified function.
/// </summary>
/// <param name="function">The function to be executed.</param>
/// <returns>The <see cref="Pos"/> returned from the function.</returns>
public static Pos Function (Func<int> function)
{
return new PosFunc (function);
}
internal class PosFactor : Pos {
float factor;
public PosFactor (float n)
{
this.factor = n;
}
internal override int Anchor (int width)
{
return (int)(width * factor);
}
public override string ToString ()
{
return $"Factor({factor})";
}
public override int GetHashCode () => factor.GetHashCode ();
public override bool Equals (object other) => other is PosFactor f && f.factor == factor;
public override bool Equals (object other) => other is PosFunc f && f._function () == _function ();
}
/// <summary>
@@ -112,41 +159,19 @@ namespace Terminal.Gui {
/// </example>
public static Pos Percent (float n)
{
if (n < 0 || n > 100)
if (n is < 0 or > 100) {
throw new ArgumentException ("Percent value must be between 0 and 100");
}
return new PosFactor (n / 100);
}
internal class PosAnchorEnd : Pos {
int n;
public PosAnchorEnd (int n)
{
this.n = n;
}
internal override int Anchor (int width)
{
return width - n;
}
public override string ToString ()
{
return $"AnchorEnd({n})";
}
public override int GetHashCode () => n.GetHashCode ();
public override bool Equals (object other) => other is PosAnchorEnd anchorEnd && anchorEnd.n == n;
}
/// <summary>
/// Creates a <see cref="Pos"/> object that is anchored to the end (right side or bottom) of the dimension,
/// useful to flush the layout from the right or bottom.
/// </summary>
/// <returns>The <see cref="Pos"/> object anchored to the end (the bottom or the right side).</returns>
/// <param name="margin">Optional margin to place to the right or below.</param>
/// <param name="offset">The view will be shifted left or up by the amount specified.</param>
/// <example>
/// This sample shows how align a <see cref="Button"/> to the bottom-right of a <see cref="View"/>.
/// <code>
@@ -155,28 +180,31 @@ namespace Terminal.Gui {
/// anchorButton.Y = Pos.AnchorEnd (1);
/// </code>
/// </example>
public static Pos AnchorEnd (int margin = 0)
public static Pos AnchorEnd (int offset = 0)
{
if (margin < 0)
throw new ArgumentException ("Margin must be positive");
return new PosAnchorEnd (margin);
if (offset < 0) {
throw new ArgumentException (@"Must be positive", nameof(offset));
}
internal class PosCenter : Pos {
internal override int Anchor (int width)
{
return width / 2;
return new PosAnchorEnd (offset);
}
public override string ToString ()
{
return "Center";
}
internal class PosAnchorEnd : Pos {
readonly int _offset;
public PosAnchorEnd (int offset) => _offset = offset;
internal override int Anchor (int width) => width - _offset;
public override string ToString () => $"AnchorEnd({_offset})";
public override int GetHashCode () => _offset.GetHashCode ();
public override bool Equals (object other) => other is PosAnchorEnd anchorEnd && anchorEnd._offset == _offset;
}
/// <summary>
/// Returns a <see cref="Pos"/> object that can be used to center the <see cref="View"/>
/// Creates a <see cref="Pos"/> object that can be used to center the <see cref="View"/>.
/// </summary>
/// <returns>The center Pos.</returns>
/// <example>
@@ -191,77 +219,66 @@ namespace Terminal.Gui {
/// };
/// </code>
/// </example>
public static Pos Center ()
{
return new PosCenter ();
}
public static Pos Center () => new PosCenter ();
internal class PosAbsolute : Pos {
int n;
public PosAbsolute (int n) { this.n = n; }
readonly int _n;
public PosAbsolute (int n) => _n = n;
public override string ToString ()
{
return $"Absolute({n})";
public override string ToString () => $"Absolute({_n})";
internal override int Anchor (int width) => _n;
public override int GetHashCode () => _n.GetHashCode ();
public override bool Equals (object other) => other is PosAbsolute abs && abs._n == _n;
}
internal override int Anchor (int width)
{
return n;
}
internal class PosCenter : Pos {
internal override int Anchor (int width) => width / 2;
public override int GetHashCode () => n.GetHashCode ();
public override bool Equals (object other) => other is PosAbsolute abs && abs.n == n;
public override string ToString () => "Center";
}
/// <summary>
/// Creates an Absolute <see cref="Pos"/> from the specified integer value.
/// Creates a <see cref="Pos"/> object that is an absolute position based on the specified integer value.
/// </summary>
/// <returns>The Absolute <see cref="Pos"/>.</returns>
/// <param name="n">The value to convert to the <see cref="Pos"/>.</param>
public static implicit operator Pos (int n)
{
return new PosAbsolute (n);
}
/// <summary>
/// Creates an Absolute <see cref="Pos"/> from the specified integer value.
/// </summary>
/// <returns>The Absolute <see cref="Pos"/>.</returns>
/// <param name="n">The value to convert to the <see cref="Pos"/>.</param>
public static Pos At (int n)
{
return new PosAbsolute (n);
}
public static Pos At (int n) => new PosAbsolute (n);
internal class PosCombine : Pos {
internal Pos left, right;
internal bool add;
internal Pos _left, _right;
internal bool _add;
public PosCombine (bool add, Pos left, Pos right)
{
this.left = left;
this.right = right;
this.add = add;
_left = left;
_right = right;
_add = add;
}
internal override int Anchor (int width)
{
var la = left.Anchor (width);
var ra = right.Anchor (width);
if (add)
int la = _left.Anchor (width);
int ra = _right.Anchor (width);
if (_add) {
return la + ra;
else
} else {
return la - ra;
}
public override string ToString ()
{
return $"Combine({left}{(add ? '+' : '-')}{right})";
}
public override string ToString () => $"Combine({_left}{(_add ? '+' : '-')}{_right})";
}
/// <summary>
/// Creates an Absolute <see cref="Pos"/> from the specified integer value.
/// </summary>
/// <returns>The Absolute <see cref="Pos"/>.</returns>
/// <param name="n">The value to convert to the <see cref="Pos"/> .</param>
public static implicit operator Pos (int n) => new PosAbsolute (n);
/// <summary>
/// Adds a <see cref="Terminal.Gui.Pos"/> to a <see cref="Terminal.Gui.Pos"/>, yielding a new <see cref="Pos"/>.
/// </summary>
@@ -273,7 +290,7 @@ namespace Terminal.Gui {
if (left is PosAbsolute && right is PosAbsolute) {
return new PosAbsolute (left.Anchor (0) + right.Anchor (0));
}
PosCombine newPos = new PosCombine (true, left, right);
var newPos = new PosCombine (true, left, right);
SetPosCombine (left, newPos);
return newPos;
}
@@ -289,7 +306,7 @@ namespace Terminal.Gui {
if (left is PosAbsolute && right is PosAbsolute) {
return new PosAbsolute (left.Anchor (0) - right.Anchor (0));
}
PosCombine newPos = new PosCombine (false, left, right);
var newPos = new PosCombine (false, left, right);
SetPosCombine (left, newPos);
return newPos;
}
@@ -303,13 +320,15 @@ namespace Terminal.Gui {
}
internal class PosView : Pos {
public View Target;
public readonly View Target;
int side;
public PosView (View view, int side)
{
Target = view;
this.side = side;
}
internal override int Anchor (int width)
{
switch (side) {
@@ -342,42 +361,42 @@ namespace Terminal.Gui {
}
/// <summary>
/// Returns a <see cref="Pos"/> object tracks the Left (X) position of the specified <see cref="View"/>.
/// Creates a <see cref="Pos"/> object that tracks the Left (X) position of the specified <see cref="View"/>.
/// </summary>
/// <returns>The <see cref="Pos"/> that depends on the other view.</returns>
/// <param name="view">The <see cref="View"/> that will be tracked.</param>
public static Pos Left (View view) => new PosView (view, 0);
/// <summary>
/// Returns a <see cref="Pos"/> object tracks the Left (X) position of the specified <see cref="View"/>.
/// Creates a <see cref="Pos"/> object that tracks the Left (X) position of the specified <see cref="View"/>.
/// </summary>
/// <returns>The <see cref="Pos"/> that depends on the other view.</returns>
/// <param name="view">The <see cref="View"/> that will be tracked.</param>
public static Pos X (View view) => new PosView (view, 0);
/// <summary>
/// Returns a <see cref="Pos"/> object tracks the Top (Y) position of the specified <see cref="View"/>.
/// Creates a <see cref="Pos"/> object that tracks the Top (Y) position of the specified <see cref="View"/>.
/// </summary>
/// <returns>The <see cref="Pos"/> that depends on the other view.</returns>
/// <param name="view">The <see cref="View"/> that will be tracked.</param>
public static Pos Top (View view) => new PosView (view, 1);
/// <summary>
/// Returns a <see cref="Pos"/> object tracks the Top (Y) position of the specified <see cref="View"/>.
/// Creates a <see cref="Pos"/> object that tracks the Top (Y) position of the specified <see cref="View"/>.
/// </summary>
/// <returns>The <see cref="Pos"/> that depends on the other view.</returns>
/// <param name="view">The <see cref="View"/> that will be tracked.</param>
public static Pos Y (View view) => new PosView(view, 1);
/// <summary>
/// Returns a <see cref="Pos"/> object tracks the Right (X+Width) coordinate of the specified <see cref="View"/>.
/// Creates a <see cref="Pos"/> object that tracks the Right (X+Width) coordinate of the specified <see cref="View"/>.
/// </summary>
/// <returns>The <see cref="Pos"/> that depends on the other view.</returns>
/// <param name="view">The <see cref="View"/> that will be tracked.</param>
public static Pos Right (View view) => new PosView (view, 2);
/// <summary>
/// Returns a <see cref="Pos"/> object tracks the Bottom (Y+Height) coordinate of the specified <see cref="View"/>
/// Creates a <see cref="Pos"/> object that tracks the Bottom (Y+Height) coordinate of the specified <see cref="View"/>
/// </summary>
/// <returns>The <see cref="Pos"/> that depends on the other view.</returns>
/// <param name="view">The <see cref="View"/> that will be tracked.</param>
@@ -395,95 +414,91 @@ namespace Terminal.Gui {
}
/// <summary>
/// Dim properties of a <see cref="View"/> to control the position.
/// <para>
/// A Dim object describes the dimensions of a <see cref="View"/>. Dim is the type of the <see cref="View.Width"/> and
/// <see cref="View.Height"/> properties of <see cref="View"/>. Dim objects enable Computed Layout (see <see cref="LayoutStyle.Computed"/>)
/// to automatically manage the dimensions of a view.
/// </para>
/// <para>
/// Integer values are implicitly convertible to an absolute <see cref="Dim"/>. These objects are created using the static methods described below.
/// The <see cref="Dim"/> objects can be combined with the addition and subtraction operators.
/// </para>
/// </summary>
/// <remarks>
/// <para>
/// Use the Dim objects on the Width or Height properties of a <see cref="View"/> to control the position.
/// <list type="table">
/// <listheader>
/// <term>Dim Object</term>
/// <description>Description</description>
/// </listheader>
/// <item>
/// <term><see cref="Dim.Function(Func{int})"/></term>
/// <description>
/// Creates a <see cref="Dim"/> object that computes the dimension by executing the provided function. The function will be called every time the dimension is needed.
/// </description>
/// </item>
/// <item>
/// <term><see cref="Dim.Percent(float, bool)"/></term>
/// <description>
/// Creates a <see cref="Dim"/> object that is a percentage of the width or height of the SuperView.
/// </description>
/// </item>
/// <item>
/// <term><see cref="Dim.Fill(int)"/></term>
/// <description>
/// Creates a <see cref="Dim"/> object that fills the dimension, leaving the specified number of columns for a margin.
/// </description>
/// </item>
/// <item>
/// <term><see cref="Dim.Width(View)"/></term>
/// <description>
/// Creates a <see cref="Dim"/> object that tracks the Width of the specified <see cref="View"/>.
/// </description>
/// </item>
/// <item>
/// <term><see cref="Dim.Height(View)"/></term>
/// <description>
/// Creates a <see cref="Dim"/> object that tracks the Height of the specified <see cref="View"/>.
/// </description>
/// </item>
/// </list>
/// </para>
/// <para>
/// These can be used to set the absolute position, when merely assigning an
/// integer value (via the implicit integer to Pos conversion), and they can be combined
/// to produce more useful layouts, like: Pos.Center - 3, which would shift the position
/// of the <see cref="View"/> 3 characters to the left after centering for example.
/// </para>
/// </remarks>
public class Dim {
internal virtual int Anchor (int width)
{
return 0;
}
// Helper class to provide dynamic value by the execution of a function that returns an integer.
internal class DimFunc : Dim {
Func<int> function;
public DimFunc (Func<int> n)
{
this.function = n;
}
internal override int Anchor (int width)
{
return function ();
}
public override string ToString ()
{
return $"DimFunc({function ()})";
}
public override int GetHashCode () => function.GetHashCode ();
public override bool Equals (object other) => other is DimFunc f && f.function () == function ();
}
internal virtual int Anchor (int width) => 0;
/// <summary>
/// Creates a "DimFunc" from the specified function.
/// Creates a function <see cref="Dim"/> object that computes the dimension by executing the provided function.
/// The function will be called every time the dimension is needed.
/// </summary>
/// <param name="function">The function to be executed.</param>
/// <returns>The <see cref="Dim"/> returned from the function.</returns>
public static Dim Function (Func<int> function)
{
return new DimFunc (function);
}
public static Dim Function (Func<int> function) => new DimFunc (function);
internal class DimFactor : Dim {
float factor;
bool remaining;
// Helper class to provide dynamic value by the execution of a function that returns an integer.
internal class DimFunc : Dim {
readonly Func<int> _function;
public DimFactor (float n, bool r = false)
{
factor = n;
remaining = r;
}
public DimFunc (Func<int> n) => _function = n;
internal override int Anchor (int width)
{
return (int)(width * factor);
}
internal override int Anchor (int width) => _function ();
public bool IsFromRemaining ()
{
return remaining;
}
public override string ToString () => $"DimFunc({_function ()})";
public override string ToString ()
{
return $"Factor({factor},{remaining})";
}
public override int GetHashCode () => _function.GetHashCode ();
public override int GetHashCode () => factor.GetHashCode ();
public override bool Equals (object other) => other is DimFactor f && f.factor == factor && f.remaining == remaining;
public override bool Equals (object other) => other is DimFunc f && f._function () == _function ();
}
/// <summary>
/// Creates a percentage <see cref="Dim"/> object
/// Creates a percentage <see cref="Dim"/> object that is a percentage of the width or height of the SuperView.
/// </summary>
/// <returns>The percent <see cref="Dim"/> object.</returns>
/// <param name="n">A value between 0 and 100 representing the percentage.</param>
/// <param name="r">If <c>true</c> the Percent is computed based on the remaining space after the X/Y anchor positions. If <c>false</c> is computed based on the whole original space.</param>
/// <param name="r">If <c>true</c> the Percent is computed based on the remaining space after the X/Y anchor positions.
/// If <c>false</c> is computed based on the whole original space.</param>
/// <example>
/// This initializes a <see cref="TextField"/>that is centered horizontally, is 50% of the way down,
/// is 30% the height, and is 80% the width of the <see cref="View"/> it added to.
@@ -498,105 +513,105 @@ namespace Terminal.Gui {
/// </example>
public static Dim Percent (float n, bool r = false)
{
if (n < 0 || n > 100)
if (n is < 0 or > 100) {
throw new ArgumentException ("Percent value must be between 0 and 100");
}
return new DimFactor (n / 100, r);
}
internal class DimFactor : Dim {
readonly float _factor;
readonly bool _remaining;
public DimFactor (float n, bool r = false)
{
_factor = n;
_remaining = r;
}
internal override int Anchor (int width) => (int)(width * _factor);
public bool IsFromRemaining () => _remaining;
public override string ToString () => $"Factor({_factor},{_remaining})";
public override int GetHashCode () => _factor.GetHashCode ();
public override bool Equals (object other) => other is DimFactor f && f._factor == _factor && f._remaining == _remaining;
}
internal class DimAbsolute : Dim {
int n;
public DimAbsolute (int n) { this.n = n; }
readonly int _n;
public DimAbsolute (int n) => _n = n;
public override string ToString ()
{
return $"Absolute({n})";
}
public override string ToString () => $"Absolute({_n})";
internal override int Anchor (int width)
{
return n;
}
internal override int Anchor (int width) => _n;
public override int GetHashCode () => n.GetHashCode ();
public override int GetHashCode () => _n.GetHashCode ();
public override bool Equals (object other) => other is DimAbsolute abs && abs.n == n;
public override bool Equals (object other) => other is DimAbsolute abs && abs._n == _n;
}
internal class DimFill : Dim {
int margin;
public DimFill (int margin) { this.margin = margin; }
readonly int _margin;
public DimFill (int margin) => _margin = margin;
public override string ToString ()
{
return $"Fill({margin})";
}
public override string ToString () => $"Fill({_margin})";
internal override int Anchor (int width)
{
return width - margin;
}
internal override int Anchor (int width) => width - _margin;
public override int GetHashCode () => margin.GetHashCode ();
public override int GetHashCode () => _margin.GetHashCode ();
public override bool Equals (object other) => other is DimFill fill && fill.margin == margin;
public override bool Equals (object other) => other is DimFill fill && fill._margin == _margin;
}
/// <summary>
/// Initializes a new instance of the <see cref="Dim"/> class that fills the dimension, but leaves the specified number of colums for a margin.
/// Creates a <see cref="Dim"/> object that fills the dimension, leaving the specified number of columns for a margin.
/// </summary>
/// <returns>The Fill dimension.</returns>
/// <param name="margin">Margin to use.</param>
public static Dim Fill (int margin = 0)
{
return new DimFill (margin);
}
public static Dim Fill (int margin = 0) => new DimFill (margin);
/// <summary>
/// Creates an Absolute <see cref="Dim"/> from the specified integer value.
/// </summary>
/// <returns>The Absolute <see cref="Dim"/>.</returns>
/// <param name="n">The value to convert to the pos.</param>
public static implicit operator Dim (int n)
{
return new DimAbsolute (n);
}
public static implicit operator Dim (int n) => new DimAbsolute (n);
/// <summary>
/// Creates an Absolute <see cref="Dim"/> from the specified integer value.
/// </summary>
/// <returns>The Absolute <see cref="Dim"/>.</returns>
/// <param name="n">The value to convert to the <see cref="Dim"/>.</param>
public static Dim Sized (int n)
{
return new DimAbsolute (n);
}
public static Dim Sized (int n) => new DimAbsolute (n);
internal class DimCombine : Dim {
internal Dim left, right;
internal bool add;
internal Dim _left, _right;
internal bool _add;
public DimCombine (bool add, Dim left, Dim right)
{
this.left = left;
this.right = right;
this.add = add;
_left = left;
_right = right;
_add = add;
}
internal override int Anchor (int width)
{
var la = left.Anchor (width);
var ra = right.Anchor (width);
if (add)
int la = _left.Anchor (width);
int ra = _right.Anchor (width);
if (_add) {
return la + ra;
else
} else {
return la - ra;
}
public override string ToString ()
{
return $"Combine({left}{(add ? '+' : '-')}{right})";
}
public override string ToString () => $"Combine({_left}{(_add ? '+' : '-')}{_right})";
}
/// <summary>
@@ -610,7 +625,7 @@ namespace Terminal.Gui {
if (left is DimAbsolute && right is DimAbsolute) {
return new DimAbsolute (left.Anchor (0) + right.Anchor (0));
}
DimCombine newDim = new DimCombine (true, left, right);
var newDim = new DimCombine (true, left, right);
SetDimCombine (left, newDim);
return newDim;
}
@@ -626,64 +641,59 @@ namespace Terminal.Gui {
if (left is DimAbsolute && right is DimAbsolute) {
return new DimAbsolute (left.Anchor (0) - right.Anchor (0));
}
DimCombine newDim = new DimCombine (false, left, right);
var newDim = new DimCombine (false, left, right);
SetDimCombine (left, newDim);
return newDim;
}
static void SetDimCombine (Dim left, DimCombine newPos)
{
var view = left as DimView;
if (view != null) {
view.Target.SetNeedsLayout ();
}
}
// BUGBUG: newPos is never used.
static void SetDimCombine (Dim left, DimCombine newPos) => (left as DimView)?.Target.SetNeedsLayout ();
internal class DimView : Dim {
public View Target;
int side;
public View Target { get; init; }
readonly int _side;
public DimView (View view, int side)
{
Target = view;
this.side = side;
_side = side;
}
internal override int Anchor (int width)
{
switch (side) {
case 0: return Target.Frame.Height;
case 1: return Target.Frame.Width;
default:
return 0;
}
}
internal override int Anchor (int width) => _side switch {
0 => Target.Frame.Height,
1 => Target.Frame.Width,
_ => 0
};
public override string ToString ()
{
string tside;
switch (side) {
case 0: tside = "Height"; break;
case 1: tside = "Width"; break;
default: tside = "unknown"; break;
if (Target == null) {
throw new NullReferenceException ();
}
return $"View({tside},{Target.ToString ()})";
string tside = _side switch {
0 => "Height",
1 => "Width",
_ => "unknown"
};
return $"View({tside},{Target})";
}
public override int GetHashCode () => Target.GetHashCode ();
public override bool Equals (object other) => other is DimView abs && abs.Target == Target;
}
/// <summary>
/// Returns a <see cref="Dim"/> object tracks the Width of the specified <see cref="View"/>.
/// Creates a <see cref="Dim"/> object that tracks the Width of the specified <see cref="View"/>.
/// </summary>
/// <returns>The <see cref="Dim"/> of the other <see cref="View"/>.</returns>
/// <returns>The width <see cref="Dim"/> of the other <see cref="View"/>.</returns>
/// <param name="view">The view that will be tracked.</param>
public static Dim Width (View view) => new DimView (view, 1);
/// <summary>
/// Returns a <see cref="Dim"/> object tracks the Height of the specified <see cref="View"/>.
/// Creates a <see cref="Dim"/> object that tracks the Height of the specified <see cref="View"/>.
/// </summary>
/// <returns>The <see cref="Dim"/> of the other <see cref="View"/>.</returns>
/// <returns>The height <see cref="Dim"/> of the other <see cref="View"/>.</returns>
/// <param name="view">The view that will be tracked.</param>
public static Dim Height (View view) => new DimView (view, 0);
@@ -697,4 +707,3 @@ namespace Terminal.Gui {
/// <see langword="true" /> if the specified object is equal to the current object; otherwise, <see langword="false" />.</returns>
public override bool Equals (object other) => other is Dim abs && abs == this;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -280,6 +280,7 @@ namespace Terminal.Gui {
_oldCanFocus = CanFocus;
_oldTabIndex = _tabIndex;
// BUGBUG: These should move to EndInit as they access Bounds causing debug spew.
UpdateTextDirection (TextDirection);
UpdateTextFormatterText ();
SetHotKey ();

View File

@@ -1,5 +1,6 @@
using System.Text;
using System;
using System.Collections.Generic;
namespace Terminal.Gui {
@@ -122,20 +123,88 @@ namespace Terminal.Gui {
UpdateTextFormatterText ();
if ((!ForceValidatePosDim && directionChanged && AutoSize)
|| (ForceValidatePosDim && directionChanged && AutoSize && isValidOldAutoSize)) {
if ((!ValidatePosDim && directionChanged && AutoSize)
|| (ValidatePosDim && directionChanged && AutoSize && isValidOldAutoSize)) {
OnResizeNeeded ();
} else if (directionChanged && IsAdded) {
ResizeBoundsToFit (Bounds.Size);
// BUGBUG: I think this call is redundant.
SetBoundsToFitFrame ();
SetFrameToFitText ();
} else {
SetBoundsToFitFrame ();
SetFrameToFitText ();
}
TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey ();
SetNeedsDisplay ();
}
/// <summary>
/// Sets the size of the View to the minimum width or height required to fit <see cref="Text"/>.
/// </summary>
/// <returns><see langword="true"/> if the size was changed; <see langword="false"/> if <see cref="AutoSize"/> == <see langword="true"/> or
/// <see cref="Text"/> will not fit.</returns>
/// <remarks>
/// Always returns <see langword="false"/> if <see cref="AutoSize"/> is <see langword="true"/> or
/// if <see cref="Height"/> (Horizontal) or <see cref="Width"/> (Vertical) are not not set or zero.
/// Does not take into account word wrapping.
/// </remarks>
bool SetFrameToFitText ()
{
// BUGBUG: This API is broken - should not assume Frame.Height == Bounds.Height
// <summary>
// Gets the minimum dimensions required to fit the View's <see cref="Text"/>, factoring in <see cref="TextDirection"/>.
// </summary>
// <param name="sizeRequired">The minimum dimensions required.</param>
// <returns><see langword="true"/> if the dimensions fit within the View's <see cref="Bounds"/>, <see langword="false"/> otherwise.</returns>
// <remarks>
// Always returns <see langword="false"/> if <see cref="AutoSize"/> is <see langword="true"/> or
// if <see cref="Height"/> (Horizontal) or <see cref="Width"/> (Vertical) are not not set or zero.
// Does not take into account word wrapping.
// </remarks>
bool GetMinimumSizeOfText (out Size sizeRequired)
{
if (!IsInitialized) {
sizeRequired = new Size (0, 0);
return false;
}
sizeRequired = Bounds.Size;
if (!AutoSize && !string.IsNullOrEmpty (TextFormatter.Text)) {
switch (TextFormatter.IsVerticalDirection (TextDirection)) {
case true:
int colWidth = TextFormatter.GetSumMaxCharWidth (new List<string> { TextFormatter.Text }, 0, 1);
// TODO: v2 - This uses frame.Width; it should only use Bounds
if (_frame.Width < colWidth &&
(Width == null ||
Bounds.Width >= 0 &&
Width is Dim.DimAbsolute &&
Width.Anchor (0) >= 0 &&
Width.Anchor (0) < colWidth)) {
sizeRequired = new Size (colWidth, Bounds.Height);
return true;
}
break;
default:
if (_frame.Height < 1 &&
(Height == null ||
Height is Dim.DimAbsolute &&
Height.Anchor (0) == 0)) {
sizeRequired = new Size (Bounds.Width, 1);
return true;
}
break;
}
}
return false;
}
if (GetMinimumSizeOfText (out var size)) {
_frame = new Rect (_frame.Location, size);
return true;
}
return false;
}
/// <summary>
/// Gets the width or height of the <see cref="Terminal.Gui.TextFormatter.HotKeySpecifier"/> characters
/// in the <see cref="Text"/> property.

View File

@@ -1,18 +1,10 @@
//
// Dialog.cs: Dialog box
//
// Authors:
// Miguel de Icaza (miguel@gnome.org)
//
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
using System.Text;
using Terminal.Gui;
using static Terminal.Gui.ConfigurationManager;
namespace Terminal.Gui {
namespace Terminal.Gui;
/// <summary>
/// The <see cref="Dialog"/> <see cref="View"/> is a <see cref="Window"/> that by default is centered and contains one
/// or more <see cref="Button"/>s. It defaults to the <see cref="Colors.Dialog"/> color scheme and has a 1 cell padding around the edges.
@@ -29,7 +21,8 @@ namespace Terminal.Gui {
/// <remarks>
/// This property can be set in a Theme.
/// </remarks>
[SerializableConfigurationProperty (Scope = typeof (ThemeScope)), JsonConverter (typeof (JsonStringEnumConverter))]
[SerializableConfigurationProperty (Scope = typeof (ThemeScope))]
[JsonConverter (typeof (JsonStringEnumConverter))]
public static ButtonAlignments DefaultButtonAlignment { get; set; } = ButtonAlignments.Center;
// TODO: Reenable once border/borderframe design is settled
@@ -40,8 +33,7 @@ namespace Terminal.Gui {
//public static Border DefaultBorder { get; set; } = new Border () {
// LineStyle = LineStyle.Single,
//};
internal List<Button> buttons = new List<Button> ();
internal List<Button> buttons = new ();
/// <summary>
/// Initializes a new instance of the <see cref="Dialog"/> class using <see cref="LayoutStyle.Computed"/> positioning
@@ -62,18 +54,16 @@ namespace Terminal.Gui {
/// By default, <see cref="View.X"/> and <see cref="View.Y"/> are set to <c>Pos.Center ()</c> and <see cref="View.Width"/> and <see cref="View.Height"/> are set
/// to <c>Width = Dim.Percent (85)</c>, centering the Dialog vertically and horizontally.
/// </remarks>
public Dialog (params Button [] buttons) : base ()
{
SetInitialProperties (buttons);
}
public Dialog (params Button [] buttons) : base () => SetInitialProperties (buttons);
private void SetInitialProperties (Button [] buttons)
void SetInitialProperties (Button [] buttons)
{
X = Pos.Center ();
Y = Pos.Center ();
ValidatePosDim = true;
Width = Dim.Percent (85);
Height = Dim.Percent (85);
Width = Dim.Percent (85);// Dim.Auto (min: Dim.Percent (10));
Height = Dim.Percent (85);//Dim.Auto (min: Dim.Percent (50));
ColorScheme = Colors.Dialog;
@@ -85,11 +75,20 @@ namespace Terminal.Gui {
AddButton (b);
}
}
}
LayoutComplete += (s, args) => {
bool inLayout = false;
/// <inheritdoc />
public override void LayoutSubviews ()
{
if (inLayout) {
return;
}
inLayout = true;
LayoutButtons ();
};
base.LayoutSubviews ();
inLayout = false;
}
/// <summary>
@@ -155,7 +154,9 @@ namespace Terminal.Gui {
void LayoutButtons ()
{
if (buttons.Count == 0 || !IsInitialized) return;
if (buttons.Count == 0 || !IsInitialized) {
return;
}
int shiftLeft = 0;
@@ -165,7 +166,7 @@ namespace Terminal.Gui {
// Center Buttons
shiftLeft = (Bounds.Width - buttonsWidth - buttons.Count - 1) / 2 + 1;
for (int i = buttons.Count - 1; i >= 0; i--) {
Button button = buttons [i];
var button = buttons [i];
shiftLeft += button.Frame.Width + (i == buttons.Count - 1 ? 0 : 1);
if (shiftLeft > -1) {
button.X = Pos.AnchorEnd (shiftLeft);
@@ -180,19 +181,19 @@ namespace Terminal.Gui {
// Justify Buttons
// leftmost and rightmost buttons are hard against edges. The rest are evenly spaced.
var spacing = (int)Math.Ceiling ((double)(Bounds.Width - buttonsWidth) / (buttons.Count - 1));
int spacing = (int)Math.Ceiling ((double)(Bounds.Width - buttonsWidth) / (buttons.Count - 1));
for (int i = buttons.Count - 1; i >= 0; i--) {
Button button = buttons [i];
var button = buttons [i];
if (i == buttons.Count - 1) {
shiftLeft += button.Frame.Width;
button.X = Pos.AnchorEnd (shiftLeft);
} else {
if (i == 0) {
// first (leftmost) button
var left = Bounds.Width;
int left = Bounds.Width;
button.X = Pos.AnchorEnd (left);
} else {
shiftLeft += button.Frame.Width + (spacing);
shiftLeft += button.Frame.Width + spacing;
button.X = Pos.AnchorEnd (shiftLeft);
}
}
@@ -206,7 +207,7 @@ namespace Terminal.Gui {
prevButton.X = 0;
prevButton.Y = Pos.AnchorEnd (1);
for (int i = 1; i < buttons.Count; i++) {
Button button = buttons [i];
var button = buttons [i];
button.X = Pos.Right (prevButton) + 1;
button.Y = Pos.AnchorEnd (1);
prevButton = button;
@@ -219,7 +220,7 @@ namespace Terminal.Gui {
buttons [buttons.Count - 1].X = Pos.AnchorEnd (shiftLeft);
buttons [buttons.Count - 1].Y = Pos.AnchorEnd (1);
for (int i = buttons.Count - 2; i >= 0; i--) {
Button button = buttons [i];
var button = buttons [i];
shiftLeft += button.Frame.Width + 1;
button.X = Pos.AnchorEnd (shiftLeft);
button.Y = Pos.AnchorEnd (1);
@@ -240,4 +241,3 @@ namespace Terminal.Gui {
return false;
}
}
}

View File

@@ -290,7 +290,7 @@ namespace Terminal.Gui {
X = 0,
Y = 0,
Width = Dim.Fill (0),
Height = Dim.Fill (1)
Height = Dim.Fill (1),
};
messageLabel.TextFormatter.WordWrap = wrapMessage;
messageLabel.TextFormatter.MultiLine = wrapMessage ? false : true;

View File

@@ -178,7 +178,7 @@ public class RadioGroup : View {
AddKeyBindingsForHotKey (KeyCode.Null, hotKey);
}
}
if (prevCount != _radioLabels.Count) {
if (IsInitialized && prevCount != _radioLabels.Count) {
SetWidthHeight (_radioLabels);
}
SelectedItem = 0;

View File

@@ -163,6 +163,19 @@ namespace UICatalog.Scenarios {
};
Application.Top.Add (oddballButton);
oddballButton = new Button ("Center - 1") {
X = Pos.Center () - 1,
Y = Pos.Bottom (oddballButton)
};
Application.Top.Add (oddballButton);
// Won't be visible:
//oddballButton = new Button ("1 - Center") {
// X = 1 - Pos.Center (),
// Y = Pos.Bottom (oddballButton)
//};
//Application.Top.Add (oddballButton);
// This demonstrates nonsense: it the same as using Pos.AnchorEnd (100/2=50 + 100/2=50 = 100 - 50)
// The `- Pos.Percent(5)` is there so at least something is visible
oddballButton = new Button ("Center + Center - Percent(50)") {

View File

@@ -114,7 +114,7 @@ namespace UICatalog.Scenarios {
};
frame.Add (styleRadioGroup);
frame.ForceValidatePosDim = true;
frame.ValidatePosDim = true;
void Top_Loaded (object sender, EventArgs args)
{
frame.Height =

View File

@@ -146,7 +146,7 @@ namespace UICatalog.Scenarios {
};
frame.Add (ckbWrapMessage);
frame.ForceValidatePosDim = true;
frame.ValidatePosDim = true;
void Top_Loaded (object sender, EventArgs args)
{
frame.Height =

View File

@@ -420,11 +420,13 @@ public class ApplicationTests {
Assert.Equal (3, count);
}
// TODO: All Toplevel layout tests should be moved to ToplevelTests.cs
[Fact]
public void Run_Toplevel_With_Modal_View_Does_Not_Refresh_If_Not_Dirty ()
{
Init ();
var count = 0;
// Don't use Dialog here as it has more layout logic. Use Window instead.
Dialog d = null;
var top = Application.Top;
top.DrawContent += (s, a) => count++;
@@ -432,6 +434,7 @@ public class ApplicationTests {
Application.Iteration += (s, a) => {
iteration++;
if (iteration == 0) {
// TODO: Don't use Dialog here as it has more layout logic. Use Window instead.
d = new Dialog ();
d.DrawContent += (s, a) => count++;
Application.Run (d);
@@ -453,13 +456,15 @@ public class ApplicationTests {
Assert.Equal (3, count);
}
// TODO: All Toplevel layout tests should be moved to ToplevelTests.cs
[Fact]
public void Run_A_Modal_Toplevel_Refresh_Background_On_Moving ()
{
Init ();
var d = new Dialog () { Width = 5, Height = 5 };
// Don't use Dialog here as it has more layout logic. Use Window instead.
var w = new Window () { Width = 5, Height = 5 };
((FakeDriver)Application.Driver).SetBufferSize (10, 10);
var rs = Application.Begin (d);
var rs = Application.Begin (w);
TestHelpers.AssertDriverContentsWithFrameAre (@"
┌───┐
│ │
@@ -471,26 +476,22 @@ public class ApplicationTests {
// 0
new Attribute (ColorName.White, ColorName.Black),
// 1
Colors.Dialog.Normal
Colors.Base.Normal
};
TestHelpers.AssertDriverColorsAre (@"
0000000000
0000000000
0011111000
0011111000
0011111000
0011111000
0011111000
0000000000
0000000000
0000000000
1111100000
1111100000
1111100000
1111100000
1111100000
", null, attributes);
// TODO: In PR #2920 this breaks because the mouse is not grabbed anymore.
// TODO: Move the mouse grap/drag mode from Toplevel to Border.
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 = 0, Y = 0, Flags = MouseFlags.Button1Pressed }));
Assert.Equal (w, Application.MouseGrabView);
// Move down and to the right.
Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () { X = 1, Y = 1, Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition }));
Application.Refresh ();
TestHelpers.AssertDriverContentsWithFrameAre (@"
@@ -504,7 +505,7 @@ public class ApplicationTests {
// 0
new Attribute (ColorName.White, ColorName.Black),
// 1
Colors.Dialog.Normal
Colors.Base.Normal
};
TestHelpers.AssertDriverColorsAre (@"
0000000000
@@ -513,10 +514,6 @@ public class ApplicationTests {
0111110000
0111110000
0111110000
0000000000
0000000000
0000000000
0000000000
", null, attributes);
Application.End (rs);
@@ -578,6 +575,7 @@ public class ApplicationTests {
var t1 = new Toplevel ();
var t2 = new Toplevel ();
var t3 = new Toplevel ();
// Don't use Dialog here as it has more layout logic. Use Window instead.
var d = new Dialog ();
var t4 = new Toplevel ();

View File

@@ -780,6 +780,8 @@ namespace Terminal.Gui.DialogTests {
[Fact, AutoInitShutdown]
public void Dialog_Opened_From_Another_Dialog ()
{
((FakeDriver)Application.Driver).SetBufferSize (30, 10);
var btn1 = new Button ("press me 1");
Button btn2 = null;
Button btn3 = null;
@@ -788,7 +790,13 @@ namespace Terminal.Gui.DialogTests {
btn2 = new Button ("Show Sub");
btn3 = new Button ("Close");
btn3.Clicked += (s, e) => Application.RequestStop ();
btn2.Clicked += (s, e) => { MessageBox.Query (string.Empty, "ya", "Ok"); };
btn2.Clicked += (s, e) => {
// Don't test MessageBox in Dialog unit tests!
var subBtn = new Button ("Ok") { IsDefault = true };
var subDlg = new Dialog (subBtn) { Text = "ya", Width = 20, Height = 5 };
subBtn.Clicked += (s, e) => Application.RequestStop (subDlg);
Application.Run (subDlg);
};
var dlg = new Dialog (btn2, btn3);
Application.Run (dlg);
@@ -802,53 +810,27 @@ namespace Terminal.Gui.DialogTests {
Assert.True (btn1.NewKeyDownEvent (new (KeyCode.Space)));
} else if (iterations == 1) {
expected = @$"
┌──────────────────────────────────────────────────────────────────┐
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
───────────────────────┐
│ │
│ │
│ │
│ │
│ │
│{CM.Glyphs.LeftBracket} Show Sub {CM.Glyphs.RightBracket} {CM.Glyphs.LeftBracket} Close {CM.Glyphs.RightBracket} │
└──────────────────────────────────────────────────────────────────┘";
───────────────────────┘";
TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
Assert.True (btn2.NewKeyDownEvent (new (KeyCode.Space)));
} else if (iterations == 2) {
TestHelpers.AssertDriverContentsWithFrameAre (@$"
┌──────────────────────────────────────────────────────────────────┐
│ │
│ │
│ │
│ │
│ │
│ │
│ ┌──────────────────────────────────────────────┐ │
───────────────────────┐
│ ┌──────────────────┐
│ │ya │ │
│ │ │ │
│ │ {btn} │ │
│ └──────────────────────────────────────────────┘
│ │
│ │
│ │
│ │
│ │
│ │
│ └──────────────────┘
│{CM.Glyphs.LeftBracket} Show Sub {CM.Glyphs.RightBracket} {CM.Glyphs.LeftBracket} Close {CM.Glyphs.RightBracket} │
└──────────────────────────────────────────────────────────────────┘", output);
───────────────────────┘", output);
Assert.True (Application.Current.NewKeyDownEvent (new (KeyCode.Enter)));
} else if (iterations == 3) {

View File

@@ -1,57 +0,0 @@
using Microsoft.VisualStudio.TestPlatform.Utilities;
using Xunit;
using Xunit.Abstractions;
// Alias Console to MockConsole so we don't accidentally use Console
namespace Terminal.Gui.TextTests;
public class UnicodeTests {
readonly ITestOutputHelper _output;
public UnicodeTests (ITestOutputHelper output)
{
this._output = output;
}
[Fact, AutoInitShutdown]
public void AddRune_On_Clip_Left_Or_Right_Replace_Previous_Or_Next_Wide_Rune_With_Space ()
{
var tv = new TextView () {
Width = Dim.Fill (),
Height = Dim.Fill (),
Text = @"これは広いルーンラインです。
これは広いルーンラインです。
これは広いルーンラインです。
これは広いルーンラインです。
これは広いルーンラインです。
これは広いルーンラインです。
これは広いルーンラインです。
これは広いルーンラインです。"
};
var win = new Window () { Width = Dim.Fill (), Height = Dim.Fill () };
win.Add (tv);
Application.Top.Add (win);
var lbl = new Label ("ワイドルーン。");
var dg = new Dialog (new Button ("選ぶ")) { Width = 14, Height = 4 };
dg.Add (lbl);
Application.Begin (Application.Top);
Application.Begin (dg);
((FakeDriver)Application.Driver).SetBufferSize (30, 10);
var expected = @$"
┌────────────────────────────┐
│これは広いルーンラインです。│
│これは広いルーンラインです。│
│これは<EFBFBD>┌────────────┐<EFBFBD>です。│
│これは<EFBFBD>│ワイドルーン│<EFBFBD>です。│
│これは<EFBFBD>│ {CM.Glyphs.LeftBracket} 選ぶ {CM.Glyphs.RightBracket} │<>です。│
│これは<EFBFBD>└────────────┘<EFBFBD>です。│
│これは広いルーンラインです。│
│これは広いルーンラインです。│
└────────────────────────────┘
";
var pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Assert.Equal (new Rect (0, 0, 30, 10), pos);
}
}

View File

@@ -25,8 +25,8 @@
<PackageReference Include="ReportGenerator" Version="5.2.0" />
<PackageReference Include="System.Collections" Version="4.3.0" />
<PackageReference Include="TestableIO.System.IO.Abstractions.TestingHelpers" Version="20.0.4" />
<PackageReference Include="xunit" Version="2.6.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.5">
<PackageReference Include="xunit" Version="2.6.4" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -2,22 +2,63 @@
using System;
using Xunit;
using Xunit.Abstractions;
using Microsoft.VisualStudio.TestPlatform.Utilities;
namespace Terminal.Gui.ViewsTests;
namespace Terminal.Gui.ViewsTests {
public class DrawTests {
readonly ITestOutputHelper output;
readonly ITestOutputHelper _output;
public DrawTests (ITestOutputHelper output)
public DrawTests (ITestOutputHelper output) => _output = output;
[Fact] [AutoInitShutdown]
public void Clipping_AddRune_Left_Or_Right_Replace_Previous_Or_Next_Wide_Rune_With_Space ()
{
this.output = output;
var tv = new TextView () {
Width = Dim.Fill (),
Height = Dim.Fill (),
Text = @"これは広いルーンラインです。
これは広いルーンラインです。
これは広いルーンラインです。
これは広いルーンラインです。
これは広いルーンラインです。
これは広いルーンラインです。
これは広いルーンラインです。
これは広いルーンラインです。"
};
var win = new Window () { Width = Dim.Fill (), Height = Dim.Fill () };
win.Add (tv);
Application.Top.Add (win);
var lbl = new Label ("ワイドルーン。");
// Don't have unit tests use things that aren't absolutely critical for the test, like Dialog
var dg = new Window () { X = 2, Y = 2, Width = 14, Height = 3 };
dg.Add (lbl);
Application.Begin (Application.Top);
Application.Begin (dg);
((FakeDriver)Application.Driver).SetBufferSize (30, 10);
string expected = @$"
┌────────────────────────────┐
│これは広いルーンラインです。│
<EFBFBD>┌────────────┐<EFBFBD>ラインです。│
<EFBFBD>│ワイドルーン│<EFBFBD>ラインです。│
<EFBFBD>└────────────┘<EFBFBD>ラインです。│
│これは広いルーンラインです。│
│これは広いルーンラインです。│
│これは広いルーンラインです。│
│これは広いルーンラインです。│
└────────────────────────────┘";
var pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Assert.Equal (new Rect (0, 0, 30, 10), pos);
}
// TODO: The tests below that use Label should use View instead.
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void Non_Bmp_ConsoleWidth_ColumnWidth_Equal_Two ()
{
string us = "\U0001d539";
Rune r = (Rune)0x1d539;
var r = (Rune)0x1d539;
Assert.Equal ("𝔹", us);
Assert.Equal ("𝔹", r.ToString ());
@@ -36,14 +77,14 @@ namespace Terminal.Gui.ViewsTests {
Application.Begin (top);
((FakeDriver)Application.Driver).SetBufferSize (10, 4);
var expected = @"
string expected = @"
┌┤𝔹├─────┐
│𝔹 │
│𝔹 │
└────────┘";
TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
TestHelpers.AssertDriverContentsAre (expected, output);
TestHelpers.AssertDriverContentsAre (expected, _output);
var expectedColors = new Attribute [] {
// 0
@@ -58,14 +99,14 @@ namespace Terminal.Gui.ViewsTests {
0020000000
0000000000
0111000000
0000000000", driver: Application.Driver, expectedColors);
0000000000", Application.Driver, expectedColors);
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void CJK_Compatibility_Ideographs_ConsoleWidth_ColumnWidth_Equal_Two ()
{
string us = "\U0000f900";
Rune r = (Rune)0xf900;
var r = (Rune)0xf900;
Assert.Equal ("豈", us);
Assert.Equal ("豈", r.ToString ());
@@ -84,14 +125,14 @@ namespace Terminal.Gui.ViewsTests {
Application.Begin (top);
((FakeDriver)Application.Driver).SetBufferSize (10, 4);
var expected = @"
string expected = @"
┌┤豈├────┐
│豈 │
│豈 │
└────────┘";
TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
TestHelpers.AssertDriverContentsAre (expected, output);
TestHelpers.AssertDriverContentsAre (expected, _output);
var expectedColors = new Attribute [] {
// 0
@@ -106,10 +147,10 @@ namespace Terminal.Gui.ViewsTests {
0022000000
0000000000
0111000000
0000000000", driver: Application.Driver, expectedColors);
0000000000", Application.Driver, expectedColors);
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void Colors_On_TextAlignment_Right_And_Bottom ()
{
var labelRight = new Label ("Test") {
@@ -138,7 +179,7 @@ namespace Terminal.Gui.ViewsTests {
T
e
s
t ", output);
t ", _output);
TestHelpers.AssertDriverColorsAre (@"
000000
@@ -147,10 +188,10 @@ t ", output);
0
0
0
0", driver: Application.Driver, new Attribute [] { Colors.Base.Normal });
0", Application.Driver, new Attribute [] { Colors.Base.Normal });
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void Draw_Negative_Bounds_Horizontal_Without_New_Lines ()
{
// BUGBUG: This previously assumed the default height of a View was 1.
@@ -165,39 +206,36 @@ t ", output);
top.Add (container);
// BUGBUG: v2 - it's bogus to reference .Frame before BeginInit. And why is the clip being set anyway???
void Top_LayoutComplete (object sender, LayoutEventArgs e)
{
Application.Driver.Clip = container.Frame;
}
void Top_LayoutComplete (object sender, LayoutEventArgs e) => Application.Driver.Clip = container.Frame;
top.LayoutComplete += Top_LayoutComplete;
Application.Begin (top);
TestHelpers.AssertDriverContentsWithFrameAre (@"
01234
subVi", output);
subVi", _output);
content.X = -1;
Application.Refresh ();
TestHelpers.AssertDriverContentsWithFrameAre (@"
12345
ubVie", output);
ubVie", _output);
content.Y = -1;
Application.Refresh ();
TestHelpers.AssertDriverContentsWithFrameAre (@"
ubVie", output);
ubVie", _output);
content.Y = -2;
Application.Refresh ();
TestHelpers.AssertDriverContentsWithFrameAre ("", output);
TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
content.X = -20;
content.Y = 0;
Application.Refresh ();
TestHelpers.AssertDriverContentsWithFrameAre ("", output);
TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void Draw_Negative_Bounds_Horizontal_With_New_Lines ()
{
var subView = new View () { Id = "subView", X = 1, Width = 1, Height = 7, Text = "s\nu\nb\nV\ni\ne\nw" };
@@ -217,7 +255,7 @@ t ", output);
1u
2b
3V
4i", output);
4i", _output);
content.X = -1;
Application.Refresh ();
@@ -226,11 +264,11 @@ t ", output);
u
b
V
i", output);
i", _output);
content.X = -2;
Application.Refresh ();
TestHelpers.AssertDriverContentsWithFrameAre (@"", output);
TestHelpers.AssertDriverContentsWithFrameAre (@"", _output);
content.X = 0;
content.Y = -1;
@@ -240,7 +278,7 @@ t ", output);
2b
3V
4i
5e", output);
5e", _output);
content.Y = -6;
Application.Refresh ();
@@ -249,24 +287,24 @@ t ", output);
7
8
9
0 ", output);
0 ", _output);
content.Y = -19;
Application.Refresh ();
TestHelpers.AssertDriverContentsWithFrameAre (@"
9", output);
9", _output);
content.Y = -20;
Application.Refresh ();
TestHelpers.AssertDriverContentsWithFrameAre ("", output);
TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
content.X = -2;
content.Y = 0;
Application.Refresh ();
TestHelpers.AssertDriverContentsWithFrameAre ("", output);
TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void Draw_Negative_Bounds_Vertical ()
{
var subView = new View () { Id = "subView", X = 1, Width = 1, Height = 7, Text = "subView", TextDirection = TextDirection.TopBottom_LeftRight };
@@ -286,7 +324,7 @@ t ", output);
1u
2b
3V
4i", output);
4i", _output);
content.X = -1;
Application.Refresh ();
@@ -295,11 +333,11 @@ t ", output);
u
b
V
i", output);
i", _output);
content.X = -2;
Application.Refresh ();
TestHelpers.AssertDriverContentsWithFrameAre (@"", output);
TestHelpers.AssertDriverContentsWithFrameAre (@"", _output);
content.X = 0;
content.Y = -1;
@@ -309,7 +347,7 @@ t ", output);
2b
3V
4i
5e", output);
5e", _output);
content.Y = -6;
Application.Refresh ();
@@ -318,22 +356,20 @@ t ", output);
7
8
9
0 ", output);
0 ", _output);
content.Y = -19;
Application.Refresh ();
TestHelpers.AssertDriverContentsWithFrameAre (@"
9", output);
9", _output);
content.Y = -20;
Application.Refresh ();
TestHelpers.AssertDriverContentsWithFrameAre ("", output);
TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
content.X = -2;
content.Y = 0;
Application.Refresh ();
TestHelpers.AssertDriverContentsWithFrameAre ("", output);
TestHelpers.AssertDriverContentsWithFrameAre ("", _output);
}
}
}

View File

@@ -1,24 +1,21 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
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.ViewTests {
public class LayoutTests_DimTests {
readonly ITestOutputHelper output;
namespace Terminal.Gui.ViewTests;
public LayoutTests_DimTests (ITestOutputHelper output)
public class DimTests {
readonly ITestOutputHelper _output;
public DimTests (ITestOutputHelper output)
{
this.output = output;
_output = output;
Console.OutputEncoding = System.Text.Encoding.Default;
// Change current culture
var culture = CultureInfo.CreateSpecificCulture ("en-US");
@@ -97,7 +94,7 @@ namespace Terminal.Gui.ViewTests {
testValView.Dispose ();
}
[Fact, TestRespondersDisposed]
[Fact] [TestRespondersDisposed]
public void Width_Equals ()
{
var testRect1 = Rect.Empty;
@@ -171,7 +168,7 @@ namespace Terminal.Gui.ViewTests {
[Fact]
public void Fill_SetsValue ()
{
var testMargin = 0;
int testMargin = 0;
var dim = Dim.Fill ();
Assert.Equal ($"Fill({testMargin})", dim.ToString ());
@@ -187,8 +184,8 @@ namespace Terminal.Gui.ViewTests {
[Fact]
public void Fill_Equal ()
{
var margin1 = 0;
var margin2 = 0;
int margin1 = 0;
int margin2 = 0;
var dim1 = Dim.Fill (margin1);
var dim2 = Dim.Fill (margin2);
Assert.Equal (dim1, dim2);
@@ -265,7 +262,7 @@ namespace Terminal.Gui.ViewTests {
Assert.Throws<ArgumentException> (() => dim = Dim.Percent (1000001));
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void ForceValidatePosDim_True_Dim_Validation_If_NewValue_Is_DimAbsolute_And_OldValue_Is_Another_Type_Throws ()
{
var t = Application.Top;
@@ -277,7 +274,7 @@ namespace Terminal.Gui.ViewTests {
var v = new View ("v") {
Width = Dim.Width (w) - 2,
Height = Dim.Percent (10),
ForceValidatePosDim = true
ValidatePosDim = true
};
w.Add (v);
@@ -288,7 +285,7 @@ namespace Terminal.Gui.ViewTests {
Assert.Equal (2, w.Height = 2);
Assert.Throws<ArgumentException> (() => v.Width = 2);
Assert.Throws<ArgumentException> (() => v.Height = 2);
v.ForceValidatePosDim = false;
v.ValidatePosDim = false;
var exception = Record.Exception (() => v.Width = 2);
Assert.Null (exception);
Assert.Equal (2, v.Width);
@@ -302,7 +299,7 @@ namespace Terminal.Gui.ViewTests {
Application.Run ();
}
[Fact, TestRespondersDisposed]
[Fact] [TestRespondersDisposed]
public void Dim_Validation_Do_Not_Throws_If_NewValue_Is_DimAbsolute_And_OldValue_Is_Null ()
{
var t = new View ("top") { Width = 80, Height = 25 };
@@ -316,7 +313,7 @@ namespace Terminal.Gui.ViewTests {
t.Dispose ();
}
[Fact, TestRespondersDisposed]
[Fact] [TestRespondersDisposed]
public void Dim_Validation_Do_Not_Throws_If_NewValue_Is_DimAbsolute_And_OldValue_Is_Another_Type_After_Sets_To_LayoutStyle_Absolute ()
{
var t = new View ("top") { Width = 80, Height = 25 };
@@ -345,7 +342,7 @@ namespace Terminal.Gui.ViewTests {
t.Dispose ();
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void Only_DimAbsolute_And_DimFactor_As_A_Different_Procedure_For_Assigning_Value_To_Width_Or_Height ()
{
// Testing with the Button because it properly handles the Dim class.
@@ -376,7 +373,7 @@ namespace Terminal.Gui.ViewTests {
Y = Pos.Bottom (f1) + 2,
Width = Dim.Width (f1) - 2,
Height = Dim.Fill () - 2,
ForceValidatePosDim = true
ValidatePosDim = true
};
var v2 = new Button ("v2") {
@@ -385,28 +382,28 @@ namespace Terminal.Gui.ViewTests {
Y = Pos.Bottom (f2) + 2,
Width = Dim.Width (f2) - 2,
Height = Dim.Fill () - 2,
ForceValidatePosDim = true
ValidatePosDim = true
};
var v3 = new Button ("v3") {
AutoSize = false,
Width = Dim.Percent (10),
Height = Dim.Percent (10),
ForceValidatePosDim = true
ValidatePosDim = true
};
var v4 = new Button ("v4") {
AutoSize = false,
Width = Dim.Sized (50),
Height = Dim.Sized (50),
ForceValidatePosDim = true
ValidatePosDim = true
};
var v5 = new Button ("v5") {
AutoSize = false,
Width = Dim.Width (v1) - Dim.Width (v3),
Height = Dim.Height (v1) - Dim.Height (v3),
ForceValidatePosDim = true
ValidatePosDim = true
};
var v6 = new Button ("v6") {
@@ -415,7 +412,7 @@ namespace Terminal.Gui.ViewTests {
Y = Pos.Bottom (f2) + 2,
Width = Dim.Percent (20, true),
Height = Dim.Percent (20, true),
ForceValidatePosDim = true
ValidatePosDim = true
};
w.Add (f1, f2, v1, v2, v3, v4, v5, v6);
@@ -559,7 +556,7 @@ namespace Terminal.Gui.ViewTests {
/// <summary>
/// This is an intentionally obtuse test. See https://github.com/gui-cs/Terminal.Gui/issues/2461
/// </summary>
[Fact, TestRespondersDisposed]
[Fact] [TestRespondersDisposed]
public void DimCombine_ObtuseScenario_Throw_If_SuperView_Refs_SubView ()
{
var t = new View () { Width = 80, Height = 25 };
@@ -581,6 +578,8 @@ namespace Terminal.Gui.ViewTests {
f.Add (v1, v2);
w.Add (f);
t.Add (w);
t.BeginInit ();
t.EndInit ();
// BUGBUG: v2 - f references t here; t is f's super-superview. This is supported!
// BUGBUG: v2 - f references v2 here; v2 is f's subview. This is not supported!
@@ -602,7 +601,7 @@ namespace Terminal.Gui.ViewTests {
t.Dispose ();
}
[Fact, TestRespondersDisposed]
[Fact] [TestRespondersDisposed]
public void DimCombine_ObtuseScenario_Does_Not_Throw_If_Two_SubViews_Refs_The_Same_SuperView ()
{
var t = new View ("top") { Width = 80, Height = 25 };
@@ -624,6 +623,8 @@ namespace Terminal.Gui.ViewTests {
f.Add (v1, v2);
w.Add (f);
t.Add (w);
t.BeginInit ();
t.EndInit ();
f.Width = Dim.Width (t) - Dim.Width (w) + 4; // 80 - 74 = 6
f.Height = Dim.Height (t) - Dim.Height (w) + 4; // 25 - 19 = 6
@@ -644,7 +645,7 @@ namespace Terminal.Gui.ViewTests {
t.Dispose ();
}
[Fact, TestRespondersDisposed]
[Fact] [TestRespondersDisposed]
public void PosCombine_View_Not_Added_Throws ()
{
var t = new View () { Width = 80, Height = 50 };
@@ -672,19 +673,22 @@ namespace Terminal.Gui.ViewTests {
sub.Width = Dim.Fill () - Dim.Width (v2);
sub.Height = Dim.Fill () - Dim.Height (v2);
t.BeginInit ();
t.EndInit ();
Assert.Throws<InvalidOperationException> (() => t.LayoutSubviews ());
t.Dispose ();
v2.Dispose ();
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void Dim_Add_Operator ()
{
var top = Application.Top;
var view = new View () { X = 0, Y = 0, Width = 20, Height = 0 };
var field = new TextField () { X = 0, Y = Pos.Bottom (view), Width = 20 };
var count = 0;
int count = 0;
field.KeyDown += (s, k) => {
if (k.KeyCode == KeyCode.Enter) {
@@ -702,7 +706,9 @@ namespace Terminal.Gui.ViewTests {
};
Application.Iteration += (s, a) => {
while (count < 20) field.NewKeyDownEvent (new (KeyCode.Enter));
while (count < 20) {
field.NewKeyDownEvent (new Key (KeyCode.Enter));
}
Application.RequestStop ();
};
@@ -718,7 +724,7 @@ namespace Terminal.Gui.ViewTests {
Assert.Equal (20, count);
}
private string [] expecteds = new string [21] {
string [] expecteds = new string [21] {
@"
┌────────────────────┐
│View with long text │
@@ -1033,10 +1039,10 @@ namespace Terminal.Gui.ViewTests {
│Label 18 │
│Label 19 │
│Label 19 │
└────────────────────┘",
└────────────────────┘"
};
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void Dim_Add_Operator_With_Text ()
{
var top = Application.Top;
@@ -1045,13 +1051,13 @@ namespace Terminal.Gui.ViewTests {
//// Although view height is zero the text it's draw due the SetMinWidthHeight method
var view = new View ("View with long text") { X = 0, Y = 0, Width = 20, Height = 1 };
var field = new TextField () { X = 0, Y = Pos.Bottom (view), Width = 20 };
var count = 0;
int count = 0;
var listLabels = new List<Label> ();
field.KeyDown += (s, k) => {
if (k.KeyCode == KeyCode.Enter) {
((FakeDriver)Application.Driver).SetBufferSize (22, count + 4);
var pos = TestHelpers.AssertDriverContentsWithFrameAre (expecteds [count], output);
var pos = TestHelpers.AssertDriverContentsWithFrameAre (expecteds [count], _output);
Assert.Equal (new Rect (0, 0, 22, count + 4), pos);
if (count < 20) {
@@ -1076,9 +1082,9 @@ namespace Terminal.Gui.ViewTests {
Application.Iteration += (s, a) => {
while (count < 21) {
field.NewKeyDownEvent (new (KeyCode.Enter));
field.NewKeyDownEvent (new Key (KeyCode.Enter));
if (count == 20) {
field.NewKeyDownEvent (new (KeyCode.Enter));
field.NewKeyDownEvent (new Key (KeyCode.Enter));
break;
}
}
@@ -1098,14 +1104,14 @@ namespace Terminal.Gui.ViewTests {
Assert.Equal (count, listLabels.Count);
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void Dim_Subtract_Operator ()
{
var top = Application.Top;
var view = new View () { X = 0, Y = 0, Width = 20, Height = 0 };
var field = new TextField () { X = 0, Y = Pos.Bottom (view), Width = 20 };
var count = 20;
int count = 20;
var listLabels = new List<Label> ();
for (int i = 0; i < count; i++) {
@@ -1137,7 +1143,9 @@ namespace Terminal.Gui.ViewTests {
};
Application.Iteration += (s, a) => {
while (count > 0) field.NewKeyDownEvent (new (KeyCode.Enter));
while (count > 0) {
field.NewKeyDownEvent (new Key (KeyCode.Enter));
}
Application.RequestStop ();
};
@@ -1153,7 +1161,7 @@ namespace Terminal.Gui.ViewTests {
Assert.Equal (0, count);
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void Dim_Subtract_Operator_With_Text ()
{
var top = Application.Top;
@@ -1162,7 +1170,7 @@ namespace Terminal.Gui.ViewTests {
//// Although view height is zero the text it's draw due the SetMinWidthHeight method
var view = new View ("View with long text") { X = 0, Y = 0, Width = 20, Height = 1 };
var field = new TextField () { X = 0, Y = Pos.Bottom (view), Width = 20 };
var count = 20;
int count = 20;
var listLabels = new List<Label> ();
for (int i = 0; i < count; i++) {
@@ -1193,7 +1201,7 @@ namespace Terminal.Gui.ViewTests {
field.KeyDown += (s, k) => {
if (k.KeyCode == KeyCode.Enter) {
((FakeDriver)Application.Driver).SetBufferSize (22, count + 4);
var pos = TestHelpers.AssertDriverContentsWithFrameAre (expecteds [count], output);
var pos = TestHelpers.AssertDriverContentsWithFrameAre (expecteds [count], _output);
Assert.Equal (new Rect (0, 0, 22, count + 4), pos);
if (count > 0) {
@@ -1204,20 +1212,21 @@ namespace Terminal.Gui.ViewTests {
Assert.Equal ($"Absolute({count + 1})", view.Height.ToString ());
view.Height -= 1;
count--;
if (listLabels.Count > 0)
if (listLabels.Count > 0) {
field.Text = listLabels [count - 1].Text;
else
} else {
field.Text = string.Empty;
}
}
Assert.Equal ($"Absolute({count + 1})", view.Height.ToString ());
}
};
Application.Iteration += (s, a) => {
while (count > -1) {
field.NewKeyDownEvent (new (KeyCode.Enter));
field.NewKeyDownEvent (new Key (KeyCode.Enter));
if (count == 0) {
field.NewKeyDownEvent (new (KeyCode.Enter));
field.NewKeyDownEvent (new Key (KeyCode.Enter));
break;
}
}
@@ -1237,7 +1246,7 @@ namespace Terminal.Gui.ViewTests {
Assert.Equal (count, listLabels.Count);
}
[Fact, TestRespondersDisposed]
[Fact] [TestRespondersDisposed]
public void Internal_Tests ()
{
var dimFactor = new Dim.DimFactor (0.10F);
@@ -1250,8 +1259,8 @@ namespace Terminal.Gui.ViewTests {
Assert.Equal (99, dimFill.Anchor (100));
var dimCombine = new Dim.DimCombine (true, dimFactor, dimAbsolute);
Assert.Equal (dimCombine.left, dimFactor);
Assert.Equal (dimCombine.right, dimAbsolute);
Assert.Equal (dimCombine._left, dimFactor);
Assert.Equal (dimCombine._right, dimAbsolute);
Assert.Equal (20, dimCombine.Anchor (100));
var view = new View (new Rect (20, 10, 20, 1));
@@ -1266,7 +1275,7 @@ namespace Terminal.Gui.ViewTests {
[Fact]
public void Function_SetsValue ()
{
var text = "Test";
string text = "Test";
var dim = Dim.Function (() => text.Length);
Assert.Equal ("DimFunc(4)", dim.ToString ());
@@ -1292,7 +1301,7 @@ namespace Terminal.Gui.ViewTests {
Assert.NotEqual (dim1, dim2);
}
[Theory, AutoInitShutdown]
[Theory] [AutoInitShutdown]
[InlineData (0, true)]
[InlineData (0, false)]
[InlineData (50, true)]
@@ -1301,18 +1310,20 @@ namespace Terminal.Gui.ViewTests {
{
var container = new View {
Width = 100,
Height = 100,
Height = 100
};
var label = new Label {
X = testHorizontal ? startingDistance : 0,
Y = testHorizontal ? 0 : startingDistance,
Width = testHorizontal ? Dim.Percent (50) + 1 : 1,
Height = testHorizontal ? 1 : Dim.Percent (50) + 1,
Height = testHorizontal ? 1 : Dim.Percent (50) + 1
};
container.Add (label);
Application.Top.Add (container);
Application.Top.BeginInit ();
Application.Top.EndInit ();
Application.Top.LayoutSubviews ();
Assert.Equal (100, container.Frame.Width);
@@ -1327,7 +1338,7 @@ namespace Terminal.Gui.ViewTests {
}
}
[Fact, TestRespondersDisposed]
[Fact] [TestRespondersDisposed]
public void Dim_Referencing_SuperView_Does_Not_Throw ()
{
var super = new View ("super") {
@@ -1336,7 +1347,7 @@ namespace Terminal.Gui.ViewTests {
};
var view = new View ("view") {
Width = Dim.Width (super), // this is allowed
Height = Dim.Height (super), // this is allowed
Height = Dim.Height (super) // this is allowed
};
super.Add (view);
@@ -1348,7 +1359,7 @@ namespace Terminal.Gui.ViewTests {
super.Dispose ();
}
[Fact, TestRespondersDisposed]
[Fact] [TestRespondersDisposed]
public void Dim_SyperView_Referencing_SubView_Throws ()
{
var super = new View ("super") {
@@ -1357,11 +1368,11 @@ namespace Terminal.Gui.ViewTests {
};
var view2 = new View ("view2") {
Width = 10,
Height = 10,
Height = 10
};
var view = new View ("view") {
Width = Dim.Width (view2), // this is not allowed
Height = Dim.Height (view2), // this is not allowed
Height = Dim.Height (view2) // this is not allowed
};
view.Add (view2);
@@ -1373,4 +1384,3 @@ namespace Terminal.Gui.ViewTests {
super.Dispose ();
}
}
}

View File

@@ -6,14 +6,12 @@ using Xunit.Abstractions;
// Alias Console to MockConsole so we don't accidentally use Console
using Console = Terminal.Gui.FakeConsole;
namespace Terminal.Gui.ViewTests {
public class LayoutTests {
readonly ITestOutputHelper output;
namespace Terminal.Gui.ViewTests;
public LayoutTests (ITestOutputHelper output)
{
this.output = output;
}
public class LayoutTests {
readonly ITestOutputHelper _output;
public LayoutTests (ITestOutputHelper output) => _output = output;
[Fact]
public void TopologicalSort_Missing_Add ()
@@ -109,18 +107,18 @@ namespace Terminal.Gui.ViewTests {
super.Dispose ();
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void TrySetWidth_ForceValidatePosDim ()
{
var top = new View () {
X = 0,
Y = 0,
Width = 80,
Width = 80
};
var v = new View () {
Width = Dim.Fill (),
ForceValidatePosDim = true
ValidatePosDim = true
};
top.Add (v);
@@ -148,7 +146,7 @@ namespace Terminal.Gui.ViewTests {
Assert.Equal (60, rWidth);
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void TrySetHeight_ForceValidatePosDim ()
{
var top = new View () {
@@ -159,7 +157,7 @@ namespace Terminal.Gui.ViewTests {
var v = new View () {
Height = Dim.Fill (),
ForceValidatePosDim = true
ValidatePosDim = true
};
top.Add (v);
@@ -188,13 +186,13 @@ namespace Terminal.Gui.ViewTests {
Assert.Equal (5, rHeight);
}
[Fact, TestRespondersDisposed]
[Fact] [TestRespondersDisposed]
public void GetCurrentWidth_TrySetWidth ()
{
var top = new View () {
X = 0,
Y = 0,
Width = 80,
Width = 80
};
var v = new View () {
@@ -349,7 +347,7 @@ namespace Terminal.Gui.ViewTests {
super.Dispose ();
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void AutoSize_False_ResizeView_With_Dim_Fill_After_IsInitialized ()
{
var win = new Window (new Rect (0, 0, 30, 80));
@@ -375,7 +373,7 @@ namespace Terminal.Gui.ViewTests {
Application.End (rs);
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void AutoSize_False_SetWidthHeight_With_Dim_Fill_And_Dim_Absolute_After_IsAdded_And_IsInitialized ()
{
var win = new Window (new Rect (0, 0, 30, 80));
@@ -413,7 +411,7 @@ namespace Terminal.Gui.ViewTests {
Application.End (rs);
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void AutoSize_False_SetWidthHeight_With_Dim_Fill_And_Dim_Absolute_With_Initialization ()
{
var win = new Window (new Rect (0, 0, 30, 80));
@@ -467,7 +465,7 @@ namespace Terminal.Gui.ViewTests {
Application.End (rs);
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void AutoSize_True_Setting_With_Height_Horizontal ()
{
var label = new Label ("Hello") { Width = 10, Height = 2 };
@@ -480,13 +478,13 @@ namespace Terminal.Gui.ViewTests {
Assert.True (label.AutoSize);
Assert.Equal (new Rect (0, 0, 10, 2), label.Frame);
var expected = @"
string expected = @"
Hello X
Y
";
var pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
var pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Assert.Equal (new Rect (0, 0, 11, 3), pos);
label.AutoSize = false;
@@ -501,12 +499,12 @@ Hello X
Y
";
pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Assert.Equal (new Rect (0, 0, 11, 3), pos);
Application.End (rs);
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void AutoSize_True_Setting_With_Height_Vertical ()
{
var label = new Label ("Hello") { Width = 2, Height = 10, TextDirection = TextDirection.TopBottom_LeftRight };
@@ -519,7 +517,7 @@ Y
Assert.True (label.AutoSize);
Assert.Equal (new Rect (0, 0, 2, 10), label.Frame);
var expected = @"
string expected = @"
H X
e
l
@@ -533,7 +531,7 @@ o
Y
";
var pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
var pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Assert.Equal (new Rect (0, 0, 3, 11), pos);
label.AutoSize = false;
@@ -556,7 +554,7 @@ o
Y
";
pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Assert.Equal (new Rect (0, 0, 3, 11), pos);
Application.End (rs);
}
@@ -585,7 +583,7 @@ Y
string GetContents ()
{
var text = "";
string text = "";
for (int i = 0; i < 4; i++) {
text += Application.Driver.Contents [0, i].Rune;
}
@@ -594,10 +592,10 @@ Y
Application.End (rs);
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void Width_Height_SetMinWidthHeight_Narrow_Wide_Runes ()
{
var text = $"First line{Environment.NewLine}Second line";
string text = $"First line{Environment.NewLine}Second line";
var horizontalView = new View () {
Width = 20,
Height = 1,
@@ -624,7 +622,7 @@ Y
Assert.False (verticalView.AutoSize);
Assert.Equal (new Rect (0, 0, 20, 1), horizontalView.Frame);
Assert.Equal (new Rect (0, 3, 1, 20), verticalView.Frame);
var expected = @"
string expected = @"
┌──────────────────────────────┐
│First line Second li │
│ │
@@ -659,7 +657,7 @@ Y
└──────────────────────────────┘
";
var pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
var pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Assert.Equal (new Rect (0, 0, 32, 32), pos);
verticalView.Text = $"最初の行{Environment.NewLine}二行目";
@@ -700,12 +698,12 @@ Y
└──────────────────────────────┘
";
pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Assert.Equal (new Rect (0, 0, 32, 32), pos);
Application.End (rs);
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void TextDirection_Toggle ()
{
var win = new Window () { Width = Dim.Fill (), Height = Dim.Fill () };
@@ -727,7 +725,7 @@ Y
Assert.Equal ("Absolute(0)", view.Y.ToString ());
Assert.Equal ("Absolute(0)", view.Width.ToString ());
Assert.Equal ("Absolute(0)", view.Height.ToString ());
var expected = @"
string expected = @"
┌────────────────────┐
│ │
│ │
@@ -752,7 +750,7 @@ Y
└────────────────────┘
";
var pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
var pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Assert.Equal (new Rect (0, 0, 22, 22), pos);
view.Text = "Hello World";
@@ -791,7 +789,7 @@ Y
└────────────────────┘
";
pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Assert.Equal (new Rect (0, 0, 22, 22), pos);
view.AutoSize = true;
@@ -828,7 +826,7 @@ Y
└────────────────────┘
";
pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Assert.Equal (new Rect (0, 0, 22, 22), pos);
view.TextDirection = TextDirection.TopBottom_LeftRight;
@@ -864,7 +862,7 @@ Y
└────────────────────┘
";
pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Assert.Equal (new Rect (0, 0, 22, 22), pos);
view.AutoSize = false;
@@ -901,7 +899,7 @@ Y
└────────────────────┘
";
pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Assert.Equal (new Rect (0, 0, 22, 22), pos);
view.PreserveTrailingSpaces = true;
@@ -937,7 +935,7 @@ Y
└────────────────────┘
";
pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Assert.Equal (new Rect (0, 0, 22, 22), pos);
view.PreserveTrailingSpaces = false;
@@ -977,7 +975,7 @@ Y
└────────────────────┘
";
pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Assert.Equal (new Rect (0, 0, 22, 22), pos);
view.AutoSize = true;
@@ -1013,15 +1011,15 @@ Y
└────────────────────┘
";
pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Assert.Equal (new Rect (0, 0, 22, 22), pos);
Application.End (rs);
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void Width_Height_AutoSize_True_Stay_True_If_TextFormatter_Size_Fit ()
{
var text = $"Fi_nish 終";
string text = $"Fi_nish 終";
var horizontalView = new View () {
Id = "horizontalView",
AutoSize = true,
@@ -1063,7 +1061,7 @@ Y
Assert.Equal ("Absolute(3)", verticalView.Y.ToString ());
Assert.Equal ("Absolute(2)", verticalView.Width.ToString ());
Assert.Equal ("Absolute(8)", verticalView.Height.ToString ());
var expected = @"
string expected = @"
┌────────────────────┐
│Finish 終 │
│ │
@@ -1088,7 +1086,7 @@ Y
└────────────────────┘
";
var pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
var pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Assert.Equal (new Rect (0, 0, 22, 22), pos);
verticalView.Text = $"最初_の行二行目";
@@ -1126,12 +1124,12 @@ Y
└────────────────────┘
";
pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Assert.Equal (new Rect (0, 0, 22, 22), pos);
Application.End (rs);
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void AutoSize_Stays_True_Center_HotKeySpecifier ()
{
var label = new Label () {
@@ -1152,7 +1150,7 @@ Y
var rs = Application.Begin (Application.Top);
((FakeDriver)Application.Driver).SetBufferSize (30, 5);
var expected = @$"
string expected = @$"
┌┤Test Demo 你├──────────────┐
│ │
│ Say Hello 你 │
@@ -1160,7 +1158,7 @@ Y
└────────────────────────────┘
";
TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Assert.True (label.AutoSize);
label.Text = "Say Hello 你 changed";
@@ -1174,11 +1172,11 @@ Y
└────────────────────────────┘
";
TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Application.End (rs);
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void AutoSize_False_Equal_Before_And_After_IsInitialized_With_Differents_Orders ()
{
var view1 = new View () { Text = "Say Hello view1 你", AutoSize = false, Width = 10, Height = 5 };
@@ -1203,7 +1201,7 @@ Y
Width = 10,
Height = 5,
TextDirection = TextDirection.TopBottom_LeftRight,
Text = "Say Hello view6 你",
Text = "Say Hello view6 你"
};
Application.Top.Add (view1, view2, view3, view4, view5, view6);
@@ -1271,7 +1269,7 @@ Y
Application.End (rs);
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void AutoSize_True_Equal_Before_And_After_IsInitialized_With_Different_Orders ()
{
var view1 = new View () { Text = "Say Hello view1 你", AutoSize = true, Width = 10, Height = 5 };
@@ -1296,7 +1294,7 @@ Y
Width = 10,
Height = 5,
TextDirection = TextDirection.TopBottom_LeftRight,
Text = "Say Hello view6 你",
Text = "Say Hello view6 你"
};
Application.Top.Add (view1, view2, view3, view4, view5, view6);
@@ -1366,7 +1364,7 @@ Y
Application.End (rs);
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void Setting_Frame_Dont_Respect_AutoSize_True_On_Layout_Absolute ()
{
var view1 = new View (new Rect (0, 0, 10, 0)) { Text = "Say Hello view1 你", AutoSize = true };
@@ -1421,7 +1419,7 @@ Y
Application.End (rs);
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void Pos_Dim_Are_Null_If_Not_Initialized_On_Constructor_IsAdded_False ()
{
var top = Application.Top;
@@ -1458,116 +1456,8 @@ Y
}
[Fact, TestRespondersDisposed]
public void SetRelativeLayout_PosCombine_Center_Plus_Absolute ()
{
var superView = new View () {
AutoSize = false,
Width = 10,
Height = 10
};
var testView = new View () {
AutoSize = false,
X = Pos.Center (),
Y = Pos.Center (),
Width = 1,
Height = 1
};
superView.Add (testView);
testView.SetRelativeLayout (superView.Frame);
Assert.Equal (4, testView.Frame.X);
Assert.Equal (4, testView.Frame.Y);
testView = new View () {
AutoSize = false,
X = Pos.Center () + 1,
Y = Pos.Center () + 1,
Width = 1,
Height = 1
};
superView.Add (testView);
testView.SetRelativeLayout (superView.Frame);
Assert.Equal (5, testView.Frame.X);
Assert.Equal (5, testView.Frame.Y);
testView = new View () {
AutoSize = false,
X = 1 + Pos.Center (),
Y = 1 + Pos.Center (),
Width = 1,
Height = 1
};
superView.Add (testView);
testView.SetRelativeLayout (superView.Frame);
Assert.Equal (5, testView.Frame.X);
Assert.Equal (5, testView.Frame.Y);
testView = new View () {
AutoSize = false,
X = 1 + Pos.Percent (50),
Y = Pos.Percent (50) + 1,
Width = 1,
Height = 1
};
superView.Add (testView);
testView.SetRelativeLayout (superView.Frame);
Assert.Equal (6, testView.Frame.X);
Assert.Equal (6, testView.Frame.Y);
testView = new View () {
AutoSize = false,
X = Pos.Percent (10) + Pos.Percent (40),
Y = Pos.Percent (10) + Pos.Percent (40),
Width = 1,
Height = 1
};
superView.Add (testView);
testView.SetRelativeLayout (superView.Frame);
Assert.Equal (5, testView.Frame.X);
Assert.Equal (5, testView.Frame.Y);
testView = new View () {
AutoSize = false,
X = 1 + Pos.Percent (10) + Pos.Percent (40) - 1,
Y = 5 + Pos.Percent (10) + Pos.Percent (40) - 5,
Width = 1,
Height = 1
};
superView.Add (testView);
testView.SetRelativeLayout (superView.Frame);
Assert.Equal (5, testView.Frame.X);
Assert.Equal (5, testView.Frame.Y);
testView = new View () {
AutoSize = false,
X = Pos.Left (testView),
Y = Pos.Left (testView),
Width = 1,
Height = 1
};
superView.Add (testView);
testView.SetRelativeLayout (superView.Frame);
Assert.Equal (5, testView.Frame.X);
Assert.Equal (5, testView.Frame.Y);
testView = new View () {
AutoSize = false,
X = 1 + Pos.Left (testView),
Y = Pos.Top (testView) + 1,
Width = 1,
Height = 1
};
superView.Add (testView);
testView.SetRelativeLayout (superView.Frame);
Assert.Equal (6, testView.Frame.X);
Assert.Equal (6, testView.Frame.Y);
superView.Dispose ();
}
[Theory, AutoInitShutdown]
[Theory] [AutoInitShutdown]
[InlineData (1)]
[InlineData (2)]
[InlineData (3)]
@@ -1600,7 +1490,7 @@ Y
((FakeDriver)Application.Driver).SetBufferSize (20, height);
Application.RunIteration (ref rs, ref firstIteration);
var expected = string.Empty;
string expected = string.Empty;
switch (height) {
case 1:
@@ -1701,11 +1591,11 @@ Y
└──────────────────┘";
break;
}
_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Application.End (rs);
}
[Theory, AutoInitShutdown]
[Theory] [AutoInitShutdown]
[InlineData (1)]
[InlineData (2)]
[InlineData (3)]
@@ -1738,7 +1628,7 @@ Y
((FakeDriver)Application.Driver).SetBufferSize (width, 7);
Application.RunIteration (ref rs, ref firstIteration);
var expected = string.Empty;
string expected = string.Empty;
switch (width) {
case 1:
@@ -1852,14 +1742,14 @@ Y
└────────┘";
break;
}
_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
_ = TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Application.End (rs);
}
[Fact, AutoInitShutdown]
[Fact] [AutoInitShutdown]
public void PosCombine_DimCombine_View_With_SubViews ()
{
var clicked = false;
bool clicked = false;
var top = Application.Top;
var win1 = new Window () { Id = "win1", Width = 20, Height = 10 };
var label = new Label ("[ ok ]");
@@ -1885,7 +1775,7 @@ Y
│ │
│ │
│ │
└──────────────────┘", output);
└──────────────────┘", _output);
Assert.Equal (new Rect (0, 0, 80, 25), top.Frame);
Assert.Equal (new Rect (0, 0, 6, 1), label.Frame);
Assert.Equal (new Rect (0, 0, 20, 10), win1.Frame);
@@ -1904,7 +1794,7 @@ Y
Application.End (rs);
}
[Fact, TestRespondersDisposed]
[Fact] [TestRespondersDisposed]
public void Draw_Vertical_Throws_IndexOutOfRangeException_With_Negative_Bounds ()
{
Application.Init (new FakeDriver ());
@@ -1935,7 +1825,7 @@ Y
Application.Shutdown ();
}
[Fact, TestRespondersDisposed]
[Fact] [TestRespondersDisposed]
public void Draw_Throws_IndexOutOfRangeException_With_Negative_Bounds ()
{
Application.Init (new FakeDriver ());
@@ -1962,4 +1852,3 @@ Y
Application.Shutdown ();
}
}
}

View File

@@ -1,23 +1,16 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Linq;
using Xunit;
using Xunit.Abstractions;
// Alias Console to MockConsole so we don't accidentally use Console
using Console = Terminal.Gui.FakeConsole;
namespace Terminal.Gui.ViewTests {
public class LayoutTests_PosTests {
readonly ITestOutputHelper output;
namespace Terminal.Gui.ViewTests;
public LayoutTests_PosTests (ITestOutputHelper output)
{
this.output = output;
}
public class PosTests {
readonly ITestOutputHelper _output;
public PosTests (ITestOutputHelper output) => _output = output;
[Fact]
public void New_Works ()
@@ -29,7 +22,7 @@ namespace Terminal.Gui.ViewTests {
[Fact]
public void AnchorEnd_SetsValue ()
{
var n = 0;
int n = 0;
var pos = Pos.AnchorEnd ();
Assert.Equal ($"AnchorEnd({n})", pos.ToString ());
@@ -41,8 +34,8 @@ namespace Terminal.Gui.ViewTests {
[Fact]
public void AnchorEnd_Equal ()
{
var n1 = 0;
var n2 = 0;
int n1 = 0;
int n2 = 0;
var pos1 = Pos.AnchorEnd (n1);
var pos2 = Pos.AnchorEnd (n2);
@@ -58,8 +51,8 @@ namespace Terminal.Gui.ViewTests {
[AutoInitShutdown]
public void AnchorEnd_Equal_Inside_Window ()
{
var viewWidth = 10;
var viewHeight = 1;
int viewWidth = 10;
int viewHeight = 1;
var tv = new TextView () {
X = Pos.AnchorEnd (viewWidth),
Y = Pos.AnchorEnd (viewHeight),
@@ -85,8 +78,8 @@ namespace Terminal.Gui.ViewTests {
[AutoInitShutdown]
public void AnchorEnd_Equal_Inside_Window_With_MenuBar_And_StatusBar_On_Toplevel ()
{
var viewWidth = 10;
var viewHeight = 1;
int viewWidth = 10;
int viewHeight = 1;
var tv = new TextView () {
X = Pos.AnchorEnd (viewWidth),
Y = Pos.AnchorEnd (viewHeight),
@@ -120,10 +113,9 @@ namespace Terminal.Gui.ViewTests {
var win = new Window ();
var label = new Label ("This should be the last line.") {
TextAlignment = TextAlignment.Centered,
ColorScheme = Colors.Menu,
Width = Dim.Fill (),
X = Pos.Center (),
X = 0,
Y = Pos.Bottom (win) - 3 // two lines top and bottom borders more one line above the bottom border
};
@@ -138,7 +130,7 @@ namespace Terminal.Gui.ViewTests {
Assert.Equal (new Rect (0, 0, 40, 10), top.Frame);
Assert.Equal (new Rect (0, 0, 40, 10), win.Frame);
Assert.Equal (new Rect (0, 7, 38, 1), label.Frame);
var expected = @"
string expected = @"
┌──────────────────────────────────────┐
│ │
│ │
@@ -151,7 +143,7 @@ namespace Terminal.Gui.ViewTests {
└──────────────────────────────────────┘
";
TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Application.End (rs);
}
@@ -162,10 +154,9 @@ namespace Terminal.Gui.ViewTests {
var win = new Window ();
var label = new Label ("This should be the last line.") {
TextAlignment = TextAlignment.Centered,
ColorScheme = Colors.Menu,
Width = Dim.Fill (),
X = Pos.Center (),
X = 0, // keep unit test focused; don't use Center here
Y = Pos.AnchorEnd (1)
};
@@ -181,7 +172,7 @@ namespace Terminal.Gui.ViewTests {
Assert.Equal (new Rect (0, 0, 40, 10), top.Frame);
Assert.Equal (new Rect (0, 0, 40, 10), win.Frame);
Assert.Equal (new Rect (0, 7, 38, 1), label.Frame);
var expected = @"
string expected = @"
┌──────────────────────────────────────┐
│ │
│ │
@@ -194,7 +185,7 @@ namespace Terminal.Gui.ViewTests {
└──────────────────────────────────────┘
";
TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Application.End (rs);
}
@@ -205,10 +196,9 @@ namespace Terminal.Gui.ViewTests {
var win = new Window ();
var label = new Label ("This should be the last line.") {
TextAlignment = TextAlignment.Centered,
ColorScheme = Colors.Menu,
Width = Dim.Fill (),
X = Pos.Center (),
X = 0,
Y = Pos.Bottom (win) - 4 // two lines top and bottom borders more two lines above border
};
@@ -226,7 +216,7 @@ namespace Terminal.Gui.ViewTests {
Assert.Equal (new Rect (0, 24, 80, 1), status.Frame);
Assert.Equal (new Rect (0, 1, 80, 23), win.Frame);
Assert.Equal (new Rect (0, 20, 78, 1), label.Frame);
var expected = @"
string expected = @"
Menu
┌──────────────────────────────────────────────────────────────────────────────┐
│ │
@@ -254,7 +244,7 @@ namespace Terminal.Gui.ViewTests {
F1 Help
";
TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Application.End (rs);
}
@@ -265,10 +255,9 @@ namespace Terminal.Gui.ViewTests {
var win = new Window ();
var label = new Label ("This should be the last line.") {
TextAlignment = TextAlignment.Centered,
ColorScheme = Colors.Menu,
Width = Dim.Fill (),
X = Pos.Center (),
X = 0,
Y = Pos.AnchorEnd (1)
};
@@ -286,7 +275,7 @@ namespace Terminal.Gui.ViewTests {
Assert.Equal (new Rect (0, 24, 80, 1), status.Frame);
Assert.Equal (new Rect (0, 1, 80, 23), win.Frame);
Assert.Equal (new Rect (0, 20, 78, 1), label.Frame);
var expected = @"
string expected = @"
Menu
┌──────────────────────────────────────────────────────────────────────────────┐
│ │
@@ -314,7 +303,7 @@ namespace Terminal.Gui.ViewTests {
F1 Help
";
TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
TestHelpers.AssertDriverContentsWithFrameAre (expected, _output);
Application.End (rs);
}
@@ -322,7 +311,7 @@ namespace Terminal.Gui.ViewTests {
public void AnchorEnd_Negative_Throws ()
{
Pos pos;
var n = -1;
int n = -1;
Assert.Throws<ArgumentException> (() => pos = Pos.AnchorEnd (n));
}
@@ -342,8 +331,8 @@ namespace Terminal.Gui.ViewTests {
[Fact]
public void At_Equal ()
{
var n1 = 0;
var n2 = 0;
int n1 = 0;
int n2 = 0;
var pos1 = Pos.At (n1);
var pos2 = Pos.At (n2);
@@ -377,12 +366,13 @@ namespace Terminal.Gui.ViewTests {
/// <summary>
/// Tests Pos.Left, Pos.X, Pos.Top, Pos.Y, Pos.Right, and Pos.Bottom set operations
/// </summary>
[Fact, TestRespondersDisposed]
[Fact]
[TestRespondersDisposed]
public void PosSide_SetsValue ()
{
string side; // used in format string
var testRect = Rect.Empty;
var testInt = 0;
int testInt = 0;
Pos pos;
// Pos.Left
@@ -532,7 +522,8 @@ namespace Terminal.Gui.ViewTests {
}
// See: https://github.com/gui-cs/Terminal.Gui/issues/504
[Fact, TestRespondersDisposed]
[Fact]
[TestRespondersDisposed]
public void LeftTopBottomRight_Win_ShouldNotThrow ()
{
// Setup Fake driver
@@ -546,12 +537,12 @@ namespace Terminal.Gui.ViewTests {
X = 0,
Y = 0,
Width = Dim.Fill (),
Height = Dim.Fill (),
Height = Dim.Fill ()
};
Application.Top.Add (win);
var button = new Button ("button") {
X = Pos.Center (),
X = Pos.Center ()
};
win.Add (button);
@@ -694,7 +685,7 @@ namespace Terminal.Gui.ViewTests {
var v = new View () {
X = Pos.Center (),
Y = Pos.Percent (10),
ForceValidatePosDim = true
ValidatePosDim = true
};
w.Add (v);
@@ -814,7 +805,8 @@ namespace Terminal.Gui.ViewTests {
// Application.Shutdown ();
//}
[Fact, TestRespondersDisposed]
[Fact]
[TestRespondersDisposed]
public void PosCombine_Will_Throws ()
{
Application.Init (new FakeDriver ());
@@ -848,7 +840,8 @@ namespace Terminal.Gui.ViewTests {
v2.Dispose ();
}
[Fact, TestRespondersDisposed]
[Fact]
[TestRespondersDisposed]
public void Pos_Add_Operator ()
{
Application.Init (new FakeDriver ());
@@ -857,7 +850,7 @@ namespace Terminal.Gui.ViewTests {
var view = new View () { X = 0, Y = 0, Width = 20, Height = 20 };
var field = new TextField () { X = 0, Y = 0, Width = 20 };
var count = 0;
int count = 0;
field.KeyDown += (s, k) => {
if (k.KeyCode == KeyCode.Enter) {
@@ -875,7 +868,9 @@ namespace Terminal.Gui.ViewTests {
};
Application.Iteration += (s, a) => {
while (count < 20) field.NewKeyDownEvent (new (KeyCode.Enter));
while (count < 20) {
field.NewKeyDownEvent (new Key (KeyCode.Enter));
}
Application.RequestStop ();
};
@@ -894,7 +889,8 @@ namespace Terminal.Gui.ViewTests {
Application.Shutdown ();
}
[Fact, TestRespondersDisposed]
[Fact]
[TestRespondersDisposed]
public void Pos_Subtract_Operator ()
{
Application.Init (new FakeDriver ());
@@ -903,7 +899,7 @@ namespace Terminal.Gui.ViewTests {
var view = new View () { X = 0, Y = 0, Width = 20, Height = 20 };
var field = new TextField () { X = 0, Y = 0, Width = 20 };
var count = 20;
int count = 20;
var listLabels = new List<Label> ();
for (int i = 0; i < count; i++) {
@@ -934,7 +930,7 @@ namespace Terminal.Gui.ViewTests {
Application.Iteration += (s, a) => {
while (count > 0) {
field.NewKeyDownEvent (new (KeyCode.Enter));
field.NewKeyDownEvent (new Key (KeyCode.Enter));
}
Application.RequestStop ();
@@ -955,7 +951,8 @@ namespace Terminal.Gui.ViewTests {
}
[Fact, TestRespondersDisposed]
[Fact]
[TestRespondersDisposed]
public void Internal_Tests ()
{
var posFactor = new Pos.PosFactor (0.10F);
@@ -971,13 +968,13 @@ namespace Terminal.Gui.ViewTests {
Assert.Equal (10, posAbsolute.Anchor (0));
var posCombine = new Pos.PosCombine (true, posFactor, posAbsolute);
Assert.Equal (posCombine.left, posFactor);
Assert.Equal (posCombine.right, posAbsolute);
Assert.Equal (posCombine._left, posFactor);
Assert.Equal (posCombine._right, posAbsolute);
Assert.Equal (20, posCombine.Anchor (100));
posCombine = new Pos.PosCombine (true, posAbsolute, posFactor);
Assert.Equal (posCombine.left, posAbsolute);
Assert.Equal (posCombine.right, posFactor);
Assert.Equal (posCombine._left, posAbsolute);
Assert.Equal (posCombine._right, posFactor);
Assert.Equal (20, posCombine.Anchor (100));
var view = new View (new Rect (20, 10, 20, 1));
@@ -996,7 +993,7 @@ namespace Terminal.Gui.ViewTests {
[Fact]
public void Function_SetsValue ()
{
var text = "Test";
string text = "Test";
var pos = Pos.Function (() => text.Length);
Assert.Equal ("PosFunc(4)", pos.ToString ());
@@ -1022,21 +1019,22 @@ namespace Terminal.Gui.ViewTests {
Assert.NotEqual (pos1, pos2);
}
[Theory, AutoInitShutdown]
[Theory]
[AutoInitShutdown]
[InlineData (true)]
[InlineData (false)]
public void PosPercentPlusOne (bool testHorizontal)
{
var container = new View {
Width = 100,
Height = 100,
Height = 100
};
var label = new Label {
X = testHorizontal ? Pos.Percent (50) + Pos.Percent (10) + 1 : 1,
Y = testHorizontal ? 1 : Pos.Percent (50) + Pos.Percent (10) + 1,
Width = 10,
Height = 10,
Height = 10
};
container.Add (label);
@@ -1064,11 +1062,11 @@ namespace Terminal.Gui.ViewTests {
};
var view1 = new View ("view1") {
Width = 2,
Height = 2,
Height = 2
};
var view2 = new View ("view2") {
Width = 2,
Height = 2,
Height = 2
};
view2.X = Pos.AnchorEnd () - (Pos.Right (view2) - Pos.Left (view2));
@@ -1121,4 +1119,4 @@ namespace Terminal.Gui.ViewTests {
pos.ToString ());
}
}
}

View File

@@ -0,0 +1,456 @@
using System;
using System.Text;
using Xunit;
using Xunit.Abstractions;
using static Terminal.Gui.SpinnerStyle;
namespace Terminal.Gui.ViewTests;
public class SetRelativeLayoutTests {
readonly ITestOutputHelper _output;
public SetRelativeLayoutTests (ITestOutputHelper output) => _output = output;
[Fact]
public void Null_Pos_Is_Same_As_PosAbsolute0 ()
{
var view = new View () {
X = null,
Y = null,
};
// Default layout style is Computed
Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.Null (view.X);
Assert.Null (view.Y);
view.BeginInit(); view.EndInit();
Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.Null (view.X);
Assert.Null (view.Y);
view.SetRelativeLayout (new Rect (5, 5, 10, 10));
Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.Null (view.X);
Assert.Null (view.Y);
Assert.Equal (0, view.Frame.X);
Assert.Equal (0, view.Frame.Y);
}
[Theory]
[InlineData (1, 1)]
[InlineData (0, 0)]
public void NonNull_Pos (int pos, int expectedPos)
{
var view = new View () {
X = pos,
Y = pos,
};
// Default layout style is Computed
Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.NotNull (view.X);
Assert.NotNull (view.Y);
view.BeginInit (); view.EndInit ();
Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.NotNull (view.X);
Assert.NotNull (view.Y);
view.SetRelativeLayout (new Rect (5, 5, 10, 10));
Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.NotNull (view.X);
Assert.NotNull (view.Y);
Assert.Equal (expectedPos, view.Frame.X);
Assert.Equal (expectedPos, view.Frame.Y);
}
[Fact]
public void Null_Dim_Is_Same_As_DimFill0 ()
{
var view = new View () {
Width = null,
Height = null,
};
// Default layout style is Computed
Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.Null (view.Width);
Assert.Null (view.Height);
view.BeginInit (); view.EndInit ();
Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.Null (view.Width);
Assert.Null (view.Height);
view.SetRelativeLayout (new Rect (5, 5, 10, 10));
Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.Null (view.Width);
Assert.Null (view.Height);
Assert.Equal (0, view.Frame.X);
Assert.Equal (0, view.Frame.Y);
Assert.Equal (10, view.Frame.Width);
Assert.Equal (10, view.Frame.Height);
view.Width = Dim.Fill (0);
view.Height = Dim.Fill (0);
view.SetRelativeLayout (new Rect (5, 5, 10, 10));
Assert.Equal (10, view.Frame.Width);
Assert.Equal (10, view.Frame.Height);
}
[Theory]
[InlineData(1, 1)]
[InlineData (0, 0)]
public void NonNull_Dim (int dim, int expectedDim)
{
var view = new View () {
Width = dim,
Height = dim,
};
// Default layout style is Computed
Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.NotNull (view.Width);
Assert.NotNull (view.Height);
view.BeginInit (); view.EndInit ();
Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.NotNull (view.Width);
Assert.NotNull (view.Height);
view.SetRelativeLayout (new Rect (5, 5, 10, 10));
Assert.Equal (LayoutStyle.Computed, view.LayoutStyle);
Assert.NotNull (view.Width);
Assert.NotNull (view.Height);
Assert.Equal (0, view.Frame.X);
Assert.Equal (0, view.Frame.Y);
// BUGBUG: Width == null is same as Dim.Absolute (0) (or should be). Thus this is a bug.
Assert.Equal (expectedDim, view.Frame.Width);
Assert.Equal (expectedDim, view.Frame.Height);
}
[Fact]
public void Fill_Pos_Within_Bounds ()
{
var screen = new Rect (0, 0, 80, 25);
var view = new View () {
X = 1,
Y = 1,
Width = 5,
Height = 4
};
view.SetRelativeLayout (screen);
Assert.Equal (1, view.Frame.X);
Assert.Equal (1, view.Frame.Y);
Assert.Equal (5, view.Frame.Width);
Assert.Equal (4, view.Frame.Height);
view.Width = 80;
view.Height = 25;
view.SetRelativeLayout (screen);
Assert.Equal (1, view.Frame.X);
Assert.Equal (1, view.Frame.Y);
Assert.Equal (80, view.Frame.Width);
Assert.Equal (25, view.Frame.Height);
view.Width = Dim.Fill ();
view.Height = Dim.Fill ();
view.SetRelativeLayout (screen);
Assert.Equal (1, view.Frame.X);
Assert.Equal (1, view.Frame.Y);
Assert.Equal (79, view.Frame.Width); // proof (80 - 1)
Assert.Equal (24, view.Frame.Height); // proof (25 - 1)
view.X = 79;
view.Width = Dim.Fill ();
view.Height = Dim.Fill ();
view.SetRelativeLayout (screen);
Assert.Equal (79, view.Frame.X);
Assert.Equal (1, view.Frame.Y);
Assert.Equal (1, view.Frame.Width); // proof (80 - 79)
Assert.Equal (24, view.Frame.Height);
view.X = 80;
view.Width = Dim.Fill ();
view.Height = Dim.Fill ();
view.SetRelativeLayout (screen);
Assert.Equal (80, view.Frame.X);
Assert.Equal (1, view.Frame.Y);
Assert.Equal (0, view.Frame.Width); // proof (80 - 80)
Assert.Equal (24, view.Frame.Height);
}
[Fact]
public void FIll_Pos_Outside_Bounds ()
{
var screen = new Rect (0, 0, 80, 25);
var view = new View () {
X = 90, // outside of screen +10
Y = -10, // outside of screen -10
Width = 15,
Height = 15
};
view.SetRelativeLayout (screen);
Assert.Equal (90, view.Frame.X);
Assert.Equal (-10, view.Frame.Y);
Assert.Equal (15, view.Frame.Width);
Assert.Equal (15, view.Frame.Height);
// prove Width=Height= same as screen size
view.Width = 80;
view.Height = 25;
view.SetRelativeLayout (screen);
Assert.Equal (90, view.Frame.X);
Assert.Equal (-10, view.Frame.Y);
Assert.Equal (80, view.Frame.Width);
Assert.Equal (25, view.Frame.Height);
view.Width = Dim.Fill ();
view.Height = Dim.Fill ();
view.SetRelativeLayout (screen);
Assert.Equal (90, view.Frame.X);
Assert.Equal (-10, view.Frame.Y);
Assert.Equal (0, view.Frame.Width); // proof: 15x15 view is placed beyond right side of screen, so fill width is 0
Assert.Equal (35, view.Frame.Height); // proof: 15x15 view is placed beyond top of screen 10 rows, screen is 25 rows. so fill height is 25 + 10 = 35
}
[Fact]
public void PosCombine_PosCenter_Minus_Absolute ()
{
// This test used to be in ViewTests.cs Internal_Tests. It was moved here because it is testing
// SetRelativeLayout. In addition, the old test was bogus because it was testing the wrong thing (and
// because in v1 Pos.Center was broken in this regard!
var screen = new Rect (0, 0, 80, 25);
var view = new View () {
X = Pos.Center () - 41, // -2 off left edge of screen
Y = Pos.Center () - 13, // -1 off top edge of screen
Width = 1,
Height = 1
};
view.SetRelativeLayout (screen);
Assert.Equal (-2, view.Frame.X); // proof: 1x1 view centered in 80x25 screen has x of 39, so -41 is -2
Assert.Equal (-1, view.Frame.Y); // proof: 1x1 view centered in 80x25 screen has y of 12, so -13 is -1
view.Width = 80;
view.Height = 25;
view.SetRelativeLayout (screen);
Assert.Equal (-41, view.Frame.X);
Assert.Equal (-13, view.Frame.Y);
Assert.Equal (80, view.Frame.Width);
Assert.Equal (25, view.Frame.Height);
view.Width = Dim.Fill ();
view.Height = Dim.Fill ();
view.SetRelativeLayout (screen);
Assert.Equal (-41, view.Frame.X);
Assert.Equal (-13, view.Frame.Y);
Assert.Equal (121, view.Frame.Width); // 121 = screen.Width - (-Center - 41)
Assert.Equal (38, view.Frame.Height);
}
[Fact]
public void FIll_And_PosCenter ()
{
var screen = new Rect (0, 0, 80, 25);
var view = new View () {
X = Pos.Center (),
Y = Pos.Center (),
Width = Dim.Fill(),
Height = Dim.Fill()
};
view.SetRelativeLayout (screen);
Assert.Equal (0, view.Frame.X);
Assert.Equal (0, view.Frame.Y);
Assert.Equal (80, view.Frame.Width);
Assert.Equal (25, view.Frame.Height);
view.X = Pos.Center () + 1;
view.SetRelativeLayout (screen);
Assert.Equal (1, view.Frame.X);
Assert.Equal (0, view.Frame.Y);
Assert.Equal (79, view.Frame.Width);
Assert.Equal (25, view.Frame.Height);
view.X = Pos.Center () + 79;
view.SetRelativeLayout (screen);
Assert.Equal (79, view.Frame.X);
Assert.Equal (0, view.Frame.Y);
Assert.Equal (1, view.Frame.Width);
Assert.Equal (25, view.Frame.Height);
view.X = Pos.Center () + 80;
view.SetRelativeLayout (screen);
Assert.Equal (80, view.Frame.X);
Assert.Equal (0, view.Frame.Y);
Assert.Equal (0, view.Frame.Width);
Assert.Equal (25, view.Frame.Height);
view.X = Pos.Center () - 1;
view.SetRelativeLayout (screen);
Assert.Equal (-1, view.Frame.X);
Assert.Equal (0, view.Frame.Y);
Assert.Equal (81, view.Frame.Width);
Assert.Equal (25, view.Frame.Height);
view.X = Pos.Center () - 2; // Fill means all the way to right. So width will be 82. (dim gets calc'd before pos).
view.SetRelativeLayout (screen);
Assert.Equal (-2, view.Frame.X);
Assert.Equal (0, view.Frame.Y);
Assert.Equal (82, view.Frame.Width);
Assert.Equal (25, view.Frame.Height);
view.X = Pos.Center () - 3; // Fill means all the way to right. So width will be 83. (dim gets calc'd before pos).
view.SetRelativeLayout (screen);
Assert.Equal (-3, view.Frame.X);
Assert.Equal (0, view.Frame.Y);
Assert.Equal (83, view.Frame.Width);
Assert.Equal (25, view.Frame.Height);
view.X = Pos.Center () - 41; // Fill means all the way to right. So width will be . (dim gets calc'd before pos).
view.SetRelativeLayout (screen);
Assert.Equal (-41, view.Frame.X);
Assert.Equal (0, view.Frame.Y);
Assert.Equal (121, view.Frame.Width);
Assert.Equal (25, view.Frame.Height);
}
[Fact]
public void PosCombine_PosCenter_Plus_Absolute ()
{
var screen = new Rect (0, 0, 80, 25);
var view = new View () {
X = Pos.Center () + 41, // ((80 / 2) - (5 / 2)) + 41 = (40 - 3 + 41) = 78
Y = Pos.Center () + 13, // ((25 / 2) - (4 / 2)) + 13 = (12 - 2 + 13) = 23
Width = 5,
Height = 4
};
view.SetRelativeLayout (screen);
Assert.Equal (78, view.Frame.X);
Assert.Equal (23, view.Frame.Y);
}
[Fact] [TestRespondersDisposed]
public void PosCombine_Plus_Absolute ()
{
var superView = new View () {
AutoSize = false,
Width = 10,
Height = 10
};
var testView = new View () {
AutoSize = false,
X = Pos.Center (),
Y = Pos.Center (),
Width = 1,
Height = 1
};
superView.Add (testView);
testView.SetRelativeLayout (superView.Frame);
Assert.Equal (4, testView.Frame.X);
Assert.Equal (4, testView.Frame.Y);
testView = new View () {
AutoSize = false,
X = Pos.Center () + 1, // ((10 / 2) - (1 / 2)) + 1 = 5 - 1 + 1 = 5
Y = Pos.Center () + 1,
Width = 1,
Height = 1
};
superView.Add (testView);
testView.SetRelativeLayout (superView.Frame);
Assert.Equal (5, testView.Frame.X);
Assert.Equal (5, testView.Frame.Y);
testView = new View () {
AutoSize = false,
X = 1 + Pos.Center (),
Y = 1 + Pos.Center (),
Width = 1,
Height = 1
};
superView.Add (testView);
testView.SetRelativeLayout (superView.Frame);
Assert.Equal (5, testView.Frame.X);
Assert.Equal (5, testView.Frame.Y);
testView = new View () {
AutoSize = false,
X = 1 + Pos.Percent (50),
Y = Pos.Percent (50) + 1,
Width = 1,
Height = 1
};
superView.Add (testView);
testView.SetRelativeLayout (superView.Frame);
Assert.Equal (6, testView.Frame.X);
Assert.Equal (6, testView.Frame.Y);
testView = new View () {
AutoSize = false,
X = Pos.Percent (10) + Pos.Percent (40),
Y = Pos.Percent (10) + Pos.Percent (40),
Width = 1,
Height = 1
};
superView.Add (testView);
testView.SetRelativeLayout (superView.Frame);
Assert.Equal (5, testView.Frame.X);
Assert.Equal (5, testView.Frame.Y);
testView = new View () {
AutoSize = false,
X = 1 + Pos.Percent (10) + Pos.Percent (40) - 1,
Y = 5 + Pos.Percent (10) + Pos.Percent (40) - 5,
Width = 1,
Height = 1
};
superView.Add (testView);
testView.SetRelativeLayout (superView.Frame);
Assert.Equal (5, testView.Frame.X);
Assert.Equal (5, testView.Frame.Y);
testView = new View () {
AutoSize = false,
X = Pos.Left (testView),
Y = Pos.Left (testView),
Width = 1,
Height = 1
};
superView.Add (testView);
testView.SetRelativeLayout (superView.Frame);
Assert.Equal (5, testView.Frame.X);
Assert.Equal (5, testView.Frame.Y);
testView = new View () {
AutoSize = false,
X = 1 + Pos.Left (testView),
Y = Pos.Top (testView) + 1,
Width = 1,
Height = 1
};
superView.Add (testView);
testView.SetRelativeLayout (superView.Frame);
Assert.Equal (6, testView.Frame.X);
Assert.Equal (6, testView.Frame.Y);
superView.Dispose ();
}
}

View File

@@ -504,6 +504,7 @@ namespace Terminal.Gui.ViewTests {
var runState = Application.Begin (top);
// BUGBUG: This is a SetRelativeLayout test. It should be moved to SetRelativeLayoutTests.cs
view.Width = Dim.Fill ();
view.Height = Dim.Fill ();
Assert.Equal (10, view.Bounds.Width);
@@ -519,6 +520,7 @@ namespace Terminal.Gui.ViewTests {
Assert.Equal (79, view.Bounds.Width);
Assert.Equal (24, view.Bounds.Height);
// BUGBUG: This is a SetRelativeLayout test. It should be moved to SetRelativeLayoutTests.cs
view.X = 0;
view.Y = 0;
Assert.Equal ("Absolute(0)", view.X.ToString ());
@@ -532,6 +534,8 @@ namespace Terminal.Gui.ViewTests {
Assert.Equal (0, view.Bounds.Y);
Assert.Equal (80, view.Bounds.Width);
Assert.Equal (25, view.Bounds.Height);
// BUGBUG: This is a layout test. It should be moved to LayoutTests.cs
bool layoutStarted = false;
view.LayoutStarted += (s, e) => layoutStarted = true;
view.OnLayoutStarted (null);
@@ -539,6 +543,10 @@ namespace Terminal.Gui.ViewTests {
view.LayoutComplete += (s, e) => layoutStarted = false;
view.OnLayoutComplete (null);
Assert.False (layoutStarted);
// This test has been moved to SetRlativeLayoutTests because it is testing
// SetRelativeLayout. In addition, the old test was bogus because it was testing the wrong thing (and
// because in v1 Pos.Center was broken in this regard!
view.X = Pos.Center () - 41;
view.Y = Pos.Center () - 13;
view.SetRelativeLayout (top.Bounds);
@@ -1340,16 +1348,15 @@ At 0,0
var frame = new FrameView ();
var label = new Label ("This should be the first line.") {
TextAlignment = Terminal.Gui.TextAlignment.Centered,
ColorScheme = Colors.Menu,
Width = Dim.Fill (),
X = Pos.Center (),
Y = Pos.Center () - 2 // center minus 2 minus two lines top and bottom borders equal to zero (4-2-2=0)
X = 0, // don't overcomplicate unit tests
Y = 0
};
var button = new Button ("Press me!") {
X = Pos.Center (),
Y = Pos.Center ()
X = 0, // don't overcomplicate unit tests
Y = 1
};
frame.Add (label, button);
@@ -1388,19 +1395,7 @@ At 0,0
frame.Frame.Left, frame.Frame.Top,
frame.Frame.Right, frame.Frame.Bottom));
Assert.Equal (new Rect (0, 0, 38, 1), label.Frame);
Assert.Equal (new Rect (12, 2, 13, 1), button.Frame);
var expected = @$"
┌──────────────────────────────────────┐
│ This should be the first line. │
│ │
│ {CM.Glyphs.LeftBracket} Press me! {CM.Glyphs.RightBracket} │
│ │
│ │
│ │
└──────────────────────────────────────┘
";
TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
Assert.Equal (new Rect (0, 1, 13, 1), button.Frame); // this proves frame was set
Application.End (runState);
}

View File

@@ -935,7 +935,8 @@ namespace Terminal.Gui.ViewsTests {
│ │
└──────────────────┘", output);
var dialog = new Dialog () { X = 2, Y = 2, Width = 15, Height = 4 };
// Don't use Dialog here as it has more layout logic. Use Window instead.
var dialog = new Window () { X = 2, Y = 2, Width = 15, Height = 4 };
dialog.Add (new TextField ("Test") { X = Pos.Center (), Width = 10 });
var rs = Application.Begin (dialog);
@@ -993,7 +994,8 @@ namespace Terminal.Gui.ViewsTests {
Assert.Equal (new Rect (0, 0, 20, 15), Application.Driver.Clip);
TestHelpers.AssertDriverContentsWithFrameAre ("", output);
var dialog = new Dialog () { X = 2, Y = 2, Width = 15, Height = 4 };
// Don't use Dialog here as it has more layout logic. Use Window instead.
var dialog = new Window () { X = 2, Y = 2, Width = 15, Height = 4 };
dialog.Add (new TextField ("Test") { X = Pos.Center (), Width = 10 });
var rs = Application.Begin (dialog);

View File

@@ -662,7 +662,7 @@ e
Width = Dim.Fill (),
Height = Dim.Percent (50f),
TextDirection = TextDirection.TopBottom_LeftRight,
ForceValidatePosDim = true
ValidatePosDim = true
};
Application.Top.Add (label);
Application.Begin (Application.Top);

View File

@@ -700,126 +700,115 @@ public class ToplevelTests {
Assert.Equal (KeyCode.Q | KeyCode.CtrlMask, Application.QuitKey);
}
[Fact] [AutoInitShutdown]
[Fact]
[AutoInitShutdown]
public void Mouse_Drag_On_Top_With_Superview_Null ()
{
var win = new Window ();
var top = Application.Top;
top.Add (win);
int iterations = -1;
Window testWindow;
Application.Iteration += (s, a) => {
iterations++;
if (iterations == 0) {
((FakeDriver)Application.Driver).SetBufferSize (40, 15);
MessageBox.Query ("", "Hello Word", "Ok");
((FakeDriver)Application.Driver).SetBufferSize (15, 7);
// Don't use MessageBox here; it's too complicated for this unit test; just use Window
testWindow = new Window () {
Text = "Hello",
X = 2,
Y = 2,
Width = 10,
Height = 3
};
Application.Run (testWindow);
} else if (iterations == 1) {
TestHelpers.AssertDriverContentsWithFrameAre (@$"
┌──────────────────────────────────────
┌─────────────┐
│ │
│ ┌────────┐ │
│ │Hello │ │
│ └────────┘ │
│ │
│ │
│ │
│ ┌──────────────────────┐ │
│ │ Hello Word │ │
│ │ │ │
│ │ {CM.Glyphs.LeftBracket}{CM.Glyphs.LeftDefaultIndicator} Ok {CM.Glyphs.RightDefaultIndicator}{CM.Glyphs.RightBracket} │ │
│ └──────────────────────┘ │
│ │
│ │
│ │
│ │
└──────────────────────────────────────┘
└─────────────┘
", output);
} else if (iterations == 2) {
Assert.Null (Application.MouseGrabView);
// Grab the mouse
Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () {
X = 8,
Y = 5,
X = 3,
Y = 2,
Flags = MouseFlags.Button1Pressed
}));
Assert.Equal (Application.Current, Application.MouseGrabView);
Assert.Equal (new Rect (8, 5, 24, 5), Application.MouseGrabView.Frame);
Assert.Equal (new Rect (2, 2, 10, 3), Application.MouseGrabView.Frame);
} else if (iterations == 3) {
Assert.Equal (Application.Current, Application.MouseGrabView);
// Drag to left
Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () {
X = 7,
Y = 5,
X = 2,
Y = 2,
Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition
}));
Application.Refresh ();
Assert.Equal (Application.Current, Application.MouseGrabView);
Assert.Equal (new Rect (7, 5, 24, 5), Application.MouseGrabView.Frame);
Assert.Equal (new Rect (1, 2, 10, 3), Application.MouseGrabView.Frame);
} else if (iterations == 4) {
Assert.Equal (Application.Current, Application.MouseGrabView);
TestHelpers.AssertDriverContentsWithFrameAre (@$"
┌──────────────────────────────────────
┌─────────────┐
│ │
│┌────────┐ │
││Hello │ │
│└────────┘ │
│ │
│ │
│ │
│ ┌──────────────────────┐ │
│ │ Hello Word │ │
│ │ │ │
│ │ {CM.Glyphs.LeftBracket}{CM.Glyphs.LeftDefaultIndicator} Ok {CM.Glyphs.RightDefaultIndicator}{CM.Glyphs.RightBracket} │ │
│ └──────────────────────┘ │
│ │
│ │
│ │
│ │
└──────────────────────────────────────┘", output);
└─────────────┘", output);
Assert.Equal (Application.Current, Application.MouseGrabView);
} else if (iterations == 5) {
Assert.Equal (Application.Current, Application.MouseGrabView);
// Drag up
Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () {
X = 7,
Y = 4,
X = 2,
Y = 1,
Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition
}));
Application.Refresh ();
Assert.Equal (Application.Current, Application.MouseGrabView);
Assert.Equal (new Rect (7, 4, 24, 5), Application.MouseGrabView.Frame);
Assert.Equal (new Rect (1, 1, 10, 3), Application.MouseGrabView.Frame);
} else if (iterations == 6) {
Assert.Equal (Application.Current, Application.MouseGrabView);
TestHelpers.AssertDriverContentsWithFrameAre (@$"
┌──────────────────────────────────────
┌─────────────┐
│┌────────┐ │
││Hello │ │
│└────────┘ │
│ │
│ │
│ │
│ ┌──────────────────────┐ │
│ │ Hello Word │ │
│ │ │ │
│ │ {CM.Glyphs.LeftBracket}{CM.Glyphs.LeftDefaultIndicator} Ok {CM.Glyphs.RightDefaultIndicator}{CM.Glyphs.RightBracket} │ │
│ └──────────────────────┘ │
│ │
│ │
│ │
│ │
│ │
└──────────────────────────────────────┘", output);
└─────────────┘", output);
Assert.Equal (Application.Current, Application.MouseGrabView);
Assert.Equal (new Rect (7, 4, 24, 5), Application.MouseGrabView.Frame);
Assert.Equal (new Rect (1, 1, 10, 3), Application.MouseGrabView.Frame);
} else if (iterations == 7) {
Assert.Equal (Application.Current, Application.MouseGrabView);
// Ungrab the mouse
Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () {
X = 7,
Y = 4,
X = 2,
Y = 1,
Flags = MouseFlags.Button1Released
}));
Application.Refresh ();
Assert.Null (Application.MouseGrabView);
@@ -833,7 +822,8 @@ public class ToplevelTests {
Application.Run ();
}
[Fact] [AutoInitShutdown]
[Fact]
[AutoInitShutdown]
public void Mouse_Drag_On_Top_With_Superview_Not_Null ()
{
var win = new Window () {
@@ -928,7 +918,8 @@ public class ToplevelTests {
Application.Run ();
}
[Fact] [AutoInitShutdown]
[Fact]
[AutoInitShutdown]
public void GetLocationThatFits_With_Border_Null_Not_Throws ()
{
var top = new Toplevel ();
@@ -941,7 +932,8 @@ public class ToplevelTests {
Assert.Null (exception);
}
[Fact] [AutoInitShutdown]
[Fact]
[AutoInitShutdown]
public void OnEnter_OnLeave_Triggered_On_Application_Begin_End ()
{
bool isEnter = false;
@@ -979,7 +971,8 @@ public class ToplevelTests {
Assert.True (v.HasFocus);
}
[Fact] [AutoInitShutdown]
[Fact]
[AutoInitShutdown]
public void OnEnter_OnLeave_Triggered_On_Application_Begin_End_With_More_Toplevels ()
{
int iterations = 0;
@@ -1069,7 +1062,8 @@ public class ToplevelTests {
Assert.Equal (5, steps [^1]);
}
[Fact] [AutoInitShutdown]
[Fact]
[AutoInitShutdown]
public void PositionCursor_SetCursorVisibility_To_Invisible_If_Focused_Is_Null ()
{
var tf = new TextField ("test") { Width = 5 };
@@ -1089,7 +1083,8 @@ public class ToplevelTests {
Assert.Equal (CursorVisibility.Invisible, cursor);
}
[Fact] [AutoInitShutdown]
[Fact]
[AutoInitShutdown]
public void IsLoaded_Application_Begin ()
{
var top = Application.Top;
@@ -1099,7 +1094,8 @@ public class ToplevelTests {
Assert.True (top.IsLoaded);
}
[Fact] [AutoInitShutdown]
[Fact]
[AutoInitShutdown]
public void IsLoaded_With_Sub_Toplevel_Application_Begin_NeedDisplay ()
{
var top = Application.Top;
@@ -1137,7 +1133,8 @@ public class ToplevelTests {
}
// BUGBUG: Broke this test with #2483 - @bdisp I need your help figuring out why
[Fact] [AutoInitShutdown]
[Fact]
[AutoInitShutdown]
public void Toplevel_Inside_ScrollView_MouseGrabView ()
{
var scrollView = new ScrollView () {
@@ -1254,32 +1251,33 @@ public class ToplevelTests {
Assert.Equal (scrollView, Application.MouseGrabView);
}
[Fact] [AutoInitShutdown]
public void Dialog_Bounds_Bigger_Than_Driver_Cols_And_Rows_Allow_Drag_Beyond_Left_Right_And_Bottom ()
[Fact]
[AutoInitShutdown]
public void Window_Bounds_Bigger_Than_Driver_Cols_And_Rows_Allow_Drag_Beyond_Left_Right_And_Bottom ()
{
var top = Application.Top;
var dialog = new Dialog (new Button ("Ok")) { Width = 20, Height = 3 };
var window = new Window () { Width = 20, Height = 3 };
Application.Begin (top);
((FakeDriver)Application.Driver).SetBufferSize (40, 10);
Application.Begin (dialog);
Application.Begin (window);
Application.Refresh ();
Assert.Equal (new Rect (0, 0, 40, 10), top.Frame);
Assert.Equal (new Rect (10, 3, 20, 3), dialog.Frame);
Assert.Equal (new Rect (0, 0, 20, 3), window.Frame);
TestHelpers.AssertDriverContentsWithFrameAre (@$"
┌──────────────────┐
{CM.Glyphs.LeftBracket} Ok {CM.Glyphs.RightBracket}
└──────────────────┘
", output);
Assert.Null (Application.MouseGrabView);
Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () {
X = 10,
Y = 3,
X = 0,
Y = 0,
Flags = MouseFlags.Button1Pressed
}));
Assert.Equal (dialog, Application.MouseGrabView);
Assert.Equal (window, Application.MouseGrabView);
Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () {
X = -11,
@@ -1289,10 +1287,10 @@ public class ToplevelTests {
Application.Refresh ();
Assert.Equal (new Rect (0, 0, 40, 10), top.Frame);
Assert.Equal (new Rect (0, 0, 20, 3), dialog.Frame);
Assert.Equal (new Rect (0, 0, 20, 3), window.Frame);
TestHelpers.AssertDriverContentsWithFrameAre (@$"
┌──────────────────┐
{CM.Glyphs.LeftBracket} Ok {CM.Glyphs.RightBracket}
└──────────────────┘
", output);
@@ -1306,10 +1304,10 @@ public class ToplevelTests {
Application.Refresh ();
Assert.Equal (new Rect (0, 0, 20, 3), top.Frame);
Assert.Equal (new Rect (0, 0, 20, 3), dialog.Frame);
Assert.Equal (new Rect (0, 0, 20, 3), window.Frame);
TestHelpers.AssertDriverContentsWithFrameAre (@$"
┌──────────────────┐
{CM.Glyphs.LeftBracket} Ok {CM.Glyphs.RightBracket}
└──────────────────┘
", output);
@@ -1323,10 +1321,10 @@ public class ToplevelTests {
Application.Refresh ();
Assert.Equal (new Rect (0, 0, 19, 2), top.Frame);
Assert.Equal (new Rect (-1, 0, 20, 3), dialog.Frame);
Assert.Equal (new Rect (-1, 0, 20, 3), window.Frame);
TestHelpers.AssertDriverContentsWithFrameAre (@$"
──────────────────┐
{CM.Glyphs.LeftBracket} Ok {CM.Glyphs.RightBracket}
", output);
Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () {
@@ -1337,7 +1335,7 @@ public class ToplevelTests {
Application.Refresh ();
Assert.Equal (new Rect (0, 0, 19, 2), top.Frame);
Assert.Equal (new Rect (18, 1, 20, 3), dialog.Frame);
Assert.Equal (new Rect (18, 1, 20, 3), window.Frame);
TestHelpers.AssertDriverContentsWithFrameAre (@"
┌", output);
@@ -1350,17 +1348,18 @@ public class ToplevelTests {
Application.Refresh ();
Assert.Equal (new Rect (0, 0, 19, 2), top.Frame);
Assert.Equal (new Rect (19, 2, 20, 3), dialog.Frame);
Assert.Equal (new Rect (19, 2, 20, 3), window.Frame);
TestHelpers.AssertDriverContentsWithFrameAre (@"", output);
}
[Fact] [AutoInitShutdown]
[Fact]
[AutoInitShutdown]
public void Modal_As_Top_Will_Drag_Cleanly ()
{
var dialog = new Dialog () { Width = 30, Height = 10 };
dialog.Add (new Label (
"How should I've to react. Cleaning all chunk trails or setting the 'Cols' and 'Rows' to this dialog length?\n" +
"Cleaning is more easy to fix this.") {
// Don't use Dialog as a Top, use a Window instead - dialog has complex layout behavior that is not needed here.
var window = new Window () { Width = 10, Height = 3};
window.Add (new Label (
"Test") {
X = Pos.Center (),
Y = Pos.Center (),
Width = Dim.Fill (),
@@ -1370,73 +1369,53 @@ public class ToplevelTests {
AutoSize = false
});
var rs = Application.Begin (dialog);
var rs = Application.Begin (window);
Assert.Null (Application.MouseGrabView);
Assert.Equal (new Rect (25, 7, 30, 10), dialog.Frame);
Assert.Equal (new Rect (0, 0, 10, 3), window.Frame);
TestHelpers.AssertDriverContentsWithFrameAre (@"
┌────────────────────────────┐
│ How should I've to react.
│Cleaning all chunk trails or│
│ setting the 'Cols' and │
│ 'Rows' to this dialog │
│ length? │
│Cleaning is more easy to fix│
│ this. │
│ │
└────────────────────────────┘", output);
────────┐
│ Test
└────────┘", output);
Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () {
X = 25,
Y = 7,
X = 0,
Y = 0,
Flags = MouseFlags.Button1Pressed
}));
bool firstIteration = false;
Application.RunIteration (ref rs, ref firstIteration);
Assert.Equal (dialog, Application.MouseGrabView);
Assert.Equal (window, Application.MouseGrabView);
Assert.Equal (new Rect (25, 7, 30, 10), dialog.Frame);
Assert.Equal (new Rect (0, 0, 10, 3), window.Frame);
TestHelpers.AssertDriverContentsWithFrameAre (@"
┌────────────────────────────┐
│ How should I've to react.
│Cleaning all chunk trails or│
│ setting the 'Cols' and │
│ 'Rows' to this dialog │
│ length? │
│Cleaning is more easy to fix│
│ this. │
│ │
└────────────────────────────┘", output);
────────┐
│ Test
└────────┘", output);
Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () {
X = 20,
Y = 10,
X = 1,
Y = 1,
Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition
}));
firstIteration = false;
Application.RunIteration (ref rs, ref firstIteration);
Assert.Equal (dialog, Application.MouseGrabView);
Assert.Equal (new Rect (20, 10, 30, 10), dialog.Frame);
Assert.Equal (window, Application.MouseGrabView);
Assert.Equal (new Rect (1, 1, 10,3), window.Frame);
TestHelpers.AssertDriverContentsWithFrameAre (@"
┌────────────────────────────┐
│ How should I've to react.
│Cleaning all chunk trails or│
│ setting the 'Cols' and │
│ 'Rows' to this dialog │
│ length? │
│Cleaning is more easy to fix│
│ this. │
│ │
└────────────────────────────┘", output);
────────┐
│ Test
└────────┘", output);
Application.End (rs);
}
// BUGBUG: Broke this test with #2483 - @bdisp I need your help figuring out why
[Fact] [AutoInitShutdown]
public void Draw_A_Top_Subview_On_A_Dialog ()
// Don't use Dialog as a Top, use a Window instead - dialog has complex layout behavior that is not needed here.
[Fact]
[AutoInitShutdown]
public void Draw_A_Top_Subview_On_A_Window ()
{
var top = Application.Top;
var win = new Window ();
@@ -1468,25 +1447,29 @@ public class ToplevelTests {
└──────────────────┘", output);
var btnPopup = new Button ("Popup");
var testWindow = new Window () { X = 2, Y = 1, Width = 15, Height = 10 };
testWindow.Add (btnPopup);
btnPopup.Clicked += (s, e) => {
var viewToScreen = btnPopup.BoundsToScreen (top.Frame);
var view = new View () {
var viewAddedToTop = new View () {
Text = "viewAddedToTop",
X = 1,
Y = viewToScreen.Y + 1,
Width = 18,
Height = 5,
Height = 16,
BorderStyle = LineStyle.Single
};
Application.Current.DrawContentComplete += Current_DrawContentComplete;
top.Add (view);
Assert.Equal (testWindow, Application.Current);
Application.Current.DrawContentComplete += testWindow_DrawContentComplete;
top.Add (viewAddedToTop);
void Current_DrawContentComplete (object sender, DrawEventArgs e)
void testWindow_DrawContentComplete (object sender, DrawEventArgs e)
{
Assert.Equal (new Rect (1, 14, 18, 5), view.Frame);
Assert.Equal (new Rect (1, 3, 18, 16), viewAddedToTop.Frame);
var savedClip = Application.Driver.Clip;
Application.Driver.Clip = top.Frame;
view.Draw ();
viewAddedToTop.Draw ();
top.Move (2, 15);
View.Driver.AddStr ("One");
top.Move (2, 16);
@@ -1495,59 +1478,59 @@ public class ToplevelTests {
View.Driver.AddStr ("Three");
Application.Driver.Clip = savedClip;
Application.Current.DrawContentComplete -= Current_DrawContentComplete;
Application.Current.DrawContentComplete -= testWindow_DrawContentComplete;
}
};
var dialog = new Dialog (btnPopup) { Width = 15, Height = 10 };
var rs = Application.Begin (dialog);
var rs = Application.Begin (testWindow);
Assert.Equal (new Rect (2, 5, 15, 10), dialog.Frame);
Assert.Equal (new Rect (2, 1, 15, 10), testWindow.Frame);
TestHelpers.AssertDriverContentsWithFrameAre (@$"
┌──────────────────┐
│ │
│ │
│ │
│ │
│ ┌─────────────┐ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │{CM.Glyphs.LeftBracket} Popup {CM.Glyphs.RightBracket} │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ └─────────────┘ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
└──────────────────┘", output);
Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent () {
X = 9,
Y = 13,
X = 5,
Y = 2,
Flags = MouseFlags.Button1Clicked
}));
Application.Top.Draw ();
bool firstIteration = false;
Application.RunIteration (ref rs, ref firstIteration);
TestHelpers.AssertDriverContentsWithFrameAre (@$"
┌──────────────────┐
│ │
│ │
│ │
│ │
│ ┌─────────────┐ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │{CM.Glyphs.LeftBracket} Popup {CM.Glyphs.RightBracket} │ │
│┌────────────────┐│
││viewAddedToTop ││
││ ││
││ ││
││ ││
││ ││
││ ││
││ ││
││ ││
││ ││
││ ││
││ ││
││One ││
││Two ││
││Three ││
@@ -1557,7 +1540,8 @@ public class ToplevelTests {
Application.End (rs);
}
[Fact] [AutoInitShutdown]
[Fact]
[AutoInitShutdown]
public void Activating_MenuBar_By_Alt_Key_Does_Not_Throw ()
{
var menu = new MenuBar (new MenuBarItem [] {
@@ -1575,7 +1559,8 @@ public class ToplevelTests {
}
[Fact] [TestRespondersDisposed]
[Fact]
[TestRespondersDisposed]
public void Multi_Thread_Toplevels ()
{
Application.Init (new FakeDriver ());
@@ -1621,12 +1606,12 @@ public class ToplevelTests {
return true;
});
t.Ready += FirstDialogToplevel;
t.Ready += FirstWindow;
void FirstDialogToplevel (object sender, EventArgs args)
void FirstWindow (object sender, EventArgs args)
{
var od = new OpenDialog ();
od.Ready += SecondDialogToplevel;
var firstWindow = new Window ();
firstWindow.Ready += SecondWindow;
Application.AddTimeout (TimeSpan.FromMilliseconds (100), () => {
count1++;
@@ -1644,12 +1629,12 @@ public class ToplevelTests {
return true;
});
Application.Run (od);
Application.Run (firstWindow);
}
void SecondDialogToplevel (object sender, EventArgs args)
void SecondWindow (object sender, EventArgs args)
{
var d = new Dialog ();
var testWindow = new Window ();
Application.AddTimeout (TimeSpan.FromMilliseconds (100), () => {
count2++;
@@ -1664,7 +1649,7 @@ public class ToplevelTests {
return true;
});
Application.Run (d);
Application.Run (testWindow);
}
Application.Run ();