diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSwitchTiny.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSwitchTiny.cs new file mode 100644 index 0000000000..dbde7ce425 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSwitchTiny.cs @@ -0,0 +1,85 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; +using osu.Game.Overlays; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Catch; +using osu.Game.Rulesets.Mania; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Taiko; +using osu.Game.Rulesets.UI; +using osuTK; + +namespace osu.Game.Tests.Visual.UserInterface +{ + [TestFixture] + public class TestSceneModSwitchTiny : OsuTestScene + { + [Test] + public void TestOsu() => createSwitchTestFor(new OsuRuleset()); + + [Test] + public void TestTaiko() => createSwitchTestFor(new TaikoRuleset()); + + [Test] + public void TestCatch() => createSwitchTestFor(new CatchRuleset()); + + [Test] + public void TestMania() => createSwitchTestFor(new ManiaRuleset()); + + private void createSwitchTestFor(Ruleset ruleset) + { + AddStep("no colour scheme", () => Child = createContent(ruleset, null)); + + foreach (var scheme in Enum.GetValues(typeof(OverlayColourScheme)).Cast()) + { + AddStep($"{scheme} colour scheme", () => Child = createContent(ruleset, scheme)); + } + + AddToggleStep("toggle active", active => this.ChildrenOfType().ForEach(s => s.Active.Value = active)); + } + + private static Drawable createContent(Ruleset ruleset, OverlayColourScheme? colourScheme) + { + var switchFlow = new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(10), + Padding = new MarginPadding(20), + ChildrenEnumerable = ruleset.CreateAllMods() + .GroupBy(mod => mod.Type) + .Select(group => new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Full, + Spacing = new Vector2(5), + ChildrenEnumerable = group.Select(mod => new ModSwitchTiny(mod)) + }) + }; + + if (colourScheme != null) + { + return new DependencyProvidingContainer + { + RelativeSizeAxes = Axes.Both, + CachedDependencies = new (Type, object)[] + { + (typeof(OverlayColourProvider), new OverlayColourProvider(colourScheme.Value)) + }, + Child = switchFlow + }; + } + + return switchFlow; + } + } +} diff --git a/osu.Game/Rulesets/UI/ModSwitchTiny.cs b/osu.Game/Rulesets/UI/ModSwitchTiny.cs new file mode 100644 index 0000000000..093c2271b6 --- /dev/null +++ b/osu.Game/Rulesets/UI/ModSwitchTiny.cs @@ -0,0 +1,91 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Utils; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Overlays; +using osu.Game.Rulesets.Mods; +using osuTK; +using osuTK.Graphics; + +#nullable enable + +namespace osu.Game.Rulesets.UI +{ + public class ModSwitchTiny : CompositeDrawable + { + public BindableBool Active { get; } = new BindableBool(); + + private readonly IMod mod; + + private readonly Box background; + private readonly OsuSpriteText acronymText; + + private Color4 activeForegroundColour; + private Color4 inactiveForegroundColour; + + private Color4 activeBackgroundColour; + private Color4 inactiveBackgroundColour; + + public ModSwitchTiny(IMod mod) + { + this.mod = mod; + Size = new Vector2(73, 30); + + InternalChild = new CircularContainer + { + RelativeSizeAxes = Axes.Both, + Masking = true, + Children = new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both + }, + acronymText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Shadow = false, + Font = OsuFont.Numeric.With(size: 24, weight: FontWeight.Black), + Text = mod.Acronym, + Margin = new MarginPadding + { + Top = 4 + } + } + } + }; + } + + [BackgroundDependencyLoader(true)] + private void load(OsuColour colours, OverlayColourProvider? colourProvider) + { + inactiveBackgroundColour = colourProvider?.Background5 ?? colours.Gray3; + activeBackgroundColour = colours.ForModType(mod.Type); + + inactiveForegroundColour = colourProvider?.Background2 ?? colours.Gray5; + activeForegroundColour = Interpolation.ValueAt(0.1f, Colour4.Black, activeForegroundColour, 0, 1); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Active.BindValueChanged(_ => updateState(), true); + FinishTransforms(true); + } + + private void updateState() + { + acronymText.FadeColour(Active.Value ? activeForegroundColour : inactiveForegroundColour, 200, Easing.OutQuint); + background.FadeColour(Active.Value ? activeBackgroundColour : inactiveBackgroundColour, 200, Easing.OutQuint); + } + } +}