Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #3521 - DimAuto equality broken #3649

Merged
merged 19 commits into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 19 additions & 27 deletions Terminal.Gui/View/Layout/Dim.cs
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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>
Expand Down Expand Up @@ -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
Expand All @@ -208,7 +200,7 @@ public bool Has (Type type, out Dim 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
Expand All @@ -228,7 +220,7 @@ public bool Has (Type type, out Dim 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>
Expand Down
12 changes: 3 additions & 9 deletions Terminal.Gui/View/Layout/DimAbsolute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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})"; }
Expand Down
73 changes: 13 additions & 60 deletions Terminal.Gui/View/Layout/DimAuto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -181,8 +134,8 @@ internal override int Calculate (int location, int superviewContentSize, View us
&& !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 ();
}
Expand All @@ -194,8 +147,8 @@ internal override int Calculate (int location, int superviewContentSize, View us
&& !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 ();
}
Expand Down Expand Up @@ -419,11 +372,11 @@ internal override int Calculate (int location, int superviewContentSize, View us

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++)
Expand Down
14 changes: 7 additions & 7 deletions Terminal.Gui/View/Layout/DimCombine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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})"; }
Expand Down
15 changes: 2 additions & 13 deletions Terminal.Gui/View/Layout/DimFill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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})"; }

Expand Down
20 changes: 7 additions & 13 deletions Terminal.Gui/View/Layout/DimFunc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/// <inheritdoc/>
public override int GetHashCode () { return Func.GetHashCode (); }
public Func<int> Fn { get; } = Fn;

/// <inheritdoc/>
public override string ToString () { return $"DimFunc({Func ()})"; }
public override string ToString () { return $"DimFunc({Fn ()})"; }

internal override int GetAnchor (int size) { return Func (); }
internal override int GetAnchor (int size) { return Fn (); }
}
23 changes: 6 additions & 17 deletions Terminal.Gui/View/Layout/DimPercent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
8 changes: 1 addition & 7 deletions Terminal.Gui/View/Layout/DimView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -26,12 +26,6 @@ public DimView (View? view, Dimension dimension)
/// </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>
Expand Down
2 changes: 1 addition & 1 deletion Terminal.Gui/View/Layout/Pos.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ namespace Terminal.Gui;
/// </list>
/// </para>
/// </remarks>
public abstract class Pos
public abstract record Pos
{
#region static Pos creation methods

Expand Down
Loading
Loading