|
|
@@ -1,7 +1,6 @@
|
|
|
// 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.
|
|
|
|
|
|
-using Avalonia.Controls.Primitives;
|
|
|
using System;
|
|
|
using System.Collections.Specialized;
|
|
|
|
|
|
@@ -11,6 +10,9 @@ namespace Avalonia.Controls
|
|
|
{
|
|
|
private double _takenSpace;
|
|
|
private int _canBeRemoved;
|
|
|
+ private double _averageItemSize;
|
|
|
+ private int _averageCount;
|
|
|
+ private double _pixelOffset;
|
|
|
|
|
|
bool IVirtualizingPanel.IsFull
|
|
|
{
|
|
|
@@ -24,12 +26,30 @@ namespace Avalonia.Controls
|
|
|
|
|
|
int IVirtualizingPanel.OverflowCount => _canBeRemoved;
|
|
|
|
|
|
+ double IVirtualizingPanel.AverageItemSize => _averageItemSize;
|
|
|
+
|
|
|
+ double IVirtualizingPanel.PixelOffset
|
|
|
+ {
|
|
|
+ get { return _pixelOffset; }
|
|
|
+
|
|
|
+ set
|
|
|
+ {
|
|
|
+ if (_pixelOffset != value)
|
|
|
+ {
|
|
|
+ _pixelOffset = value;
|
|
|
+ InvalidateArrange();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
Action IVirtualizingPanel.ArrangeCompleted { get; set; }
|
|
|
|
|
|
protected override Size ArrangeOverride(Size finalSize)
|
|
|
{
|
|
|
_canBeRemoved = 0;
|
|
|
_takenSpace = 0;
|
|
|
+ _averageItemSize = 0;
|
|
|
+ _averageCount = 0;
|
|
|
var result = base.ArrangeOverride(finalSize);
|
|
|
((IVirtualizingPanel)this).ArrangeCompleted?.Invoke();
|
|
|
return result;
|
|
|
@@ -44,7 +64,7 @@ namespace Avalonia.Controls
|
|
|
case NotifyCollectionChangedAction.Add:
|
|
|
foreach (IControl control in e.NewItems)
|
|
|
{
|
|
|
- UpdatePhysicalSizeForAdd(control);
|
|
|
+ UpdateAdd(control);
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
@@ -52,7 +72,7 @@ namespace Avalonia.Controls
|
|
|
case NotifyCollectionChangedAction.Remove:
|
|
|
foreach (IControl control in e.OldItems)
|
|
|
{
|
|
|
- UpdatePhysicalSizeForRemove(control);
|
|
|
+ UpdateRemove(control);
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
@@ -65,64 +85,93 @@ namespace Avalonia.Controls
|
|
|
Size panelSize,
|
|
|
Orientation orientation)
|
|
|
{
|
|
|
- base.ArrangeChild(child, rect, panelSize, orientation);
|
|
|
-
|
|
|
- if (orientation == Orientation.Horizontal)
|
|
|
+ if (orientation == Orientation.Vertical)
|
|
|
{
|
|
|
- if (rect.X >= panelSize.Width)
|
|
|
+ rect = new Rect(rect.X, rect.Y - _pixelOffset, rect.Width, rect.Height);
|
|
|
+ child.Arrange(rect);
|
|
|
+
|
|
|
+ if (rect.Y >= panelSize.Height)
|
|
|
{
|
|
|
++_canBeRemoved;
|
|
|
}
|
|
|
|
|
|
- if (rect.Right >= _takenSpace)
|
|
|
+ if (rect.Bottom >= _takenSpace)
|
|
|
{
|
|
|
- _takenSpace = rect.Right;
|
|
|
+ _takenSpace = rect.Bottom;
|
|
|
}
|
|
|
+
|
|
|
+ AddToAverageItemSize(rect.Height);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- if (rect.Y >= panelSize.Height)
|
|
|
+ rect = new Rect(rect.X - _pixelOffset, rect.Y, rect.Width, rect.Height);
|
|
|
+ child.Arrange(rect);
|
|
|
+
|
|
|
+ if (rect.X >= panelSize.Width)
|
|
|
{
|
|
|
++_canBeRemoved;
|
|
|
}
|
|
|
|
|
|
- if (rect.Bottom >= _takenSpace)
|
|
|
+ if (rect.Right >= _takenSpace)
|
|
|
{
|
|
|
- _takenSpace = rect.Bottom;
|
|
|
+ _takenSpace = rect.Right;
|
|
|
}
|
|
|
+
|
|
|
+ AddToAverageItemSize(rect.Width);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void UpdatePhysicalSizeForAdd(IControl child)
|
|
|
+ private void UpdateAdd(IControl child)
|
|
|
{
|
|
|
var bounds = Bounds;
|
|
|
var gap = Gap;
|
|
|
|
|
|
child.Measure(bounds.Size);
|
|
|
+ ++_averageCount;
|
|
|
|
|
|
if (Orientation == Orientation.Vertical)
|
|
|
{
|
|
|
- _takenSpace += child.DesiredSize.Height + gap;
|
|
|
+ var height = child.DesiredSize.Height;
|
|
|
+ _takenSpace += height + gap;
|
|
|
+ AddToAverageItemSize(height);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- _takenSpace += child.DesiredSize.Width + gap;
|
|
|
+ var width = child.DesiredSize.Width;
|
|
|
+ _takenSpace += width + gap;
|
|
|
+ AddToAverageItemSize(width);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void UpdatePhysicalSizeForRemove(IControl child)
|
|
|
+ private void UpdateRemove(IControl child)
|
|
|
{
|
|
|
var bounds = Bounds;
|
|
|
var gap = Gap;
|
|
|
|
|
|
if (Orientation == Orientation.Vertical)
|
|
|
{
|
|
|
- _takenSpace -= child.DesiredSize.Height + gap;
|
|
|
+ var height = child.DesiredSize.Height;
|
|
|
+ _takenSpace -= height + gap;
|
|
|
+ RemoveFromAverageItemSize(height);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- _takenSpace -= child.DesiredSize.Width + gap;
|
|
|
+ var width = child.DesiredSize.Width;
|
|
|
+ _takenSpace -= width + gap;
|
|
|
+ RemoveFromAverageItemSize(width);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ private void AddToAverageItemSize(double value)
|
|
|
+ {
|
|
|
+ ++_averageCount;
|
|
|
+ _averageItemSize += (value - _averageItemSize) / _averageCount;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void RemoveFromAverageItemSize(double value)
|
|
|
+ {
|
|
|
+ _averageItemSize = ((_averageItemSize * _averageCount) - value) / (_averageCount - 1);
|
|
|
+ --_averageCount;
|
|
|
+ }
|
|
|
}
|
|
|
}
|