1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-12 00:27:25 +08:00
osu-lazer/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

160 lines
4.9 KiB
C#
Raw Normal View History

// 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.
2018-04-13 17:19:50 +08:00
using System;
using System.Collections.Generic;
2017-12-12 16:48:38 +08:00
using System.Linq;
2018-04-13 17:19:50 +08:00
2017-12-12 16:48:38 +08:00
namespace osu.Game.Screens.Select.Carousel
{
/// <summary>
/// A group which ensures at least one item is selected (if the group itself is selected).
2017-12-12 16:48:38 +08:00
/// </summary>
public class CarouselGroupEagerSelect : CarouselGroup
{
public CarouselGroupEagerSelect()
2017-12-12 16:48:38 +08:00
{
State.ValueChanged += state =>
2017-12-12 16:48:38 +08:00
{
if (state.NewValue == CarouselItemState.Selected)
attemptSelection();
2017-12-12 16:48:38 +08:00
};
}
2018-04-13 17:19:50 +08:00
/// <summary>
/// The last selected item.
/// </summary>
2023-01-09 02:02:48 +08:00
protected CarouselItem? LastSelected { get; private set; }
2018-04-13 17:19:50 +08:00
/// <summary>
/// We need to keep track of the index for cases where the selection is removed but we want to select a new item based on its old location.
/// </summary>
private int lastSelectedIndex;
2018-04-13 17:19:50 +08:00
/// <summary>
/// To avoid overhead during filter operations, we don't attempt any selections until after all
/// items have been filtered. This bool will be true during the base <see cref="Filter(FilterCriteria)"/>
/// operation.
/// </summary>
private bool filteringItems;
2018-04-13 17:19:50 +08:00
public override void Filter(FilterCriteria criteria)
{
filteringItems = true;
base.Filter(criteria);
filteringItems = false;
2018-04-13 17:19:50 +08:00
attemptSelection();
}
2018-04-13 17:19:50 +08:00
public override void RemoveItem(CarouselItem i)
{
base.RemoveItem(i);
2018-04-13 17:19:50 +08:00
if (i != LastSelected)
updateSelectedIndex();
}
2018-04-13 17:19:50 +08:00
private bool addingItems;
public void AddItems(IEnumerable<CarouselItem> items)
{
addingItems = true;
foreach (var i in items)
AddItem(i);
addingItems = false;
attemptSelection();
}
public override void AddItem(CarouselItem i)
{
base.AddItem(i);
if (!addingItems)
attemptSelection();
}
2018-04-13 17:19:50 +08:00
protected override void ChildItemStateChanged(CarouselItem item, CarouselItemState value)
{
base.ChildItemStateChanged(item, value);
2018-04-13 17:19:50 +08:00
switch (value)
{
case CarouselItemState.Selected:
updateSelected(item);
break;
2019-04-01 11:44:46 +08:00
case CarouselItemState.NotSelected:
case CarouselItemState.Collapsed:
attemptSelection();
break;
}
}
2018-04-13 17:19:50 +08:00
private void attemptSelection()
{
if (filteringItems) return;
2018-04-13 17:19:50 +08:00
// we only perform eager selection if we are a currently selected group.
2019-02-21 17:56:34 +08:00
if (State.Value != CarouselItemState.Selected) return;
2018-04-13 17:19:50 +08:00
// we only perform eager selection if none of our items are in a selected state already.
if (Items.Any(i => i.State.Value == CarouselItemState.Selected)) return;
2018-04-13 17:19:50 +08:00
PerformSelection();
}
2018-04-13 17:19:50 +08:00
/// <summary>
/// Finds the item this group would select next if it attempted selection
/// </summary>
/// <returns>An unfiltered item nearest to the last selected one or null if all items are filtered</returns>
2023-01-09 02:02:48 +08:00
protected virtual CarouselItem? GetNextToSelect()
2020-03-26 06:19:54 +08:00
{
if (Items.Count == 0)
return null;
int forwardsIndex = lastSelectedIndex;
int backwardsIndex = Math.Min(lastSelectedIndex, Items.Count - 1);
while (true)
{
bool hasBackwards = backwardsIndex >= 0 && backwardsIndex < Items.Count;
bool hasForwards = forwardsIndex < Items.Count;
if (!hasBackwards && !hasForwards)
return null;
if (hasForwards && !Items[forwardsIndex].Filtered.Value)
2022-08-26 18:32:49 +08:00
return Items[forwardsIndex];
if (hasBackwards && !Items[backwardsIndex].Filtered.Value)
2022-08-26 18:32:49 +08:00
return Items[backwardsIndex];
forwardsIndex++;
backwardsIndex--;
}
2020-03-26 06:19:54 +08:00
}
protected virtual void PerformSelection()
{
2023-01-09 02:02:48 +08:00
CarouselItem? nextToSelect = GetNextToSelect();
2018-04-13 17:19:50 +08:00
if (nextToSelect != null)
nextToSelect.State.Value = CarouselItemState.Selected;
else
updateSelected(null);
}
2018-04-13 17:19:50 +08:00
2023-01-09 02:02:48 +08:00
private void updateSelected(CarouselItem? newSelection)
{
if (newSelection != null)
LastSelected = newSelection;
updateSelectedIndex();
}
2018-04-13 17:19:50 +08:00
private void updateSelectedIndex() => lastSelectedIndex = LastSelected == null ? 0 : Math.Max(0, GetIndexOfItem(LastSelected));
2017-12-12 16:48:38 +08:00
}
}