Browse Source

Added pixel offset to virtualizing panel.

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

85
src/Avalonia.Controls/VirtualizingStackPanel.cs

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