|
@@ -1,7 +1,6 @@
|
|
|
#nullable enable
|
|
|
|
|
|
using System.ComponentModel;
|
|
|
-using System.Drawing;
|
|
|
|
|
|
namespace Terminal.Gui;
|
|
|
|
|
@@ -31,12 +30,6 @@ public record PosAlign : Pos
|
|
|
/// </summary>
|
|
|
public int? _cachedLocation;
|
|
|
|
|
|
- /// <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.
|
|
|
- /// </summary>
|
|
|
- public int GroupId { get; init; }
|
|
|
-
|
|
|
private readonly Aligner? _aligner;
|
|
|
|
|
|
/// <summary>
|
|
@@ -57,91 +50,64 @@ public record PosAlign : Pos
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // TODO: PosAlign.CalculateMinDimension is a hack. Need to figure out a better way of doing this.
|
|
|
/// <summary>
|
|
|
- /// Aligns the views in <paramref name="views"/> that have the same group ID as <paramref name="groupId"/>.
|
|
|
- /// Updates each view's cached _location.
|
|
|
+ /// Returns the minimum size a group of views with the same <paramref name="groupId"/> can be.
|
|
|
/// </summary>
|
|
|
/// <param name="groupId"></param>
|
|
|
/// <param name="views"></param>
|
|
|
/// <param name="dimension"></param>
|
|
|
- /// <param name="size"></param>
|
|
|
- private static void AlignAndUpdateGroup (int groupId, IList<View> views, Dimension dimension, int size)
|
|
|
+ /// <returns></returns>
|
|
|
+ public static int CalculateMinDimension (int groupId, IList<View> views, Dimension dimension)
|
|
|
{
|
|
|
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 (typeof (PosAlign), out var pos):
|
|
|
-
|
|
|
- if (pos is PosAlign posAlignX && posAlignX.GroupId == groupId)
|
|
|
- {
|
|
|
- return posAlignX;
|
|
|
- }
|
|
|
-
|
|
|
- break;
|
|
|
- case Dimension.Height when v.Y.Has (typeof (PosAlign), out var pos):
|
|
|
- if (pos is PosAlign posAlignY && posAlignY.GroupId == groupId)
|
|
|
- {
|
|
|
- return posAlignY;
|
|
|
- }
|
|
|
-
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- return null;
|
|
|
- })
|
|
|
+ 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 ();
|
|
|
|
|
|
- // PERF: We iterate over viewsInGroup multiple times here.
|
|
|
-
|
|
|
- Aligner? firstInGroup = null;
|
|
|
-
|
|
|
- // Update the dimensionList with the sizes of the views
|
|
|
- for (var index = 0; index < posAligns.Count; index++)
|
|
|
+ if (viewsInGroup.Count == 0)
|
|
|
{
|
|
|
- if (posAligns [index] is { })
|
|
|
- {
|
|
|
- if (firstInGroup is null)
|
|
|
- {
|
|
|
- firstInGroup = posAligns [index]!.Aligner;
|
|
|
- }
|
|
|
-
|
|
|
- dimensionsList.Add (dimension == Dimension.Width ? views [index].Frame.Width : views [index].Frame.Height);
|
|
|
- }
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
- if (firstInGroup is null)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
+ // PERF: We iterate over viewsInGroup multiple times here.
|
|
|
|
|
|
- // Update the first item in the group with the new container size.
|
|
|
- firstInGroup.ContainerSize = size;
|
|
|
+ // Update the dimensionList with the sizes of the views
|
|
|
+ for (var index = 0; index < viewsInGroup.Count; index++)
|
|
|
+ {
|
|
|
+ View view = viewsInGroup [index];
|
|
|
|
|
|
- // Align
|
|
|
- int [] locations = firstInGroup.Align (dimensionsList.ToArray ());
|
|
|
+ PosAlign? posAlign = dimension == Dimension.Width ? view.X as PosAlign : view.Y as PosAlign;
|
|
|
|
|
|
- // Update the cached location for each item
|
|
|
- for (int posIndex = 0, locIndex = 0; posIndex < posAligns.Count; posIndex++)
|
|
|
- {
|
|
|
- if (posAligns [posIndex] is { })
|
|
|
+ if (posAlign is { })
|
|
|
{
|
|
|
- posAligns [posIndex]!._cachedLocation = locations [locIndex++];
|
|
|
+ dimensionsList.Add (dimension == Dimension.Width ? view.Frame.Width : view.Frame.Height);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ // Align
|
|
|
+ return dimensionsList.Sum ();
|
|
|
}
|
|
|
|
|
|
- private void Aligner_PropertyChanged (object? sender, PropertyChangedEventArgs e) { _cachedLocation = null; }
|
|
|
+ /// <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.
|
|
|
+ /// </summary>
|
|
|
+ public int GroupId { get; init; }
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
public override string ToString () { return $"Align(alignment={Aligner.Alignment},modes={Aligner.AlignmentModes},groupId={GroupId})"; }
|
|
|
|
|
|
- internal override int GetAnchor (int width) { return _cachedLocation ?? 0 - width; }
|
|
|
-
|
|
|
internal override int Calculate (int superviewDimension, Dim dim, View us, Dimension dimension)
|
|
|
{
|
|
|
if (_cachedLocation.HasValue && Aligner.ContainerSize == superviewDimension)
|
|
@@ -164,52 +130,85 @@ public record PosAlign : Pos
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- // TODO: PosAlign.CalculateMinDimension is a hack. Need to figure out a better way of doing this.
|
|
|
+ internal override int GetAnchor (int width) { return _cachedLocation ?? 0 - width; }
|
|
|
+
|
|
|
/// <summary>
|
|
|
- /// Returns the minimum size a group of views with the same <paramref name="groupId"/> can be.
|
|
|
+ /// Aligns the views in <paramref name="views"/> that have the same group ID as <paramref name="groupId"/>.
|
|
|
+ /// Updates each view's cached _location.
|
|
|
/// </summary>
|
|
|
/// <param name="groupId"></param>
|
|
|
/// <param name="views"></param>
|
|
|
/// <param name="dimension"></param>
|
|
|
- /// <returns></returns>
|
|
|
- public static int CalculateMinDimension (int groupId, IList<View> views, Dimension dimension)
|
|
|
+ /// <param name="size"></param>
|
|
|
+ private static void AlignAndUpdateGroup (int groupId, IList<View> views, Dimension dimension, int size)
|
|
|
{
|
|
|
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 ();
|
|
|
-
|
|
|
- if (viewsInGroup.Count == 0)
|
|
|
- {
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ List<PosAlign?> posAligns = views.Select (
|
|
|
+ v =>
|
|
|
+ {
|
|
|
+ switch (dimension)
|
|
|
+ {
|
|
|
+ case Dimension.Width when v.X.Has (typeof (PosAlign), out Pos pos):
|
|
|
+
|
|
|
+ if (pos is PosAlign posAlignX && posAlignX.GroupId == groupId)
|
|
|
+ {
|
|
|
+ return posAlignX;
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+ case Dimension.Height when v.Y.Has (typeof (PosAlign), out Pos pos):
|
|
|
+ if (pos is PosAlign posAlignY && posAlignY.GroupId == groupId)
|
|
|
+ {
|
|
|
+ return posAlignY;
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ })
|
|
|
+ .ToList ();
|
|
|
|
|
|
// PERF: We iterate over viewsInGroup multiple times here.
|
|
|
|
|
|
+ Aligner? firstInGroup = null;
|
|
|
+
|
|
|
// Update the dimensionList with the sizes of the views
|
|
|
- for (var index = 0; index < viewsInGroup.Count; index++)
|
|
|
+ for (var index = 0; index < posAligns.Count; index++)
|
|
|
{
|
|
|
- View view = viewsInGroup [index];
|
|
|
-
|
|
|
- PosAlign? posAlign = dimension == Dimension.Width ? view.X as PosAlign : view.Y as PosAlign;
|
|
|
-
|
|
|
- if (posAlign is { })
|
|
|
+ if (posAligns [index] is { })
|
|
|
{
|
|
|
- dimensionsList.Add (dimension == Dimension.Width ? view.Frame.Width : view.Frame.Height);
|
|
|
+ if (firstInGroup is null)
|
|
|
+ {
|
|
|
+ firstInGroup = posAligns [index]!.Aligner;
|
|
|
+ }
|
|
|
+
|
|
|
+ dimensionsList.Add (dimension == Dimension.Width ? views [index].Frame.Width : views [index].Frame.Height);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (firstInGroup is null)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Update the first item in the group with the new container size.
|
|
|
+ firstInGroup.ContainerSize = size;
|
|
|
+
|
|
|
// Align
|
|
|
- return dimensionsList.Sum ();
|
|
|
+ int [] locations = firstInGroup.Align (dimensionsList.ToArray ());
|
|
|
+
|
|
|
+ // Update the cached location for each item
|
|
|
+ for (int posIndex = 0, locIndex = 0; posIndex < posAligns.Count; posIndex++)
|
|
|
+ {
|
|
|
+ if (posAligns [posIndex] is { })
|
|
|
+ {
|
|
|
+ posAligns [posIndex]!._cachedLocation = locations [locIndex++];
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ private void Aligner_PropertyChanged (object? sender, PropertyChangedEventArgs e) { _cachedLocation = null; }
|
|
|
}
|