Skip to content
Open
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
103 changes: 84 additions & 19 deletions osu.Game.Tests/Visual/UserInterface/TestSceneModDisplay.cs
Original file line number Diff line number Diff line change
@@ -1,38 +1,103 @@
// 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.

using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.Play.HUD;
using osu.Game.Tests.Visual.Gameplay;

namespace osu.Game.Tests.Visual.UserInterface
{
public partial class TestSceneModDisplay : OsuTestScene
public partial class TestSceneModDisplay : SkinnableHUDComponentTestScene
{
[Test]
public void TestMode([Values] ExpansionMode mode)
[SetUpSteps]
public override void SetUpSteps()
{
AddStep("create mod display", () =>
AddStep("setup mods", () =>
{
Child = new ModDisplay
SelectedMods.Value = new Mod[]
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
ExpansionMode = mode,
Current =
{
Value = new Mod[]
{
new OsuModHardRock(),
new OsuModDoubleTime(),
new OsuModDifficultyAdjust(),
new OsuModEasy(),
}
}
new OsuModHardRock(),
new OsuModDoubleTime { SpeedChange = { Value = 2.0 } },
new OsuModDifficultyAdjust(),
new OsuModEasy(),
};
});

base.SetUpSteps();
}

protected override Drawable CreateDefaultImplementation()
{
return new FillFlowContainer
{
Direction = FillDirection.Vertical,
RelativeSizeAxes = Axes.X,
Children = new[]
{
new ModDisplay
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Current = SelectedMods,
ExpansionMode = ExpansionMode.AlwaysContracted
},
new ModDisplay
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Current = SelectedMods,
ExpansionMode = ExpansionMode.AlwaysExpanded
},
new ModDisplay
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Current = SelectedMods,
ExpansionMode = ExpansionMode.ExpandOnHover
},
}
};
}

protected override Drawable CreateLegacyImplementation()
{
return new FillFlowContainer
{
Direction = FillDirection.Vertical,
RelativeSizeAxes = Axes.X,
Children = new[]
{
new ModDisplay(useSkinIcons: true)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Current = SelectedMods,
ExpansionMode = ExpansionMode.AlwaysContracted
},
new ModDisplay(useSkinIcons: true)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Current = SelectedMods,
ExpansionMode = ExpansionMode.AlwaysExpanded
},
new ModDisplay(useSkinIcons: true)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Current = SelectedMods,
ExpansionMode = ExpansionMode.ExpandOnHover
},
}
};
}

protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
}
}
10 changes: 10 additions & 0 deletions osu.Game/Localisation/SkinComponents/SkinnableModDisplayStrings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ public static class SkinnableModDisplayStrings
/// </summary>
public static LocalisableString AlwaysExpanded => new TranslatableString(getKey(@"always_expanded"), @"Always expanded");

/// <summary>
/// "Use legacy skin icons"
/// </summary>
public static LocalisableString UseSkinIcons => new TranslatableString(getKey(@"use_skin_icons"), @"Use legacy skin icons");

/// <summary>
/// "Whether to use legacy skin mod icons or the new ones."
/// </summary>
public static LocalisableString UseSkinIconsDescription => new TranslatableString(getKey(@"use_skin_icons_description"), @"Whether to use legacy skin mod icons or the new ones.");

private static string getKey(string key) => $@"{prefix}:{key}";
}
}
88 changes: 78 additions & 10 deletions osu.Game/Rulesets/UI/ModIcon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using osu.Game.Graphics.Sprites;
using osu.Game.Overlays;
using osu.Game.Rulesets.Mods;
using osu.Game.Skinning;
using osuTK;
using osuTK.Graphics;

Expand All @@ -41,6 +42,8 @@ public partial class ModIcon : Container, IHasCustomTooltip<Mod>
private readonly bool showTooltip;

private bool showExtendedInformation;
private bool useSkinIcon;
private bool canShowExtendedInformation = true;

public bool ShowExtendedInformation
{
Expand All @@ -52,6 +55,16 @@ public bool ShowExtendedInformation
}
}

public bool UseSkinIcon
{
get => useSkinIcon;
set
{
useSkinIcon = value;
updateMod(mod);
}
}

public IMod Mod
{
get => mod;
Expand Down Expand Up @@ -86,6 +99,9 @@ public IMod Mod
private SpriteIcon cogBackground = null!;
private SpriteIcon cog = null!;

private readonly Bindable<Skin> skin = new Bindable<Skin>();
private Sprite skinIcon = null!;

private ModSettingChangeTracker? modSettingsChangeTracker;

/// <summary>
Expand All @@ -94,7 +110,8 @@ public IMod Mod
/// <param name="mod">The mod to be displayed</param>
/// <param name="showTooltip">Whether a tooltip describing the mod should display on hover.</param>
/// <param name="showExtendedInformation">Whether to display a mod's extended information, if available.</param>
public ModIcon(IMod mod, bool showTooltip = true, bool showExtendedInformation = true)
/// <param name="useSkinIcon">Whether the icon should be skin-sourced, if available.</param>
public ModIcon(IMod mod, bool showTooltip = true, bool showExtendedInformation = true, bool useSkinIcon = false)
{
// May expand due to expanded content, so autosize here.
AutoSizeAxes = Axes.X;
Expand All @@ -103,10 +120,11 @@ public ModIcon(IMod mod, bool showTooltip = true, bool showExtendedInformation =
this.mod = mod ?? throw new ArgumentNullException(nameof(mod));
this.showTooltip = showTooltip;
this.showExtendedInformation = showExtendedInformation;
this.useSkinIcon = useSkinIcon;
}

[BackgroundDependencyLoader]
private void load(TextureStore textures)
private void load(TextureStore textures, SkinManager skinManager)
{
Children = new Drawable[]
{
Expand Down Expand Up @@ -176,6 +194,12 @@ private void load(TextureStore textures)
Height = 92 / 135f,
Icon = FontAwesome.Solid.Question
},
skinIcon = new Sprite
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
RelativeSizeAxes = Axes.Both
},
adjustmentMarker = new Container
{
Size = new Vector2(20),
Expand Down Expand Up @@ -203,6 +227,8 @@ private void load(TextureStore textures)
}
},
};

