Skip to content

Commit

Permalink
Merge pull request #18819 from peppy/difficulty-icon-refactor-pass
Browse files Browse the repository at this point in the history
Refactor difficulty icons to not suck
  • Loading branch information
smoogipoo authored Jun 24, 2022
2 parents 6487cd6 + 8912f07 commit c7e92f4
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 222 deletions.
4 changes: 2 additions & 2 deletions osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -872,10 +872,10 @@ public void TestGroupedDifficultyIconSelecting()
return set != null;
});

FilterableGroupedDifficultyIcon groupIcon = null;
GroupedDifficultyIcon groupIcon = null;
AddUntilStep("Find group icon for different ruleset", () =>
{
return (groupIcon = set.ChildrenOfType<FilterableGroupedDifficultyIcon>()
return (groupIcon = set.ChildrenOfType<GroupedDifficultyIcon>()
.FirstOrDefault(icon => icon.Items.First().BeatmapInfo.Ruleset.OnlineID == 3)) != null;
});

Expand Down
131 changes: 36 additions & 95 deletions osu.Game/Beatmaps/Drawables/DifficultyIcon.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// 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.

#nullable disable

using System;
using System.Collections.Generic;
using System.Threading;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
Expand All @@ -16,19 +10,17 @@
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osuTK;
using osuTK.Graphics;

namespace osu.Game.Beatmaps.Drawables
{
public class DifficultyIcon : CompositeDrawable, IHasCustomTooltip<DifficultyIconTooltipContent>
public class DifficultyIcon : CompositeDrawable, IHasCustomTooltip<DifficultyIconTooltipContent>, IHasCurrentValue<StarDifficulty>
{
private readonly Container iconContainer;

/// <summary>
/// Size of this difficulty icon.
/// </summary>
Expand All @@ -38,58 +30,54 @@ public class DifficultyIcon : CompositeDrawable, IHasCustomTooltip<DifficultyIco
set => iconContainer.Size = value;
}

[NotNull]
private readonly IBeatmapInfo beatmapInfo;
/// <summary>
/// Whether to display a tooltip on hover. Only works if a beatmap was provided at construction time.
/// </summary>
public bool ShowTooltip { get; set; } = true;

private readonly IBeatmapInfo? beatmap;

[CanBeNull]
private readonly IRulesetInfo ruleset;

[CanBeNull]
private readonly IReadOnlyList<Mod> mods;
private Drawable background = null!;

private readonly bool shouldShowTooltip;
private readonly Container iconContainer;

private readonly bool performBackgroundDifficultyLookup;
private readonly BindableWithCurrent<StarDifficulty> difficulty = new BindableWithCurrent<StarDifficulty>();

private readonly Bindable<StarDifficulty> difficultyBindable = new Bindable<StarDifficulty>();
public virtual Bindable<StarDifficulty> Current
{
get => difficulty.Current;
set => difficulty.Current = value;
}

private Drawable background;
[Resolved]
private IRulesetStore rulesets { get; set; } = null!;

/// <summary>
/// Creates a new <see cref="DifficultyIcon"/> with a given <see cref="RulesetInfo"/> and <see cref="Mod"/> combination.
/// Creates a new <see cref="DifficultyIcon"/>. Will use provided beatmap's <see cref="BeatmapInfo.StarRating"/> for initial value.
/// </summary>
/// <param name="beatmapInfo">The beatmap to show the difficulty of.</param>
/// <param name="ruleset">The ruleset to show the difficulty with.</param>
/// <param name="mods">The mods to show the difficulty with.</param>
/// <param name="shouldShowTooltip">Whether to display a tooltip when hovered.</param>
/// <param name="performBackgroundDifficultyLookup">Whether to perform difficulty lookup (including calculation if necessary).</param>
public DifficultyIcon([NotNull] IBeatmapInfo beatmapInfo, [CanBeNull] IRulesetInfo ruleset, [CanBeNull] IReadOnlyList<Mod> mods, bool shouldShowTooltip = true, bool performBackgroundDifficultyLookup = true)
: this(beatmapInfo, shouldShowTooltip, performBackgroundDifficultyLookup)
/// <param name="beatmap">The beatmap to be displayed in the tooltip, and to be used for the initial star rating value.</param>
/// <param name="ruleset">An optional ruleset to be used for the icon display, in place of the beatmap's ruleset.</param>
public DifficultyIcon(IBeatmapInfo beatmap, IRulesetInfo? ruleset = null)
: this(ruleset ?? beatmap.Ruleset)
{
this.ruleset = ruleset ?? beatmapInfo.Ruleset;
this.mods = mods ?? Array.Empty<Mod>();
this.beatmap = beatmap;
Current.Value = new StarDifficulty(beatmap.StarRating, 0);
}

/// <summary>
/// Creates a new <see cref="DifficultyIcon"/> that follows the currently-selected ruleset and mods.
/// Creates a new <see cref="DifficultyIcon"/> without an associated beatmap.
/// </summary>
/// <param name="beatmapInfo">The beatmap to show the difficulty of.</param>
/// <param name="shouldShowTooltip">Whether to display a tooltip when hovered.</param>
/// <param name="performBackgroundDifficultyLookup">Whether to perform difficulty lookup (including calculation if necessary).</param>
public DifficultyIcon([NotNull] IBeatmapInfo beatmapInfo, bool shouldShowTooltip = true, bool performBackgroundDifficultyLookup = true)
/// <param name="ruleset">The ruleset to be used for the icon display.</param>
public DifficultyIcon(IRulesetInfo ruleset)
{
this.beatmapInfo = beatmapInfo ?? throw new ArgumentNullException(nameof(beatmapInfo));
this.shouldShowTooltip = shouldShowTooltip;
this.performBackgroundDifficultyLookup = performBackgroundDifficultyLookup;
this.ruleset = ruleset;

AutoSizeAxes = Axes.Both;

InternalChild = iconContainer = new Container { Size = new Vector2(20f) };
}

[Resolved]
private IRulesetStore rulesets { get; set; }

[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Expand All @@ -111,7 +99,6 @@ private void load(OsuColour colours)
Child = background = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.ForStarDifficulty(beatmapInfo.StarRating) // Default value that will be re-populated once difficulty calculation completes
},
},
new ConstrainedIconContainer
Expand All @@ -124,69 +111,23 @@ private void load(OsuColour colours)
},
};

