mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
Merge pull request #3649 from tig/v2_3521-DimAuto-Equality
Fixes #3521 - `DimAuto` equality broken
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
#nullable enable
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Terminal.Gui;
|
||||
|
||||
using System.Numerics;
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// A Dim object describes the dimensions of a <see cref="View"/>. Dim is the type of the
|
||||
@@ -78,7 +78,7 @@ namespace Terminal.Gui;
|
||||
/// </para>
|
||||
/// <para></para>
|
||||
/// </remarks>
|
||||
public abstract class Dim
|
||||
public abstract record Dim : IEqualityOperators<Dim, Dim, bool>
|
||||
{
|
||||
#region static Dim creation methods
|
||||
|
||||
@@ -113,12 +113,10 @@ public abstract class Dim
|
||||
/// <param name="maximumContentDim">The maximum dimension the View's ContentSize will be fit to.</param>
|
||||
public static Dim? Auto (DimAutoStyle style = DimAutoStyle.Auto, Dim? minimumContentDim = null, Dim? maximumContentDim = null)
|
||||
{
|
||||
return new DimAuto ()
|
||||
{
|
||||
MinimumContentDim = minimumContentDim,
|
||||
MaximumContentDim = maximumContentDim,
|
||||
Style = style
|
||||
};
|
||||
return new DimAuto (
|
||||
MinimumContentDim: minimumContentDim,
|
||||
MaximumContentDim: maximumContentDim,
|
||||
Style: style);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -172,28 +170,22 @@ public abstract class Dim
|
||||
|
||||
#endregion static Dim creation methods
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the specified type is in the hierarchy of this Dim object.
|
||||
/// Indicates whether the specified type <typeparamref name="T"/> is in the hierarchy of this Dim object.
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="dim"></param>
|
||||
/// <param name="dim">A reference to this <see cref="Dim"/> instance.</param>
|
||||
/// <returns></returns>
|
||||
public bool Has (Type type, out Dim dim)
|
||||
public bool Has<T> (out Dim dim) where T : Dim
|
||||
{
|
||||
dim = this;
|
||||
if (type == GetType ())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we are a PosCombine, we have to check the left and right
|
||||
// to see if they are of the type we are looking for.
|
||||
if (this is DimCombine { } combine && (combine.Left.Has (type, out dim) || combine.Right.Has (type, out dim)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return this switch
|
||||
{
|
||||
DimCombine combine => combine.Left.Has<T> (out dim) || combine.Right.Has<T> (out dim),
|
||||
T => true,
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
|
||||
#region virtual methods
|
||||
@@ -208,7 +200,7 @@ public abstract class Dim
|
||||
/// subclass of Dim that is used. For example, DimAbsolute returns a fixed dimension, DimFactor returns a
|
||||
/// dimension that is a certain percentage of the super view's size, and so on.
|
||||
/// </returns>
|
||||
internal virtual int GetAnchor (int size) { return 0; }
|
||||
internal abstract int GetAnchor (int size);
|
||||
|
||||
/// <summary>
|
||||
/// Calculates and returns the dimension of a <see cref="View"/> object. It takes into account the location of the
|
||||
@@ -228,7 +220,7 @@ public abstract class Dim
|
||||
/// </returns>
|
||||
internal virtual int Calculate (int location, int superviewContentSize, View us, Dimension dimension)
|
||||
{
|
||||
return Math.Max (GetAnchor (superviewContentSize - location), 0);
|
||||
return Math.Clamp (GetAnchor (superviewContentSize - location), 0, short.MaxValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -10,19 +10,13 @@ namespace Terminal.Gui;
|
||||
/// methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="size"></param>
|
||||
public class DimAbsolute (int size) : Dim
|
||||
/// <param name="Size"></param>
|
||||
public record DimAbsolute (int Size) : Dim
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals (object? other) { return other is DimAbsolute abs && abs.Size == Size; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode () { return Size.GetHashCode (); }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the dimension.
|
||||
/// </summary>
|
||||
public int Size { get; } = size;
|
||||
public int Size { get; } = Size;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString () { return $"Absolute({Size})"; }
|
||||
|
||||
@@ -15,64 +15,17 @@ namespace Terminal.Gui;
|
||||
/// methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class DimAuto : Dim
|
||||
/// <param name="MaximumContentDim">The maximum dimension the View's ContentSize will be fit to.</param>
|
||||
/// <param name="MinimumContentDim">The minimum dimension the View's ContentSize will be constrained to.</param>
|
||||
/// <param name="Style">The <see cref="DimAutoStyle"/> of the <see cref="DimAuto"/>.</param>
|
||||
public record DimAuto (Dim? MaximumContentDim, Dim? MinimumContentDim, DimAutoStyle Style) : Dim
|
||||
{
|
||||
private readonly Dim? _maximumContentDim;
|
||||
|
||||
private readonly Dim? _minimumContentDim;
|
||||
|
||||
private readonly DimAutoStyle _style;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals (object? other)
|
||||
{
|
||||
if (other is not DimAuto auto)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return auto.MinimumContentDim == MinimumContentDim && auto.MaximumContentDim == MaximumContentDim && auto.Style == Style;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode () { return HashCode.Combine (MinimumContentDim, MaximumContentDim, Style); }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum dimension the View's ContentSize will be fit to. NOT CURRENTLY SUPPORTED.
|
||||
/// </summary>
|
||||
|
||||
// ReSharper disable once ConvertToAutoProperty
|
||||
public required Dim? MaximumContentDim
|
||||
{
|
||||
get => _maximumContentDim;
|
||||
init => _maximumContentDim = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the minimum dimension the View's ContentSize will be constrained to.
|
||||
/// </summary>
|
||||
|
||||
// ReSharper disable once ConvertToAutoProperty
|
||||
public required Dim? MinimumContentDim
|
||||
{
|
||||
get => _minimumContentDim;
|
||||
init => _minimumContentDim = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the style of the DimAuto.
|
||||
/// </summary>
|
||||
|
||||
// ReSharper disable once ConvertToAutoProperty
|
||||
public required DimAutoStyle Style
|
||||
{
|
||||
get => _style;
|
||||
init => _style = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString () { return $"Auto({Style},{MinimumContentDim},{MaximumContentDim})"; }
|
||||
|
||||
/// <inheritdoc />
|
||||
internal override int GetAnchor (int size) => 0;
|
||||
|
||||
internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension)
|
||||
{
|
||||
var textSize = 0;
|
||||
@@ -181,8 +134,8 @@ public class DimAuto : Dim
|
||||
&& !v.X.Has (typeof (PosAnchorEnd), out _)
|
||||
&& !v.X.Has (typeof (PosAlign), out _)
|
||||
&& !v.X.Has (typeof (PosCenter), out _)
|
||||
&& !v.Width.Has (typeof (DimFill), out _)
|
||||
&& !v.Width.Has (typeof (DimPercent), out _)
|
||||
&& !v.Width.Has<DimFill> (out _)
|
||||
&& !v.Width.Has<DimPercent> (out _)
|
||||
)
|
||||
.ToList ();
|
||||
}
|
||||
@@ -194,8 +147,8 @@ public class DimAuto : Dim
|
||||
&& !v.Y.Has (typeof (PosAnchorEnd), out _)
|
||||
&& !v.Y.Has (typeof (PosAlign), out _)
|
||||
&& !v.Y.Has (typeof (PosCenter), out _)
|
||||
&& !v.Height.Has (typeof (DimFill), out _)
|
||||
&& !v.Height.Has (typeof (DimPercent), out _)
|
||||
&& !v.Height.Has<DimFill> (out _)
|
||||
&& !v.Height.Has<DimPercent> (out _)
|
||||
)
|
||||
.ToList ();
|
||||
}
|
||||
@@ -419,11 +372,11 @@ public class DimAuto : Dim
|
||||
|
||||
if (dimension == Dimension.Width)
|
||||
{
|
||||
dimViewSubViews = includedSubviews.Where (v => v.Width is { } && v.Width.Has (typeof (DimView), out _)).ToList ();
|
||||
dimViewSubViews = includedSubviews.Where (v => v.Width is { } && v.Width.Has<DimView> (out _)).ToList ();
|
||||
}
|
||||
else
|
||||
{
|
||||
dimViewSubViews = includedSubviews.Where (v => v.Height is { } && v.Height.Has (typeof (DimView), out _)).ToList ();
|
||||
dimViewSubViews = includedSubviews.Where (v => v.Height is { } && v.Height.Has<DimView> (out _)).ToList ();
|
||||
}
|
||||
|
||||
for (var i = 0; i < dimViewSubViews.Count; i++)
|
||||
|
||||
@@ -4,31 +4,31 @@ namespace Terminal.Gui;
|
||||
/// <summary>
|
||||
/// Represents a dimension that is a combination of two other dimensions.
|
||||
/// </summary>
|
||||
/// <param name="add">
|
||||
/// <param name="Add">
|
||||
/// Indicates whether the two dimensions are added or subtracted.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// This is a low-level API that is typically used internally by the layout system. Use the various static
|
||||
/// methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
|
||||
/// </remarks>
|
||||
/// <param name="left">The left dimension.</param>
|
||||
/// <param name="right">The right dimension.</param>
|
||||
public class DimCombine (AddOrSubtract add, Dim left, Dim right) : Dim
|
||||
/// <param name="Left">The left dimension.</param>
|
||||
/// <param name="Right">The right dimension.</param>
|
||||
public record DimCombine (AddOrSubtract Add, Dim Left, Dim Right) : Dim
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets whether the two dimensions are added or subtracted.
|
||||
/// </summary>
|
||||
public AddOrSubtract Add { get; } = add;
|
||||
public AddOrSubtract Add { get; } = Add;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the left dimension.
|
||||
/// </summary>
|
||||
public Dim Left { get; } = left;
|
||||
public Dim Left { get; } = Left;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the right dimension.
|
||||
/// </summary>
|
||||
public Dim Right { get; } = right;
|
||||
public Dim Right { get; } = Right;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString () { return $"Combine({Left}{(Add == AddOrSubtract.Add ? '+' : '-')}{Right})"; }
|
||||
|
||||
@@ -8,20 +8,9 @@ namespace Terminal.Gui;
|
||||
/// This is a low-level API that is typically used internally by the layout system. Use the various static
|
||||
/// methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
|
||||
/// </remarks>
|
||||
/// <param name="margin">The margin to not fill.</param>
|
||||
public class DimFill (int margin) : Dim
|
||||
/// <param name="Margin">The margin to not fill.</param>
|
||||
public record DimFill (int Margin) : Dim
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals (object? other) { return other is DimFill fill && fill.Margin == Margin; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode () { return Margin.GetHashCode (); }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the margin to not fill.
|
||||
/// </summary>
|
||||
public int Margin { get; } = margin;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString () { return $"Fill({Margin})"; }
|
||||
|
||||
|
||||
@@ -2,28 +2,22 @@
|
||||
namespace Terminal.Gui;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a function <see cref="Dim"/> object that computes the dimension by executing the provided function.
|
||||
/// Represents a function <see cref="Gui.Dim"/> object that computes the dimension by executing the provided function.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a low-level API that is typically used internally by the layout system. Use the various static
|
||||
/// methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
|
||||
/// methods on the <see cref="Gui.Dim"/> class to create <see cref="Gui.Dim"/> objects instead.
|
||||
/// </remarks>
|
||||
/// <param name="dim"></param>
|
||||
public class DimFunc (Func<int> dim) : Dim
|
||||
/// <param name="Fn">The function that computes the dimension.</param>
|
||||
public record DimFunc (Func<int> Fn) : Dim
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals (object? other) { return other is DimFunc f && f.Func () == Func (); }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the function that computes the dimension.
|
||||
/// </summary>
|
||||
public new Func<int> Func { get; } = dim;
|
||||
public Func<int> Fn { get; } = Fn;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode () { return Func.GetHashCode (); }
|
||||
public override string ToString () { return $"DimFunc({Fn ()})"; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString () { return $"DimFunc({Func ()})"; }
|
||||
|
||||
internal override int GetAnchor (int size) { return Func (); }
|
||||
internal override int GetAnchor (int size) { return Fn (); }
|
||||
}
|
||||
@@ -8,35 +8,24 @@ namespace Terminal.Gui;
|
||||
/// This is a low-level API that is typically used internally by the layout system. Use the various static
|
||||
/// methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
|
||||
/// </remarks>
|
||||
/// <param name="percent">The percentage.</param>
|
||||
/// <param name="mode">
|
||||
/// <param name="Percentage">The percentage.</param>
|
||||
/// <param name="Mode">
|
||||
/// If <see cref="DimPercentMode.Position"/> the dimension is computed using the View's position (<see cref="View.X"/> or
|
||||
/// <see cref="View.Y"/>); otherwise, the dimension is computed using the View's <see cref="View.GetContentSize ()"/>.
|
||||
/// </param>
|
||||
public class DimPercent (int percent, DimPercentMode mode = DimPercentMode.ContentSize) : Dim
|
||||
public record DimPercent (int Percentage, DimPercentMode Mode = DimPercentMode.ContentSize) : Dim
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals (object? other) { return other is DimPercent f && f.Percent == Percent && f.Mode == Mode; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode () { return Percent.GetHashCode (); }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the percentage.
|
||||
/// </summary>
|
||||
public new int Percent { get; } = percent;
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString () { return $"Percent({Percent},{Mode})"; }
|
||||
public override string ToString () { return $"Percent({Percentage},{Mode})"; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the dimension is computed using the View's position or GetContentSize ().
|
||||
/// </summary>
|
||||
public DimPercentMode Mode { get; } = mode;
|
||||
public DimPercentMode Mode { get; } = Mode;
|
||||
|
||||
internal override int GetAnchor (int size) { return (int)(size * (Percent / 100f)); }
|
||||
internal override int GetAnchor (int size) { return (int)(size * (Percentage / 100f)); }
|
||||
|
||||
internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Terminal.Gui;
|
||||
/// This is a low-level API that is typically used internally by the layout system. Use the various static
|
||||
/// methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
|
||||
/// </remarks>
|
||||
public class DimView : Dim
|
||||
public record DimView : Dim
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DimView"/> class.
|
||||
@@ -26,12 +26,6 @@ public class DimView : Dim
|
||||
/// </summary>
|
||||
public Dimension Dimension { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals (object? other) { return other is DimView abs && abs.Target == Target && abs.Dimension == Dimension; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode () { return Target!.GetHashCode (); }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the View the dimension is anchored to.
|
||||
/// </summary>
|
||||
|
||||
@@ -131,7 +131,7 @@ namespace Terminal.Gui;
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public abstract class Pos
|
||||
public abstract record Pos
|
||||
{
|
||||
#region static Pos creation methods
|
||||
|
||||
|
||||
@@ -10,19 +10,13 @@ namespace Terminal.Gui;
|
||||
/// methods on the <see cref="Pos"/> class to create <see cref="Pos"/> objects instead.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="position"></param>
|
||||
public class PosAbsolute (int position) : Pos
|
||||
/// <param name="Position"></param>
|
||||
public record PosAbsolute (int Position) : Pos
|
||||
{
|
||||
/// <summary>
|
||||
/// The position of the <see cref="View"/> in the layout.
|
||||
/// </summary>
|
||||
public int Position { get; } = position;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals (object? other) { return other is PosAbsolute abs && abs.Position == Position; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode () { return Position.GetHashCode (); }
|
||||
public int Position { get; } = Position;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString () { return $"Absolute({Position})"; }
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#nullable enable
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Terminal.Gui;
|
||||
|
||||
@@ -24,19 +23,13 @@ namespace Terminal.Gui;
|
||||
/// The alignment is applied to all views with the same <see cref="GroupId"/>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class PosAlign : Pos
|
||||
public record PosAlign : Pos
|
||||
{
|
||||
/// <summary>
|
||||
/// The cached location. Used to store the calculated location to minimize recalculating it.
|
||||
/// </summary>
|
||||
public int? _cachedLocation;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the identifier of a set of views that should be aligned together. When only a single
|
||||
/// set of views in a SuperView is aligned, setting <see cref="GroupId"/> is not needed because it defaults to 0.
|
||||
/// </summary>
|
||||
public int GroupId { get; init; }
|
||||
|
||||
private readonly Aligner? _aligner;
|
||||
|
||||
/// <summary>
|
||||
@@ -57,6 +50,88 @@ public class PosAlign : Pos
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: PosAlign.CalculateMinDimension is a hack. Need to figure out a better way of doing this.
|
||||
/// <summary>
|
||||
/// Returns the minimum size a group of views with the same <paramref name="groupId"/> can be.
|
||||
/// </summary>
|
||||
/// <param name="groupId"></param>
|
||||
/// <param name="views"></param>
|
||||
/// <param name="dimension"></param>
|
||||
/// <returns></returns>
|
||||
public static int CalculateMinDimension (int groupId, IList<View> views, Dimension dimension)
|
||||
{
|
||||
List<int> dimensionsList = new ();
|
||||
|
||||
// PERF: If this proves a perf issue, consider caching a ref to this list in each item
|
||||
List<View> viewsInGroup = views.Where (
|
||||
v =>
|
||||
{
|
||||
return dimension switch
|
||||
{
|
||||
Dimension.Width when v.X is PosAlign alignX => alignX.GroupId == groupId,
|
||||
Dimension.Height when v.Y is PosAlign alignY => alignY.GroupId == groupId,
|
||||
_ => false
|
||||
};
|
||||
})
|
||||
.ToList ();
|
||||
|
||||
if (viewsInGroup.Count == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// PERF: We iterate over viewsInGroup multiple times here.
|
||||
|
||||
// Update the dimensionList with the sizes of the views
|
||||
for (var index = 0; index < viewsInGroup.Count; index++)
|
||||
{
|
||||
View view = viewsInGroup [index];
|
||||
|
||||
PosAlign? posAlign = dimension == Dimension.Width ? view.X as PosAlign : view.Y as PosAlign;
|
||||
|
||||
if (posAlign is { })
|
||||
{
|
||||
dimensionsList.Add (dimension == Dimension.Width ? view.Frame.Width : view.Frame.Height);
|
||||
}
|
||||
}
|
||||
|
||||
// Align
|
||||
return dimensionsList.Sum ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the identifier of a set of views that should be aligned together. When only a single
|
||||
/// set of views in a SuperView is aligned, setting <see cref="GroupId"/> is not needed because it defaults to 0.
|
||||
/// </summary>
|
||||
public int GroupId { get; init; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString () { return $"Align(alignment={Aligner.Alignment},modes={Aligner.AlignmentModes},groupId={GroupId})"; }
|
||||
|
||||
internal override int Calculate (int superviewDimension, Dim dim, View us, Dimension dimension)
|
||||
{
|
||||
if (_cachedLocation.HasValue && Aligner.ContainerSize == superviewDimension)
|
||||
{
|
||||
return _cachedLocation.Value;
|
||||
}
|
||||
|
||||
if (us?.SuperView is null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
AlignAndUpdateGroup (GroupId, us.SuperView.Subviews, dimension, superviewDimension);
|
||||
|
||||
if (_cachedLocation.HasValue)
|
||||
{
|
||||
return _cachedLocation.Value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal override int GetAnchor (int width) { return _cachedLocation ?? 0 - width; }
|
||||
|
||||
/// <summary>
|
||||
/// Aligns the views in <paramref name="views"/> that have the same group ID as <paramref name="groupId"/>.
|
||||
/// Updates each view's cached _location.
|
||||
@@ -71,30 +146,30 @@ public class PosAlign : Pos
|
||||
|
||||
// PERF: If this proves a perf issue, consider caching a ref to this list in each item
|
||||
List<PosAlign?> posAligns = views.Select (
|
||||
v =>
|
||||
{
|
||||
switch (dimension)
|
||||
{
|
||||
case Dimension.Width when v.X.Has (typeof (PosAlign), out var pos):
|
||||
v =>
|
||||
{
|
||||
switch (dimension)
|
||||
{
|
||||
case Dimension.Width when v.X.Has (typeof (PosAlign), out Pos pos):
|
||||
|
||||
if (pos is PosAlign posAlignX && posAlignX.GroupId == groupId)
|
||||
{
|
||||
return posAlignX;
|
||||
}
|
||||
if (pos is PosAlign posAlignX && posAlignX.GroupId == groupId)
|
||||
{
|
||||
return posAlignX;
|
||||
}
|
||||
|
||||
break;
|
||||
case Dimension.Height when v.Y.Has (typeof (PosAlign), out var pos):
|
||||
if (pos is PosAlign posAlignY && posAlignY.GroupId == groupId)
|
||||
{
|
||||
return posAlignY;
|
||||
}
|
||||
break;
|
||||
case Dimension.Height when v.Y.Has (typeof (PosAlign), out Pos pos):
|
||||
if (pos is PosAlign posAlignY && posAlignY.GroupId == groupId)
|
||||
{
|
||||
return posAlignY;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return null;
|
||||
})
|
||||
.ToList ();
|
||||
return null;
|
||||
})
|
||||
.ToList ();
|
||||
|
||||
// PERF: We iterate over viewsInGroup multiple times here.
|
||||
|
||||
@@ -136,92 +211,4 @@ public class PosAlign : Pos
|
||||
}
|
||||
|
||||
private void Aligner_PropertyChanged (object? sender, PropertyChangedEventArgs e) { _cachedLocation = null; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals (object? other)
|
||||
{
|
||||
return other is PosAlign align
|
||||
&& GroupId == align.GroupId
|
||||
&& align.Aligner.Alignment == Aligner.Alignment
|
||||
&& align.Aligner.AlignmentModes == Aligner.AlignmentModes;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode () { return HashCode.Combine (Aligner, GroupId); }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString () { return $"Align(alignment={Aligner.Alignment},modes={Aligner.AlignmentModes},groupId={GroupId})"; }
|
||||
|
||||
internal override int GetAnchor (int width) { return _cachedLocation ?? 0 - width; }
|
||||
|
||||
internal override int Calculate (int superviewDimension, Dim dim, View us, Dimension dimension)
|
||||
{
|
||||
if (_cachedLocation.HasValue && Aligner.ContainerSize == superviewDimension)
|
||||
{
|
||||
return _cachedLocation.Value;
|
||||
}
|
||||
|
||||
if (us?.SuperView is null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
AlignAndUpdateGroup (GroupId, us.SuperView.Subviews, dimension, superviewDimension);
|
||||
|
||||
if (_cachedLocation.HasValue)
|
||||
{
|
||||
return _cachedLocation.Value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: PosAlign.CalculateMinDimension is a hack. Need to figure out a better way of doing this.
|
||||
/// <summary>
|
||||
/// Returns the minimum size a group of views with the same <paramref name="groupId"/> can be.
|
||||
/// </summary>
|
||||
/// <param name="groupId"></param>
|
||||
/// <param name="views"></param>
|
||||
/// <param name="dimension"></param>
|
||||
/// <returns></returns>
|
||||
public static int CalculateMinDimension (int groupId, IList<View> views, Dimension dimension)
|
||||
{
|
||||
List<int> dimensionsList = new ();
|
||||
|
||||
// PERF: If this proves a perf issue, consider caching a ref to this list in each item
|
||||
List<View> viewsInGroup = views.Where (
|
||||
v =>
|
||||
{
|
||||
return dimension switch
|
||||
{
|
||||
Dimension.Width when v.X is PosAlign alignX => alignX.GroupId == groupId,
|
||||
Dimension.Height when v.Y is PosAlign alignY => alignY.GroupId == groupId,
|
||||
_ => false
|
||||
};
|
||||
})
|
||||
.ToList ();
|
||||
|
||||
if (viewsInGroup.Count == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// PERF: We iterate over viewsInGroup multiple times here.
|
||||
|
||||
// Update the dimensionList with the sizes of the views
|
||||
for (var index = 0; index < viewsInGroup.Count; index++)
|
||||
{
|
||||
View view = viewsInGroup [index];
|
||||
|
||||
PosAlign? posAlign = dimension == Dimension.Width ? view.X as PosAlign : view.Y as PosAlign;
|
||||
|
||||
if (posAlign is { })
|
||||
{
|
||||
dimensionsList.Add (dimension == Dimension.Width ? view.Frame.Width : view.Frame.Height);
|
||||
}
|
||||
}
|
||||
|
||||
// Align
|
||||
return dimensionsList.Sum ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Terminal.Gui;
|
||||
/// methods on the <see cref="Pos"/> class to create <see cref="Pos"/> objects instead.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class PosAnchorEnd : Pos
|
||||
public record PosAnchorEnd : Pos
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the offset of the position from the right/bottom.
|
||||
@@ -30,12 +30,6 @@ public class PosAnchorEnd : Pos
|
||||
/// <param name="offset"></param>
|
||||
public PosAnchorEnd (int offset) { Offset = offset; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals (object? other) { return other is PosAnchorEnd anchorEnd && anchorEnd.Offset == Offset; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode () { return Offset.GetHashCode (); }
|
||||
|
||||
/// <summary>
|
||||
/// If true, the offset is the width of the view, if false, the offset is the offset value.
|
||||
/// </summary>
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Terminal.Gui;
|
||||
/// <summary>
|
||||
/// Represents a position that is centered.
|
||||
/// </summary>
|
||||
public class PosCenter : Pos
|
||||
public record PosCenter : Pos
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override string ToString () { return "Center"; }
|
||||
|
||||
@@ -10,27 +10,27 @@ namespace Terminal.Gui;
|
||||
/// methods on the <see cref="Pos"/> class to create <see cref="Pos"/> objects instead.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="add">
|
||||
/// <param name="Add">
|
||||
/// Indicates whether the two positions are added or subtracted.
|
||||
/// </param>
|
||||
/// <param name="left">The left position.</param>
|
||||
/// <param name="right">The right position.</param>
|
||||
public class PosCombine (AddOrSubtract add, Pos left, Pos right) : Pos
|
||||
/// <param name="Left">The left position.</param>
|
||||
/// <param name="Right">The right position.</param>
|
||||
public record PosCombine (AddOrSubtract Add, Pos Left, Pos Right) : Pos
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets whether the two positions are added or subtracted.
|
||||
/// </summary>
|
||||
public AddOrSubtract Add { get; } = add;
|
||||
public AddOrSubtract Add { get; } = Add;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the left position.
|
||||
/// </summary>
|
||||
public new Pos Left { get; } = left;
|
||||
public new Pos Left { get; } = Left;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the right position.
|
||||
/// </summary>
|
||||
public new Pos Right { get; } = right;
|
||||
public new Pos Right { get; } = Right;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString () { return $"Combine({Left}{(Add == AddOrSubtract.Add ? '+' : '-')}{Right})"; }
|
||||
|
||||
@@ -4,28 +4,11 @@ namespace Terminal.Gui;
|
||||
/// <summary>
|
||||
/// Represents a position that is computed by executing a function that returns an integer position.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This is a low-level API that is typically used internally by the layout system. Use the various static
|
||||
/// methods on the <see cref="Pos"/> class to create <see cref="Pos"/> objects instead.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="pos">The position.</param>
|
||||
public class PosFunc (Func<int> pos) : Pos
|
||||
/// <param name="Fn">The function that computes the position.</param>
|
||||
public record PosFunc (Func<int> Fn) : Pos
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the function that computes the position.
|
||||
/// </summary>
|
||||
public new Func<int> Func { get; } = pos;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals (object? other) { return other is PosFunc f && f.Func () == Func (); }
|
||||
public override string ToString () { return $"PosFunc({Fn ()})"; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode () { return Func.GetHashCode (); }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString () { return $"PosFunc({Func ()})"; }
|
||||
|
||||
internal override int GetAnchor (int size) { return Func (); }
|
||||
internal override int GetAnchor (int size) { return Fn (); }
|
||||
}
|
||||
@@ -10,19 +10,13 @@ namespace Terminal.Gui;
|
||||
/// methods on the <see cref="Pos"/> class to create <see cref="Pos"/> objects instead.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="percent"></param>
|
||||
public class PosPercent (int percent) : Pos
|
||||
/// <param name="Percent"></param>
|
||||
public record PosPercent (int Percent) : Pos
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the percentage of the width or height of the SuperView.
|
||||
/// </summary>
|
||||
public new int Percent { get; } = percent;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals (object? other) { return other is PosPercent i && i.Percent == Percent; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode () { return Percent.GetHashCode (); }
|
||||
public new int Percent { get; } = Percent;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString () { return $"Percent({Percent})"; }
|
||||
|
||||
@@ -10,25 +10,19 @@ namespace Terminal.Gui;
|
||||
/// methods on the <see cref="Pos"/> class to create <see cref="Pos"/> objects instead.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="view">The View the position is anchored to.</param>
|
||||
/// <param name="side">The side of the View the position is anchored to.</param>
|
||||
public class PosView (View? view, Side side) : Pos
|
||||
/// <param name="View">The View the position is anchored to.</param>
|
||||
/// <param name="Side">The side of the View the position is anchored to.</param>
|
||||
public record PosView (View? View, Side Side) : Pos
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the View the position is anchored to.
|
||||
/// </summary>
|
||||
public View? Target { get; } = view;
|
||||
public View? Target { get; } = View;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the side of the View the position is anchored to.
|
||||
/// </summary>
|
||||
public Side Side { get; } = side;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals (object? other) { return other is PosView abs && abs.Target == Target && abs.Side == Side; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode () { return Target!.GetHashCode (); }
|
||||
public Side Side { get; } = Side;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString ()
|
||||
|
||||
@@ -474,7 +474,7 @@ public partial class View // Layout APIs
|
||||
return;
|
||||
}
|
||||
|
||||
if (_height is { } && _height.Has (typeof (DimAuto), out _))
|
||||
if (_height is { } && _height.Has<DimAuto> (out _))
|
||||
{
|
||||
// Reset ContentSize to Viewport
|
||||
_contentSize = null;
|
||||
@@ -523,7 +523,7 @@ public partial class View // Layout APIs
|
||||
return;
|
||||
}
|
||||
|
||||
if (_width is { } && _width.Has (typeof (DimAuto), out _))
|
||||
if (_width is { } && _width.Has<DimAuto> (out _))
|
||||
{
|
||||
// Reset ContentSize to Viewport
|
||||
_contentSize = null;
|
||||
|
||||
@@ -4,33 +4,36 @@ using static Terminal.Gui.Dim;
|
||||
|
||||
namespace Terminal.Gui.LayoutTests;
|
||||
|
||||
[Trait("Category", "Layout")]
|
||||
public partial class DimAutoTests (ITestOutputHelper output)
|
||||
{
|
||||
private readonly ITestOutputHelper _output = output;
|
||||
|
||||
private class DimAutoTestView : View
|
||||
[SetupFakeDriver]
|
||||
[Fact]
|
||||
public void Change_To_Non_Auto_Resets_ContentSize ()
|
||||
{
|
||||
public DimAutoTestView ()
|
||||
View view = new ()
|
||||
{
|
||||
ValidatePosDim = true;
|
||||
Width = Auto ();
|
||||
Height = Auto ();
|
||||
}
|
||||
Width = Auto (),
|
||||
Height = Auto (),
|
||||
Text = "01234"
|
||||
};
|
||||
view.SetRelativeLayout (new (100, 100));
|
||||
Assert.Equal (new (0, 0, 5, 1), view.Frame);
|
||||
Assert.Equal (new (5, 1), view.GetContentSize ());
|
||||
|
||||
public DimAutoTestView (Dim width, Dim height)
|
||||
{
|
||||
ValidatePosDim = true;
|
||||
Width = width;
|
||||
Height = height;
|
||||
}
|
||||
// Change text to a longer string
|
||||
view.Text = "0123456789";
|
||||
|
||||
public DimAutoTestView (string text, Dim width, Dim height)
|
||||
{
|
||||
ValidatePosDim = true;
|
||||
Text = text;
|
||||
Width = width;
|
||||
Height = height;
|
||||
}
|
||||
Assert.Equal (new (0, 0, 10, 1), view.Frame);
|
||||
Assert.Equal (new (10, 1), view.GetContentSize ());
|
||||
|
||||
// If ContentSize was reset, these should cause it to update
|
||||
view.Width = 5;
|
||||
view.Height = 1;
|
||||
|
||||
Assert.Equal (new (5, 1), view.GetContentSize ());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@@ -74,6 +77,46 @@ public partial class DimAutoTests (ITestOutputHelper output)
|
||||
Assert.Equal (new (0, 0, 10, expectedHeight), superView.Frame);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[CombinatorialData]
|
||||
public void HotKey_TextFormatter_Height_Correct ([CombinatorialValues ("1234", "_1234", "1_234", "____")] string text)
|
||||
{
|
||||
View view = new ()
|
||||
{
|
||||
HotKeySpecifier = (Rune)'_',
|
||||
Text = text,
|
||||
Width = Auto (),
|
||||
Height = 1
|
||||
};
|
||||
Assert.Equal (4, view.TextFormatter.ConstrainToWidth);
|
||||
Assert.Equal (1, view.TextFormatter.ConstrainToHeight);
|
||||
|
||||
view = new ()
|
||||
{
|
||||
HotKeySpecifier = (Rune)'_',
|
||||
TextDirection = TextDirection.TopBottom_LeftRight,
|
||||
Text = text,
|
||||
Width = 1,
|
||||
Height = Auto ()
|
||||
};
|
||||
Assert.Equal (1, view.TextFormatter.ConstrainToWidth);
|
||||
Assert.Equal (4, view.TextFormatter.ConstrainToHeight);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[CombinatorialData]
|
||||
public void HotKey_TextFormatter_Width_Correct ([CombinatorialValues ("1234", "_1234", "1_234", "____")] string text)
|
||||
{
|
||||
View view = new ()
|
||||
{
|
||||
Text = text,
|
||||
Height = 1,
|
||||
Width = Auto ()
|
||||
};
|
||||
Assert.Equal (4, view.TextFormatter.ConstrainToWidth);
|
||||
Assert.Equal (1, view.TextFormatter.ConstrainToHeight);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NoSubViews_Does_Nothing ()
|
||||
{
|
||||
@@ -158,6 +201,122 @@ public partial class DimAutoTests (ITestOutputHelper output)
|
||||
Assert.Equal (new (0, 0, expectedWidth, expectedHeight), superView.Frame);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestEquality ()
|
||||
{
|
||||
var a = new DimAuto (
|
||||
MaximumContentDim: null,
|
||||
MinimumContentDim: 1,
|
||||
Style: DimAutoStyle.Auto
|
||||
);
|
||||
|
||||
var b = new DimAuto (
|
||||
MaximumContentDim: null,
|
||||
MinimumContentDim: 1,
|
||||
Style: DimAutoStyle.Auto
|
||||
);
|
||||
|
||||
var c = new DimAuto(
|
||||
MaximumContentDim: 2,
|
||||
MinimumContentDim: 1,
|
||||
Style: DimAutoStyle.Auto
|
||||
);
|
||||
|
||||
var d = new DimAuto (
|
||||
MaximumContentDim: null,
|
||||
MinimumContentDim: 1,
|
||||
Style: DimAutoStyle.Content
|
||||
);
|
||||
|
||||
var e = new DimAuto (
|
||||
MaximumContentDim: null,
|
||||
MinimumContentDim: 2,
|
||||
Style: DimAutoStyle.Auto
|
||||
);
|
||||
|
||||
// Test equality with same values
|
||||
Assert.True (a.Equals (b));
|
||||
Assert.True (a.GetHashCode () == b.GetHashCode ());
|
||||
|
||||
// Test inequality with different MaximumContentDim
|
||||
Assert.False (a.Equals (c));
|
||||
Assert.False (a.GetHashCode () == c.GetHashCode ());
|
||||
|
||||
// Test inequality with different Style
|
||||
Assert.False (a.Equals (d));
|
||||
Assert.False (a.GetHashCode () == d.GetHashCode ());
|
||||
|
||||
// Test inequality with different MinimumContentDim
|
||||
Assert.False (a.Equals (e));
|
||||
Assert.False (a.GetHashCode () == e.GetHashCode ());
|
||||
|
||||
// Test inequality with null
|
||||
Assert.False (a.Equals (null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestEquality_Simple ()
|
||||
{
|
||||
Dim a = Auto ();
|
||||
Dim b = Auto ();
|
||||
Assert.True (a.Equals (b));
|
||||
Assert.True (a.GetHashCode () == b.GetHashCode ());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TextFormatter_Settings_Change_View_Size ()
|
||||
{
|
||||
View view = new ()
|
||||
{
|
||||
Text = "_1234",
|
||||
Width = Auto ()
|
||||
};
|
||||
Assert.Equal (new (4, 0), view.Frame.Size);
|
||||
|
||||
view.Height = 1;
|
||||
view.SetRelativeLayout (Application.Screen.Size);
|
||||
Assert.Equal (new (4, 1), view.Frame.Size);
|
||||
Size lastSize = view.Frame.Size;
|
||||
|
||||
view.TextAlignment = Alignment.Fill;
|
||||
Assert.Equal (lastSize, view.Frame.Size);
|
||||
|
||||
view = new ()
|
||||
{
|
||||
Text = "_1234",
|
||||
Width = Auto (),
|
||||
Height = 1
|
||||
};
|
||||
view.SetRelativeLayout (Application.Screen.Size);
|
||||
|
||||
lastSize = view.Frame.Size;
|
||||
view.VerticalTextAlignment = Alignment.Center;
|
||||
Assert.Equal (lastSize, view.Frame.Size);
|
||||
|
||||
view = new ()
|
||||
{
|
||||
Text = "_1234",
|
||||
Width = Auto (),
|
||||
Height = 1
|
||||
};
|
||||
view.SetRelativeLayout (Application.Screen.Size);
|
||||
lastSize = view.Frame.Size;
|
||||
view.HotKeySpecifier = (Rune)'*';
|
||||
view.SetRelativeLayout (Application.Screen.Size);
|
||||
Assert.NotEqual (lastSize, view.Frame.Size);
|
||||
|
||||
view = new ()
|
||||
{
|
||||
Text = "_1234",
|
||||
Width = Auto (),
|
||||
Height = 1
|
||||
};
|
||||
view.SetRelativeLayout (Application.Screen.Size);
|
||||
lastSize = view.Frame.Size;
|
||||
view.Text = "*ABCD";
|
||||
Assert.NotEqual (lastSize, view.Frame.Size);
|
||||
}
|
||||
|
||||
// Test validation
|
||||
[Fact]
|
||||
public void ValidatePosDim_True_Throws_When_SubView_Uses_SuperView_Dims ()
|
||||
@@ -410,46 +569,6 @@ public partial class DimAutoTests (ITestOutputHelper output)
|
||||
Assert.Equal (expectedWidth, superView.Frame.Width);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (0, 1, 1)]
|
||||
[InlineData (1, 1, 1)]
|
||||
[InlineData (9, 1, 1)]
|
||||
[InlineData (10, 1, 1)]
|
||||
[InlineData (0, 10, 10)]
|
||||
[InlineData (1, 10, 10)]
|
||||
[InlineData (9, 10, 10)]
|
||||
[InlineData (10, 10, 10)]
|
||||
public void Width_Auto_Text_Does_Not_Constrain_To_SuperView (int subX, int textLen, int expectedSubWidth)
|
||||
{
|
||||
var superView = new View
|
||||
{
|
||||
X = 0,
|
||||
Y = 0,
|
||||
Width = 10,
|
||||
Height = 1,
|
||||
ValidatePosDim = true
|
||||
};
|
||||
|
||||
var subView = new View
|
||||
{
|
||||
Text = new ('*', textLen),
|
||||
X = subX,
|
||||
Y = 0,
|
||||
Width = Auto (DimAutoStyle.Text),
|
||||
Height = 1,
|
||||
ValidatePosDim = true
|
||||
};
|
||||
|
||||
superView.Add (subView);
|
||||
|
||||
superView.BeginInit ();
|
||||
superView.EndInit ();
|
||||
superView.SetRelativeLayout (superView.GetContentSize ());
|
||||
|
||||
superView.LayoutSubviews ();
|
||||
Assert.Equal (expectedSubWidth, subView.Frame.Width);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (0, 1, 1)]
|
||||
[InlineData (1, 1, 1)]
|
||||
@@ -499,31 +618,69 @@ public partial class DimAutoTests (ITestOutputHelper output)
|
||||
Assert.Equal (expectedSubWidth, subView.Frame.Width);
|
||||
}
|
||||
|
||||
[SetupFakeDriver]
|
||||
[Fact]
|
||||
public void Change_To_Non_Auto_Resets_ContentSize ()
|
||||
[Theory]
|
||||
[InlineData (0, 1, 1)]
|
||||
[InlineData (1, 1, 1)]
|
||||
[InlineData (9, 1, 1)]
|
||||
[InlineData (10, 1, 1)]
|
||||
[InlineData (0, 10, 10)]
|
||||
[InlineData (1, 10, 10)]
|
||||
[InlineData (9, 10, 10)]
|
||||
[InlineData (10, 10, 10)]
|
||||
public void Width_Auto_Text_Does_Not_Constrain_To_SuperView (int subX, int textLen, int expectedSubWidth)
|
||||
{
|
||||
View view = new ()
|
||||
var superView = new View
|
||||
{
|
||||
Width = Auto (),
|
||||
Height = Auto (),
|
||||
Text = "01234"
|
||||
X = 0,
|
||||
Y = 0,
|
||||
Width = 10,
|
||||
Height = 1,
|
||||
ValidatePosDim = true
|
||||
};
|
||||
view.SetRelativeLayout (new (100, 100));
|
||||
Assert.Equal (new (0, 0, 5, 1), view.Frame);
|
||||
Assert.Equal (new (5, 1), view.GetContentSize ());
|
||||
|
||||
// Change text to a longer string
|
||||
view.Text = "0123456789";
|
||||
var subView = new View
|
||||
{
|
||||
Text = new ('*', textLen),
|
||||
X = subX,
|
||||
Y = 0,
|
||||
Width = Auto (DimAutoStyle.Text),
|
||||
Height = 1,
|
||||
ValidatePosDim = true
|
||||
};
|
||||
|
||||
Assert.Equal (new (0, 0, 10, 1), view.Frame);
|
||||
Assert.Equal (new (10, 1), view.GetContentSize ());
|
||||
superView.Add (subView);
|
||||
|
||||
// If ContentSize was reset, these should cause it to update
|
||||
view.Width = 5;
|
||||
view.Height = 1;
|
||||
superView.BeginInit ();
|
||||
superView.EndInit ();
|
||||
superView.SetRelativeLayout (superView.GetContentSize ());
|
||||
|
||||
Assert.Equal (new (5, 1), view.GetContentSize ());
|
||||
superView.LayoutSubviews ();
|
||||
Assert.Equal (expectedSubWidth, subView.Frame.Width);
|
||||
}
|
||||
|
||||
private class DimAutoTestView : View
|
||||
{
|
||||
public DimAutoTestView ()
|
||||
{
|
||||
ValidatePosDim = true;
|
||||
Width = Auto ();
|
||||
Height = Auto ();
|
||||
}
|
||||
|
||||
public DimAutoTestView (Dim width, Dim height)
|
||||
{
|
||||
ValidatePosDim = true;
|
||||
Width = width;
|
||||
Height = height;
|
||||
}
|
||||
|
||||
public DimAutoTestView (string text, Dim width, Dim height)
|
||||
{
|
||||
ValidatePosDim = true;
|
||||
Text = text;
|
||||
Width = width;
|
||||
Height = height;
|
||||
}
|
||||
}
|
||||
|
||||
#region DimAutoStyle.Auto tests
|
||||
@@ -544,7 +701,6 @@ public partial class DimAutoTests (ITestOutputHelper output)
|
||||
view.SetRelativeLayout (Application.Screen.Size);
|
||||
|
||||
Assert.Equal (new (expectedW, expectedH), view.Frame.Size);
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -653,7 +809,6 @@ public partial class DimAutoTests (ITestOutputHelper output)
|
||||
view.SetRelativeLayout (Application.Screen.Size);
|
||||
|
||||
Assert.Equal (new (expectedW, expectedH), view.Frame.Size);
|
||||
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@@ -665,15 +820,14 @@ public partial class DimAutoTests (ITestOutputHelper output)
|
||||
public void DimAutoStyle_Text_Sizes_Correctly_With_Min (string text, int minWidth, int minHeight, int expectedW, int expectedH)
|
||||
{
|
||||
var view = new View ();
|
||||
view.Width = Auto (DimAutoStyle.Text, minimumContentDim: minWidth);
|
||||
view.Height = Auto (DimAutoStyle.Text, minimumContentDim: minHeight);
|
||||
view.Width = Auto (DimAutoStyle.Text, minWidth);
|
||||
view.Height = Auto (DimAutoStyle.Text, minHeight);
|
||||
|
||||
view.Text = text;
|
||||
|
||||
view.SetRelativeLayout (Application.Screen.Size);
|
||||
|
||||
Assert.Equal (new (expectedW, expectedH), view.Frame.Size);
|
||||
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@@ -699,7 +853,6 @@ public partial class DimAutoTests (ITestOutputHelper output)
|
||||
[InlineData ("01234", 5, 1)]
|
||||
[InlineData ("01234ABCDE", 10, 1)]
|
||||
[InlineData ("01234\nABCDE", 5, 2)]
|
||||
|
||||
public void DimAutoStyle_Text_NoMin_Not_Constrained_By_ContentSize (string text, int expectedW, int expectedH)
|
||||
{
|
||||
var view = new View ();
|
||||
@@ -711,7 +864,6 @@ public partial class DimAutoTests (ITestOutputHelper output)
|
||||
Assert.Equal (new (expectedW, expectedH), view.Frame.Size);
|
||||
}
|
||||
|
||||
|
||||
[Theory]
|
||||
[InlineData ("", 0, 0)]
|
||||
[InlineData (" ", 1, 1)]
|
||||
@@ -720,7 +872,7 @@ public partial class DimAutoTests (ITestOutputHelper output)
|
||||
[InlineData ("01234\nABCDE", 5, 2)]
|
||||
public void DimAutoStyle_Text_NoMin_Not_Constrained_By_SuperView (string text, int expectedW, int expectedH)
|
||||
{
|
||||
var superView = new View ()
|
||||
var superView = new View
|
||||
{
|
||||
Width = 1, Height = 1
|
||||
};
|
||||
@@ -870,100 +1022,5 @@ public partial class DimAutoTests (ITestOutputHelper output)
|
||||
|
||||
#endregion DimAutoStyle.Content tests
|
||||
|
||||
[Fact]
|
||||
public void TextFormatter_Settings_Change_View_Size ()
|
||||
{
|
||||
View view = new ()
|
||||
{
|
||||
Text = "_1234",
|
||||
Width = Auto ()
|
||||
};
|
||||
Assert.Equal (new (4, 0), view.Frame.Size);
|
||||
|
||||
view.Height = 1;
|
||||
view.SetRelativeLayout (Application.Screen.Size);
|
||||
Assert.Equal (new (4, 1), view.Frame.Size);
|
||||
Size lastSize = view.Frame.Size;
|
||||
|
||||
view.TextAlignment = Alignment.Fill;
|
||||
Assert.Equal (lastSize, view.Frame.Size);
|
||||
|
||||
view = new ()
|
||||
{
|
||||
Text = "_1234",
|
||||
Width = Auto (),
|
||||
Height = 1
|
||||
};
|
||||
view.SetRelativeLayout (Application.Screen.Size);
|
||||
|
||||
lastSize = view.Frame.Size;
|
||||
view.VerticalTextAlignment = Alignment.Center;
|
||||
Assert.Equal (lastSize, view.Frame.Size);
|
||||
|
||||
view = new ()
|
||||
{
|
||||
Text = "_1234",
|
||||
Width = Auto (),
|
||||
Height = 1
|
||||
};
|
||||
view.SetRelativeLayout (Application.Screen.Size);
|
||||
lastSize = view.Frame.Size;
|
||||
view.HotKeySpecifier = (Rune)'*';
|
||||
view.SetRelativeLayout (Application.Screen.Size);
|
||||
Assert.NotEqual (lastSize, view.Frame.Size);
|
||||
|
||||
view = new ()
|
||||
{
|
||||
Text = "_1234",
|
||||
Width = Auto (),
|
||||
Height = 1
|
||||
};
|
||||
view.SetRelativeLayout (Application.Screen.Size);
|
||||
lastSize = view.Frame.Size;
|
||||
view.Text = "*ABCD";
|
||||
Assert.NotEqual (lastSize, view.Frame.Size);
|
||||
}
|
||||
|
||||
|
||||
[Theory]
|
||||
[CombinatorialData]
|
||||
public void HotKey_TextFormatter_Width_Correct ([CombinatorialValues ("1234", "_1234", "1_234", "____")] string text)
|
||||
{
|
||||
View view = new ()
|
||||
{
|
||||
Text = text,
|
||||
Height = 1,
|
||||
Width = Auto ()
|
||||
};
|
||||
Assert.Equal (4, view.TextFormatter.ConstrainToWidth);
|
||||
Assert.Equal (1, view.TextFormatter.ConstrainToHeight);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[CombinatorialData]
|
||||
public void HotKey_TextFormatter_Height_Correct ([CombinatorialValues ("1234", "_1234", "1_234", "____")] string text)
|
||||
{
|
||||
View view = new ()
|
||||
{
|
||||
HotKeySpecifier = (Rune)'_',
|
||||
Text = text,
|
||||
Width = Auto (),
|
||||
Height = 1
|
||||
};
|
||||
Assert.Equal (4, view.TextFormatter.ConstrainToWidth);
|
||||
Assert.Equal (1, view.TextFormatter.ConstrainToHeight);
|
||||
|
||||
view = new ()
|
||||
{
|
||||
HotKeySpecifier = (Rune)'_',
|
||||
TextDirection = TextDirection.TopBottom_LeftRight,
|
||||
Text = text,
|
||||
Width = 1,
|
||||
Height = Auto ()
|
||||
};
|
||||
Assert.Equal (1, view.TextFormatter.ConstrainToWidth);
|
||||
Assert.Equal (4, view.TextFormatter.ConstrainToHeight);
|
||||
}
|
||||
|
||||
// Test variations of Frame
|
||||
}
|
||||
|
||||
@@ -14,9 +14,12 @@ public class DimFuncTests (ITestOutputHelper output)
|
||||
Func<int> f2 = () => 0;
|
||||
|
||||
Dim dim1 = Func (f1);
|
||||
Dim dim2 = Func (f2);
|
||||
Dim dim2 = Func (f1);
|
||||
Assert.Equal (dim1, dim2);
|
||||
|
||||
dim2 = Func (f2);
|
||||
Assert.NotEqual (dim1, dim2);
|
||||
|
||||
f2 = () => 1;
|
||||
dim2 = Func (f2);
|
||||
Assert.NotEqual (dim1, dim2);
|
||||
|
||||
@@ -15,7 +15,6 @@ public class DimPercentTests
|
||||
Assert.Equal (50, result);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void DimPercent_Equals ()
|
||||
{
|
||||
@@ -63,6 +62,15 @@ public class DimPercentTests
|
||||
Assert.NotEqual (dim1, dim2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestEquality ()
|
||||
{
|
||||
var a = Dim.Percent (32);
|
||||
var b = Dim.Percent (32);
|
||||
Assert.True (a.Equals (b));
|
||||
Assert.True (a.GetHashCode () == b.GetHashCode ());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DimPercent_Invalid_Throws ()
|
||||
{
|
||||
@@ -157,7 +165,7 @@ public class DimPercentTests
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0)]
|
||||
[InlineData (0)]
|
||||
[InlineData (1)]
|
||||
[InlineData (50)]
|
||||
[InlineData (100)]
|
||||
|
||||
@@ -27,58 +27,58 @@ public class PosAlignTests
|
||||
Assert.Equal (0, posAlign.Aligner.ContainerSize);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (Alignment.Start, Alignment.Start, AlignmentModes.AddSpaceBetweenItems, AlignmentModes.AddSpaceBetweenItems, true)]
|
||||
[InlineData (Alignment.Center, Alignment.Center, AlignmentModes.AddSpaceBetweenItems, AlignmentModes.AddSpaceBetweenItems, true)]
|
||||
[InlineData (Alignment.Start, Alignment.Center, AlignmentModes.AddSpaceBetweenItems, AlignmentModes.AddSpaceBetweenItems, false)]
|
||||
[InlineData (Alignment.Center, Alignment.Start, AlignmentModes.AddSpaceBetweenItems, AlignmentModes.AddSpaceBetweenItems, false)]
|
||||
[InlineData (Alignment.Start, Alignment.Start, AlignmentModes.StartToEnd, AlignmentModes.AddSpaceBetweenItems, false)]
|
||||
public void PosAlign_Equals (Alignment align1, Alignment align2, AlignmentModes mode1, AlignmentModes mode2, bool expectedEquals)
|
||||
{
|
||||
var posAlign1 = new PosAlign
|
||||
{
|
||||
Aligner = new()
|
||||
{
|
||||
Alignment = align1,
|
||||
AlignmentModes = mode1
|
||||
}
|
||||
};
|
||||
//[Theory]
|
||||
//[InlineData (Alignment.Start, Alignment.Start, AlignmentModes.AddSpaceBetweenItems, AlignmentModes.AddSpaceBetweenItems, true)]
|
||||
//[InlineData (Alignment.Center, Alignment.Center, AlignmentModes.AddSpaceBetweenItems, AlignmentModes.AddSpaceBetweenItems, true)]
|
||||
//[InlineData (Alignment.Start, Alignment.Center, AlignmentModes.AddSpaceBetweenItems, AlignmentModes.AddSpaceBetweenItems, false)]
|
||||
//[InlineData (Alignment.Center, Alignment.Start, AlignmentModes.AddSpaceBetweenItems, AlignmentModes.AddSpaceBetweenItems, false)]
|
||||
//[InlineData (Alignment.Start, Alignment.Start, AlignmentModes.StartToEnd, AlignmentModes.AddSpaceBetweenItems, false)]
|
||||
//public void PosAlign_Equals (Alignment align1, Alignment align2, AlignmentModes mode1, AlignmentModes mode2, bool expectedEquals)
|
||||
//{
|
||||
// var posAlign1 = new PosAlign
|
||||
// {
|
||||
// Aligner = new ()
|
||||
// {
|
||||
// Alignment = align1,
|
||||
// AlignmentModes = mode1
|
||||
// }
|
||||
// };
|
||||
|
||||
var posAlign2 = new PosAlign
|
||||
{
|
||||
Aligner = new()
|
||||
{
|
||||
Alignment = align2,
|
||||
AlignmentModes = mode2
|
||||
}
|
||||
};
|
||||
// var posAlign2 = new PosAlign
|
||||
// {
|
||||
// Aligner = new ()
|
||||
// {
|
||||
// Alignment = align2,
|
||||
// AlignmentModes = mode2
|
||||
// }
|
||||
// };
|
||||
|
||||
Assert.Equal (expectedEquals, posAlign1.Equals (posAlign2));
|
||||
Assert.Equal (expectedEquals, posAlign2.Equals (posAlign1));
|
||||
}
|
||||
// Assert.Equal (expectedEquals, posAlign1.Equals (posAlign2));
|
||||
// Assert.Equal (expectedEquals, posAlign2.Equals (posAlign1));
|
||||
//}
|
||||
|
||||
[Fact]
|
||||
public void PosAlign_Equals_CachedLocation_Not_Used ()
|
||||
{
|
||||
View superView = new ()
|
||||
{
|
||||
Width = 10,
|
||||
Height = 25
|
||||
};
|
||||
View view = new ();
|
||||
superView.Add (view);
|
||||
//[Fact]
|
||||
//public void PosAlign_Equals_CachedLocation_Not_Used ()
|
||||
//{
|
||||
// View superView = new ()
|
||||
// {
|
||||
// Width = 10,
|
||||
// Height = 25
|
||||
// };
|
||||
// View view = new ();
|
||||
// superView.Add (view);
|
||||
|
||||
Pos posAlign1 = Pos.Align (Alignment.Center);
|
||||
view.X = posAlign1;
|
||||
int pos1 = posAlign1.Calculate (10, Dim.Absolute (0)!, view, Dimension.Width);
|
||||
// Pos posAlign1 = Pos.Align (Alignment.Center);
|
||||
// view.X = posAlign1;
|
||||
// int pos1 = posAlign1.Calculate (10, Dim.Absolute (0)!, view, Dimension.Width);
|
||||
|
||||
Pos posAlign2 = Pos.Align (Alignment.Center);
|
||||
view.Y = posAlign2;
|
||||
int pos2 = posAlign2.Calculate (25, Dim.Absolute (0)!, view, Dimension.Height);
|
||||
// Pos posAlign2 = Pos.Align (Alignment.Center);
|
||||
// view.Y = posAlign2;
|
||||
// int pos2 = posAlign2.Calculate (25, Dim.Absolute (0)!, view, Dimension.Height);
|
||||
|
||||
Assert.NotEqual (pos1, pos2);
|
||||
Assert.Equal (posAlign1, posAlign2);
|
||||
}
|
||||
// Assert.NotEqual (pos1, pos2);
|
||||
// Assert.Equal (posAlign1, posAlign2);
|
||||
//}
|
||||
|
||||
[Fact]
|
||||
public void PosAlign_ToString ()
|
||||
|
||||
@@ -27,15 +27,6 @@ public class PosAnchorEndTests (ITestOutputHelper output)
|
||||
Assert.Equal (expectedEquals, posAnchorEnd2.Equals (posAnchorEnd1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PosAnchorEnd_GetHashCode ()
|
||||
{
|
||||
var posAnchorEnd = new PosAnchorEnd (10);
|
||||
var expectedHashCode = 10.GetHashCode ();
|
||||
|
||||
Assert.Equal (expectedHashCode, posAnchorEnd.GetHashCode ());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PosAnchorEnd_ToString ()
|
||||
{
|
||||
|
||||
@@ -15,16 +15,6 @@ public class PosCenterTests (ITestOutputHelper output)
|
||||
Assert.NotNull (posCenter);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PosCenter_Equals ()
|
||||
{
|
||||
var posCenter1 = new PosCenter ();
|
||||
var posCenter2 = new PosCenter ();
|
||||
|
||||
Assert.False (posCenter1.Equals (posCenter2));
|
||||
Assert.False (posCenter2.Equals (posCenter1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PosCenter_ToString ()
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@ public class PosFuncTests (ITestOutputHelper output)
|
||||
Func<int> f2 = () => 0;
|
||||
|
||||
Pos pos1 = Pos.Func (f1);
|
||||
Pos pos2 = Pos.Func (f2);
|
||||
Pos pos2 = Pos.Func (f1);
|
||||
Assert.Equal (pos1, pos2);
|
||||
|
||||
f2 = () => 1;
|
||||
|
||||
@@ -145,21 +145,6 @@ public class PosTests ()
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PosFunction_Equal ()
|
||||
{
|
||||
Func<int> f1 = () => 0;
|
||||
Func<int> f2 = () => 0;
|
||||
|
||||
Pos pos1 = Pos.Func (f1);
|
||||
Pos pos2 = Pos.Func (f2);
|
||||
Assert.Equal (pos1, pos2);
|
||||
|
||||
f2 = () => 1;
|
||||
pos2 = Pos.Func (f2);
|
||||
Assert.NotEqual (pos1, pos2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PosFunction_SetsValue ()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user