Browse Source

Merge branch 'master' into refactor/2709-mutable-pen

pull/2744/head
Steven Kirk 7 years ago
committed by GitHub
parent
commit
f642a0044d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      src/Avalonia.Controls/Image.cs
  2. 145
      src/Avalonia.Controls/StackPanel.cs
  3. 3
      src/Avalonia.Layout/Layoutable.cs
  4. 33
      tests/Avalonia.Controls.UnitTests/GridTests.cs
  5. 16
      tests/Avalonia.Controls.UnitTests/StackPanelTests.cs

2
src/Avalonia.Controls/Image.cs

@ -96,7 +96,7 @@ namespace Avalonia.Controls
}
}
return result.Constrain(availableSize);
return result;
}
/// <inheritdoc/>

145
src/Avalonia.Controls/StackPanel.cs

@ -1,8 +1,9 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
// This source file is adapted from the Windows Presentation Foundation project.
// (https://github.com/dotnet/wpf/)
//
// Licensed to The Avalonia Project under MIT License, courtesy of The .NET Foundation.
using System;
using System.Linq;
using Avalonia.Input;
using Avalonia.Layout;
@ -155,106 +156,122 @@ 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>
/// <param name="availableSize">Constraint</param>
/// <returns>Desired size</returns>
protected override Size MeasureOverride(Size availableSize)
{
double childAvailableWidth = double.PositiveInfinity;
double childAvailableHeight = double.PositiveInfinity;
Size stackDesiredSize = new Size();
var children = Children;
Size layoutSlotSize = availableSize;
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);
bool isVisible = child.IsVisible;
foreach (Control child in Children)
{
child.Measure(new Size(childAvailableWidth, childAvailableHeight));
Size size = child.DesiredSize;
if (isVisible && !hasVisibleChild)
{
hasVisibleChild = true;
}
if (Orientation == Orientation.Vertical)
// Measure the child.
child.Measure(layoutSlotSize);
Size childDesiredSize = child.DesiredSize;
// Accumulate child size.
if (fHorizontal)
{
measuredHeight += size.Height + (child.IsVisible ? spacing : 0);
measuredWidth = Math.Max(measuredWidth, size.Width);
stackDesiredSize = stackDesiredSize.WithWidth(stackDesiredSize.Width + (isVisible ? spacing : 0) + childDesiredSize.Width);
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 + (isVisible ? spacing : 0) + childDesiredSize.Height);
}
}
if (Orientation == Orientation.Vertical)
if (fHorizontal)
{
measuredHeight -= (hasVisibleChild ? spacing : 0);
stackDesiredSize = stackDesiredSize.WithWidth(stackDesiredSize.Width - (hasVisibleChild ? spacing : 0));
}
else
{
measuredWidth -= (hasVisibleChild ? spacing : 0);
{
stackDesiredSize = stackDesiredSize.WithHeight(stackDesiredSize.Height - (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));
previousChildSize += spacing;
}
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));
previousChildSize += spacing;
}
ArrangeChild(child, rcChild, finalSize, Orientation);
}
return finalSize;

3
src/Avalonia.Layout/Layoutable.cs

@ -534,6 +534,9 @@ namespace Avalonia.Layout
height = Math.Min(height, MaxHeight);
height = Math.Max(height, MinHeight);
width = Math.Min(width, availableSize.Width);
height = Math.Min(height, availableSize.Height);
if (UseLayoutRounding)
{
var scale = GetLayoutScale();

33
tests/Avalonia.Controls.UnitTests/GridTests.cs

@ -1357,5 +1357,36 @@ namespace Avalonia.Controls.UnitTests
PrintColumnDefinitions(grid);
Assert.All(grid.ColumnDefinitions.Where(cd => cd.SharedSizeGroup == null), cd => Assert.Equal(50, cd.ActualWidth));
}
[Fact]
public void Correct_Grid_Bounds_When_Child_Control_Has_DesiredSize_Larger_Than_Available_Space()
{
// Issue #2746
var grid = new Grid
{
RowDefinitions = RowDefinitions.Parse("Auto"),
Children =
{
new TestControl
{
MeasureSize = new Size(150, 150),
}
}
};
var parent = new Decorator { Child = grid };
parent.Measure(new Size(100, 100));
parent.Arrange(new Rect(grid.DesiredSize));
Assert.Equal(new Size(100, 100), grid.Bounds.Size);
}
private class TestControl : Control
{
public Size MeasureSize { get; set; }
protected override Size MeasureOverride(Size availableSize) => MeasureSize;
}
}
}
}

16
tests/Avalonia.Controls.UnitTests/StackPanelTests.cs

@ -210,13 +210,13 @@ namespace Avalonia.Controls.UnitTests
new[]
{
new Rect(0, 0, 50, 10),
new Rect(0, 10, 150, 10),
new Rect(0, 10, 100, 10),
new Rect(25, 20, 50, 10),
new Rect(-25, 30, 150, 10),
new Rect(0, 30, 100, 10),
new Rect(50, 40, 50, 10),
new Rect(-50, 50, 150, 10),
new Rect(0, 50, 100, 10),
new Rect(0, 60, 100, 10),
new Rect(0, 70, 150, 10),
new Rect(0, 70, 100, 10),
}, bounds);
}
@ -283,13 +283,13 @@ namespace Avalonia.Controls.UnitTests
new[]
{
new Rect(0, 0, 10, 50),
new Rect(10, 0, 10, 150),
new Rect(10, 0, 10, 100),
new Rect(20, 25, 10, 50),
new Rect(30, -25, 10, 150),
new Rect(30, 0, 10, 100),
new Rect(40, 50, 10, 50),
new Rect(50, -50, 10, 150),
new Rect(50, 0, 10, 100),
new Rect(60, 0, 10, 100),
new Rect(70, 0, 10, 150),
new Rect(70, 0, 10, 100),
}, bounds);
}

Loading…
Cancel
Save