Clarified what dimauot min/max mean.

Disabled diagnostic spew
This commit is contained in:
Tig
2024-05-14 09:44:46 -07:00
parent a5eca55f29
commit 82e681c45a
11 changed files with 194 additions and 88 deletions

View File

@@ -648,7 +648,7 @@ public class Pos
public class Dim
{
/// <summary>
/// Specifies how <see cref="DimAuto"/> will compute the dimension.
/// Specifies how <see cref="Dim.Auto"/> will compute the dimension.
/// </summary>
[Flags]
public enum DimAutoStyle
@@ -731,18 +731,18 @@ public class Dim
/// </example>
/// <returns>The <see cref="Dim"/> object.</returns>
/// <param name="style">
/// Specifies how <see cref="DimAuto"/> will compute the dimension. The default is <see cref="DimAutoStyle.Auto"/>.
/// Specifies how <see cref="Dim.Auto"/> will compute the dimension. The default is <see cref="DimAutoStyle.Auto"/>.
/// </param>
/// <param name="min">Specifies the minimum dimension that view will be automatically sized to.</param>
/// <param name="max">Specifies the maximum dimension that view will be automatically sized to. NOT CURRENTLY SUPPORTED.</param>
public static Dim Auto (DimAutoStyle style = DimAutoStyle.Auto, Dim min = null, Dim max = null)
/// <param name="minimumContentDim">The minimum dimension the View's ContentSize will be constrained to.</param>
/// <param name="maximumContentDim">The maximum dimension the View's ContentSize will be fit to. NOT CURRENTLY SUPPORTED.</param>
public static Dim Auto (DimAutoStyle style = DimAutoStyle.Auto, Dim minimumContentDim = null, Dim maximumContentDim = null)
{
if (max != null)
if (maximumContentDim != null)
{
throw new NotImplementedException (@"max is not implemented");
throw new NotImplementedException (@"maximumContentDim is not implemented");
}
return new DimAuto (style, min, max);
return new DimAuto (style, minimumContentDim, maximumContentDim);
}
/// <summary>Determines whether the specified object is equal to the current object.</summary>
@@ -928,33 +928,33 @@ public class Dim
/// <param name="style">
/// Specifies how <see cref="Dim.DimAuto"/> will compute the dimension. The default is <see cref="Dim.DimAutoStyle.Auto"/>.
/// </param>
/// <param name="min">Specifies the minimum dimension that view will be automatically sized to.</param>
/// <param name="max">Specifies the maximum dimension that view will be automatically sized to. NOT CURRENTLY SUPPORTED.</param>
public class DimAuto (DimAutoStyle style, Dim min, Dim max) : Dim
/// <param name="minimumContentDim">The minimum dimension the View's ContentSize will be constrained to.</param>
/// <param name="maximumContentDim">The maximum dimension the View's ContentSize will be fit to. NOT CURRENTLY SUPPORTED.</param>
public class DimAuto (DimAutoStyle style, Dim minimumContentDim, Dim maximumContentDim) : Dim
{
internal readonly Dim _max = max;
internal readonly Dim _min = min;
internal readonly Dim _minContentDim = minimumContentDim;
internal readonly Dim _maxContentDim = maximumContentDim;
internal readonly DimAutoStyle _style = style;
internal int _size;
/// <inheritdoc />
public override bool Equals (object other) { return other is DimAuto auto && auto._min == _min && auto._max == _max && auto._style == _style; }
public override bool Equals (object other) { return other is DimAuto auto && auto._minContentDim == _minContentDim && auto._maxContentDim == _maxContentDim && auto._style == _style; }
/// <inheritdoc />
public override int GetHashCode () { return HashCode.Combine (base.GetHashCode (), _min, _max, _style); }
public override int GetHashCode () { return HashCode.Combine (base.GetHashCode (), _minContentDim, _maxContentDim, _style); }
/// <inheritdoc />
public override string ToString () { return $"Auto({_style},{_min},{_max})"; }
public override string ToString () { return $"Auto({_style},{_minContentDim},{_maxContentDim})"; }
internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension)
{
if (us == null)
{
return _max?.Anchor (0) ?? 0;
return _maxContentDim?.Anchor (0) ?? 0;
}
var textSize = 0;
var subviewsSize = 0;
int autoMin = _min?.Anchor (superviewContentSize) ?? 0;
int autoMin = _minContentDim?.Anchor (superviewContentSize) ?? 0;
if (superviewContentSize < autoMin)
{
@@ -1005,10 +1005,15 @@ public class Dim
}
}
// All sizes here are content-relative; ignoring adornments.
// We take the larger of text and content.
int max = int.Max (textSize, subviewsSize);
Thickness thickness = us.GetAdornmentsThickness ();
// And, if min: is set, it wins if larger
max = int.Max (max, autoMin);
// Factor in adornments
Thickness thickness = us.GetAdornmentsThickness ();
if (dimension == Dimension.Width)
{
max += thickness.Horizontal;
@@ -1018,8 +1023,8 @@ public class Dim
max += thickness.Vertical;
}
max = int.Max (max, autoMin);
return int.Min (max, _max?.Anchor (superviewContentSize) ?? superviewContentSize);
// If max: is set, clamp the return - BUGBUG: Not tested
return int.Min (max, _maxContentDim?.Anchor (superviewContentSize) ?? superviewContentSize);
}
/// <summary>
@@ -1029,7 +1034,7 @@ public class Dim
internal override bool ReferencesOtherViews ()
{
// BUGBUG: This is not correct. _contentSize may be null.
return _style.HasFlag (Dim.DimAutoStyle.Content);
return false;//_style.HasFlag (Dim.DimAutoStyle.Content);
}
}

