Browse Source

Added pixel offset to virtualizing panel.

pull/554/head
Steven Kirk 10 years ago
parent
commit
63a688817e
  1. 4
      src/Avalonia.Controls/IVirtualizingPanel.cs
  2. 12
      src/Avalonia.Controls/Presenters/ThingamybobPresenter.cs
  3. 85
      src/Avalonia.Controls/VirtualizingStackPanel.cs

4
src/Avalonia.Controls/IVirtualizingPanel.cs

@ -8,6 +8,10 @@ namespace Avalonia.Controls
int OverflowCount { get; }
double AverageItemSize { get; }
double PixelOffset { get; set; }
Action ArrangeCompleted { get; set; }
}
}

12
src/Avalonia.Controls/Presenters/ThingamybobPresenter.cs

@ -17,6 +17,7 @@ namespace Avalonia.Controls.Presenters
_panel = new VirtualizingStackPanel();
_panel.ArrangeCompleted = CheckPanel;
Child = _panel;
CheckPanel();
}
}
@ -24,28 +25,31 @@ namespace Avalonia.Controls.Presenters
Action IScrollable.InvalidateScroll { get; set; }
Size IScrollable.Extent => new Size(1, 100);
Size IScrollable.Extent => new Size(1, 100 * AverageItemSize );
Vector IScrollable.Offset
{
get
{
return new Vector(0, _firstIndex);
return new Vector(0, _firstIndex * AverageItemSize);
}
set
{
var count = _lastIndex - _firstIndex;
_firstIndex = (int)Math.Round(value.Y);
_firstIndex = (int)(value.Y / AverageItemSize);
_lastIndex = _firstIndex + count;
_panel.PixelOffset = value.Y % AverageItemSize;
Renumber();
}
}
Size IScrollable.Viewport => new Size(1, _lastIndex - _firstIndex);
Size IScrollable.Viewport => new Size(1, (_lastIndex - _firstIndex) * AverageItemSize);
Size IScrollable.ScrollSize => new Size(0, 1);
Size IScrollable.PageScrollSize => new Size(0, 1);
private double AverageItemSize => _panel?.AverageItemSize ?? 1;
protected override Size ArrangeOverride(Size finalSize)
{
var result = base.ArrangeOverride(finalSize);

85
src/Avalonia.Controls/VirtualizingStackPanel.cs

@ -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;
}
}
}

Loading…
Cancel
Save