Store y positions inside items rather than in a separate array

This commit is contained in:
Dean Herbert
2020-10-13 13:21:21 +09:00
parent b92c22ad42
commit f6aa448523
2 changed files with 46 additions and 18 deletions

View File

@ -116,7 +116,6 @@ namespace osu.Game.Screens.Select
}); });
} }
private readonly List<float> yPositions = new List<float>();
private readonly List<CarouselItem> visibleItems = new List<CarouselItem>(); private readonly List<CarouselItem> visibleItems = new List<CarouselItem>();
private readonly Cached itemsCache = new Cached(); private readonly Cached itemsCache = new Cached();
@ -570,23 +569,15 @@ namespace osu.Game.Screens.Select
if (revalidateItems) if (revalidateItems)
updateYPositions(); updateYPositions();
// Find index range of all items that should be on-screen var (firstIndex, lastIndex) = getDisplayRange();
int firstIndex = yPositions.BinarySearch(visibleUpperBound);
if (firstIndex < 0) firstIndex = ~firstIndex;
int lastIndex = yPositions.BinarySearch(visibleBottomBound);
if (lastIndex < 0) lastIndex = ~lastIndex;
// as we can't be 100% sure on the size of individual carousel drawables,
// always play it safe and extend bounds by one.
firstIndex = Math.Max(0, firstIndex - 1);
lastIndex = Math.Min(yPositions.Count, lastIndex + 1);
if (revalidateItems || firstIndex != displayedRange.first || lastIndex != displayedRange.last) if (revalidateItems || firstIndex != displayedRange.first || lastIndex != displayedRange.last)
{ {
Logger.Log("revalidation requested"); Logger.Log("revalidation requested");
// Remove all items that should no longer be on-screen // Remove all items that should no longer be on-screen
scrollableContent.RemoveAll(p => p.Y + p.Item.TotalHeight < visibleUpperBound || p.Y > visibleBottomBound); // TODO: figure out a more resilient way of doing this removal.
// scrollableContent.RemoveAll(p => p.Y + p.Item.TotalHeight < visibleUpperBound || p.Y > visibleBottomBound);
displayedRange = (firstIndex, lastIndex); displayedRange = (firstIndex, lastIndex);
@ -601,7 +592,7 @@ namespace osu.Game.Screens.Select
{ {
Logger.Log($"getting panel for {item} from pool"); Logger.Log($"getting panel for {item} from pool");
panel = setPool.Get(p => p.Item = item); panel = setPool.Get(p => p.Item = item);
panel.Y = yPositions[i]; panel.Y = item.CarouselYPosition;
panel.Depth = i; panel.Depth = i;
panel.ClearTransforms(); panel.ClearTransforms();
@ -611,9 +602,9 @@ namespace osu.Game.Screens.Select
else else
{ {
if (panel.IsPresent) if (panel.IsPresent)
panel.MoveToY(yPositions[i], 800, Easing.OutQuint); panel.MoveToY(item.CarouselYPosition, 800, Easing.OutQuint);
else else
panel.Y = yPositions[i]; panel.Y = item.CarouselYPosition;
scrollableContent.ChangeChildDepth(panel, i); scrollableContent.ChangeChildDepth(panel, i);
} }
@ -626,6 +617,22 @@ namespace osu.Game.Screens.Select
updateItem(p); updateItem(p);
} }
private (int firstIndex, int lastIndex) getDisplayRange()
{
// Find index range of all items that should be on-screen
// TODO: reduce allocs of CarouselBoundsItem.
int firstIndex = visibleItems.BinarySearch(new CarouselBoundsItem(visibleUpperBound));
if (firstIndex < 0) firstIndex = ~firstIndex;
int lastIndex = visibleItems.BinarySearch(new CarouselBoundsItem(visibleBottomBound));
if (lastIndex < 0) lastIndex = ~lastIndex;
// as we can't be 100% sure on the size of individual carousel drawables,
// always play it safe and extend bounds by one.
firstIndex = Math.Max(0, firstIndex - 1);
lastIndex = Math.Min(visibleItems.Count, lastIndex + 1);
return (firstIndex, lastIndex);
}
protected override void UpdateAfterChildren() protected override void UpdateAfterChildren()
{ {
base.UpdateAfterChildren(); base.UpdateAfterChildren();
@ -698,7 +705,6 @@ namespace osu.Game.Screens.Select
/// <returns>The Y position of the currently selected item.</returns> /// <returns>The Y position of the currently selected item.</returns>
private void updateYPositions() private void updateYPositions()
{ {
yPositions.Clear();
visibleItems.Clear(); visibleItems.Clear();
float currentY = visibleHalfHeight; float currentY = visibleHalfHeight;
@ -715,7 +721,7 @@ namespace osu.Game.Screens.Select
case CarouselBeatmapSet set: case CarouselBeatmapSet set:
{ {
visibleItems.Add(set); visibleItems.Add(set);
yPositions.Add(currentY); set.CarouselYPosition = currentY;
if (item.State.Value == CarouselItemState.Selected) if (item.State.Value == CarouselItemState.Selected)
{ {
@ -815,6 +821,20 @@ namespace osu.Game.Screens.Select
p.SetMultiplicativeAlpha(Math.Clamp(1.75f - 1.5f * dist, 0, 1)); p.SetMultiplicativeAlpha(Math.Clamp(1.75f - 1.5f * dist, 0, 1));
} }
/// <summary>
/// A carousel item strictly used for binary search purposes.
/// </summary>
private class CarouselBoundsItem : CarouselItem
{
public CarouselBoundsItem(in float pos)
{
CarouselYPosition = pos;
}
public override DrawableCarouselItem CreateDrawableRepresentation() =>
throw new NotImplementedException();
}
private class CarouselRoot : CarouselGroupEagerSelect private class CarouselRoot : CarouselGroupEagerSelect
{ {
private readonly BeatmapCarousel carousel; private readonly BeatmapCarousel carousel;

View File

@ -1,14 +1,20 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Bindables; using osu.Framework.Bindables;
namespace osu.Game.Screens.Select.Carousel namespace osu.Game.Screens.Select.Carousel
{ {
public abstract class CarouselItem public abstract class CarouselItem : IComparable<CarouselItem>
{ {
public virtual float TotalHeight => 0; public virtual float TotalHeight => 0;
/// <summary>
/// An externally defined value used to determine this item's vertical display offset relative to the carousel.
/// </summary>
public float CarouselYPosition;
public readonly BindableBool Filtered = new BindableBool(); public readonly BindableBool Filtered = new BindableBool();
public readonly Bindable<CarouselItemState> State = new Bindable<CarouselItemState>(CarouselItemState.NotSelected); public readonly Bindable<CarouselItemState> State = new Bindable<CarouselItemState>(CarouselItemState.NotSelected);
@ -42,6 +48,8 @@ namespace osu.Game.Screens.Select.Carousel
} }
public virtual int CompareTo(FilterCriteria criteria, CarouselItem other) => ChildID.CompareTo(other.ChildID); public virtual int CompareTo(FilterCriteria criteria, CarouselItem other) => ChildID.CompareTo(other.ChildID);
public int CompareTo(CarouselItem other) => CarouselYPosition.CompareTo(other.CarouselYPosition);
} }
public enum CarouselItemState public enum CarouselItemState