if (performBackgroundDifficultyLookup)
iconContainer.Add(new DelayedLoadUnloadWrapper(() => new DifficultyRetriever(beatmapInfo, ruleset, mods) { StarDifficulty = { BindTarget = difficultyBindable } }, 0));
else
difficultyBindable.Value = new StarDifficulty(beatmapInfo.StarRating, 0);

difficultyBindable.BindValueChanged(difficulty => background.Colour = colours.ForStarDifficulty(difficulty.NewValue.Stars));
Current.BindValueChanged(difficulty => background.Colour = colours.ForStarDifficulty(difficulty.NewValue.Stars), true);
}

private Drawable getRulesetIcon()
{
int? onlineID = (ruleset ?? beatmapInfo.Ruleset).OnlineID;
int? onlineID = ruleset.OnlineID;

if (onlineID >= 0 && rulesets.GetRuleset(onlineID.Value)?.CreateInstance() is Ruleset rulesetInstance)
return rulesetInstance.CreateIcon();

return new SpriteIcon { Icon = FontAwesome.Regular.QuestionCircle };
}

ITooltip<DifficultyIconTooltipContent> IHasCustomTooltip<DifficultyIconTooltipContent>.GetCustomTooltip() => new DifficultyIconTooltip();
ITooltip<DifficultyIconTooltipContent> IHasCustomTooltip<DifficultyIconTooltipContent>.
GetCustomTooltip() => new DifficultyIconTooltip();

DifficultyIconTooltipContent IHasCustomTooltip<DifficultyIconTooltipContent>.TooltipContent => shouldShowTooltip ? new DifficultyIconTooltipContent(beatmapInfo, difficultyBindable) : null;

