|
|
@ -4,11 +4,13 @@ |
|
|
using System; |
|
|
using System; |
|
|
using System.Collections.Specialized; |
|
|
using System.Collections.Specialized; |
|
|
using Avalonia.Layout; |
|
|
using Avalonia.Layout; |
|
|
|
|
|
using Avalonia.VisualTree; |
|
|
|
|
|
|
|
|
namespace Avalonia.Controls |
|
|
namespace Avalonia.Controls |
|
|
{ |
|
|
{ |
|
|
public class VirtualizingStackPanel : StackPanel, IVirtualizingPanel |
|
|
public class VirtualizingStackPanel : StackPanel, IVirtualizingPanel |
|
|
{ |
|
|
{ |
|
|
|
|
|
private Size _availableSpace; |
|
|
private double _takenSpace; |
|
|
private double _takenSpace; |
|
|
private int _canBeRemoved; |
|
|
private int _canBeRemoved; |
|
|
private double _averageItemSize; |
|
|
private double _averageItemSize; |
|
|
@ -20,15 +22,14 @@ namespace Avalonia.Controls |
|
|
get |
|
|
get |
|
|
{ |
|
|
{ |
|
|
return Orientation == Orientation.Horizontal ? |
|
|
return Orientation == Orientation.Horizontal ? |
|
|
_takenSpace >= AvailableSpace.Width : |
|
|
_takenSpace >= _availableSpace.Width : |
|
|
_takenSpace >= AvailableSpace.Height; |
|
|
_takenSpace >= _availableSpace.Height; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
IVirtualizingController IVirtualizingPanel.Controller { get; set; } |
|
|
int IVirtualizingPanel.OverflowCount => _canBeRemoved; |
|
|
int IVirtualizingPanel.OverflowCount => _canBeRemoved; |
|
|
|
|
|
|
|
|
Orientation IVirtualizingPanel.ScrollDirection => Orientation; |
|
|
Orientation IVirtualizingPanel.ScrollDirection => Orientation; |
|
|
|
|
|
|
|
|
double IVirtualizingPanel.AverageItemSize => _averageItemSize; |
|
|
double IVirtualizingPanel.AverageItemSize => _averageItemSize; |
|
|
|
|
|
|
|
|
double IVirtualizingPanel.PixelOverflow |
|
|
double IVirtualizingPanel.PixelOverflow |
|
|
@ -55,16 +56,30 @@ namespace Avalonia.Controls |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// TODO: We need to put a reasonable limit on this, probably based on the max window size.
|
|
|
private IVirtualizingController Controller => ((IVirtualizingPanel)this).Controller; |
|
|
private Size AvailableSpace => ((ILayoutable)this).PreviousMeasure ?? Bounds.Size; |
|
|
|
|
|
|
|
|
protected override Size MeasureOverride(Size availableSize) |
|
|
|
|
|
{ |
|
|
|
|
|
if (availableSize != ((ILayoutable)this).PreviousMeasure) |
|
|
|
|
|
{ |
|
|
|
|
|
// TODO: We need to put a reasonable limit on this, probably based on the max
|
|
|
|
|
|
// window size.
|
|
|
|
|
|
_availableSpace = availableSize; |
|
|
|
|
|
Controller?.UpdateControls(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return base.MeasureOverride(availableSize); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
protected override Size ArrangeOverride(Size finalSize) |
|
|
protected override Size ArrangeOverride(Size finalSize) |
|
|
{ |
|
|
{ |
|
|
|
|
|
_availableSpace = finalSize; |
|
|
_canBeRemoved = 0; |
|
|
_canBeRemoved = 0; |
|
|
_takenSpace = 0; |
|
|
_takenSpace = 0; |
|
|
_averageItemSize = 0; |
|
|
_averageItemSize = 0; |
|
|
_averageCount = 0; |
|
|
_averageCount = 0; |
|
|
var result = base.ArrangeOverride(finalSize); |
|
|
var result = base.ArrangeOverride(finalSize); |
|
|
|
|
|
Controller?.UpdateControls(); |
|
|
return result; |
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -103,7 +118,7 @@ namespace Avalonia.Controls |
|
|
rect = new Rect(rect.X, rect.Y - _pixelOffset, rect.Width, rect.Height); |
|
|
rect = new Rect(rect.X, rect.Y - _pixelOffset, rect.Width, rect.Height); |
|
|
child.Arrange(rect); |
|
|
child.Arrange(rect); |
|
|
|
|
|
|
|
|
if (rect.Y >= AvailableSpace.Height) |
|
|
if (rect.Y >= _availableSpace.Height) |
|
|
{ |
|
|
{ |
|
|
++_canBeRemoved; |
|
|
++_canBeRemoved; |
|
|
} |
|
|
} |
|
|
@ -120,7 +135,7 @@ namespace Avalonia.Controls |
|
|
rect = new Rect(rect.X - _pixelOffset, rect.Y, rect.Width, rect.Height); |
|
|
rect = new Rect(rect.X - _pixelOffset, rect.Y, rect.Width, rect.Height); |
|
|
child.Arrange(rect); |
|
|
child.Arrange(rect); |
|
|
|
|
|
|
|
|
if (rect.X >= AvailableSpace.Width) |
|
|
if (rect.X >= _availableSpace.Width) |
|
|
{ |
|
|
{ |
|
|
++_canBeRemoved; |
|
|
++_canBeRemoved; |
|
|
} |
|
|
} |
|
|
@ -139,7 +154,7 @@ namespace Avalonia.Controls |
|
|
var bounds = Bounds; |
|
|
var bounds = Bounds; |
|
|
var gap = Gap; |
|
|
var gap = Gap; |
|
|
|
|
|
|
|
|
child.Measure(AvailableSpace); |
|
|
child.Measure(_availableSpace); |
|
|
++_averageCount; |
|
|
++_averageCount; |
|
|
|
|
|
|
|
|
if (Orientation == Orientation.Vertical) |
|
|
if (Orientation == Orientation.Vertical) |
|
|
@ -173,6 +188,11 @@ namespace Avalonia.Controls |
|
|
_takenSpace -= width + gap; |
|
|
_takenSpace -= width + gap; |
|
|
RemoveFromAverageItemSize(width); |
|
|
RemoveFromAverageItemSize(width); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (_canBeRemoved > 0) |
|
|
|
|
|
{ |
|
|
|
|
|
--_canBeRemoved; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private void AddToAverageItemSize(double value) |
|
|
private void AddToAverageItemSize(double value) |
|
|
|