|
|
|
@ -110,6 +110,12 @@ namespace Avalonia.Layout |
|
|
|
public static readonly StyledProperty<double> MinRowSpacingProperty = |
|
|
|
AvaloniaProperty.Register<UniformGridLayout, double>(nameof(MinRowSpacing)); |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Defines the <see cref="MaximumRowsOrColumnsProperty"/> property.
|
|
|
|
/// </summary>
|
|
|
|
public static readonly StyledProperty<int> MaximumRowsOrColumnsProperty = |
|
|
|
AvaloniaProperty.Register<UniformGridLayout, int>(nameof(MinItemWidth)); |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Defines the <see cref="Orientation"/> property.
|
|
|
|
/// </summary>
|
|
|
|
@ -123,6 +129,7 @@ namespace Avalonia.Layout |
|
|
|
private double _minColumnSpacing; |
|
|
|
private UniformGridLayoutItemsJustification _itemsJustification; |
|
|
|
private UniformGridLayoutItemsStretch _itemsStretch; |
|
|
|
private int _maximumRowsOrColumns = int.MaxValue; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Initializes a new instance of the <see cref="UniformGridLayout"/> class.
|
|
|
|
@ -219,6 +226,15 @@ namespace Avalonia.Layout |
|
|
|
set => SetValue(MinRowSpacingProperty, value); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets or sets the maximum row or column count.
|
|
|
|
/// </summary>
|
|
|
|
public int MaximumRowsOrColumns |
|
|
|
{ |
|
|
|
get => GetValue(MaximumRowsOrColumnsProperty); |
|
|
|
set => SetValue(MaximumRowsOrColumnsProperty, value); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets or sets the axis along which items are laid out.
|
|
|
|
/// </summary>
|
|
|
|
@ -269,15 +285,17 @@ namespace Avalonia.Layout |
|
|
|
{ |
|
|
|
var gridState = (UniformGridLayoutState)context.LayoutState; |
|
|
|
var lastExtent = gridState.FlowAlgorithm.LastExtent; |
|
|
|
int itemsPerLine = Math.Max(1, (int)(_orientation.Minor(availableSize) / GetMinorSizeWithSpacing(context))); |
|
|
|
double majorSize = (itemsCount / itemsPerLine) * GetMajorSizeWithSpacing(context); |
|
|
|
double realizationWindowStartWithinExtent = _orientation.MajorStart(realizationRect) - _orientation.MajorStart(lastExtent); |
|
|
|
var itemsPerLine = Math.Min( // note use of unsigned ints
|
|
|
|
Math.Max(1u, (uint)(_orientation.Minor(availableSize) / GetMinorSizeWithSpacing(context))), |
|
|
|
Math.Max(1u, (uint)_maximumRowsOrColumns)); |
|
|
|
var majorSize = (itemsCount / itemsPerLine) * GetMajorSizeWithSpacing(context); |
|
|
|
var realizationWindowStartWithinExtent = _orientation.MajorStart(realizationRect) - _orientation.MajorStart(lastExtent); |
|
|
|
if ((realizationWindowStartWithinExtent + _orientation.MajorSize(realizationRect)) >= 0 && realizationWindowStartWithinExtent <= majorSize) |
|
|
|
{ |
|
|
|
double offset = Math.Max(0.0, _orientation.MajorStart(realizationRect) - _orientation.MajorStart(lastExtent)); |
|
|
|
int anchorRowIndex = (int)(offset / GetMajorSizeWithSpacing(context)); |
|
|
|
|
|
|
|
anchorIndex = Math.Max(0, Math.Min(itemsCount - 1, anchorRowIndex * itemsPerLine)); |
|
|
|
anchorIndex = (int)Math.Max(0, Math.Min(itemsCount - 1, anchorRowIndex * itemsPerLine)); |
|
|
|
bounds = GetLayoutRectForDataIndex(availableSize, anchorIndex, lastExtent, context); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -299,7 +317,9 @@ namespace Avalonia.Layout |
|
|
|
int count = context.ItemCount; |
|
|
|
if (targetIndex >= 0 && targetIndex < count) |
|
|
|
{ |
|
|
|
int itemsPerLine = Math.Max(1, (int)(_orientation.Minor(availableSize) / GetMinorSizeWithSpacing(context))); |
|
|
|
int itemsPerLine = (int)Math.Min( // note use of unsigned ints
|
|
|
|
Math.Max(1u, (uint)(_orientation.Minor(availableSize) / GetMinorSizeWithSpacing(context))), |
|
|
|
Math.Max(1u, _maximumRowsOrColumns)); |
|
|
|
int indexOfFirstInLine = (targetIndex / itemsPerLine) * itemsPerLine; |
|
|
|
index = indexOfFirstInLine; |
|
|
|
var state = context.LayoutState as UniformGridLayoutState; |
|
|
|
@ -329,17 +349,21 @@ namespace Avalonia.Layout |
|
|
|
// Constants
|
|
|
|
int itemsCount = context.ItemCount; |
|
|
|
double availableSizeMinor = _orientation.Minor(availableSize); |
|
|
|
int itemsPerLine = Math.Max(1, !double.IsInfinity(availableSizeMinor) ? |
|
|
|
(int)(availableSizeMinor / GetMinorSizeWithSpacing(context)) : itemsCount); |
|
|
|
int itemsPerLine = |
|
|
|
(int)Math.Min( // note use of unsigned ints
|
|
|
|
Math.Max(1u, !double.IsInfinity(availableSizeMinor) |
|
|
|
? (uint)(availableSizeMinor / GetMinorSizeWithSpacing(context)) |
|
|
|
: (uint)itemsCount), |
|
|
|
Math.Max(1u, _maximumRowsOrColumns)); |
|
|
|
double lineSize = GetMajorSizeWithSpacing(context); |
|
|
|
|
|
|
|
if (itemsCount > 0) |
|
|
|
{ |
|
|
|
_orientation.SetMinorSize( |
|
|
|
ref extent, |
|
|
|
!double.IsInfinity(availableSizeMinor) ? |
|
|
|
!double.IsInfinity(availableSizeMinor) && _itemsStretch == UniformGridLayoutItemsStretch.Fill ? |
|
|
|
availableSizeMinor : |
|
|
|
Math.Max(0.0, itemsCount * GetMinorSizeWithSpacing(context) - (double)MinItemSpacing)); |
|
|
|
Math.Max(0.0, itemsPerLine * GetMinorSizeWithSpacing(context) - (double)MinItemSpacing)); |
|
|
|
_orientation.SetMajorSize( |
|
|
|
ref extent, |
|
|
|
Math.Max(0.0, (itemsCount / itemsPerLine) * lineSize - (double)LineSpacing)); |
|
|
|
@ -398,7 +422,7 @@ namespace Avalonia.Layout |
|
|
|
// Set the width and height on the grid state. If the user already set them then use the preset.
|
|
|
|
// If not, we have to measure the first element and get back a size which we're going to be using for the rest of the items.
|
|
|
|
var gridState = (UniformGridLayoutState)context.LayoutState; |
|
|
|
gridState.EnsureElementSize(availableSize, context, _minItemWidth, _minItemHeight, _itemsStretch, Orientation, MinRowSpacing, MinColumnSpacing); |
|
|
|
gridState.EnsureElementSize(availableSize, context, _minItemWidth, _minItemHeight, _itemsStretch, Orientation, MinRowSpacing, MinColumnSpacing, _maximumRowsOrColumns); |
|
|
|
|
|
|
|
var desiredSize = GetFlowAlgorithm(context).Measure( |
|
|
|
availableSize, |
|
|
|
@ -406,6 +430,7 @@ namespace Avalonia.Layout |
|
|
|
true, |
|
|
|
MinItemSpacing, |
|
|
|
LineSpacing, |
|
|
|
_maximumRowsOrColumns, |
|
|
|
_orientation.ScrollOrientation, |
|
|
|
LayoutId); |
|
|
|
|
|
|
|
@ -421,6 +446,7 @@ namespace Avalonia.Layout |
|
|
|
var value = GetFlowAlgorithm(context).Arrange( |
|
|
|
finalSize, |
|
|
|
context, |
|
|
|
true, |
|
|
|
(FlowLayoutAlgorithm.LineAlignment)_itemsJustification, |
|
|
|
LayoutId); |
|
|
|
return new Size(value.Width, value.Height); |
|
|
|
@ -471,6 +497,10 @@ namespace Avalonia.Layout |
|
|
|
{ |
|
|
|
_minItemHeight = (double)args.NewValue; |
|
|
|
} |
|
|
|
else if (args.Property == MaximumRowsOrColumnsProperty) |
|
|
|
{ |
|
|
|
_maximumRowsOrColumns = (int)args.NewValue; |
|
|
|
} |
|
|
|
|
|
|
|
InvalidateLayout(); |
|
|
|
} |
|
|
|
@ -499,7 +529,9 @@ namespace Avalonia.Layout |
|
|
|
Rect lastExtent, |
|
|
|
VirtualizingLayoutContext context) |
|
|
|
{ |
|
|
|
int itemsPerLine = Math.Max(1, (int)(_orientation.Minor(availableSize) / GetMinorSizeWithSpacing(context))); |
|
|
|
int itemsPerLine = (int)Math.Min( //note use of unsigned ints
|
|
|
|
Math.Max(1u, (uint)(_orientation.Minor(availableSize) / GetMinorSizeWithSpacing(context))), |
|
|
|
Math.Max(1u, _maximumRowsOrColumns)); |
|
|
|
int rowIndex = (int)(index / itemsPerLine); |
|
|
|
int indexInRow = index - (rowIndex * itemsPerLine); |
|
|
|
|
|
|
|
|