mirror of
https://github.com/osukey/osukey.git
synced 2025-07-02 16:59:53 +09:00
Greatly improve performance when many hidden panels are on-screen
This commit is contained in:
@ -44,7 +44,7 @@ namespace osu.Game.Screens.Select
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public BeatmapSetInfo SelectedBeatmapSet => selectedBeatmapSet?.BeatmapSet;
|
public BeatmapSetInfo SelectedBeatmapSet => selectedBeatmapSet?.BeatmapSet;
|
||||||
|
|
||||||
private CarouselBeatmapSet selectedBeatmapSet => beatmapSets.FirstOrDefault(s => s.State == CarouselItemState.Selected);
|
private CarouselBeatmapSet selectedBeatmapSet;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raised when the <see cref="SelectedBeatmap"/> is changed.
|
/// Raised when the <see cref="SelectedBeatmap"/> is changed.
|
||||||
@ -73,26 +73,14 @@ namespace osu.Game.Screens.Select
|
|||||||
Schedule(() =>
|
Schedule(() =>
|
||||||
{
|
{
|
||||||
root = newRoot;
|
root = newRoot;
|
||||||
updateItems();
|
scrollableContent.Clear(false);
|
||||||
|
yPositionsCache.Invalidate();
|
||||||
BeatmapSetsChanged?.Invoke();
|
BeatmapSetsChanged?.Invoke();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Call after altering <see cref="BeatmapSets"/> in any way.
|
|
||||||
/// </summary>
|
|
||||||
private void updateItems()
|
|
||||||
{
|
|
||||||
scrollableContent.Clear(false);
|
|
||||||
Items = root.Drawables.ToList();
|
|
||||||
yPositionsCache.Invalidate();
|
|
||||||
|
|
||||||
if (root.Children == null || root.Children.All(c => c.Filtered))
|
|
||||||
SelectionChanged?.Invoke(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly List<float> yPositions = new List<float>();
|
private readonly List<float> yPositions = new List<float>();
|
||||||
private Cached yPositionsCache = new Cached();
|
private Cached yPositionsCache = new Cached();
|
||||||
|
|
||||||
@ -126,7 +114,7 @@ namespace osu.Game.Screens.Select
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
root.RemoveChild(existingSet);
|
root.RemoveChild(existingSet);
|
||||||
updateItems();
|
yPositionsCache.Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateBeatmapSet(BeatmapSetInfo beatmapSet)
|
public void UpdateBeatmapSet(BeatmapSetInfo beatmapSet)
|
||||||
@ -142,7 +130,7 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
if (newSet == null)
|
if (newSet == null)
|
||||||
{
|
{
|
||||||
updateItems();
|
yPositionsCache.Invalidate();
|
||||||
SelectNext();
|
SelectNext();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -155,7 +143,7 @@ namespace osu.Game.Screens.Select
|
|||||||
if (hadSelection)
|
if (hadSelection)
|
||||||
select((CarouselItem)newSet.Beatmaps.FirstOrDefault(b => b.Beatmap.ID == selectedBeatmap?.Beatmap.ID) ?? newSet);
|
select((CarouselItem)newSet.Beatmaps.FirstOrDefault(b => b.Beatmap.ID == selectedBeatmap?.Beatmap.ID) ?? newSet);
|
||||||
|
|
||||||
updateItems();
|
yPositionsCache.Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SelectBeatmap(BeatmapInfo beatmap)
|
public void SelectBeatmap(BeatmapInfo beatmap)
|
||||||
@ -200,8 +188,10 @@ namespace osu.Game.Screens.Select
|
|||||||
select(beatmap);
|
select(beatmap);
|
||||||
return;
|
return;
|
||||||
case CarouselBeatmapSet set:
|
case CarouselBeatmapSet set:
|
||||||
if (!skipDifficulties) continue;
|
if (skipDifficulties)
|
||||||
select(set);
|
select(set);
|
||||||
|
else
|
||||||
|
select(direction > 0 ? set.Beatmaps.First() : set.Beatmaps.Last());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -209,10 +199,7 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
public void SelectNextRandom()
|
public void SelectNextRandom()
|
||||||
{
|
{
|
||||||
if (!beatmapSets.Any())
|
var visible = beatmapSets.Where(s => !s.Filtered).ToList();
|
||||||
return;
|
|
||||||
|
|
||||||
var visible = beatmapSets.Where(select => !select.Filtered).ToList();
|
|
||||||
if (!visible.Any())
|
if (!visible.Any())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -291,7 +278,7 @@ namespace osu.Game.Screens.Select
|
|||||||
FilterTask = null;
|
FilterTask = null;
|
||||||
|
|
||||||
root.Filter(activeCriteria);
|
root.Filter(activeCriteria);
|
||||||
updateItems();
|
yPositionsCache.Invalidate();
|
||||||
|
|
||||||
if (scroll) ScrollToSelected(false);
|
if (scroll) ScrollToSelected(false);
|
||||||
}
|
}
|
||||||
@ -329,6 +316,7 @@ namespace osu.Game.Screens.Select
|
|||||||
{
|
{
|
||||||
if (v == CarouselItemState.Selected)
|
if (v == CarouselItemState.Selected)
|
||||||
{
|
{
|
||||||
|
selectedBeatmapSet = set;
|
||||||
SelectionChanged?.Invoke(c.Beatmap);
|
SelectionChanged?.Invoke(c.Beatmap);
|
||||||
yPositionsCache.Invalidate();
|
yPositionsCache.Invalidate();
|
||||||
Schedule(() => ScrollToSelected());
|
Schedule(() => ScrollToSelected());
|
||||||
@ -410,6 +398,12 @@ namespace osu.Game.Screens.Select
|
|||||||
yPositionsCache.Validate();
|
yPositionsCache.Validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void noSelection()
|
||||||
|
{
|
||||||
|
if (root.Children == null || root.Children.All(c => c.Filtered))
|
||||||
|
SelectionChanged?.Invoke(null);
|
||||||
|
}
|
||||||
|
|
||||||
private void select(CarouselItem item)
|
private void select(CarouselItem item)
|
||||||
{
|
{
|
||||||
if (item == null) return;
|
if (item == null) return;
|
||||||
@ -450,11 +444,18 @@ namespace osu.Game.Screens.Select
|
|||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
float drawHeight = DrawHeight;
|
// todo: scheduled scrolls...
|
||||||
|
|
||||||
if (!yPositionsCache.IsValid)
|
if (!yPositionsCache.IsValid)
|
||||||
|
{
|
||||||
|
Items = root.Drawables.ToList();
|
||||||
computeYPositions();
|
computeYPositions();
|
||||||
|
|
||||||
|
if (selectedBeatmapSet != null && beatmapSets.All(s => s.Filtered))
|
||||||
|
SelectionChanged?.Invoke(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
float drawHeight = DrawHeight;
|
||||||
|
|
||||||
// Remove all items that should no longer be on-screen
|
// Remove all items that should no longer be on-screen
|
||||||
scrollableContent.RemoveAll(delegate (DrawableCarouselItem p)
|
scrollableContent.RemoveAll(delegate (DrawableCarouselItem p)
|
||||||
{
|
{
|
||||||
@ -469,21 +470,21 @@ namespace osu.Game.Screens.Select
|
|||||||
int firstIndex = yPositions.BinarySearch(Current - DrawableCarouselItem.MAX_HEIGHT);
|
int firstIndex = yPositions.BinarySearch(Current - DrawableCarouselItem.MAX_HEIGHT);
|
||||||
if (firstIndex < 0) firstIndex = ~firstIndex;
|
if (firstIndex < 0) firstIndex = ~firstIndex;
|
||||||
int lastIndex = yPositions.BinarySearch(Current + drawHeight);
|
int lastIndex = yPositions.BinarySearch(Current + drawHeight);
|
||||||
if (lastIndex < 0)
|
if (lastIndex < 0) lastIndex = ~lastIndex;
|
||||||
{
|
|
||||||
lastIndex = ~lastIndex;
|
|
||||||
|
|
||||||
// Add the first item of the last visible beatmap group to preload its data.
|
int notVisibleCount = 0;
|
||||||
if (lastIndex != 0 && Items[lastIndex - 1] is DrawableCarouselBeatmapSet)
|
|
||||||
lastIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add those items within the previously found index range that should be displayed.
|
// Add those items within the previously found index range that should be displayed.
|
||||||
for (int i = firstIndex; i < lastIndex; ++i)
|
for (int i = firstIndex; i < lastIndex; ++i)
|
||||||
{
|
{
|
||||||
DrawableCarouselItem item = Items[i];
|
DrawableCarouselItem item = Items[i];
|
||||||
|
|
||||||
if (!item.Item.Visible) continue;
|
if (!item.Item.Visible)
|
||||||
|
{
|
||||||
|
if (!item.IsPresent)
|
||||||
|
notVisibleCount++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Only add if we're not already part of the content.
|
// Only add if we're not already part of the content.
|
||||||
if (!scrollableContent.Contains(item))
|
if (!scrollableContent.Contains(item))
|
||||||
@ -506,6 +507,10 @@ namespace osu.Game.Screens.Select
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this is not actually useful right now, but once we have groups may well be.
|
||||||
|
if (notVisibleCount > 50)
|
||||||
|
yPositionsCache.Invalidate();
|
||||||
|
|
||||||
// Update externally controlled state of currently visible items
|
// Update externally controlled state of currently visible items
|
||||||
// (e.g. x-offset and opacity).
|
// (e.g. x-offset and opacity).
|
||||||
float halfHeight = drawHeight / 2;
|
float halfHeight = drawHeight / 2;
|
||||||
|
@ -67,6 +67,7 @@ namespace osu.Game.Screens.Select.Carousel
|
|||||||
updateSelected(item);
|
updateSelected(item);
|
||||||
break;
|
break;
|
||||||
case CarouselItemState.NotSelected:
|
case CarouselItemState.NotSelected:
|
||||||
|
case CarouselItemState.Collapsed:
|
||||||
attemptSelection();
|
attemptSelection();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -29,12 +29,11 @@ namespace osu.Game.Screens.Select.Carousel
|
|||||||
List<DrawableCarouselItem> items = new List<DrawableCarouselItem>();
|
List<DrawableCarouselItem> items = new List<DrawableCarouselItem>();
|
||||||
|
|
||||||
var self = drawableRepresentation.Value;
|
var self = drawableRepresentation.Value;
|
||||||
if (self != null) items.Add(self);
|
if (self?.IsPresent == true) items.Add(self);
|
||||||
|
|
||||||
if (InternalChildren != null)
|
if (InternalChildren != null)
|
||||||
foreach (var c in InternalChildren)
|
foreach (var c in InternalChildren)
|
||||||
// if (!c.Filtered) <- potential optimisation at the cost of no fade out animations.
|
items.AddRange(c.Drawables);
|
||||||
items.AddRange(c.Drawables);
|
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
@ -48,7 +47,7 @@ namespace osu.Game.Screens.Select.Carousel
|
|||||||
|
|
||||||
// it's important we do the deselection after removing, so any further actions based on
|
// it's important we do the deselection after removing, so any further actions based on
|
||||||
// State.ValueChanged make decisions post-removal.
|
// State.ValueChanged make decisions post-removal.
|
||||||
if (i.State.Value == CarouselItemState.Selected) i.State.Value = CarouselItemState.NotSelected;
|
i.State.Value = CarouselItemState.Collapsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CarouselItem()
|
protected CarouselItem()
|
||||||
|
Reference in New Issue
Block a user