Skip to content

Add expanded state tracking to beatmap carousel v2 #31787

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,8 @@ protected void WaitForGroupSelection(int group, int panel)
var groupingFilter = Carousel.Filters.OfType<BeatmapCarouselFilterGrouping>().Single();

GroupDefinition g = groupingFilter.GroupItems.Keys.ElementAt(group);
CarouselItem item = groupingFilter.GroupItems[g].ElementAt(panel);
// offset by one because the group itself is included in the items list.
CarouselItem item = groupingFilter.GroupItems[g].ElementAt(panel + 1);

return ReferenceEquals(Carousel.CurrentSelection, item.Model);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public override void SetUpSteps()
}

[Test]
public void TestOpenCloseGroupWithNoSelection()
public void TestOpenCloseGroupWithNoSelectionMouse()
{
AddBeatmaps(10, 5);
WaitForDrawablePanels();
Expand All @@ -41,6 +41,29 @@ public void TestOpenCloseGroupWithNoSelection()
CheckNoSelection();
}

[Test]
public void TestOpenCloseGroupWithNoSelectionKeyboard()
{
AddBeatmaps(10, 5);
WaitForDrawablePanels();

AddAssert("no beatmaps visible", () => Carousel.ChildrenOfType<BeatmapPanel>().Count(p => p.Alpha > 0), () => Is.Zero);
CheckNoSelection();

SelectNextPanel();
Select();
AddUntilStep("some beatmaps visible", () => Carousel.ChildrenOfType<BeatmapPanel>().Count(p => p.Alpha > 0), () => Is.GreaterThan(0));
AddAssert("keyboard selected is expanded", () => getKeyboardSelectedPanel()?.Expanded.Value, () => Is.True);
CheckNoSelection();

Select();
AddUntilStep("no beatmaps visible", () => Carousel.ChildrenOfType<BeatmapPanel>().Count(p => p.Alpha > 0), () => Is.Zero);
AddAssert("keyboard selected is collapsed", () => getKeyboardSelectedPanel()?.Expanded.Value, () => Is.False);
CheckNoSelection();

GroupPanel? getKeyboardSelectedPanel() => Carousel.ChildrenOfType<GroupPanel>().SingleOrDefault(p => p.KeyboardSelected.Value);
}

[Test]
public void TestCarouselRemembersSelection()
{
Expand Down
38 changes: 24 additions & 14 deletions osu.Game/Screens/SelectV2/BeatmapCarousel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,12 @@ protected override bool HandleItemSelected(object? model)
// Special case – collapsing an open group.
if (lastSelectedGroup == group)
{
setVisibilityOfGroupItems(lastSelectedGroup, false);
setExpansionStateOfGroup(lastSelectedGroup, false);
lastSelectedGroup = null;
return false;
}

setVisibleGroup(group);
setExpandedGroup(group);
return false;

case BeatmapSetInfo setInfo:
Expand All @@ -127,11 +127,11 @@ protected override bool HandleItemSelected(object? model)
GroupDefinition? group = grouping.GroupItems.SingleOrDefault(kvp => kvp.Value.Any(i => ReferenceEquals(i.Model, beatmapInfo))).Key;

if (group != null)
setVisibleGroup(group);
setExpandedGroup(group);
}
else
{
setVisibleSet(beatmapInfo);
setExpandedSet(beatmapInfo);
}

return true;
Expand All @@ -158,37 +158,47 @@ protected override bool CheckValidForGroupSelection(CarouselItem item)
}
}

private void setVisibleGroup(GroupDefinition group)
private void setExpandedGroup(GroupDefinition group)
{
if (lastSelectedGroup != null)
setVisibilityOfGroupItems(lastSelectedGroup, false);
setExpansionStateOfGroup(lastSelectedGroup, false);
lastSelectedGroup = group;
setVisibilityOfGroupItems(group, true);
setExpansionStateOfGroup(group, true);
}

private void setVisibilityOfGroupItems(GroupDefinition group, bool visible)
private void setExpansionStateOfGroup(GroupDefinition group, bool expanded)
{
if (grouping.GroupItems.TryGetValue(group, out var items))
{
foreach (var i in items)
i.IsVisible = visible;
{
if (i.Model is GroupDefinition)
i.IsExpanded = expanded;
else
i.IsVisible = expanded;
}
}
}

