diff --git a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs
index 0a7ca5a6bb..10bc069cfc 100644
--- a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs
+++ b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs
@@ -102,23 +102,15 @@ namespace osu.Game.Screens.SelectV2
switch (model)
{
case GroupDefinition group:
- if (lastSelectedGroup != null)
- setVisibilityOfGroupItems(lastSelectedGroup, false);
-
- // Collapsing an open group.
+ // Special case – collapsing an open group.
if (lastSelectedGroup == group)
{
+ setVisibilityOfGroupItems(lastSelectedGroup, false);
lastSelectedGroup = null;
return false;
}
- lastSelectedGroup = group;
-
- setVisibilityOfGroupItems(group, true);
-
- // In stable, you can kinda select a group (expand without changing selection)
- // For simplicity, let's not do that for now and handle similar to a beatmap set header.
- CurrentSelection = grouping.GroupItems[group].First().Model;
+ setVisibleGroup(group);
return false;
case BeatmapSetInfo setInfo:
@@ -127,28 +119,52 @@ namespace osu.Game.Screens.SelectV2
return false;
case BeatmapInfo beatmapInfo:
- if (lastSelectedBeatmap != null)
- setVisibilityOfSetItems(lastSelectedBeatmap.BeatmapSet!, false);
- lastSelectedBeatmap = beatmapInfo;
// If we have groups, we need to account for them.
- if (grouping.GroupItems.Count > 0)
+ if (Criteria.SplitOutDifficulties)
{
// Find the containing group. There should never be too many groups so iterating is efficient enough.
- var group = grouping.GroupItems.Single(kvp => kvp.Value.Any(i => ReferenceEquals(i.Model, beatmapInfo))).Key;
- setVisibilityOfGroupItems(group, true);
+ GroupDefinition group = grouping.GroupItems.Single(kvp => kvp.Value.Any(i => ReferenceEquals(i.Model, beatmapInfo))).Key;
+
+ setVisibleGroup(group);
}
else
- setVisibilityOfSetItems(beatmapInfo.BeatmapSet!, true);
+ {
+ setVisibleSet(beatmapInfo);
+ }
- // Ensure the group containing this beatmap is also visible.
- // TODO: need to update visibility of correct group?
return true;
}
return true;
}
+ protected override bool CheckValidForGroupSelection(CarouselItem item)
+ {
+ switch (item.Model)
+ {
+ case BeatmapSetInfo:
+ return true;
+
+ case BeatmapInfo:
+ return Criteria.SplitOutDifficulties;
+
+ case GroupDefinition:
+ return false;
+
+ default:
+ throw new ArgumentException($"Unsupported model type {item.Model}");
+ }
+ }
+
+ private void setVisibleGroup(GroupDefinition group)
+ {
+ if (lastSelectedGroup != null)
+ setVisibilityOfGroupItems(lastSelectedGroup, false);
+ lastSelectedGroup = group;
+ setVisibilityOfGroupItems(group, true);
+ }
+
private void setVisibilityOfGroupItems(GroupDefinition group, bool visible)
{
if (grouping.GroupItems.TryGetValue(group, out var items))
@@ -158,6 +174,14 @@ namespace osu.Game.Screens.SelectV2
}
}
+ private void setVisibleSet(BeatmapInfo beatmapInfo)
+ {
+ if (lastSelectedBeatmap != null)
+ setVisibilityOfSetItems(lastSelectedBeatmap.BeatmapSet!, false);
+ lastSelectedBeatmap = beatmapInfo;
+ setVisibilityOfSetItems(beatmapInfo.BeatmapSet!, true);
+ }
+
private void setVisibilityOfSetItems(BeatmapSetInfo set, bool visible)
{
if (grouping.SetItems.TryGetValue(set, out var items))
diff --git a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterGrouping.cs b/osu.Game/Screens/SelectV2/BeatmapCarouselFilterGrouping.cs
index 9ecf735980..951b010564 100644
--- a/osu.Game/Screens/SelectV2/BeatmapCarouselFilterGrouping.cs
+++ b/osu.Game/Screens/SelectV2/BeatmapCarouselFilterGrouping.cs
@@ -56,11 +56,7 @@ namespace osu.Game.Screens.SelectV2
{
starGroup = (int)Math.Floor(b.StarRating);
group = new GroupDefinition($"{starGroup} - {++starGroup} *");
- diffItems.Add(new CarouselItem(group)
- {
- DrawHeight = GroupPanel.HEIGHT,
- IsGroupSelectionTarget = true
- });
+ diffItems.Add(new CarouselItem(group) { DrawHeight = GroupPanel.HEIGHT });
}
if (!groupItems.TryGetValue(group!, out var related))
@@ -70,7 +66,6 @@ namespace osu.Game.Screens.SelectV2
diffItems.Add(item);
item.IsVisible = false;
- item.IsGroupSelectionTarget = true;
}
return diffItems;
@@ -92,7 +87,6 @@ namespace osu.Game.Screens.SelectV2
newItems.Add(new CarouselItem(b.BeatmapSet!)
{
DrawHeight = BeatmapSetPanel.HEIGHT,
- IsGroupSelectionTarget = true
});
}
@@ -104,7 +98,6 @@ namespace osu.Game.Screens.SelectV2
newItems.Add(item);
lastItem = item;
- item.IsGroupSelectionTarget = false;
item.IsVisible = false;
}
diff --git a/osu.Game/Screens/SelectV2/BeatmapSetPanel.cs b/osu.Game/Screens/SelectV2/BeatmapSetPanel.cs
index 37e8b88f71..06e3ad3426 100644
--- a/osu.Game/Screens/SelectV2/BeatmapSetPanel.cs
+++ b/osu.Game/Screens/SelectV2/BeatmapSetPanel.cs
@@ -67,7 +67,6 @@ namespace osu.Game.Screens.SelectV2
base.PrepareForUse();
Debug.Assert(Item != null);
- Debug.Assert(Item.IsGroupSelectionTarget);
var beatmapSetInfo = (BeatmapSetInfo)Item.Model;
diff --git a/osu.Game/Screens/SelectV2/Carousel.cs b/osu.Game/Screens/SelectV2/Carousel.cs
index 7184aaa866..a76b6efee9 100644
--- a/osu.Game/Screens/SelectV2/Carousel.cs
+++ b/osu.Game/Screens/SelectV2/Carousel.cs
@@ -168,6 +168,13 @@ namespace osu.Game.Screens.SelectV2
protected Drawable? GetMaterialisedDrawableForItem(CarouselItem item) =>
scroll.Panels.SingleOrDefault(p => ((ICarouselPanel)p).Item == item);
+ ///
+ /// When a user is traversing the carousel via group selection keys, assert whether the item provided is a valid target.
+ ///
+ /// The candidate item.
+ /// Whether the provided item is a valid group target. If false, more panels will be checked in the user's requested direction until a valid target is found.
+ protected virtual bool CheckValidForGroupSelection(CarouselItem item) => true;
+
///
/// Called when an item is "selected".
///
@@ -373,7 +380,7 @@ namespace osu.Game.Screens.SelectV2
// make sure to go back to the group header this item belongs to, so that the block below doesn't find it and stop too early.
if (isGroupSelection && direction < 0)
{
- while (!carouselItems[selectionIndex].IsGroupSelectionTarget)
+ while (!CheckValidForGroupSelection(carouselItems[selectionIndex]))
selectionIndex--;
}
@@ -394,7 +401,11 @@ namespace osu.Game.Screens.SelectV2
bool attemptSelection(CarouselItem item)
{
- if (!item.IsVisible || (isGroupSelection && !item.IsGroupSelectionTarget))
+ // Keyboard (non-group) selection should only consider visible items.
+ if (!isGroupSelection && !item.IsVisible)
+ return false;
+
+ if (isGroupSelection && !CheckValidForGroupSelection(item))
return false;
if (isGroupSelection)
@@ -427,8 +438,9 @@ namespace osu.Game.Screens.SelectV2
currentKeyboardSelection = new Selection(model);
currentSelection = currentKeyboardSelection;
- selectionValid.Invalidate();
}
+
+ selectionValid.Invalidate();
}
private void setKeyboardSelection(object? model)
diff --git a/osu.Game/Screens/SelectV2/CarouselItem.cs b/osu.Game/Screens/SelectV2/CarouselItem.cs
index 2cb96a3d7f..13d5c840cf 100644
--- a/osu.Game/Screens/SelectV2/CarouselItem.cs
+++ b/osu.Game/Screens/SelectV2/CarouselItem.cs
@@ -29,11 +29,6 @@ namespace osu.Game.Screens.SelectV2
///
public float DrawHeight { get; set; } = DEFAULT_HEIGHT;
- ///
- /// Whether this item should be a valid target for user group selection hotkeys.
- ///
- public bool IsGroupSelectionTarget { get; set; }
-
///
/// Whether this item is visible or collapsed (hidden).
///
diff --git a/osu.Game/Screens/SelectV2/GroupPanel.cs b/osu.Game/Screens/SelectV2/GroupPanel.cs
index e837d8a32f..882d77cb8d 100644
--- a/osu.Game/Screens/SelectV2/GroupPanel.cs
+++ b/osu.Game/Screens/SelectV2/GroupPanel.cs
@@ -79,7 +79,6 @@ namespace osu.Game.Screens.SelectV2
base.PrepareForUse();
Debug.Assert(Item != null);
- Debug.Assert(Item.IsGroupSelectionTarget);
GroupDefinition group = (GroupDefinition)Item.Model;