|
|
|
@ -92,109 +92,127 @@ namespace Avalonia.Controls |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private UVSize CreateUVSize(Size size) => new UVSize(Orientation, size); |
|
|
|
|
|
|
|
private UVSize CreateUVSize() => new UVSize(Orientation); |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
protected override Size MeasureOverride(Size availableSize) |
|
|
|
protected override Size MeasureOverride(Size constraint) |
|
|
|
{ |
|
|
|
var desiredSize = CreateUVSize(); |
|
|
|
var lineSize = CreateUVSize(); |
|
|
|
var uvAvailableSize = CreateUVSize(availableSize); |
|
|
|
var curLineSize = new UVSize(Orientation); |
|
|
|
var panelSize = new UVSize(Orientation); |
|
|
|
var uvConstraint = new UVSize(Orientation, constraint.Width, constraint.Height); |
|
|
|
|
|
|
|
foreach (var child in Children) |
|
|
|
var childConstraint = new Size(constraint.Width, constraint.Height); |
|
|
|
|
|
|
|
for (int i = 0, count = Children.Count; i < count; i++) |
|
|
|
{ |
|
|
|
child.Measure(availableSize); |
|
|
|
var childSize = CreateUVSize(child.DesiredSize); |
|
|
|
if (lineSize.U + childSize.U <= uvAvailableSize.U) // same line
|
|
|
|
var child = Children[i]; |
|
|
|
if (child == null) continue; |
|
|
|
|
|
|
|
//Flow passes its own constrint to children
|
|
|
|
child.Measure(childConstraint); |
|
|
|
|
|
|
|
//this is the size of the child in UV space
|
|
|
|
var sz = new UVSize(Orientation, child.DesiredSize.Width, child.DesiredSize.Height); |
|
|
|
|
|
|
|
if ((curLineSize.U + sz.U) > uvConstraint.U) //need to switch to another line
|
|
|
|
{ |
|
|
|
lineSize.U += childSize.U; |
|
|
|
lineSize.V = Max(lineSize.V, childSize.V); |
|
|
|
panelSize.U = Max(curLineSize.U, panelSize.U); |
|
|
|
panelSize.V += curLineSize.V; |
|
|
|
curLineSize = sz; |
|
|
|
|
|
|
|
if (sz.U > uvConstraint.U) //the element is wider then the constrint - give it a separate line
|
|
|
|
{ |
|
|
|
panelSize.U = Max(sz.U, panelSize.U); |
|
|
|
panelSize.V += sz.V; |
|
|
|
curLineSize = new UVSize(Orientation); |
|
|
|
} |
|
|
|
} |
|
|
|
else // moving to next line
|
|
|
|
else //continue to accumulate a line
|
|
|
|
{ |
|
|
|
desiredSize.U = Max(lineSize.U, uvAvailableSize.U); |
|
|
|
desiredSize.V += lineSize.V; |
|
|
|
lineSize = childSize; |
|
|
|
curLineSize.U += sz.U; |
|
|
|
curLineSize.V = Max(sz.V, curLineSize.V); |
|
|
|
} |
|
|
|
} |
|
|
|
// last element
|
|
|
|
desiredSize.U = Max(lineSize.U, desiredSize.U); |
|
|
|
desiredSize.V += lineSize.V; |
|
|
|
|
|
|
|
return desiredSize.ToSize(); |
|
|
|
//the last line size, if any should be added
|
|
|
|
panelSize.U = Max(curLineSize.U, panelSize.U); |
|
|
|
panelSize.V += curLineSize.V; |
|
|
|
|
|
|
|
//go from UV space to W/H space
|
|
|
|
return new Size(panelSize.Width, panelSize.Height); |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
protected override Size ArrangeOverride(Size finalSize) |
|
|
|
{ |
|
|
|
int firstInLine = 0; |
|
|
|
double accumulatedV = 0; |
|
|
|
var uvFinalSize = CreateUVSize(finalSize); |
|
|
|
var lineSize = CreateUVSize(); |
|
|
|
int firstChildInLineIndex = 0; |
|
|
|
for (int index = 0; index < Children.Count; index++) |
|
|
|
UVSize curLineSize = new UVSize(Orientation); |
|
|
|
UVSize uvFinalSize = new UVSize(Orientation, finalSize.Width, finalSize.Height); |
|
|
|
|
|
|
|
for (int i = 0; i < Children.Count; i++) |
|
|
|
{ |
|
|
|
var child = Children[index]; |
|
|
|
var childSize = CreateUVSize(child.DesiredSize); |
|
|
|
if (lineSize.U + childSize.U <= uvFinalSize.U) // same line
|
|
|
|
var child = Children[i]; |
|
|
|
if (child == null) continue; |
|
|
|
|
|
|
|
var sz = new UVSize(Orientation, child.DesiredSize.Width, child.DesiredSize.Height); |
|
|
|
|
|
|
|
if ((curLineSize.U + sz.U) > uvFinalSize.U) //need to switch to another line
|
|
|
|
{ |
|
|
|
lineSize.U += childSize.U; |
|
|
|
lineSize.V = Max(lineSize.V, childSize.V); |
|
|
|
arrangeLine(accumulatedV, curLineSize.V, firstInLine, i); |
|
|
|
|
|
|
|
accumulatedV += curLineSize.V; |
|
|
|
curLineSize = sz; |
|
|
|
|
|
|
|
if (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
|
|
|
|
arrangeLine(accumulatedV, sz.V, i, ++i); |
|
|
|
|
|
|
|
accumulatedV += sz.V; |
|
|
|
curLineSize = new UVSize(Orientation); |
|
|
|
} |
|
|
|
firstInLine = i; |
|
|
|
} |
|
|
|
else // moving to next line
|
|
|
|
else //continue to accumulate a line
|
|
|
|
{ |
|
|
|
var controlsInLine = GetControlsBetween(firstChildInLineIndex, index); |
|
|
|
ArrangeLine(accumulatedV, lineSize.V, controlsInLine); |
|
|
|
accumulatedV += lineSize.V; |
|
|
|
lineSize = childSize; |
|
|
|
firstChildInLineIndex = index; |
|
|
|
curLineSize.U += sz.U; |
|
|
|
curLineSize.V = Max(sz.V, curLineSize.V); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (firstChildInLineIndex < Children.Count) |
|
|
|
//arrange the last line, if any
|
|
|
|
if (firstInLine < Children.Count) |
|
|
|
{ |
|
|
|
var controlsInLine = GetControlsBetween(firstChildInLineIndex, Children.Count); |
|
|
|
ArrangeLine(accumulatedV, lineSize.V, controlsInLine); |
|
|
|
arrangeLine(accumulatedV, curLineSize.V, firstInLine, Children.Count); |
|
|
|
} |
|
|
|
return finalSize; |
|
|
|
} |
|
|
|
|
|
|
|
private IEnumerable<IControl> GetControlsBetween(int first, int last) |
|
|
|
{ |
|
|
|
return Children.Skip(first).Take(last - first); |
|
|
|
return finalSize; |
|
|
|
} |
|
|
|
|
|
|
|
private void ArrangeLine(double v, double lineV, IEnumerable<IControl> controls) |
|
|
|
private void arrangeLine(double v, double lineV, int start, int end) |
|
|
|
{ |
|
|
|
double u = 0; |
|
|
|
bool isHorizontal = (Orientation == Orientation.Horizontal); |
|
|
|
foreach (var child in controls) |
|
|
|
|
|
|
|
for (int i = 0, count = Children.Count; i < count; i++) |
|
|
|
{ |
|
|
|
var childSize = CreateUVSize(child.DesiredSize); |
|
|
|
var x = isHorizontal ? u : v; |
|
|
|
var y = isHorizontal ? v : u; |
|
|
|
var width = isHorizontal ? childSize.U : lineV; |
|
|
|
var height = isHorizontal ? lineV : childSize.U; |
|
|
|
child.Arrange(new Rect(x, y, width, height)); |
|
|
|
u += childSize.U; |
|
|
|
var child = Children[i]; |
|
|
|
if (child != null) |
|
|
|
{ |
|
|
|
UVSize childSize = new UVSize(Orientation, child.DesiredSize.Width, child.DesiredSize.Height); |
|
|
|
double layoutSlotU = childSize.U; |
|
|
|
child.Arrange(new Rect( |
|
|
|
(isHorizontal ? u : v), |
|
|
|
(isHorizontal ? v : u), |
|
|
|
(isHorizontal ? layoutSlotU : lineV), |
|
|
|
(isHorizontal ? lineV : layoutSlotU))); |
|
|
|
u += layoutSlotU; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
/// <summary>
|
|
|
|
/// Used to not not write separate code for horizontal and vertical orientation.
|
|
|
|
/// U is direction in line. (x if orientation is horizontal)
|
|
|
|
/// V is direction of lines. (y if orientation is horizontal)
|
|
|
|
/// </summary>
|
|
|
|
[DebuggerDisplay("U = {U} V = {V}")] |
|
|
|
|
|
|
|
private struct UVSize |
|
|
|
{ |
|
|
|
private readonly Orientation _orientation; |
|
|
|
|
|
|
|
internal double U; |
|
|
|
|
|
|
|
internal double V; |
|
|
|
|
|
|
|
private UVSize(Orientation orientation, double width, double height) |
|
|
|
internal UVSize(Orientation orientation, double width, double height) |
|
|
|
{ |
|
|
|
U = V = 0d; |
|
|
|
_orientation = orientation; |
|
|
|
@ -202,52 +220,25 @@ namespace Avalonia.Controls |
|
|
|
Height = height; |
|
|
|
} |
|
|
|
|
|
|
|
internal UVSize(Orientation orientation, Size size) |
|
|
|
: this(orientation, size.Width, size.Height) |
|
|
|
{ |
|
|
|
} |
|
|
|
|
|
|
|
internal UVSize(Orientation orientation) |
|
|
|
{ |
|
|
|
U = V = 0d; |
|
|
|
_orientation = orientation; |
|
|
|
} |
|
|
|
|
|
|
|
private double Width |
|
|
|
internal double U; |
|
|
|
internal double V; |
|
|
|
private Orientation _orientation; |
|
|
|
|
|
|
|
internal double Width |
|
|
|
{ |
|
|
|
get { return (_orientation == Orientation.Horizontal ? U : V); } |
|
|
|
set |
|
|
|
{ |
|
|
|
if (_orientation == Orientation.Horizontal) |
|
|
|
{ |
|
|
|
U = value; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
V = value; |
|
|
|
} |
|
|
|
} |
|
|
|
set { if (_orientation == Orientation.Horizontal) U = value; else V = value; } |
|
|
|
} |
|
|
|
|
|
|
|
private double Height |
|
|
|
internal double Height |
|
|
|
{ |
|
|
|
get { return (_orientation == Orientation.Horizontal ? V : U); } |
|
|
|
set |
|
|
|
{ |
|
|
|
if (_orientation == Orientation.Horizontal) |
|
|
|
{ |
|
|
|
V = value; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
U = value; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public Size ToSize() |
|
|
|
{ |
|
|
|
return new Size(Width, Height); |
|
|
|
set { if (_orientation == Orientation.Horizontal) V = value; else U = value; } |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|