private void setVisibleSet(BeatmapInfo beatmapInfo)
private void setExpandedSet(BeatmapInfo beatmapInfo)
{
if (lastSelectedBeatmap != null)
setVisibilityOfSetItems(lastSelectedBeatmap.BeatmapSet!, false);
setExpansionStateOfSetItems(lastSelectedBeatmap.BeatmapSet!, false);
lastSelectedBeatmap = beatmapInfo;
setVisibilityOfSetItems(beatmapInfo.BeatmapSet!, true);
setExpansionStateOfSetItems(beatmapInfo.BeatmapSet!, true);
}

private void setVisibilityOfSetItems(BeatmapSetInfo set, bool visible)
private void setExpansionStateOfSetItems(BeatmapSetInfo set, bool expanded)
{
if (grouping.SetItems.TryGetValue(set, out var items))
{
foreach (var i in items)
i.IsVisible = visible;
{
if (i.Model is BeatmapSetInfo)
i.IsExpanded = expanded;
else
i.IsVisible = expanded;
}
}
}

Expand Down
20 changes: 10 additions & 10 deletions osu.Game/Screens/SelectV2/BeatmapCarouselFilterGrouping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,11 @@ public async Task<IEnumerable<CarouselItem>> Run(IEnumerable<CarouselItem> items
if (b.StarRating > starGroup)
{
starGroup = (int)Math.Floor(b.StarRating);
newItems.Add(new CarouselItem(new GroupDefinition($"{starGroup} - {++starGroup} *")) { DrawHeight = GroupPanel.HEIGHT });
var groupDefinition = new GroupDefinition($"{starGroup} - {++starGroup} *");
var groupItem = new CarouselItem(groupDefinition) { DrawHeight = GroupPanel.HEIGHT };

newItems.Add(groupItem);
groupItems[groupDefinition] = new HashSet<CarouselItem> { groupItem };
}

newItems.Add(item);
Expand All @@ -91,14 +95,13 @@ public async Task<IEnumerable<CarouselItem>> Run(IEnumerable<CarouselItem> items

if (newBeatmapSet)
{
newItems.Insert(i, new CarouselItem(beatmap.BeatmapSet!) { DrawHeight = BeatmapSetPanel.HEIGHT });
var setItem = new CarouselItem(beatmap.BeatmapSet!) { DrawHeight = BeatmapSetPanel.HEIGHT };
setItems[beatmap.BeatmapSet!] = new HashSet<CarouselItem> { setItem };
newItems.Insert(i, setItem);
i++;
}

if (!setItems.TryGetValue(beatmap.BeatmapSet!, out var related))
setItems[beatmap.BeatmapSet!] = related = new HashSet<CarouselItem>();

related.Add(item);
setItems[beatmap.BeatmapSet!].Add(item);
item.IsVisible = false;
}

Expand All @@ -121,10 +124,7 @@ public async Task<IEnumerable<CarouselItem>> Run(IEnumerable<CarouselItem> items

if (lastGroup != null)
{
if (!groupItems.TryGetValue(lastGroup, out var groupRelated))
groupItems[lastGroup] = groupRelated = new HashSet<CarouselItem>();
groupRelated.Add(item);

groupItems[lastGroup].Add(item);
item.IsVisible = false;
}
}
Expand Down
1 change: 1 addition & 0 deletions osu.Game/Screens/SelectV2/BeatmapPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ protected override bool OnClick(ClickEvent e)

public CarouselItem? Item { get; set; }
public BindableBool Selected { get; } = new BindableBool();
public BindableBool Expanded { get; } = new BindableBool();
public BindableBool KeyboardSelected { get; } = new BindableBool();

public double DrawYPosition { get; set; }
Expand Down
9 changes: 8 additions & 1 deletion osu.Game/Screens/SelectV2/BeatmapSetPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public partial class BeatmapSetPanel : PoolableDrawable, ICarouselPanel
private BeatmapCarousel carousel { get; set; } = null!;

private OsuSpriteText text = null!;
private Box box = null!;

[BackgroundDependencyLoader]
private void load()
Expand All @@ -34,7 +35,7 @@ private void load()

InternalChildren = new Drawable[]
{
new Box
box = new Box
{
Colour = Color4.Yellow.Darken(5),
Alpha = 0.8f,
Expand All @@ -48,6 +49,11 @@ private void load()
}
};

Expanded.BindValueChanged(value =>
{
box.FadeColour(value.NewValue ? Color4.Yellow.Darken(2) : Color4.Yellow.Darken(5), 500, Easing.OutQuint);
});

KeyboardSelected.BindValueChanged(value =>
{
if (value.NewValue)
Expand Down Expand Up @@ -85,6 +91,7 @@ protected override bool OnClick(ClickEvent e)

public CarouselItem? Item { get; set; }
public BindableBool Selected { get; } = new BindableBool();
public BindableBool Expanded { get; } = new BindableBool();
public BindableBool KeyboardSelected { get; } = new BindableBool();

public double DrawYPosition { get; set; }
Expand Down
2 changes: 2 additions & 0 deletions osu.Game/Screens/SelectV2/Carousel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,7 @@ protected override void Update()

c.Selected.Value = c.Item == currentSelection?.CarouselItem;
c.KeyboardSelected.Value = c.Item == currentKeyboardSelection?.CarouselItem;
c.Expanded.Value = c.Item.IsExpanded;
}
}

Expand Down Expand Up @@ -674,6 +675,7 @@ private static void expirePanelImmediately(Drawable panel)
carouselPanel.Item = null;
carouselPanel.Selected.Value = false;
carouselPanel.KeyboardSelected.Value = false;
carouselPanel.Expanded.Value = false;
}

