mirror of
https://github.com/ppy/osu.git
synced 2025-01-27 02:32:59 +08:00
Add per-difficulty filtering support
Filters based on selected ruleset
This commit is contained in:
parent
ce37688cd3
commit
f58c554d19
@ -40,6 +40,7 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
public BeatmapSetInfo BeatmapSet;
|
||||
|
||||
private BeatmapGroupState state;
|
||||
|
||||
public BeatmapGroupState State
|
||||
{
|
||||
get { return state; }
|
||||
@ -52,7 +53,8 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
case BeatmapGroupState.Expanded:
|
||||
Header.State = PanelSelectedState.Selected;
|
||||
foreach (BeatmapPanel panel in BeatmapPanels)
|
||||
panel.State = panel == SelectedPanel ? PanelSelectedState.Selected : PanelSelectedState.NotSelected;
|
||||
panel.State = panel == SelectedPanel ? PanelSelectedState.Selected :
|
||||
!panel.Filtered ? PanelSelectedState.NotSelected : PanelSelectedState.Hidden;
|
||||
break;
|
||||
case BeatmapGroupState.Collapsed:
|
||||
Header.State = PanelSelectedState.NotSelected;
|
||||
@ -108,7 +110,7 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
|
||||
//we want to make sure one of our children is selected in the case none have been selected yet.
|
||||
if (SelectedPanel == null)
|
||||
BeatmapPanels.First().State = PanelSelectedState.Selected;
|
||||
BeatmapPanels.First(p => !p.Filtered).State = PanelSelectedState.Selected;
|
||||
}
|
||||
|
||||
private void panelGainedSelection(BeatmapPanel panel)
|
||||
|
@ -61,6 +61,8 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
return base.OnClick(state);
|
||||
}
|
||||
|
||||
public bool Filtered { get; set; }
|
||||
|
||||
protected override void ApplyState(PanelSelectedState last = PanelSelectedState.Hidden)
|
||||
{
|
||||
if (!IsLoaded) return;
|
||||
|
@ -131,7 +131,7 @@ namespace osu.Game.Screens.Select
|
||||
var newSelection =
|
||||
newGroup.BeatmapPanels.Find(p => p.Beatmap.ID == selectedPanel?.Beatmap.ID);
|
||||
|
||||
if(newSelection == null && oldGroup != null && selectedPanel != null)
|
||||
if (newSelection == null && oldGroup != null && selectedPanel != null)
|
||||
newSelection = newGroup.BeatmapPanels[Math.Min(newGroup.BeatmapPanels.Count - 1, oldGroup.BeatmapPanels.IndexOf(selectedPanel))];
|
||||
|
||||
selectGroup(newGroup, newSelection);
|
||||
@ -178,42 +178,62 @@ namespace osu.Game.Screens.Select
|
||||
SelectionChanged?.Invoke(null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Increment selection in the carousel in a chosen direction.
|
||||
/// </summary>
|
||||
/// <param name="direction">The direction to increment. Negative is backwards.</param>
|
||||
/// <param name="skipDifficulties">Whether to skip individual difficulties and only increment over full groups.</param>
|
||||
public void SelectNext(int direction = 1, bool skipDifficulties = true)
|
||||
{
|
||||
// todo: we may want to refactor and remove this as an optimisation in the future.
|
||||
if (groups.All(g => g.State == BeatmapGroupState.Hidden))
|
||||
{
|
||||
selectNullBeatmap();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!skipDifficulties && selectedGroup != null)
|
||||
{
|
||||
int i = selectedGroup.BeatmapPanels.IndexOf(selectedPanel) + direction;
|
||||
int originalIndex = Math.Max(0, groups.IndexOf(selectedGroup));
|
||||
int currentIndex = originalIndex;
|
||||
|
||||
if (i >= 0 && i < selectedGroup.BeatmapPanels.Count)
|
||||
{
|
||||
//changing difficulty panel, not set.
|
||||
selectGroup(selectedGroup, selectedGroup.BeatmapPanels[i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// local function to increment the index in the required direction, wrapping over extremities.
|
||||
int incrementIndex() => currentIndex = (currentIndex + direction + groups.Count) % groups.Count;
|
||||
|
||||
int startIndex = Math.Max(0, groups.IndexOf(selectedGroup));
|
||||
int index = startIndex;
|
||||
// in the case we are skipping difficulties, we want to increment the index once before starting to find out new target
|
||||
// (we don't care about the currently selected group).
|
||||
if (skipDifficulties)
|
||||
incrementIndex();
|
||||
|
||||
do
|
||||
{
|
||||
index = (index + direction + groups.Count) % groups.Count;
|
||||
if (groups[index].State != BeatmapGroupState.Hidden)
|
||||
{
|
||||
if (skipDifficulties)
|
||||
SelectBeatmap(groups[index].SelectedPanel != null ? groups[index].SelectedPanel.Beatmap : groups[index].BeatmapPanels.First().Beatmap);
|
||||
else
|
||||
SelectBeatmap(direction == 1 ? groups[index].BeatmapPanels.First().Beatmap : groups[index].BeatmapPanels.Last().Beatmap);
|
||||
var group = groups[currentIndex];
|
||||
|
||||
if (group.State == BeatmapGroupState.Hidden) continue;
|
||||
|
||||
// we are only interested in non-filtered panels.
|
||||
IEnumerable<BeatmapPanel> validPanels = group.BeatmapPanels.Where(p => !p.Filtered);
|
||||
|
||||
// if we are considering difficulties, we need to do a few extrea steps.
|
||||
if (!skipDifficulties)
|
||||
{
|
||||
// we want to reverse the panel order if we are searching backwards.
|
||||
if (direction < 0)
|
||||
validPanels = validPanels.Reverse();
|
||||
|
||||
// if we are currently on the selected panel, let's try to find a valid difficulty before leaving to the next group.
|
||||
// the first valid difficulty is found by skipping to the selected panel and then one further.
|
||||
if (currentIndex == originalIndex)
|
||||
validPanels = validPanels.SkipWhile(p => p != selectedPanel).Skip(1);
|
||||
}
|
||||
|
||||
var next = validPanels.FirstOrDefault();
|
||||
|
||||
// at this point, we can perform the selection change if we have a valid new target, else continue to increment in the specified direction.
|
||||
if (next != null)
|
||||
{
|
||||
selectGroup(group, next);
|
||||
return;
|
||||
}
|
||||
} while (index != startIndex);
|
||||
} while (incrementIndex() != originalIndex);
|
||||
}
|
||||
|
||||
private IEnumerable<BeatmapGroup> getVisibleGroups() => groups.Where(selectGroup => selectGroup.State != BeatmapGroupState.Hidden);
|
||||
@ -416,6 +436,8 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
foreach (BeatmapPanel panel in group.BeatmapPanels)
|
||||
{
|
||||
if (panel.Filtered) continue;
|
||||
|
||||
if (panel == selectedPanel)
|
||||
selectedY = currentY + panel.DrawHeight / 2 - DrawHeight / 2;
|
||||
|
||||
@ -460,7 +482,7 @@ namespace osu.Game.Screens.Select
|
||||
try
|
||||
{
|
||||
if (panel == null)
|
||||
panel = group.BeatmapPanels.First();
|
||||
panel = group.BeatmapPanels.First(p => !p.Filtered);
|
||||
|
||||
if (selectedPanel == panel) return;
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Drawables;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Screens.Select.Filter;
|
||||
@ -18,19 +19,26 @@ namespace osu.Game.Screens.Select
|
||||
public RulesetInfo Ruleset;
|
||||
public bool AllowConvertedBeatmaps;
|
||||
|
||||
private bool canConvert(BeatmapInfo beatmapInfo) => beatmapInfo.RulesetID == Ruleset.ID || beatmapInfo.RulesetID == 0 && Ruleset.ID > 0 && AllowConvertedBeatmaps;
|
||||
|
||||
public void Filter(List<BeatmapGroup> groups)
|
||||
{
|
||||
foreach (var g in groups)
|
||||
{
|
||||
var set = g.BeatmapSet;
|
||||
|
||||
bool hasCurrentMode = AllowConvertedBeatmaps || set.Beatmaps.Any(bm => bm.RulesetID == (Ruleset?.ID ?? 0));
|
||||
// we only support converts from osu! mode to other modes for now.
|
||||
// in the future this will have to change, at which point this condition will become a touch more complicated.
|
||||
bool hasCurrentMode = set.Beatmaps.Any(canConvert);
|
||||
|
||||
bool match = hasCurrentMode;
|
||||
|
||||
if (!string.IsNullOrEmpty(SearchText))
|
||||
match &= set.Metadata.SearchableTerms.Any(term => term.IndexOf(SearchText, StringComparison.InvariantCultureIgnoreCase) >= 0);
|
||||
|
||||
foreach (var panel in g.BeatmapPanels)
|
||||
panel.Filtered = !canConvert(panel.Beatmap);
|
||||
|
||||
switch (g.State)
|
||||
{
|
||||
case BeatmapGroupState.Hidden:
|
||||
|
@ -602,6 +602,7 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-frame
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Constants/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=EnumMember/@EntryIndexedValue"><Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=LocalConstants/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=LocalFunctions/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb"><ExtraRule Prefix="_" Suffix="" Style="aaBb" /></Policy></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
|
Loading…
Reference in New Issue
Block a user