729 lines
27 KiB
C#
729 lines
27 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Media;
|
|
using HandyControl.Data;
|
|
using HandyControl.Expression.Drawing;
|
|
using HandyControl.Tools;
|
|
using HandyControl.Tools.Extension;
|
|
|
|
namespace HandyControl.Controls
|
|
{
|
|
public class FlexPanel : Panel
|
|
{
|
|
private UVSize _uvConstraint;
|
|
|
|
private int _lineCount;
|
|
|
|
private readonly List<FlexItemInfo> _orderList = new List<FlexItemInfo>();
|
|
|
|
#region Item
|
|
|
|
public static readonly DependencyProperty OrderProperty = DependencyProperty.RegisterAttached(
|
|
"Order", typeof(int), typeof(FlexPanel),
|
|
new FrameworkPropertyMetadata(ValueBoxes.Int0Box, OnItemPropertyChanged));
|
|
|
|
public static void SetOrder(DependencyObject element, int value)
|
|
=> element.SetValue(OrderProperty, value);
|
|
|
|
public static int GetOrder(DependencyObject element)
|
|
=> (int) element.GetValue(OrderProperty);
|
|
|
|
public static readonly DependencyProperty FlexGrowProperty = DependencyProperty.RegisterAttached(
|
|
"FlexGrow", typeof(double), typeof(FlexPanel),
|
|
new FrameworkPropertyMetadata(ValueBoxes.Double0Box, OnItemPropertyChanged),
|
|
ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
|
|
|
|
public static void SetFlexGrow(DependencyObject element, double value)
|
|
=> element.SetValue(FlexGrowProperty, value);
|
|
|
|
public static double GetFlexGrow(DependencyObject element)
|
|
=> (double) element.GetValue(FlexGrowProperty);
|
|
|
|
public static readonly DependencyProperty FlexShrinkProperty = DependencyProperty.RegisterAttached(
|
|
"FlexShrink", typeof(double), typeof(FlexPanel),
|
|
new FrameworkPropertyMetadata(ValueBoxes.Double1Box, OnItemPropertyChanged),
|
|
ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
|
|
|
|
public static void SetFlexShrink(DependencyObject element, double value)
|
|
=> element.SetValue(FlexShrinkProperty, value);
|
|
|
|
public static double GetFlexShrink(DependencyObject element)
|
|
=> (double) element.GetValue(FlexShrinkProperty);
|
|
|
|
public static readonly DependencyProperty FlexBasisProperty = DependencyProperty.RegisterAttached(
|
|
"FlexBasis", typeof(double), typeof(FlexPanel),
|
|
new FrameworkPropertyMetadata(double.NaN, OnItemPropertyChanged));
|
|
|
|
public static void SetFlexBasis(DependencyObject element, double value)
|
|
=> element.SetValue(FlexBasisProperty, value);
|
|
|
|
public static double GetFlexBasis(DependencyObject element)
|
|
=> (double) element.GetValue(FlexBasisProperty);
|
|
|
|
public static readonly DependencyProperty AlignSelfProperty = DependencyProperty.RegisterAttached(
|
|
"AlignSelf", typeof(FlexItemAlignment), typeof(FlexPanel),
|
|
new FrameworkPropertyMetadata(default(FlexItemAlignment), OnItemPropertyChanged));
|
|
|
|
public static void SetAlignSelf(DependencyObject element, FlexItemAlignment value)
|
|
=> element.SetValue(AlignSelfProperty, value);
|
|
|
|
#endregion
|
|
|
|
#region Panel
|
|
|
|
public static FlexItemAlignment GetAlignSelf(DependencyObject element)
|
|
=> (FlexItemAlignment) element.GetValue(AlignSelfProperty);
|
|
|
|
public static readonly DependencyProperty FlexDirectionProperty = DependencyProperty.Register(
|
|
"FlexDirection", typeof(FlexDirection), typeof(FlexPanel),
|
|
new FrameworkPropertyMetadata(default(FlexDirection), FrameworkPropertyMetadataOptions.AffectsMeasure));
|
|
|
|
public FlexDirection FlexDirection
|
|
{
|
|
get => (FlexDirection) GetValue(FlexDirectionProperty);
|
|
set => SetValue(FlexDirectionProperty, value);
|
|
}
|
|
|
|
public static readonly DependencyProperty FlexWrapProperty = DependencyProperty.Register(
|
|
"FlexWrap", typeof(FlexWrap), typeof(FlexPanel),
|
|
new FrameworkPropertyMetadata(default(FlexWrap), FrameworkPropertyMetadataOptions.AffectsMeasure));
|
|
|
|
public FlexWrap FlexWrap
|
|
{
|
|
get => (FlexWrap) GetValue(FlexWrapProperty);
|
|
set => SetValue(FlexWrapProperty, value);
|
|
}
|
|
|
|
public static readonly DependencyProperty JustifyContentProperty = DependencyProperty.Register(
|
|
"JustifyContent", typeof(FlexContentJustify), typeof(FlexPanel),
|
|
new FrameworkPropertyMetadata(default(FlexContentJustify),
|
|
FrameworkPropertyMetadataOptions.AffectsMeasure));
|
|
|
|
public FlexContentJustify JustifyContent
|
|
{
|
|
get => (FlexContentJustify) GetValue(JustifyContentProperty);
|
|
set => SetValue(JustifyContentProperty, value);
|
|
}
|
|
|
|
public static readonly DependencyProperty AlignItemsProperty = DependencyProperty.Register(
|
|
"AlignItems", typeof(FlexItemsAlignment), typeof(FlexPanel),
|
|
new FrameworkPropertyMetadata(default(FlexItemsAlignment),
|
|
FrameworkPropertyMetadataOptions.AffectsMeasure));
|
|
|
|
public FlexItemsAlignment AlignItems
|
|
{
|
|
get => (FlexItemsAlignment) GetValue(AlignItemsProperty);
|
|
set => SetValue(AlignItemsProperty, value);
|
|
}
|
|
|
|
public static readonly DependencyProperty AlignContentProperty = DependencyProperty.Register(
|
|
"AlignContent", typeof(FlexContentAlignment), typeof(FlexPanel),
|
|
new FrameworkPropertyMetadata(default(FlexContentAlignment),
|
|
FrameworkPropertyMetadataOptions.AffectsMeasure));
|
|
|
|
public FlexContentAlignment AlignContent
|
|
{
|
|
get => (FlexContentAlignment) GetValue(AlignContentProperty);
|
|
set => SetValue(AlignContentProperty, value);
|
|
}
|
|
|
|
#endregion
|
|
|
|
private static void OnItemPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
if (d is UIElement element)
|
|
{
|
|
if (VisualTreeHelper.GetParent(element) is FlexPanel p)
|
|
{
|
|
p.InvalidateMeasure();
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override Size MeasureOverride(Size constraint)
|
|
{
|
|
var flexDirection = FlexDirection;
|
|
var flexWrap = FlexWrap;
|
|
|
|
var curLineSize = new UVSize(flexDirection);
|
|
var panelSize = new UVSize(flexDirection);
|
|
_uvConstraint = new UVSize(flexDirection, constraint);
|
|
var childConstraint = new Size(constraint.Width, constraint.Height);
|
|
_lineCount = 1;
|
|
var children = InternalChildren;
|
|
|
|
_orderList.Clear();
|
|
for (var i = 0; i < children.Count; i++)
|
|
{
|
|
var child = children[i];
|
|
if (child == null) continue;
|
|
|
|
_orderList.Add(new FlexItemInfo(i, GetOrder(child)));
|
|
}
|
|
|
|
_orderList.Sort();
|
|
|
|
for (var i = 0; i < children.Count; i++)
|
|
{
|
|
var child = children[_orderList[i].Index];
|
|
if (child == null) continue;
|
|
|
|
var flexBasis = GetFlexBasis(child);
|
|
if (!flexBasis.IsNaN())
|
|
{
|
|
child.SetCurrentValue(WidthProperty, flexBasis);
|
|
}
|
|
child.Measure(childConstraint);
|
|
|
|
var sz = new UVSize(flexDirection, child.DesiredSize);
|
|
|
|
if (flexWrap == FlexWrap.NoWrap) //continue to accumulate a line
|
|
{
|
|
curLineSize.U += sz.U;
|
|
curLineSize.V = Math.Max(sz.V, curLineSize.V);
|
|
}
|
|
else
|
|
{
|
|
if (MathHelper.GreaterThan(curLineSize.U + sz.U, _uvConstraint.U)) //need to switch to another line
|
|
{
|
|
panelSize.U = Math.Max(curLineSize.U, panelSize.U);
|
|
panelSize.V += curLineSize.V;
|
|
curLineSize = sz;
|
|
_lineCount++;
|
|
|
|
if (MathHelper.GreaterThan(sz.U, _uvConstraint.U)) //the element is wider then the constrint - give it a separate line
|
|
{
|
|
panelSize.U = Math.Max(sz.U, panelSize.U);
|
|
panelSize.V += sz.V;
|
|
curLineSize = new UVSize(flexDirection);
|
|
_lineCount++;
|
|
}
|
|
}
|
|
else //continue to accumulate a line
|
|
{
|
|
curLineSize.U += sz.U;
|
|
curLineSize.V = Math.Max(sz.V, curLineSize.V);
|
|
}
|
|
}
|
|
}
|
|
|
|
//the last line size, if any should be added
|
|
panelSize.U = Math.Max(curLineSize.U, panelSize.U);
|
|
panelSize.V += curLineSize.V;
|
|
|
|
//go from UV space to W/H space
|
|
return new Size(panelSize.Width, panelSize.Height);
|
|
}
|
|
|
|
protected override Size ArrangeOverride(Size arrangeSize)
|
|
{
|
|
var flexDirection = FlexDirection;
|
|
var flexWrap = FlexWrap;
|
|
var alignContent = AlignContent;
|
|
|
|
var uvFinalSize = new UVSize(flexDirection, arrangeSize);
|
|
if (MathHelper.IsZero(uvFinalSize.U) || MathHelper.IsZero(uvFinalSize.V)) return arrangeSize;
|
|
|
|
// init status
|
|
var children = InternalChildren;
|
|
var lineIndex = 0;
|
|
|
|
var curLineSizeArr = new UVSize[_lineCount];
|
|
curLineSizeArr[0] = new UVSize(flexDirection);
|
|
|
|
var lastInLineArr = new int[_lineCount];
|
|
for (var i = 0; i < _lineCount; i++)
|
|
{
|
|
lastInLineArr[i] = int.MaxValue;
|
|
}
|
|
|
|
// calculate line max U space
|
|
for (var i = 0; i < children.Count; i++)
|
|
{
|
|
var child = children[_orderList[i].Index];
|
|
if (child == null) continue;
|
|
|
|
var sz = new UVSize(flexDirection, child.DesiredSize);
|
|
|
|
if (flexWrap == FlexWrap.NoWrap)
|
|
{
|
|
curLineSizeArr[lineIndex].U += sz.U;
|
|
curLineSizeArr[lineIndex].V = Math.Max(sz.V, curLineSizeArr[lineIndex].V);
|
|
}
|
|
else
|
|
{
|
|
if (MathHelper.GreaterThan(curLineSizeArr[lineIndex].U + sz.U, uvFinalSize.U)) //need to switch to another line
|
|
{
|
|
lastInLineArr[lineIndex] = i;
|
|
lineIndex++;
|
|
curLineSizeArr[lineIndex] = sz;
|
|
|
|
if (MathHelper.GreaterThan(sz.U, uvFinalSize.U)) //the element is wider then the constraint - give it a separate line
|
|
{
|
|
//switch to next line which only contain one element
|
|
lastInLineArr[lineIndex] = i;
|
|
lineIndex++;
|
|
curLineSizeArr[lineIndex] = new UVSize(flexDirection);
|
|
}
|
|
}
|
|
else //continue to accumulate a line
|
|
{
|
|
curLineSizeArr[lineIndex].U += sz.U;
|
|
curLineSizeArr[lineIndex].V = Math.Max(sz.V, curLineSizeArr[lineIndex].V);
|
|
}
|
|
}
|
|
}
|
|
|
|
// init status
|
|
var scaleU = Math.Min(_uvConstraint.U / uvFinalSize.U, 1);
|
|
var firstInLine = 0;
|
|
var wrapReverseAdd = 0;
|
|
var wrapReverseFlag = flexWrap == FlexWrap.WrapReverse ? -1 : 1;
|
|
var accumulatedFlag = flexWrap == FlexWrap.WrapReverse ? 1 : 0;
|
|
var itemsU = .0;
|
|
var accumulatedV = .0;
|
|
var freeV = uvFinalSize.V;
|
|
foreach (var flexSize in curLineSizeArr)
|
|
{
|
|
freeV -= flexSize.V;
|
|
}
|
|
|
|
var freeItemV = freeV;
|
|
|
|
// calculate status
|
|
var lineFreeVArr = new double[_lineCount];
|
|
switch (alignContent)
|
|
{
|
|
case FlexContentAlignment.Stretch:
|
|
if (_lineCount > 1)
|
|
{
|
|
freeItemV = freeV / _lineCount;
|
|
for (var i = 0; i < _lineCount; i++)
|
|
{
|
|
lineFreeVArr[i] = freeItemV;
|
|
}
|
|
|
|
accumulatedV = flexWrap == FlexWrap.WrapReverse ? uvFinalSize.V - curLineSizeArr[0].V - lineFreeVArr[0] : 0;
|
|
}
|
|
|
|
break;
|
|
case FlexContentAlignment.FlexStart:
|
|
wrapReverseAdd = flexWrap == FlexWrap.WrapReverse ? 0 : 1;
|
|
if (_lineCount > 1)
|
|
{
|
|
accumulatedV = flexWrap == FlexWrap.WrapReverse ? uvFinalSize.V - curLineSizeArr[0].V : 0;
|
|
}
|
|
else
|
|
{
|
|
wrapReverseAdd = 0;
|
|
}
|
|
|
|
break;
|
|
case FlexContentAlignment.FlexEnd:
|
|
wrapReverseAdd = flexWrap == FlexWrap.WrapReverse ? 1 : 0;
|
|
if (_lineCount > 1)
|
|
{
|
|
accumulatedV = flexWrap == FlexWrap.WrapReverse ? uvFinalSize.V - curLineSizeArr[0].V - freeV : freeV;
|
|
}
|
|
else
|
|
{
|
|
wrapReverseAdd = 0;
|
|
}
|
|
|
|
break;
|
|
case FlexContentAlignment.Center:
|
|
if (_lineCount > 1)
|
|
{
|
|
accumulatedV = flexWrap == FlexWrap.WrapReverse ? uvFinalSize.V - curLineSizeArr[0].V - freeV * 0.5 : freeV * 0.5;
|
|
}
|
|
|
|
break;
|
|
case FlexContentAlignment.SpaceBetween:
|
|
if (_lineCount > 1)
|
|
{
|
|
freeItemV = freeV / (_lineCount - 1);
|
|
for (var i = 0; i < _lineCount - 1; i++)
|
|
{
|
|
lineFreeVArr[i] = freeItemV;
|
|
}
|
|
|
|
accumulatedV = flexWrap == FlexWrap.WrapReverse ? uvFinalSize.V - curLineSizeArr[0].V : 0;
|
|
}
|
|
|
|
break;
|
|
case FlexContentAlignment.SpaceAround:
|
|
if (_lineCount > 1)
|
|
{
|
|
freeItemV = freeV / _lineCount * 0.5;
|
|
for (var i = 0; i < _lineCount - 1; i++)
|
|
{
|
|
lineFreeVArr[i] = freeItemV * 2;
|
|
}
|
|
|
|
accumulatedV = flexWrap == FlexWrap.WrapReverse ? uvFinalSize.V - curLineSizeArr[0].V - freeItemV : freeItemV;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// clear status
|
|
lineIndex = 0;
|
|
|
|
// arrange line
|
|
for (var i = 0; i < children.Count; i++)
|
|
{
|
|
var child = children[_orderList[i].Index];
|
|
if (child == null) continue;
|
|
|
|
var sz = new UVSize(flexDirection, child.DesiredSize);
|
|
|
|
if (flexWrap != FlexWrap.NoWrap)
|
|
{
|
|
if (i >= lastInLineArr[lineIndex]) //need to switch to another line
|
|
{
|
|
ArrangeLine(new FlexLineInfo
|
|
{
|
|
ItemsU = itemsU,
|
|
OffsetV = accumulatedV + freeItemV * wrapReverseAdd,
|
|
LineV = curLineSizeArr[lineIndex].V,
|
|
LineFreeV = freeItemV,
|
|
LineU = uvFinalSize.U,
|
|
ItemStartIndex = firstInLine,
|
|
ItemEndIndex = i,
|
|
ScaleU = scaleU
|
|
});
|
|
|
|
accumulatedV += (lineFreeVArr[lineIndex] + curLineSizeArr[lineIndex + accumulatedFlag].V) * wrapReverseFlag;
|
|
lineIndex++;
|
|
itemsU = 0;
|
|
|
|
if (i >= lastInLineArr[lineIndex]) //the element is wider then the constraint - give it a separate line
|
|
{
|
|
//switch to next line which only contain one element
|
|
ArrangeLine(new FlexLineInfo
|
|
{
|
|
ItemsU = itemsU,
|
|
OffsetV = accumulatedV + freeItemV * wrapReverseAdd,
|
|
LineV = curLineSizeArr[lineIndex].V,
|
|
LineFreeV = freeItemV,
|
|
LineU = uvFinalSize.U,
|
|
ItemStartIndex = i,
|
|
ItemEndIndex = ++i,
|
|
ScaleU = scaleU
|
|
});
|
|
|
|
accumulatedV += (lineFreeVArr[lineIndex] + curLineSizeArr[lineIndex + accumulatedFlag].V) * wrapReverseFlag;
|
|
lineIndex++;
|
|
itemsU = 0;
|
|
}
|
|
|
|
firstInLine = i;
|
|
}
|
|
}
|
|
|
|
itemsU += sz.U;
|
|
}
|
|
|
|
// arrange the last line, if any
|
|
if (firstInLine < children.Count)
|
|
{
|
|
ArrangeLine(new FlexLineInfo
|
|
{
|
|
ItemsU = itemsU,
|
|
OffsetV = accumulatedV + freeItemV * wrapReverseAdd,
|
|
LineV = curLineSizeArr[lineIndex].V,
|
|
LineFreeV = freeItemV,
|
|
LineU = uvFinalSize.U,
|
|
ItemStartIndex = firstInLine,
|
|
ItemEndIndex = children.Count,
|
|
ScaleU = scaleU
|
|
});
|
|
}
|
|
|
|
return arrangeSize;
|
|
}
|
|
|
|
private void ArrangeLine(FlexLineInfo lineInfo)
|
|
{
|
|
var flexDirection = FlexDirection;
|
|
var flexWrap = FlexWrap;
|
|
var justifyContent = JustifyContent;
|
|
var alignItems = AlignItems;
|
|
|
|
var isHorizontal = flexDirection == FlexDirection.Row || flexDirection == FlexDirection.RowReverse;
|
|
var isReverse = flexDirection == FlexDirection.RowReverse || flexDirection == FlexDirection.ColumnReverse;
|
|
var itemCount = lineInfo.ItemEndIndex - lineInfo.ItemStartIndex;
|
|
var children = InternalChildren;
|
|
var lineFreeU = lineInfo.LineU - lineInfo.ItemsU;
|
|
var constraintFreeU = _uvConstraint.U - lineInfo.ItemsU;
|
|
|
|
// calculate initial u
|
|
var u = .0;
|
|
if (isReverse)
|
|
{
|
|
u = justifyContent switch
|
|
{
|
|
FlexContentJustify.FlexStart => lineInfo.LineU,
|
|
FlexContentJustify.SpaceBetween => lineInfo.LineU,
|
|
FlexContentJustify.SpaceAround => lineInfo.LineU,
|
|
FlexContentJustify.FlexEnd => lineInfo.ItemsU,
|
|
FlexContentJustify.Center => (lineInfo.LineU + lineInfo.ItemsU) * 0.5,
|
|
_ => u
|
|
};
|
|
}
|
|
else
|
|
{
|
|
u = justifyContent switch
|
|
{
|
|
FlexContentJustify.FlexEnd => lineFreeU,
|
|
FlexContentJustify.Center => lineFreeU * 0.5,
|
|
_ => u
|
|
};
|
|
}
|
|
|
|
u *= lineInfo.ScaleU;
|
|
|
|
// apply FlexGrow
|
|
var flexGrowUArr = new double[itemCount];
|
|
if (constraintFreeU > 0)
|
|
{
|
|
var ignoreFlexGrow = true;
|
|
var flexGrowSum = .0;
|
|
|
|
for (var i = 0; i < itemCount; i++)
|
|
{
|
|
var flexGrow = GetFlexGrow(children[_orderList[i].Index]);
|
|
ignoreFlexGrow &= MathHelper.IsVerySmall(flexGrow);
|
|
flexGrowUArr[i] = flexGrow;
|
|
flexGrowSum += flexGrow;
|
|
}
|
|
|
|
if (!ignoreFlexGrow)
|
|
{
|
|
var flexGrowItem = .0;
|
|
if (flexGrowSum > 0)
|
|
{
|
|
flexGrowItem = constraintFreeU / flexGrowSum;
|
|
lineInfo.ScaleU = 1;
|
|
lineFreeU = 0; //line free U was used up
|
|
}
|
|
|
|
for (var i = 0; i < itemCount; i++)
|
|
{
|
|
flexGrowUArr[i] *= flexGrowItem;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
flexGrowUArr = new double[itemCount];
|
|
}
|
|
}
|
|
|
|
// apply FlexShrink
|
|
var flexShrinkUArr = new double[itemCount];
|
|
if (constraintFreeU < 0)
|
|
{
|
|
var ignoreFlexShrink = true;
|
|
var flexShrinkSum = .0;
|
|
|
|
for (var i = 0; i < itemCount; i++)
|
|
{
|
|
var flexShrink = GetFlexShrink(children[_orderList[i].Index]);
|
|
ignoreFlexShrink &= MathHelper.IsVerySmall(flexShrink - 1);
|
|
flexShrinkUArr[i] = flexShrink;
|
|
flexShrinkSum += flexShrink;
|
|
}
|
|
|
|
if (!ignoreFlexShrink)
|
|
{
|
|
var flexShrinkItem = .0;
|
|
if (flexShrinkSum > 0)
|
|
{
|
|
flexShrinkItem = constraintFreeU / flexShrinkSum;
|
|
lineInfo.ScaleU = 1;
|
|
lineFreeU = 0; //line free U was used up
|
|
}
|
|
|
|
for (var i = 0; i < itemCount; i++)
|
|
{
|
|
flexShrinkUArr[i] *= flexShrinkItem;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
flexShrinkUArr = new double[itemCount];
|
|
}
|
|
}
|
|
|
|
// calculate offset u
|
|
var offsetUArr = new double[itemCount];
|
|
if (lineFreeU > 0)
|
|
{
|
|
if (justifyContent == FlexContentJustify.SpaceBetween)
|
|
{
|
|
var freeItemU = lineFreeU / (itemCount - 1);
|
|
for (var i = 1; i < itemCount; i++)
|
|
{
|
|
offsetUArr[i] = freeItemU;
|
|
}
|
|
}
|
|
else if (justifyContent == FlexContentJustify.SpaceAround)
|
|
{
|
|
var freeItemU = lineFreeU / itemCount * 0.5;
|
|
offsetUArr[0] = freeItemU;
|
|
for (var i = 1; i < itemCount; i++)
|
|
{
|
|
offsetUArr[i] = freeItemU * 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
// arrange item
|
|
for (int i = lineInfo.ItemStartIndex, j = 0; i < lineInfo.ItemEndIndex; i++, j++)
|
|
{
|
|
var child = children[_orderList[i].Index];
|
|
if (child == null) continue;
|
|
|
|
var childSize = new UVSize(flexDirection, isHorizontal
|
|
? new Size(child.DesiredSize.Width * lineInfo.ScaleU, child.DesiredSize.Height)
|
|
: new Size(child.DesiredSize.Width, child.DesiredSize.Height * lineInfo.ScaleU));
|
|
|
|
childSize.U += flexGrowUArr[j] + flexShrinkUArr[j];
|
|
|
|
if (isReverse)
|
|
{
|
|
u -= childSize.U;
|
|
u -= offsetUArr[j];
|
|
}
|
|
else
|
|
{
|
|
u += offsetUArr[j];
|
|
}
|
|
|
|
var v = lineInfo.OffsetV;
|
|
var alignSelf = GetAlignSelf(child);
|
|
var alignment = alignSelf == FlexItemAlignment.Auto ? alignItems : (FlexItemsAlignment) alignSelf;
|
|
|
|
switch (alignment)
|
|
{
|
|
case FlexItemsAlignment.Stretch:
|
|
if (_lineCount == 1 && flexWrap == FlexWrap.NoWrap)
|
|
{
|
|
childSize.V = lineInfo.LineV + lineInfo.LineFreeV;
|
|
}
|
|
else
|
|
{
|
|
childSize.V = lineInfo.LineV;
|
|
}
|
|
|
|
break;
|
|
case FlexItemsAlignment.FlexEnd:
|
|
v += lineInfo.LineV - childSize.V;
|
|
break;
|
|
case FlexItemsAlignment.Center:
|
|
v += (lineInfo.LineV - childSize.V) * 0.5;
|
|
break;
|
|
}
|
|
|
|
child.Arrange(isHorizontal ? new Rect(u, v, childSize.U, childSize.V) : new Rect(v, u, childSize.V, childSize.U));
|
|
|
|
if (!isReverse)
|
|
{
|
|
u += childSize.U;
|
|
}
|
|
}
|
|
}
|
|
|
|
private readonly struct FlexItemInfo : IComparable<FlexItemInfo>
|
|
{
|
|
public FlexItemInfo(int index, int order)
|
|
{
|
|
Index = index;
|
|
Order = order;
|
|
}
|
|
|
|
private int Order { get; }
|
|
|
|
public int Index { get; }
|
|
|
|
public int CompareTo(FlexItemInfo other) => Order.CompareTo(other.Order);
|
|
}
|
|
|
|
private struct FlexLineInfo
|
|
{
|
|
public double ItemsU { get; set; }
|
|
|
|
public double OffsetV { get; set; }
|
|
|
|
public double LineU { get; set; }
|
|
|
|
public double LineV { get; set; }
|
|
|
|
public double LineFreeV { get; set; }
|
|
|
|
public int ItemStartIndex { get; set; }
|
|
|
|
public int ItemEndIndex { get; set; }
|
|
|
|
public double ScaleU { get; set; }
|
|
}
|
|
|
|
private struct UVSize
|
|
{
|
|
public UVSize(FlexDirection direction, Size size)
|
|
{
|
|
U = V = 0d;
|
|
FlexDirection = direction;
|
|
Width = size.Width;
|
|
Height = size.Height;
|
|
}
|
|
|
|
public UVSize(FlexDirection direction)
|
|
{
|
|
U = V = 0d;
|
|
FlexDirection = direction;
|
|
}
|
|
|
|
public double U { get; set; }
|
|
|
|
public double V { get; set; }
|
|
|
|
private FlexDirection FlexDirection { get; }
|
|
|
|
public double Width
|
|
{
|
|
get => FlexDirection == FlexDirection.Row || FlexDirection == FlexDirection.RowReverse ? U : V;
|
|
private set
|
|
{
|
|
if (FlexDirection == FlexDirection.Row || FlexDirection == FlexDirection.RowReverse)
|
|
{
|
|
U = value;
|
|
}
|
|
else
|
|
{
|
|
V = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
public double Height
|
|
{
|
|
get => FlexDirection == FlexDirection.Row || FlexDirection == FlexDirection.RowReverse ? V : U;
|
|
private set
|
|
{
|
|
if (FlexDirection == FlexDirection.Row || FlexDirection == FlexDirection.RowReverse)
|
|
{
|
|
V = value;
|
|
}
|
|
else
|
|
{
|
|
U = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|