|
|
|
@ -2,9 +2,7 @@ |
|
|
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|
|
|
|
|
|
|
using System; |
|
|
|
using System.Linq; |
|
|
|
using Avalonia.Input; |
|
|
|
using Avalonia.Layout; |
|
|
|
using Avalonia.Input |
|
|
|
|
|
|
|
namespace Avalonia.Controls |
|
|
|
{ |
|
|
|
@ -155,106 +153,118 @@ namespace Avalonia.Controls |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Measures the control.
|
|
|
|
/// General StackPanel layout behavior is to grow unbounded in the "stacking" direction (Size To Content).
|
|
|
|
/// Children in this dimension are encouraged to be as large as they like. In the other dimension,
|
|
|
|
/// StackPanel will assume the maximum size of its children.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="availableSize">The available size.</param>
|
|
|
|
/// <returns>The desired size of the control.</returns>
|
|
|
|
protected override Size MeasureOverride(Size availableSize) |
|
|
|
/// <param name="constraint">Constraint</param>
|
|
|
|
/// <returns>Desired size</returns>
|
|
|
|
protected override Size MeasureOverride(Size constraint) |
|
|
|
{ |
|
|
|
double childAvailableWidth = double.PositiveInfinity; |
|
|
|
double childAvailableHeight = double.PositiveInfinity; |
|
|
|
Size stackDesiredSize = new Size(); |
|
|
|
var children = Children; |
|
|
|
Size layoutSlotSize = constraint; |
|
|
|
bool fHorizontal = (Orientation == Orientation.Horizontal); |
|
|
|
double spacing = Spacing; |
|
|
|
bool hasVisibleChild = false; |
|
|
|
|
|
|
|
if (Orientation == Orientation.Vertical) |
|
|
|
//
|
|
|
|
// Initialize child sizing and iterator data
|
|
|
|
// Allow children as much size as they want along the stack.
|
|
|
|
//
|
|
|
|
if (fHorizontal) |
|
|
|
{ |
|
|
|
childAvailableWidth = availableSize.Width; |
|
|
|
|
|
|
|
if (!double.IsNaN(Width)) |
|
|
|
{ |
|
|
|
childAvailableWidth = Width; |
|
|
|
} |
|
|
|
|
|
|
|
childAvailableWidth = Math.Min(childAvailableWidth, MaxWidth); |
|
|
|
childAvailableWidth = Math.Max(childAvailableWidth, MinWidth); |
|
|
|
layoutSlotSize = layoutSlotSize.WithWidth(Double.PositiveInfinity); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
childAvailableHeight = availableSize.Height; |
|
|
|
layoutSlotSize = layoutSlotSize.WithHeight(Double.PositiveInfinity); |
|
|
|
} |
|
|
|
|
|
|
|
if (!double.IsNaN(Height)) |
|
|
|
{ |
|
|
|
childAvailableHeight = Height; |
|
|
|
} |
|
|
|
//
|
|
|
|
// Iterate through children.
|
|
|
|
// While we still supported virtualization, this was hidden in a child iterator (see source history).
|
|
|
|
//
|
|
|
|
for (int i = 0, count = children.Count; i < count; ++i) |
|
|
|
{ |
|
|
|
// Get next child.
|
|
|
|
var child = children[i]; |
|
|
|
|
|
|
|
childAvailableHeight = Math.Min(childAvailableHeight, MaxHeight); |
|
|
|
childAvailableHeight = Math.Max(childAvailableHeight, MinHeight); |
|
|
|
} |
|
|
|
if (child == null) |
|
|
|
{ continue; } |
|
|
|
|
|
|
|
double measuredWidth = 0; |
|
|
|
double measuredHeight = 0; |
|
|
|
double spacing = Spacing; |
|
|
|
bool hasVisibleChild = Children.Any(c => c.IsVisible); |
|
|
|
if (child.IsVisible) |
|
|
|
{ |
|
|
|
hasVisibleChild = true; |
|
|
|
} |
|
|
|
|
|
|
|
foreach (Control child in Children) |
|
|
|
{ |
|
|
|
child.Measure(new Size(childAvailableWidth, childAvailableHeight)); |
|
|
|
Size size = child.DesiredSize; |
|
|
|
// Measure the child.
|
|
|
|
child.Measure(layoutSlotSize); |
|
|
|
Size childDesiredSize = child.DesiredSize; |
|
|
|
|
|
|
|
if (Orientation == Orientation.Vertical) |
|
|
|
// Accumulate child size.
|
|
|
|
if (fHorizontal) |
|
|
|
{ |
|
|
|
measuredHeight += size.Height + (child.IsVisible ? spacing : 0); |
|
|
|
measuredWidth = Math.Max(measuredWidth, size.Width); |
|
|
|
stackDesiredSize = stackDesiredSize.WithWidth(stackDesiredSize.Width + childDesiredSize.Width + (child.IsVisible ? spacing : 0)); |
|
|
|
stackDesiredSize = stackDesiredSize.WithHeight(Math.Max(stackDesiredSize.Height, childDesiredSize.Height)); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
measuredWidth += size.Width + (child.IsVisible ? spacing : 0); |
|
|
|
measuredHeight = Math.Max(measuredHeight, size.Height); |
|
|
|
stackDesiredSize = stackDesiredSize.WithWidth(Math.Max(stackDesiredSize.Width, childDesiredSize.Width)); |
|
|
|
stackDesiredSize = stackDesiredSize.WithHeight(stackDesiredSize.Height + childDesiredSize.Height + (child.IsVisible ? spacing : 0)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (Orientation == Orientation.Vertical) |
|
|
|
{ |
|
|
|
measuredHeight -= (hasVisibleChild ? spacing : 0); |
|
|
|
stackDesiredSize = stackDesiredSize.WithHeight(stackDesiredSize.Height - (hasVisibleChild ? spacing : 0)); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
measuredWidth -= (hasVisibleChild ? spacing : 0); |
|
|
|
stackDesiredSize = stackDesiredSize.WithWidth(stackDesiredSize.Width - (hasVisibleChild ? spacing : 0)); |
|
|
|
} |
|
|
|
|
|
|
|
return new Size(measuredWidth, measuredHeight).Constrain(availableSize); |
|
|
|
return stackDesiredSize; |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
/// <summary>
|
|
|
|
/// Content arrangement.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="finalSize">Arrange size</param>
|
|
|
|
protected override Size ArrangeOverride(Size finalSize) |
|
|
|
{ |
|
|
|
var orientation = Orientation; |
|
|
|
var children = Children; |
|
|
|
bool fHorizontal = (Orientation == Orientation.Horizontal); |
|
|
|
Rect rcChild = new Rect(finalSize); |
|
|
|
double previousChildSize = 0.0; |
|
|
|
var spacing = Spacing; |
|
|
|
var finalRect = new Rect(finalSize); |
|
|
|
var pos = 0.0; |
|
|
|
|
|
|
|
foreach (Control child in Children) |
|
|
|
//
|
|
|
|
// Arrange and Position Children.
|
|
|
|
//
|
|
|
|
for (int i = 0, count = children.Count; i < count; ++i) |
|
|
|
{ |
|
|
|
if (!child.IsVisible) |
|
|
|
{ |
|
|
|
continue; |
|
|
|
} |
|
|
|
var child = children[i]; |
|
|
|
|
|
|
|
double childWidth = child.DesiredSize.Width; |
|
|
|
double childHeight = child.DesiredSize.Height; |
|
|
|
if (child == null) |
|
|
|
{ continue; } |
|
|
|
|
|
|
|
if (orientation == Orientation.Vertical) |
|
|
|
if (fHorizontal) |
|
|
|
{ |
|
|
|
var rect = new Rect(0, pos, childWidth, childHeight) |
|
|
|
.Align(finalRect, child.HorizontalAlignment, VerticalAlignment.Top); |
|
|
|
ArrangeChild(child, rect, finalSize, orientation); |
|
|
|
pos += childHeight + spacing; |
|
|
|
rcChild = rcChild.WithX(rcChild.X + previousChildSize); |
|
|
|
previousChildSize = child.DesiredSize.Width; |
|
|
|
rcChild = rcChild.WithWidth(previousChildSize); |
|
|
|
rcChild = rcChild.WithHeight(Math.Max(finalSize.Height, child.DesiredSize.Height) + (child.IsVisible ? spacing : 0)); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
var rect = new Rect(pos, 0, childWidth, childHeight) |
|
|
|
.Align(finalRect, HorizontalAlignment.Left, child.VerticalAlignment); |
|
|
|
ArrangeChild(child, rect, finalSize, orientation); |
|
|
|
pos += childWidth + spacing; |
|
|
|
rcChild = rcChild.WithY(rcChild.Y + previousChildSize); |
|
|
|
previousChildSize = child.DesiredSize.Height; |
|
|
|
rcChild = rcChild.WithHeight(previousChildSize); |
|
|
|
rcChild = rcChild.WithWidth(Math.Max(finalSize.Width, child.DesiredSize.Width) + (child.IsVisible ? spacing : 0)); |
|
|
|
} |
|
|
|
|
|
|
|
child.Arrange(rcChild); |
|
|
|
} |
|
|
|
|
|
|
|
return finalSize; |
|
|
|
|