skin.BindTarget = skinManager.CurrentSkin;
}

protected override void LoadComplete()
Expand All @@ -211,6 +237,9 @@ protected override void LoadComplete()

Selected.BindValueChanged(_ => updateColour());

if (useSkinIcon)
skin.BindValueChanged(_ => updateMod(mod));

updateMod(mod);
}

Expand All @@ -224,21 +253,50 @@ private void updateMod(IMod value)
modSettingsChangeTracker.SettingChanged = _ => updateExtendedInformation();
}

modAcronym.Text = value.Acronym;
modIcon.Icon = value.Icon ?? FontAwesome.Solid.Question;
TooltipContent = showTooltip ? value as Mod : null;
Texture? skinIconTexture = null;

if (useSkinIcon)
{
string textureName = getModIconSpriteName(mod);
skinIconTexture = skin.Value.GetTexture(textureName);
}

if (value.Icon == null)
if (skinIconTexture != null)
{
skinIcon.Texture = skinIconTexture;
skinIcon.FadeIn();

modAcronym.FadeOut();
modIcon.FadeOut();
modAcronym.FadeIn();
background.FadeOut();

// we want to hide the extended information for skin icons because the extended background clashes with custom icons
canShowExtendedInformation = false;
}
else
{
modIcon.FadeIn();
modAcronym.FadeOut();
skinIcon.FadeOut();
background.FadeIn();

modAcronym.Text = value.Acronym;
modIcon.Icon = value.Icon ?? FontAwesome.Solid.Question;

if (value.Icon == null)
{
modIcon.FadeOut();
modAcronym.FadeIn();
}
else
{
modIcon.FadeIn();
modAcronym.FadeOut();
}

canShowExtendedInformation = true;
}

TooltipContent = showTooltip ? value as Mod : null;

backgroundColour = colours.ForModType(value.Type);
updateColour();

Expand All @@ -247,7 +305,7 @@ private void updateMod(IMod value)

private void updateExtendedInformation()
{
bool showExtended = showExtendedInformation && !string.IsNullOrEmpty(mod.ExtendedIconInformation);
bool showExtended = showExtendedInformation && canShowExtendedInformation && !string.IsNullOrEmpty(mod.ExtendedIconInformation);

extendedContent.Alpha = showExtended ? 1 : 0;
extendedText.Text = mod.ExtendedIconInformation;
Expand All @@ -268,6 +326,16 @@ private void updateColour()
extendedBackground.Colour = Selected.Value ? backgroundColour.Darken(2.4f) : backgroundColour.Darken(2.8f);
}

private string getModIconSpriteName(IMod mod)
{
// autopilot has a special legacy name
string modName = mod.Name == "Autopilot"
? "relax2"
: mod.Name.Replace(" ", "").Trim().ToLowerInvariant();

return $"selection-mod-{modName}";
}

protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
Expand Down
17 changes: 15 additions & 2 deletions osu.Game/Screens/Play/HUD/ModDisplay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public Bindable<IReadOnlyList<Mod>> Current
}

private bool showExtendedInformation;
private bool useSkinIcons;

public bool ShowExtendedInformation
{
Expand All @@ -73,11 +74,23 @@ public FillDirection FillDirection
set => iconsContainer.Direction = value;
}

public bool UseSkinIcons
{
get => useSkinIcons;
set
{
useSkinIcons = value;
foreach (var icon in iconsContainer)
icon.UseSkinIcon = value;
}
}

private readonly FillFlowContainer<ModIcon> iconsContainer;

public ModDisplay(bool showExtendedInformation = true)
public ModDisplay(bool showExtendedInformation = true, bool useSkinIcons = false)
{
this.showExtendedInformation = showExtendedInformation;
this.useSkinIcons = useSkinIcons;

AutoSizeAxes = Axes.Both;

Expand All @@ -101,7 +114,7 @@ private void updateDisplay(ValueChangedEvent<IReadOnlyList<Mod>> mods)
iconsContainer.Clear();

foreach (Mod mod in mods.NewValue.AsOrdered())
iconsContainer.Add(new ModIcon(mod, showExtendedInformation: showExtendedInformation) { Scale = new Vector2(MOD_ICON_SCALE) });
iconsContainer.Add(new ModIcon(mod, showExtendedInformation: showExtendedInformation, useSkinIcon: useSkinIcons) { Scale = new Vector2(MOD_ICON_SCALE) });
}

private void updateExpansionMode(double duration = 500)
Expand Down
Loading
Loading