mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2026-02-10 04:03:41 +01:00
Phase 4: Add GetMinimumContribution method to reduce DimAuto coupling
Co-authored-by: tig <585482+tig@users.noreply.github.com>
This commit is contained in:
@@ -466,6 +466,28 @@ public abstract record Dim : IEqualityOperators<Dim, Dim, bool>
|
||||
/// </returns>
|
||||
internal virtual bool CanContributeToAutoSizing => true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the minimum contribution this Dim makes to auto-sizing calculations.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This method is used by <see cref="DimAuto"/> to determine the minimum size contribution
|
||||
/// of a Dim during auto-sizing calculations. The default implementation returns the
|
||||
/// result of <see cref="Calculate"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Types that have special minimum contribution logic (like <see cref="DimFill"/> with
|
||||
/// <see cref="DimFill.MinimumContentDim"/>) should override this method.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="location">The starting point from where the size calculation begins.</param>
|
||||
/// <param name="superviewContentSize">The size of the SuperView's content.</param>
|
||||
/// <param name="us">The View that holds this Dim object.</param>
|
||||
/// <param name="dimension">Width or Height</param>
|
||||
/// <returns>The minimum size contribution for auto-sizing calculations.</returns>
|
||||
internal virtual int GetMinimumContribution (int location, int superviewContentSize, View us, Dimension dimension) =>
|
||||
Calculate (location, superviewContentSize, us, dimension);
|
||||
|
||||
#endregion virtual methods
|
||||
|
||||
#region operators
|
||||
|
||||
@@ -434,18 +434,20 @@ public record DimAuto (Dim? MaximumContentDim, Dim? MinimumContentDim, DimAutoSt
|
||||
.ToList ();
|
||||
}
|
||||
|
||||
// Process DimFill views with MinimumContentDim or To
|
||||
// Process DimFill views that can contribute
|
||||
for (var i = 0; i < contributingDimFillSubViews.Count; i++)
|
||||
{
|
||||
View dimFillSubView = contributingDimFillSubViews [i];
|
||||
DimFill? dimFill = dimension == Dimension.Width ? dimFillSubView.Width as DimFill : dimFillSubView.Height as DimFill;
|
||||
Dim dimFill = dimension == Dimension.Width ? dimFillSubView.Width : dimFillSubView.Height;
|
||||
|
||||
if (dimFill?.MinimumContentDim is { })
|
||||
// Get the minimum contribution from the Dim itself
|
||||
int minContribution = dimFill.GetMinimumContribution (0, maxCalculatedSize, dimFillSubView, dimension);
|
||||
|
||||
if (minContribution > 0)
|
||||
{
|
||||
// This DimFill has a minimum - it contributes to auto-sizing
|
||||
int minSize = dimFill.MinimumContentDim.Calculate (0, maxCalculatedSize, dimFillSubView, dimension);
|
||||
// Add position offset to get total size needed
|
||||
int positionOffset = dimension == Dimension.Width ? dimFillSubView.Frame.X : dimFillSubView.Frame.Y;
|
||||
int totalSize = positionOffset + minSize;
|
||||
int totalSize = positionOffset + minContribution;
|
||||
|
||||
if (totalSize > maxCalculatedSize)
|
||||
{
|
||||
@@ -453,13 +455,13 @@ public record DimAuto (Dim? MaximumContentDim, Dim? MinimumContentDim, DimAutoSt
|
||||
}
|
||||
}
|
||||
|
||||
if (dimFill?.To is { })
|
||||
// Handle special case for DimFill with To (still needs type-specific logic)
|
||||
if (dimFill is DimFill dimFillTyped && dimFillTyped.To is { })
|
||||
{
|
||||
// This DimFill has a To view - it contributes to auto-sizing
|
||||
// The SuperView needs to be large enough to contain both the dimFillSubView and the To view
|
||||
int dimFillPos = dimension == Dimension.Width ? dimFillSubView.Frame.X : dimFillSubView.Frame.Y;
|
||||
int toViewPos = dimension == Dimension.Width ? dimFill.To.Frame.X : dimFill.To.Frame.Y;
|
||||
int toViewSize = dimension == Dimension.Width ? dimFill.To.Frame.Width : dimFill.To.Frame.Height;
|
||||
int toViewPos = dimension == Dimension.Width ? dimFillTyped.To.Frame.X : dimFillTyped.To.Frame.Y;
|
||||
int toViewSize = dimension == Dimension.Width ? dimFillTyped.To.Frame.Width : dimFillTyped.To.Frame.Height;
|
||||
int totalSize = int.Max (dimFillPos, toViewPos + toViewSize);
|
||||
|
||||
if (totalSize > maxCalculatedSize)
|
||||
|
||||
@@ -95,6 +95,28 @@ public record DimCombine (AddOrSubtract Add, Dim Left, Dim Right) : Dim
|
||||
/// <inheritdoc/>
|
||||
internal override bool CanContributeToAutoSizing => Left.CanContributeToAutoSizing || Right.CanContributeToAutoSizing;
|
||||
|
||||
/// <inheritdoc/>
|
||||
internal override int GetMinimumContribution (int location, int superviewContentSize, View us, Dimension dimension)
|
||||
{
|
||||
int newDimension;
|
||||
|
||||
if (Add == AddOrSubtract.Add)
|
||||
{
|
||||
newDimension = Left.GetMinimumContribution (location, superviewContentSize, us, dimension)
|
||||
+ Right.GetMinimumContribution (location, superviewContentSize, us, dimension);
|
||||
}
|
||||
else
|
||||
{
|
||||
newDimension = Math.Max (
|
||||
0,
|
||||
Left.GetMinimumContribution (location, superviewContentSize, us, dimension)
|
||||
- Right.GetMinimumContribution (location, superviewContentSize, us, dimension)
|
||||
);
|
||||
}
|
||||
|
||||
return newDimension;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override bool HasInner<TDim> (out TDim dim) => Left.Has (out dim) || Right.Has (out dim);
|
||||
}
|
||||
|
||||
@@ -94,6 +94,21 @@ public record DimFill (Dim Margin, Dim? MinimumContentDim = null, View? To = nul
|
||||
/// <inheritdoc/>
|
||||
internal override bool CanContributeToAutoSizing => MinimumContentDim is { } || To is { };
|
||||
|
||||
/// <inheritdoc/>
|
||||
internal override int GetMinimumContribution (int location, int superviewContentSize, View us, Dimension dimension)
|
||||
{
|
||||
// DimFill's minimum contribution depends on MinimumContentDim and To
|
||||
if (MinimumContentDim is { })
|
||||
{
|
||||
// Return the minimum content dimension
|
||||
return MinimumContentDim.Calculate (0, superviewContentSize, us, dimension);
|
||||
}
|
||||
|
||||
// If only To is set (without MinimumContentDim), we need special handling in DimAuto
|
||||
// because the contribution depends on the To view's position
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override bool HasInner<TDim> (out TDim dim)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
#nullable disable
|
||||
|
||||
// Claude - Opus 4.5
|
||||
|
||||
namespace ViewBaseTests.Layout;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for the GetMinimumContribution method on Dim types.
|
||||
/// This method is used by DimAuto to get minimum size contribution during auto-sizing.
|
||||
/// </summary>
|
||||
public class GetMinimumContributionTests
|
||||
{
|
||||
[Fact]
|
||||
public void DimAbsolute_GetMinimumContribution_ReturnsAbsoluteValue ()
|
||||
{
|
||||
Dim dim = Dim.Absolute (42);
|
||||
int contribution = dim.GetMinimumContribution (0, 100, null, Dimension.None);
|
||||
Assert.Equal (42, contribution);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DimAuto_GetMinimumContribution_ReturnsCalculatedValue ()
|
||||
{
|
||||
var view = new View { Width = Dim.Auto (), Height = Dim.Auto () };
|
||||
view.BeginInit ();
|
||||
view.EndInit ();
|
||||
|
||||
// DimAuto calculates based on content
|
||||
int contribution = view.Width.GetMinimumContribution (0, 100, view, Dimension.Width);
|
||||
Assert.True (contribution >= 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DimFunc_GetMinimumContribution_ReturnsCalculatedValue ()
|
||||
{
|
||||
Dim dim = Dim.Func (_ => 25);
|
||||
int contribution = dim.GetMinimumContribution (0, 100, null, Dimension.None);
|
||||
Assert.Equal (25, contribution);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DimView_GetMinimumContribution_ReturnsTargetViewSize ()
|
||||
{
|
||||
var targetView = new View { Width = 30, Height = 20 };
|
||||
Dim dim = Dim.Width (targetView);
|
||||
|
||||
int contribution = dim.GetMinimumContribution (0, 100, null, Dimension.Width);
|
||||
Assert.Equal (30, contribution);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DimPercent_GetMinimumContribution_ReturnsCalculatedPercentage ()
|
||||
{
|
||||
Dim dim = Dim.Percent (50);
|
||||
int contribution = dim.GetMinimumContribution (0, 100, null, Dimension.None);
|
||||
Assert.Equal (50, contribution);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DimFill_WithoutMinimumContentDim_ReturnsZero ()
|
||||
{
|
||||
Dim dim = Dim.Fill ();
|
||||
int contribution = dim.GetMinimumContribution (0, 100, null, Dimension.None);
|
||||
Assert.Equal (0, contribution);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DimFill_WithMargin_WithoutMinimumContentDim_ReturnsZero ()
|
||||
{
|
||||
Dim dim = Dim.Fill (5);
|
||||
int contribution = dim.GetMinimumContribution (0, 100, null, Dimension.None);
|
||||
Assert.Equal (0, contribution);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DimFill_WithMinimumContentDim_ReturnsMinimumSize ()
|
||||
{
|
||||
Dim dim = Dim.Fill (0, 35);
|
||||
int contribution = dim.GetMinimumContribution (0, 100, null, Dimension.None);
|
||||
Assert.Equal (35, contribution);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DimFill_WithMarginAndMinimumContentDim_ReturnsMinimumSize ()
|
||||
{
|
||||
Dim dim = Dim.Fill (5, 40);
|
||||
int contribution = dim.GetMinimumContribution (0, 100, null, Dimension.None);
|
||||
Assert.Equal (40, contribution);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DimFill_WithMinimumContentDim_UsesCalculatedValue ()
|
||||
{
|
||||
// MinimumContentDim can also be dynamic (e.g., Percent)
|
||||
Dim dim = Dim.Fill (0, Dim.Percent (25));
|
||||
int contribution = dim.GetMinimumContribution (0, 100, null, Dimension.None);
|
||||
Assert.Equal (25, contribution);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DimFill_WithTo_ReturnsZero ()
|
||||
{
|
||||
// When only To is set (without MinimumContentDim), GetMinimumContribution returns 0
|
||||
// because the actual contribution depends on the To view's position, which DimAuto handles specially
|
||||
var toView = new View { X = 50, Y = 30 };
|
||||
Dim dim = Dim.Fill (toView);
|
||||
|
||||
int contribution = dim.GetMinimumContribution (0, 100, null, Dimension.Width);
|
||||
Assert.Equal (0, contribution);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DimFill_WithMarginAndTo_ReturnsZero ()
|
||||
{
|
||||
var toView = new View { X = 50, Y = 30 };
|
||||
Dim dim = Dim.Fill (5, toView);
|
||||
|
||||
int contribution = dim.GetMinimumContribution (0, 100, null, Dimension.Width);
|
||||
Assert.Equal (0, contribution);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DimCombine_GetMinimumContribution_CombinesValues ()
|
||||
{
|
||||
// Addition
|
||||
Dim dim1 = Dim.Absolute (10) + Dim.Absolute (5);
|
||||
int contribution1 = dim1.GetMinimumContribution (0, 100, null, Dimension.None);
|
||||
Assert.Equal (15, contribution1);
|
||||
|
||||
// Subtraction
|
||||
Dim dim2 = Dim.Absolute (20) - Dim.Absolute (8);
|
||||
int contribution2 = dim2.GetMinimumContribution (0, 100, null, Dimension.None);
|
||||
Assert.Equal (12, contribution2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DimCombine_WithDimFill_HandlesMinimumContentDim ()
|
||||
{
|
||||
// DimFill with MinimumContentDim + Absolute
|
||||
Dim dim = Dim.Fill (0, 30) + Dim.Absolute (10);
|
||||
int contribution = dim.GetMinimumContribution (0, 100, null, Dimension.None);
|
||||
Assert.Equal (40, contribution);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DimCombine_WithDimFill_WithoutMinimum_UsesZero ()
|
||||
{
|
||||
// DimFill without MinimumContentDim + Absolute = 0 + 10 = 10
|
||||
Dim dim = Dim.Fill () + Dim.Absolute (10);
|
||||
int contribution = dim.GetMinimumContribution (0, 100, null, Dimension.None);
|
||||
Assert.Equal (10, contribution);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user