private class DifficultyRetriever : Component
{
public readonly Bindable<StarDifficulty> StarDifficulty = new Bindable<StarDifficulty>();

private readonly IBeatmapInfo beatmapInfo;
private readonly IRulesetInfo ruleset;
private readonly IReadOnlyList<Mod> mods;

private CancellationTokenSource difficultyCancellation;

[Resolved]
private BeatmapDifficultyCache difficultyCache { get; set; }

public DifficultyRetriever(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset, IReadOnlyList<Mod> mods)
{
this.beatmapInfo = beatmapInfo;
this.ruleset = ruleset;
this.mods = mods;
}

private IBindable<StarDifficulty?> localStarDifficulty;

[BackgroundDependencyLoader]
private void load()
{
difficultyCancellation = new CancellationTokenSource();
localStarDifficulty = ruleset != null
? difficultyCache.GetBindableDifficulty(beatmapInfo, ruleset, mods, difficultyCancellation.Token)
: difficultyCache.GetBindableDifficulty(beatmapInfo, difficultyCancellation.Token);
localStarDifficulty.BindValueChanged(d =>
{
if (d.NewValue is StarDifficulty diff)
StarDifficulty.Value = diff;
});
}

protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
difficultyCancellation?.Cancel();
}
}
DifficultyIconTooltipContent IHasCustomTooltip<DifficultyIconTooltipContent>.
TooltipContent => (ShowTooltip && beatmap != null ? new DifficultyIconTooltipContent(beatmap, Current) : null)!;
}
}
39 changes: 0 additions & 39 deletions osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs

This file was deleted.

4 changes: 3 additions & 1 deletion osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,10 @@ public DifficultySelectorButton(APIBeatmap beatmapInfo)
Alpha = 0.5f
}
},
icon = new DifficultyIcon(beatmapInfo, shouldShowTooltip: false)
icon = new DifficultyIcon(beatmapInfo)
{
ShowTooltip = false,
Current = { Value = new StarDifficulty(beatmapInfo.StarRating, 0) },
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(size - tile_icon_padding * 2),
Expand Down
78 changes: 0 additions & 78 deletions osu.Game/Screens/OnlinePlay/Components/ModeTypeInfo.cs

This file was deleted.

2 changes: 1 addition & 1 deletion osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ private void refresh()
}

if (beatmap != null)
difficultyIconContainer.Child = new DifficultyIcon(beatmap, ruleset, requiredMods, performBackgroundDifficultyLookup: false) { Size = new Vector2(icon_height) };
difficultyIconContainer.Child = new DifficultyIcon(beatmap, ruleset) { Size = new Vector2(icon_height) };
else
difficultyIconContainer.Clear();

Expand Down
7 changes: 6 additions & 1 deletion osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ public class DrawableCarouselBeatmap : DrawableCarouselItem, IHasContextMenu
private Action<BeatmapInfo> hideRequested;

private Triangles triangles;

private StarCounter starCounter;
private DifficultyIcon difficultyIcon;

[Resolved(CanBeNull = true)]
private BeatmapSetOverlay beatmapOverlay { get; set; }
Expand Down Expand Up @@ -113,8 +115,9 @@ private void load(BeatmapManager manager, SongSelect songSelect)
Origin = Anchor.CentreLeft,
Children = new Drawable[]
{
new DifficultyIcon(beatmapInfo, shouldShowTooltip: false)
difficultyIcon = new DifficultyIcon(beatmapInfo)
{
ShowTooltip = false,
Scale = new Vector2(1.8f),
},
new FillFlowContainer
Expand Down Expand Up @@ -216,6 +219,8 @@ protected override void ApplyState()
starDifficultyBindable.BindValueChanged(d =>
{
starCounter.Current = (float)(d.NewValue?.Stars ?? 0);
if (d.NewValue != null)
difficultyIcon.Current.Value = d.NewValue.Value;
}, true);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class FilterableDifficultyIcon : DifficultyIcon
public readonly CarouselBeatmap Item;

public FilterableDifficultyIcon(CarouselBeatmap item)
: base(item.BeatmapInfo, performBackgroundDifficultyLookup: false)
: base(item.BeatmapInfo)
{
filtered.BindTo(item.Filtered);
filtered.ValueChanged += isFiltered => Schedule(() => this.FadeTo(isFiltered.NewValue ? 0.1f : 1, 100));
Expand Down
Loading

0 comments on commit c7e92f4

Please sign in to comment.