1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-08 12:23:21 +08:00

Fix backwards traversal of groupings and allow toggling groups without updating selection

This commit is contained in:
Dean Herbert 2025-01-31 20:58:32 +09:00
parent 764f799dcb
commit d74939e6e9
No known key found for this signature in database
6 changed files with 60 additions and 38 deletions

View File

@ -102,23 +102,15 @@ namespace osu.Game.Screens.SelectV2
switch (model) switch (model)
{ {
case GroupDefinition group: case GroupDefinition group:
if (lastSelectedGroup != null) // Special case collapsing an open group.
setVisibilityOfGroupItems(lastSelectedGroup, false);
// Collapsing an open group.
if (lastSelectedGroup == group) if (lastSelectedGroup == group)
{ {
setVisibilityOfGroupItems(lastSelectedGroup, false);
lastSelectedGroup = null; lastSelectedGroup = null;
return false; return false;
} }
lastSelectedGroup = group; setVisibleGroup(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;
return false; return false;
case BeatmapSetInfo setInfo: case BeatmapSetInfo setInfo:
@ -127,28 +119,52 @@ namespace osu.Game.Screens.SelectV2
return false; return false;
case BeatmapInfo beatmapInfo: case BeatmapInfo beatmapInfo:
if (lastSelectedBeatmap != null)
setVisibilityOfSetItems(lastSelectedBeatmap.BeatmapSet!, false);
lastSelectedBeatmap = beatmapInfo;
// If we have groups, we need to account for them. // 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. // 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; GroupDefinition group = grouping.GroupItems.Single(kvp => kvp.Value.Any(i => ReferenceEquals(i.Model, beatmapInfo))).Key;
setVisibilityOfGroupItems(group, true);
setVisibleGroup(group);
} }
else 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;
} }
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) private void setVisibilityOfGroupItems(GroupDefinition group, bool visible)
{ {
if (grouping.GroupItems.TryGetValue(group, out var items)) 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) private void setVisibilityOfSetItems(BeatmapSetInfo set, bool visible)
{ {
if (grouping.SetItems.TryGetValue(set, out var items)) if (grouping.SetItems.TryGetValue(set, out var items))

View File

@ -56,11 +56,7 @@ namespace osu.Game.Screens.SelectV2
{ {
starGroup = (int)Math.Floor(b.StarRating); starGroup = (int)Math.Floor(b.StarRating);
group = new GroupDefinition($"{starGroup} - {++starGroup} *"); group = new GroupDefinition($"{starGroup} - {++starGroup} *");
diffItems.Add(new CarouselItem(group) diffItems.Add(new CarouselItem(group) { DrawHeight = GroupPanel.HEIGHT });
{
DrawHeight = GroupPanel.HEIGHT,
IsGroupSelectionTarget = true
});
} }
if (!groupItems.TryGetValue(group!, out var related)) if (!groupItems.TryGetValue(group!, out var related))
@ -70,7 +66,6 @@ namespace osu.Game.Screens.SelectV2
diffItems.Add(item); diffItems.Add(item);
item.IsVisible = false; item.IsVisible = false;
item.IsGroupSelectionTarget = true;
} }
return diffItems; return diffItems;
@ -92,7 +87,6 @@ namespace osu.Game.Screens.SelectV2
newItems.Add(new CarouselItem(b.BeatmapSet!) newItems.Add(new CarouselItem(b.BeatmapSet!)
{ {
DrawHeight = BeatmapSetPanel.HEIGHT, DrawHeight = BeatmapSetPanel.HEIGHT,
IsGroupSelectionTarget = true
}); });
} }
@ -104,7 +98,6 @@ namespace osu.Game.Screens.SelectV2
newItems.Add(item); newItems.Add(item);
lastItem = item; lastItem = item;
item.IsGroupSelectionTarget = false;
item.IsVisible = false; item.IsVisible = false;
} }

View File

@ -67,7 +67,6 @@ namespace osu.Game.Screens.SelectV2
base.PrepareForUse(); base.PrepareForUse();
Debug.Assert(Item != null); Debug.Assert(Item != null);
Debug.Assert(Item.IsGroupSelectionTarget);
var beatmapSetInfo = (BeatmapSetInfo)Item.Model; var beatmapSetInfo = (BeatmapSetInfo)Item.Model;

View File

@ -168,6 +168,13 @@ namespace osu.Game.Screens.SelectV2
protected Drawable? GetMaterialisedDrawableForItem(CarouselItem item) => protected Drawable? GetMaterialisedDrawableForItem(CarouselItem item) =>
scroll.Panels.SingleOrDefault(p => ((ICarouselPanel)p).Item == item); scroll.Panels.SingleOrDefault(p => ((ICarouselPanel)p).Item == item);
/// <summary>
/// When a user is traversing the carousel via group selection keys, assert whether the item provided is a valid target.
/// </summary>
/// <param name="item">The candidate item.</param>
/// <returns>Whether the provided item is a valid group target. If <c>false</c>, more panels will be checked in the user's requested direction until a valid target is found.</returns>
protected virtual bool CheckValidForGroupSelection(CarouselItem item) => true;
/// <summary> /// <summary>
/// Called when an item is "selected". /// Called when an item is "selected".
/// </summary> /// </summary>
@ -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. // 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) if (isGroupSelection && direction < 0)
{ {
while (!carouselItems[selectionIndex].IsGroupSelectionTarget) while (!CheckValidForGroupSelection(carouselItems[selectionIndex]))
selectionIndex--; selectionIndex--;
} }
@ -394,7 +401,11 @@ namespace osu.Game.Screens.SelectV2
bool attemptSelection(CarouselItem item) 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; return false;
if (isGroupSelection) if (isGroupSelection)
@ -427,8 +438,9 @@ namespace osu.Game.Screens.SelectV2
currentKeyboardSelection = new Selection(model); currentKeyboardSelection = new Selection(model);
currentSelection = currentKeyboardSelection; currentSelection = currentKeyboardSelection;
selectionValid.Invalidate();
} }
selectionValid.Invalidate();
} }
private void setKeyboardSelection(object? model) private void setKeyboardSelection(object? model)

View File

@ -29,11 +29,6 @@ namespace osu.Game.Screens.SelectV2
/// </summary> /// </summary>
public float DrawHeight { get; set; } = DEFAULT_HEIGHT; public float DrawHeight { get; set; } = DEFAULT_HEIGHT;
/// <summary>
/// Whether this item should be a valid target for user group selection hotkeys.
/// </summary>
public bool IsGroupSelectionTarget { get; set; }
/// <summary> /// <summary>
/// Whether this item is visible or collapsed (hidden). /// Whether this item is visible or collapsed (hidden).
/// </summary> /// </summary>

View File

@ -79,7 +79,6 @@ namespace osu.Game.Screens.SelectV2
base.PrepareForUse(); base.PrepareForUse();
Debug.Assert(Item != null); Debug.Assert(Item != null);
Debug.Assert(Item.IsGroupSelectionTarget);
GroupDefinition group = (GroupDefinition)Item.Model; GroupDefinition group = (GroupDefinition)Item.Model;