DimAuto fixes

This commit is contained in:
Tig
2024-10-19 17:37:55 -06:00
parent 2d48bc9d49
commit 2e163eef75
8 changed files with 140 additions and 113 deletions

View File

@@ -238,22 +238,12 @@ public record DimAuto (Dim? MaximumContentDim, Dim? MinimumContentDim, DimAutoSt
List<int> groupIds = includedSubviews.Select (
v =>
{
if (dimension == Dimension.Width)
{
if (v.X.Has<PosAlign> (out Pos posAlign))
{
return ((PosAlign)posAlign).GroupId;
}
}
else
{
if (v.Y.Has<PosAlign> (out Pos posAlign))
{
return ((PosAlign)posAlign).GroupId;
}
}
return -1;
return dimension switch
{
Dimension.Width when v.X.Has<PosAlign> (out PosAlign posAlign) => ((PosAlign)posAlign).GroupId,
Dimension.Height when v.Y.Has<PosAlign> (out PosAlign posAlign) => ((PosAlign)posAlign).GroupId,
_ => -1
};
})
.Distinct ()
.ToList ();
@@ -261,18 +251,7 @@ public record DimAuto (Dim? MaximumContentDim, Dim? MinimumContentDim, DimAutoSt
foreach (int groupId in groupIds.Where (g => g != -1))
{
// PERF: If this proves a perf issue, consider caching a ref to this list in each item
List<PosAlign?> posAlignsInGroup = includedSubviews.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
};
})
List<PosAlign?> posAlignsInGroup = includedSubviews.Where (v => PosAlign.HasGroupId (v, dimension, groupId))
.Select (v => dimension == Dimension.Width ? v.X as PosAlign : v.Y as PosAlign)
.ToList ();
@@ -350,16 +329,9 @@ public record DimAuto (Dim? MaximumContentDim, Dim? MinimumContentDim, DimAutoSt
// BUGBUG: The order may not be correct. May need to call TopologicalSort?
// TODO: Figure out a way to not have Calculate change the state of subviews (calling SRL).
if (dimension == Dimension.Width)
{
v.SetRelativeLayout (new (maxCalculatedSize, 0));
}
else
{
v.SetRelativeLayout (new (0, maxCalculatedSize));
}
int maxPosView = dimension == Dimension.Width ? v.Frame.X + v.Frame.Width : v.Frame.Y + v.Frame.Height;
int maxPosView = dimension == Dimension.Width
? v.Frame.X + v.Width!.Calculate (0, maxCalculatedSize, v, dimension)
: v.Frame.Y + v.Height!.Calculate (0, maxCalculatedSize, v, dimension);
if (maxPosView > maxCalculatedSize)
{
@@ -391,16 +363,9 @@ public record DimAuto (Dim? MaximumContentDim, Dim? MinimumContentDim, DimAutoSt
// BUGBUG: The order may not be correct. May need to call TopologicalSort?
// TODO: Figure out a way to not have Calculate change the state of subviews (calling SRL).
if (dimension == Dimension.Width)
{
v.SetRelativeLayout (new (maxCalculatedSize, 0));
}
else
{
v.SetRelativeLayout (new (0, maxCalculatedSize));
}
int maxDimView = dimension == Dimension.Width ? v.Frame.X + v.Frame.Width : v.Frame.Y + v.Frame.Height;
int maxDimView = dimension == Dimension.Width
? v.Frame.X + v.Width!.Calculate (0, maxCalculatedSize, v, dimension)
: v.Frame.Y + v.Height!.Calculate (0, maxCalculatedSize, v, dimension);
if (maxDimView > maxCalculatedSize)
{
@@ -428,16 +393,9 @@ public record DimAuto (Dim? MaximumContentDim, Dim? MinimumContentDim, DimAutoSt
{
View v = dimAutoSubViews [i];
if (dimension == Dimension.Width)
{
v.SetRelativeLayout (new (maxCalculatedSize, 0));
}
else
{
v.SetRelativeLayout (new (0, maxCalculatedSize));
}
int maxDimAuto= dimension == Dimension.Width ? v.Frame.X + v.Frame.Width : v.Frame.Y + v.Frame.Height;
int maxDimAuto = dimension == Dimension.Width
? v.Frame.X + v.Width!.Calculate (0, maxCalculatedSize, v, dimension)
: v.Frame.Y + v.Height!.Calculate (0, maxCalculatedSize, v, dimension);
if (maxDimAuto > maxCalculatedSize)
{

View File

@@ -335,9 +335,9 @@ public abstract record Pos
/// </summary>
/// <param name="pos">A reference to this <see cref="Pos"/> instance.</param>
/// <returns></returns>
public bool Has<T> (out Pos pos) where T : Pos
public bool Has<T> (out T pos) where T : Pos
{
pos = this;
pos = (this as T)!;
return this switch
{

View File

@@ -63,17 +63,7 @@ public record PosAlign : Pos
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 ();
List<View> viewsInGroup = views.Where (v => HasGroupId (v, dimension, groupId)).ToList ();
if (viewsInGroup.Count == 0)
{
@@ -99,6 +89,16 @@ public record PosAlign : Pos
return dimensionsList.Sum ();
}
internal static bool HasGroupId (View v, Dimension dimension, int groupId)
{
return dimension switch
{
Dimension.Width when v.X.Has<PosAlign> (out PosAlign pos) => pos.GroupId == groupId,
Dimension.Height when v.Y.Has<PosAlign> (out PosAlign pos) => pos.GroupId == groupId,
_ => false
};
}
/// <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.
@@ -115,12 +115,18 @@ public record PosAlign : Pos
return _cachedLocation.Value;
}
IList<View>? groupViews;
if (us.SuperView is null)
{
return 0;
groupViews = new List<View> ();
groupViews.Add (us);
}
else
{
groupViews = us.SuperView!.Subviews;
}
AlignAndUpdateGroup (GroupId, us.SuperView.Subviews, dimension, superviewDimension);
AlignAndUpdateGroup (GroupId, groupViews, dimension, superviewDimension);
if (_cachedLocation.HasValue)
{
@@ -145,31 +151,9 @@ public record PosAlign : Pos
List<int> dimensionsList = new ();
// 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<PosAlign> (out Pos pos):
if (pos is PosAlign posAlignX && posAlignX.GroupId == groupId)
{
return posAlignX;
}
break;
case Dimension.Height when v.Y.Has<PosAlign> (out Pos pos):
if (pos is PosAlign posAlignY && posAlignY.GroupId == groupId)
{
return posAlignY;
}
break;
}
return null;
})
.ToList ();
List<PosAlign?> posAligns = views.Where (v => PosAlign.HasGroupId (v, dimension, groupId))
.Select (v => dimension == Dimension.Width ? v.X as PosAlign : v.Y as PosAlign)
.ToList ();
// PERF: We iterate over viewsInGroup multiple times here.
@@ -185,7 +169,9 @@ public record PosAlign : Pos
firstInGroup = posAligns [index]!.Aligner;
}
dimensionsList.Add (dimension == Dimension.Width ? views [index].Frame.Width : views [index].Frame.Height);
dimensionsList.Add (dimension == Dimension.Width
? views [index].Width!.Calculate(0, size, views [index], dimension)
: views [index].Height!.Calculate (0, size, views [index], dimension));
}
}

View File

@@ -348,7 +348,7 @@ public partial class View // Layout APIs
SetLayoutNeeded ();
if (IsAbsoluteLayout())
if (IsAbsoluteLayout ())
{
// Implicit layout is ok here because all Pos/Dim are Absolute values.
Layout ();
@@ -546,13 +546,24 @@ public partial class View // Layout APIs
/// <returns><see langword="false"/>If the view could not be laid out (typically because a dependencies was not ready). </returns>
public bool Layout (Size contentSize)
{
int bailAfter = 100;
// Note, SetRelativeLayout calls SetTextFormatterSize
if (SetRelativeLayout (contentSize))
{
LayoutSubviews ();
//while (NeedsLayout)
//{
if (SetRelativeLayout (contentSize))
{
LayoutSubviews ();
return true;
}
Debug.Assert(!NeedsLayout);
return true;
}
// if (--bailAfter == 0)
// {
// Debug.Write ($"Layout: After {100} tries, SetRelativeLayout was unable to complete.");
// return false;
// }
//}
return false;
}

View File

@@ -137,10 +137,6 @@ public class Shortcut : View, IOrientation, IDesignable
DimAutoStyle.Content,
Dim.Func (() =>
{
if (Subviews [0].NeedsLayout)
{
// throw new Exception ();
}
return PosAlign.CalculateMinDimension (0, Subviews, Dimension.Width);
}),
Dim.Func (() =>

View File

@@ -45,6 +45,47 @@ public partial class DimAutoTests
#endregion PosAbsolute
#region PosAlign
//[Theory]
//[InlineData (0, 0, 0, 0, 0, 0)]
//[InlineData (0, 19, 0, 9, 19, 9)]
//[InlineData (0, 20, 0, 10, 20, 10)]
//[InlineData (0, 21, 0, 11, 20, 10)]
//[InlineData (1, 21, 1, 11, 20, 10)]
//[InlineData (21, 21, 11, 11, 21, 11)]
//public void With_Subview_Using_PosAlign (int minWidth, int maxWidth, int minHeight, int maxHeight, int expectedWidth, int expectedHeight)
//{
// var view = new View
// {
// Width = Dim.Auto (minimumContentDim: minWidth, maximumContentDim: maxWidth),
// Height = Dim.Auto (minimumContentDim: minHeight, maximumContentDim: maxHeight)
// };
// var subview = new View
// {
// X = Pos.Align (Alignment.Center),
// Y = Pos.Absolute (5),
// Width = 20,
// Height = 10
// };
// view.Add (subview);
// // Assuming the calculation is done after layout
// int calculatedX = view.X.Calculate (100, view.Width, view, Dimension.Width);
// int calculatedY = view.Y.Calculate (100, view.Height, view, Dimension.Height);
// int calculatedWidth = view.Width.Calculate (0, 100, view, Dimension.Width);
// int calculatedHeight = view.Height.Calculate (0, 100, view, Dimension.Height);
// Assert.Equal (expectedWidth, calculatedWidth);
// Assert.Equal (expectedHeight, calculatedHeight);
// Assert.Equal (0, calculatedX);
// Assert.Equal (0, calculatedY);
//}
#endregion PosAlign
#region PosPercent
[Theory]

View File

@@ -106,6 +106,25 @@ public class PosAlignTests
Assert.IsType<PosAlign> (pos);
}
[Fact]
public void PosAlign_Laysout ()
{
var view = new View ()
{
Id = "view",
X = Pos.Align (Alignment.Center),
Width = 1,
Height = 1
};
view.Layout (new (10, 10));
Assert.Equal (4, view.Frame.X);
}
// TODO: Test scenarios where views with matching GroupId's are added/removed from a Superview
// TODO: Make AlignAndUpdateGroup internal and write low-level unit tests for it
[Fact]
public void PosAlign_Set_View_X ()
{
@@ -127,6 +146,18 @@ public class PosAlignTests
view.X = posAlign;
superView.Layout ();
Assert.Equal (4, view.Frame.X);
superView.Remove (view);
view = new View ()
{
Id = "view",
X = posAlign,
Width = 1,
Height = 1
};
superView.Add (view);
superView.Layout ();
Assert.Equal (4, view.Frame.X);
posAlign = Pos.Align (Alignment.End);
view.X = posAlign;

View File

@@ -21,9 +21,9 @@ public class ShortcutTests
{
var shortcut = new Shortcut ();
shortcut.BeginInit();
shortcut.EndInit();
shortcut.EndInit ();
shortcut.Layout ();
Assert.Equal (2, shortcut.Frame.Width);
Assert.Equal (1, shortcut.Frame.Height);
Assert.Equal (2, shortcut.Viewport.Width);
@@ -45,7 +45,9 @@ public class ShortcutTests
Key = Key.A,
HelpText = "0"
};
shortcut.SetRelativeLayout (new (100, 100));
shortcut.BeginInit ();
shortcut.EndInit ();
shortcut.Layout ();
Assert.Equal (8, shortcut.Frame.Width);
Assert.Equal (1, shortcut.Frame.Height);
Assert.Equal (8, shortcut.Viewport.Width);
@@ -68,7 +70,9 @@ public class ShortcutTests
Key = Key.A,
HelpText = "0"
};
shortcut.SetRelativeLayout (new (100, 100));
shortcut.BeginInit ();
shortcut.EndInit ();
shortcut.Layout ();
Assert.Equal (9, shortcut.Frame.Width);
Assert.Equal (1, shortcut.Frame.Height);
Assert.Equal (9, shortcut.Viewport.Width);