#endregion
Expand Down
7 changes: 6 additions & 1 deletion osu.Game/Screens/SelectV2/CarouselItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,15 @@ public sealed class CarouselItem : IComparable<CarouselItem>
public float DrawHeight { get; set; } = DEFAULT_HEIGHT;

/// <summary>
/// Whether this item is visible or collapsed (hidden).
/// Whether this item is visible or hidden.
/// </summary>
public bool IsVisible { get; set; } = true;

/// <summary>
/// Whether this item is expanded or not. Should only be used for headers of groups.
/// </summary>
public bool IsExpanded { get; set; }

public CarouselItem(object model)
{
Model = model;
Expand Down
10 changes: 9 additions & 1 deletion osu.Game/Screens/SelectV2/GroupPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public partial class GroupPanel : PoolableDrawable, ICarouselPanel
private Box activationFlash = null!;
private OsuSpriteText text = null!;

private Box box = null!;

[BackgroundDependencyLoader]
private void load()
{
Expand All @@ -34,7 +36,7 @@ private void load()

InternalChildren = new Drawable[]
{
new Box
box = new Box
{
Colour = Color4.DarkBlue.Darken(5),
Alpha = 0.8f,
Expand All @@ -60,6 +62,11 @@ private void load()
activationFlash.FadeTo(value.NewValue ? 0.2f : 0, 500, Easing.OutQuint);
});

Expanded.BindValueChanged(value =>
{
box.FadeColour(value.NewValue ? Color4.SkyBlue : Color4.DarkBlue.Darken(5), 500, Easing.OutQuint);
});

KeyboardSelected.BindValueChanged(value =>
{
if (value.NewValue)
Expand Down Expand Up @@ -97,6 +104,7 @@ protected override bool OnClick(ClickEvent e)

public CarouselItem? Item { get; set; }
public BindableBool Selected { get; } = new BindableBool();
public BindableBool Expanded { get; } = new BindableBool();
public BindableBool KeyboardSelected { get; } = new BindableBool();

public double DrawYPosition { get; set; }
Expand Down
7 changes: 6 additions & 1 deletion osu.Game/Screens/SelectV2/ICarouselPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,15 @@ namespace osu.Game.Screens.SelectV2
public interface ICarouselPanel
{
/// <summary>
/// Whether this item has selection. Should be read from to update the visual state.
/// Whether this item has selection (see <see cref="Carousel{T}.CurrentSelection"/>). Should be read from to update the visual state.
/// </summary>
BindableBool Selected { get; }

/// <summary>
/// Whether this item is expanded (see <see cref="CarouselItem.IsExpanded"/>). Should be read from to update the visual state.
/// </summary>
BindableBool Expanded { get; }

/// <summary>
/// Whether this item has keyboard selection. Should be read from to update the visual state.
/// </summary>
Expand Down
Loading