View File

@@ -101,12 +101,9 @@ public partial class View
// This is the only place where _frame should be set directly. Use Frame = or SetFrame instead.
_frame = frame;
OnViewportChanged (new (IsInitialized ? Viewport : Rectangle.Empty, oldViewport));
SetTextFormatterSize ();
if (!TextFormatter.AutoSize)
{
TextFormatter.Size = ContentSize;
}
OnViewportChanged (new (IsInitialized ? Viewport : Rectangle.Empty, oldViewport));
}
/// <summary>Gets the <see cref="Frame"/> with a screen-relative location.</summary>
@@ -155,10 +152,10 @@ public partial class View
}
Point superViewViewportOffset = SuperView.GetViewportOffsetFromFrame ();
superViewViewportOffset.Offset(-SuperView.Viewport.X, -SuperView.Viewport.Y);
superViewViewportOffset.Offset (-SuperView.Viewport.X, -SuperView.Viewport.Y);
Point frame = location;
frame.Offset(-superViewViewportOffset.X, -superViewViewportOffset.Y);
frame.Offset (-superViewViewportOffset.X, -superViewViewportOffset.Y);
frame = SuperView.ScreenToFrame (frame);
frame.Offset (-Frame.X, -Frame.Y);
@@ -1033,31 +1030,30 @@ public partial class View
// Diagnostics to highlight when X or Y is read before the view has been initialized
private Pos VerifyIsInitialized (Pos pos, string member)
{
#if DEBUG
if ((pos.ReferencesOtherViews () || pos.ReferencesOtherViews ()) && !IsInitialized)
{
Debug.WriteLine (
$"WARNING: The {pos} of {this} is dependent on other views and {member} "
+ $"is being accessed before the View has been initialized. This is likely a bug."
);
}
#endif // DEBUG
//#if DEBUG
// if (pos.ReferencesOtherViews () && !IsInitialized)
// {
// Debug.WriteLine (
// $"WARNING: {member} = {pos} of {this} is dependent on other views and {member} "
// + $"is being accessed before the View has been initialized. This is likely a bug."
// );
// }
//#endif // DEBUG
return pos;
}
// Diagnostics to highlight when Width or Height is read before the view has been initialized
private Dim VerifyIsInitialized (Dim dim, string member)
{
#if DEBUG
if ((dim.ReferencesOtherViews () || dim.ReferencesOtherViews ()) && !IsInitialized)
{
Debug.WriteLine (
$"WARNING: The {member} of {this} is dependent on other views and is "
+ $"is being accessed before the View has been initialized. This is likely a bug. "
+ $"{member} is {dim}"
);
}
#endif // DEBUG
//#if DEBUG
// if (dim.ReferencesOtherViews () && !IsInitialized)
// {
// Debug.WriteLine (
// $"WARNING: {member} = {dim} of {this} is dependent on other views and {member} "
// + $"is being accessed before the View has been initialized. This is likely a bug."
// );
// }
//#endif // DEBUG
return dim;
}
@@ -1087,13 +1083,13 @@ public partial class View
// Verify none of the subviews are using Dim objects that depend on the SuperView's dimensions.
foreach (View view in Subviews)
{
if (Width is Dim.DimAuto { _min: null })
if (Width is Dim.DimAuto { _minContentDim: null })
{
ThrowInvalid (view, view.Width, nameof (view.Width));
ThrowInvalid (view, view.X, nameof (view.X));
}
if (Height is Dim.DimAuto { _min: null })
if (Height is Dim.DimAuto { _minContentDim: null })
{
ThrowInvalid (view, view.Height, nameof (view.Height));
ThrowInvalid (view, view.Y, nameof (view.Y));

View File

@@ -186,8 +186,8 @@ public partial class View
// Use _width & _height instead of Width & Height to avoid debug spew
Dim.DimAuto widthAuto = _width as Dim.DimAuto;
Dim.DimAuto heightAuto = _height as Dim.DimAuto;
if ((widthAuto is {} && widthAuto._style.HasFlag (Dim.DimAutoStyle.Text))
|| (heightAuto is {} && heightAuto._style.HasFlag (Dim.DimAutoStyle.Text)))
if ((widthAuto is { } && widthAuto._style.HasFlag (Dim.DimAutoStyle.Text))
|| (heightAuto is { } && heightAuto._style.HasFlag (Dim.DimAutoStyle.Text)))
{
size = TextFormatter.GetAutoSize ();

View File

@@ -45,8 +45,8 @@ public class Button : View
_leftDefault = Glyphs.LeftDefaultIndicator;
_rightDefault = Glyphs.RightDefaultIndicator;
Height = Dim.Auto (Dim.DimAutoStyle.Text);
Width = Dim.Auto (Dim.DimAutoStyle.Text);
Height = Dim.Auto (Dim.DimAutoStyle.Text, minimumContentDim: 1);
CanFocus = true;
HighlightStyle |= HighlightStyle.Pressed;

View File

@@ -20,8 +20,8 @@ public class CheckBox : View
_charChecked = Glyphs.Checked;
_charUnChecked = Glyphs.UnChecked;
Height = Dim.Auto (Dim.DimAutoStyle.Text);
Width = Dim.Auto (Dim.DimAutoStyle.Text);
Height = Dim.Auto (Dim.DimAutoStyle.Text, minimumContentDim: 1);
CanFocus = true;

View File

@@ -61,7 +61,7 @@ public class ProgressBar : View
set
{
_bidirectionalMarquee = value;
SetContentSize (Viewport.Size with { Height = 1 });
// SetContentSize (Viewport.Size with { Height = 1 });
}
}
@@ -74,7 +74,7 @@ public class ProgressBar : View
{
_fraction = Math.Min (value, 1);
_isActivity = false;
SetContentSize (Viewport.Size with { Height = 1 });
// SetContentSize (Viewport.Size with { Height = 1 });
}
}
@@ -87,7 +87,7 @@ public class ProgressBar : View
set
{
_progressBarFormat = value;
SetContentSize (Viewport.Size with { Height = 1 });
// SetContentSize (Viewport.Size with { Height = 1 });
}
}
@@ -119,7 +119,7 @@ public class ProgressBar : View
break;
}
SetContentSize (Viewport.Size with { Height = 1 });
// SetContentSize (Viewport.Size with { Height = 1 });
}
}
@@ -130,7 +130,7 @@ public class ProgressBar : View
set
{
_segmentCharacter = value;
SetContentSize (Viewport.Size with { Height = 1 });
// SetContentSize (Viewport.Size with { Height = 1 });
}
}
@@ -279,7 +279,7 @@ public class ProgressBar : View
private void ProgressBar_Initialized (object sender, EventArgs e)
{
SetContentSize (Viewport.Size with { Height = 1 });
// SetContentSize (Viewport.Size with { Height = 1 });
ColorScheme = new ColorScheme (ColorScheme ?? SuperView?.ColorScheme ?? Colors.ColorSchemes ["Base"])
{
@@ -289,7 +289,7 @@ public class ProgressBar : View
private void SetInitialProperties ()
{
Height = Dim.Auto (Dim.DimAutoStyle.Content);
Height = Dim.Auto (Dim.DimAutoStyle.Content, minimumContentDim: 1);
CanFocus = false;
_fraction = 0;
Initialized += ProgressBar_Initialized;

View File

@@ -407,7 +407,7 @@ public class AllViewsTester : Scenario
view.Width = _wRadioGroup.SelectedItem switch
{
0 => Dim.Auto (min: _wVal),
0 => Dim.Auto (minimumContentDim: _wVal),
1 => Dim.Percent (_wVal),
2 => Dim.Fill (_wVal),
3 => Dim.Sized (_wVal),
@@ -416,7 +416,7 @@ public class AllViewsTester : Scenario
view.Height = _hRadioGroup.SelectedItem switch
{
0 => Dim.Auto (min: _hVal),
0 => Dim.Auto (minimumContentDim: _hVal),
1 => Dim.Percent (_hVal),
2 => Dim.Fill (_hVal),
3 => Dim.Sized (_hVal),

View File

@@ -15,17 +15,19 @@ public class DimAutoDemo : Scenario
// Setup - Create a top-level application window and configure it.
Window appWindow = new ()
{
Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}"
Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}",
};
appWindow.Padding.Thickness = new Thickness (1);
var view = new FrameView
{
Title = "Type to make View grow",
X = 1,
Y = 1,
Width = Auto (DimAutoStyle.Content, 40),
Height = Auto (DimAutoStyle.Content, 10)
X = 0,
Y = 0,
Width = Auto (DimAutoStyle.Content, minimumContentDim: Dim.Percent (25)),
Height = Auto (DimAutoStyle.Content, minimumContentDim: 10)
};
view.Margin.Thickness = new Thickness (1);
view.ValidatePosDim = true;
var textEdit = new TextView
@@ -110,7 +112,7 @@ public class DimAutoDemo : Scenario
var movingButton = new Button
{
Text = "_Move down",
Text = "_Click\nTo Move\nDown",
X = Pos.Right (vlabel),
Y = Pos.Bottom (vlabel)
};
@@ -121,7 +123,7 @@ public class DimAutoDemo : Scenario
{
Text = "_Reset Button (AnchorEnd)",
X = Pos.AnchorEnd (),
Y = Pos.Top (movingButton)
Y = Pos.AnchorEnd ()
};
resetButton.Accept += (s, e) => { movingButton.Y = Pos.Bottom (hlabel); };
@@ -150,7 +152,7 @@ public class DimAutoDemo : Scenario
var dlg = new Dialog
{
Title = "Test Dialog",
Width = Auto (min: Percent (10))
Width = Auto (minimumContentDim: Percent (10))
//Height = Dim.Auto (min: Dim.Percent (50))
};
@@ -158,7 +160,7 @@ public class DimAutoDemo : Scenario
{
ValidatePosDim = true,
Text = "TextField: X=1; Y=Pos.Bottom (label)+1, Width=Dim.Fill (0); Height=1",
TextFormatter = new() { WordWrap = true },
TextFormatter = new () { WordWrap = true },
X = 0,
Y = 0, //Pos.Bottom (label) + 1,
Width = Fill (10),

View File

@@ -52,8 +52,8 @@ public class ProgressBarStyles : Scenario
Title = "Focused ProgressBar",
Y = 0,
X = Pos.Center (),
Width = 30,
Height = 7,
Width = Dim.Auto (),
Height = Dim.Auto (),
BorderStyle = LineStyle.Single
};
@@ -168,7 +168,7 @@ public class ProgressBarStyles : Scenario
Title = "Blocks",
X = Pos.Center (),
Y = Pos.Bottom (button) + 1,
Width = Dim.Width (pbList),
Width = Dim.Percent(50),
BorderStyle = LineStyle.Single,
CanFocus = true
};
@@ -179,7 +179,7 @@ public class ProgressBarStyles : Scenario
Title = "Continuous",
X = Pos.Center (),
Y = Pos.Bottom (blocksPB) + 1,
Width = Dim.Width (pbList),
Width = Dim.Percent (50),
ProgressBarStyle = ProgressBarStyle.Continuous,
BorderStyle = LineStyle.Single,
CanFocus = true
@@ -229,7 +229,7 @@ public class ProgressBarStyles : Scenario
Title = "Marquee Blocks",
X = Pos.Center (),
Y = Pos.Bottom (ckbBidirectional) + 1,
Width = Dim.Width (pbList),
Width = Dim.Percent (50),
ProgressBarStyle = ProgressBarStyle.MarqueeBlocks,
BorderStyle = LineStyle.Single,
CanFocus = true
@@ -241,7 +241,7 @@ public class ProgressBarStyles : Scenario
Title = "Marquee Continuous",
X = Pos.Center (),
Y = Pos.Bottom (marqueesBlocksPB) + 1,
Width = Dim.Width (pbList),
Width = Dim.Percent (50),
ProgressBarStyle = ProgressBarStyle.MarqueeContinuous,
BorderStyle = LineStyle.Single,
CanFocus = true

View File

@@ -42,8 +42,8 @@ public class DimAutoTests (ITestOutputHelper output)
{
X = 0,
Y = 0,
Width = Dim.Auto (min: 10),
Height = Dim.Auto (min: 10),
Width = Dim.Auto (minimumContentDim: 10),
Height = Dim.Auto (minimumContentDim: 10),
ValidatePosDim = true
};
@@ -66,6 +66,68 @@ public class DimAutoTests (ITestOutputHelper output)
Assert.Equal (10, superView.Frame.Height);
}
[Theory]
[InlineData (0, 2, 4)]
[InlineData (1, 2, 4)]
[InlineData (2, 2, 4)]
[InlineData (3, 2, 5)]
[InlineData (1, 0, 3)]
public void Min_Absolute_Is_Content_Relative (int contentSize, int minAbsolute, int expected)
{
var view = new View
{
X = 0,
Y = 0,
Width = Dim.Auto (minimumContentDim: minAbsolute),
BorderStyle = LineStyle.Single, // a 1 thick adornment
ValidatePosDim = true
};
view.SetContentSize (new (contentSize, 0));
Assert.Equal (expected, view.Frame.Width);
}
[Theory]
[InlineData (1, 100, 100)]
[InlineData (1, 50, 50)]
public void Min_Percent (int contentSize, int minPercent, int expected)
{
var view = new View
{
X = 0,
Y = 0,
Width = Dim.Auto (minimumContentDim: Dim.Percent (minPercent)),
ValidatePosDim = true
};
view.SetContentSize (new (contentSize, 0));
view.SetRelativeLayout (new (100, 100));
Assert.Equal (expected, view.Frame.Width);
}
[Theory]
[InlineData (1, 100, 100)]
[InlineData (1, 50, 50)]
public void Min_Percent_Is_Content_Relative (int contentSize, int minPercent, int expected)
{
var view = new View
{
X = 0,
Y = 0,
Width = Dim.Auto (minimumContentDim: Dim.Percent (minPercent)),
BorderStyle = LineStyle.Single, // a 1 thick adornment
ValidatePosDim = true
};
view.SetContentSize (new (contentSize, 0));
view.SetRelativeLayout (new (100, 100));
Assert.Equal (expected, view.Frame.Width);
}
// what happens if DimAuto (min: 10) and the subview moves to a negative coord?
[Fact]
public void Min_Resets_If_Subview_Moves_Negative ()
@@ -74,8 +136,8 @@ public class DimAutoTests (ITestOutputHelper output)
{
X = 0,
Y = 0,
Width = Dim.Auto (min: 10),
Height = Dim.Auto (min: 10),
Width = Dim.Auto (minimumContentDim: 10),
Height = Dim.Auto (minimumContentDim: 10),
ValidatePosDim = true
};
@@ -116,8 +178,8 @@ public class DimAutoTests (ITestOutputHelper output)
{
X = 0,
Y = 0,
Width = Dim.Auto (min: 10),
Height = Dim.Auto (min: 10),
Width = Dim.Auto (minimumContentDim: 10),
Height = Dim.Auto (minimumContentDim: 10),
ValidatePosDim = true
};
@@ -517,7 +579,7 @@ public class DimAutoTests (ITestOutputHelper output)
{
X = 0,
Y = 0,
Width = Dim.Auto (min: min),
Width = Dim.Auto (minimumContentDim: min),
Height = 1,
ValidatePosDim = true
};
@@ -548,7 +610,7 @@ public class DimAutoTests (ITestOutputHelper output)
{
X = 0,
Y = 0,
Width = Dim.Auto (min: superMinWidth),
Width = Dim.Auto (minimumContentDim: superMinWidth),
Height = 1,
ValidatePosDim = true
};
@@ -692,6 +754,22 @@ public class DimAutoTests (ITestOutputHelper output)
}
// TextFormatter.Size normally tracks ContentSize, but with DimAuto, tracks the text size
[Theory]
[InlineData ("", 0, 0)]
[InlineData (" ", 1, 1)]
[InlineData ("01234", 5, 1)]
public void DimAutoStyle_Text_TextFormatter_Size_Ignores_ContentSize (string text, int expectedW, int expectedH)
{
var view = new View ();
view.Width = Auto (DimAutoStyle.Text);
view.Height = Auto (DimAutoStyle.Text);
view.SetContentSize (new (1, 1));
view.Text = text;
Assert.Equal (new (expectedW, expectedH), view.TextFormatter.Size);
}
// Test that changing TextFormatter does not impact View dimensions if Dim.Auto is not in play
[Fact]
public void Not_Used_TextFormatter_Does_Not_Change_View_Size ()
@@ -1102,8 +1180,8 @@ public class DimAutoTests (ITestOutputHelper output)
[Fact (Skip = "TextOnly")]
public void With_Subview_At_PosAnchorEnd ()
{
var dimWidth = Dim.Auto (min: 50);
var dimHeight = Dim.Auto (min: 50);
var dimWidth = Dim.Auto (minimumContentDim: 50);
var dimHeight = Dim.Auto (minimumContentDim: 50);
var view = new View ()
{

View File

@@ -12,6 +12,31 @@ public class TextTests (ITestOutputHelper output)
{
private readonly ITestOutputHelper _output = output;
// TextFormatter.Size should be empty unless DimAuto is set or ContentSize is set
[Theory]
[InlineData ("", 0, 0)]
[InlineData (" ", 0, 0)]
[InlineData ("01234", 0, 0)]
public void TextFormatter_Size_Default (string text, int expectedW, int expectedH)
{
var view = new View ();
view.Text = text;
Assert.Equal (new (expectedW, expectedH), view.TextFormatter.Size);
}
// TextFormatter.Size should track ContentSize (without DimAuto)
[Theory]
[InlineData ("", 1, 1)]
[InlineData (" ", 1, 1)]
[InlineData ("01234", 1, 1)]
public void TextFormatter_Size_Tracks_ContentSize (string text, int expectedW, int expectedH)
{
var view = new View ();
view.SetContentSize(new (1,1));
view.Text = text;
Assert.Equal (new (expectedW, expectedH), view.TextFormatter.Size);
}
[Fact]
[SetupFakeDriver]
public void Setting_With_Height_Horizontal ()