mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-27 08:17:53 +01:00
DimAuto fixes
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 (() =>
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user