From 713f89a59c7d0c964d5c4f1c0760dd45fe596bdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 23 Feb 2022 23:11:38 +0100 Subject: [PATCH] Implement incompatibility-displaying variant of mod panel --- .../Visual/UserInterface/TestSceneModPanel.cs | 39 ++++++++ .../Mods/IncompatibilityDisplayingModPanel.cs | 88 +++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 osu.Game/Overlays/Mods/IncompatibilityDisplayingModPanel.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModPanel.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModPanel.cs index bdf3f98863..95323e5dfa 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModPanel.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModPanel.cs @@ -1,14 +1,17 @@ // 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 NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Overlays; using osu.Game.Overlays.Mods; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; using osuTK; +using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { @@ -38,5 +41,41 @@ namespace osu.Game.Tests.Visual.UserInterface } }); } + + [Test] + public void TestIncompatibilityDisplay() + { + IncompatibilityDisplayingModPanel panel = null; + + AddStep("create panel with DT", () => Child = panel = new IncompatibilityDisplayingModPanel(new OsuModDoubleTime()) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.None, + Width = 300 + }); + + clickPanel(); + AddAssert("panel active", () => panel.Active.Value); + + clickPanel(); + AddAssert("panel not active", () => !panel.Active.Value); + + AddStep("set incompatible mod", () => SelectedMods.Value = new[] { new OsuModHalfTime() }); + + clickPanel(); + AddAssert("panel not active", () => !panel.Active.Value); + + AddStep("reset mods", () => SelectedMods.Value = Array.Empty()); + + clickPanel(); + AddAssert("panel active", () => panel.Active.Value); + + void clickPanel() => AddStep("click panel", () => + { + InputManager.MoveMouseTo(panel); + InputManager.Click(MouseButton.Left); + }); + } } } diff --git a/osu.Game/Overlays/Mods/IncompatibilityDisplayingModPanel.cs b/osu.Game/Overlays/Mods/IncompatibilityDisplayingModPanel.cs new file mode 100644 index 0000000000..4b6759c209 --- /dev/null +++ b/osu.Game/Overlays/Mods/IncompatibilityDisplayingModPanel.cs @@ -0,0 +1,88 @@ +// 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.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Input.Events; +using osu.Game.Rulesets.Mods; +using osu.Game.Utils; + +namespace osu.Game.Overlays.Mods +{ + public class IncompatibilityDisplayingModPanel : ModPanel, IHasCustomTooltip + { + private readonly BindableBool incompatible = new BindableBool(); + + [Resolved] + private Bindable> selectedMods { get; set; } + + public IncompatibilityDisplayingModPanel(Mod mod) + : base(mod) + { + } + + protected override void LoadComplete() + { + selectedMods.BindValueChanged(_ => updateIncompatibility(), true); + incompatible.BindValueChanged(_ => Scheduler.AddOnce(UpdateState)); + // base call will run `UpdateState()` first time and finish transforms. + base.LoadComplete(); + } + + private void updateIncompatibility() + { + incompatible.Value = selectedMods.Value.Count > 0 && !selectedMods.Value.Contains(Mod) && !ModUtils.CheckCompatibleSet(selectedMods.Value.Append(Mod)); + } + + protected override void UpdateState() + { + Action = incompatible.Value ? () => { } : (Action)Active.Toggle; + + if (incompatible.Value) + { + Colour4 backgroundColour = ColourProvider.Background5; + Colour4 textBackgroundColour = ColourProvider.Background4; + + Content.TransformTo(nameof(BorderColour), ColourInfo.GradientVertical(backgroundColour, textBackgroundColour), TRANSITION_DURATION, Easing.OutQuint); + Background.FadeColour(backgroundColour, TRANSITION_DURATION, Easing.OutQuint); + + SwitchContainer.ResizeWidthTo(IDLE_SWITCH_WIDTH, TRANSITION_DURATION, Easing.OutQuint); + SwitchContainer.FadeColour(Colour4.Gray, TRANSITION_DURATION, Easing.OutQuint); + MainContentContainer.TransformTo(nameof(Padding), new MarginPadding + { + Left = IDLE_SWITCH_WIDTH, + Right = CORNER_RADIUS + }, TRANSITION_DURATION, Easing.OutQuint); + + TextBackground.FadeColour(textBackgroundColour, TRANSITION_DURATION, Easing.OutQuint); + TextFlow.FadeColour(Colour4.White.Opacity(0.5f), TRANSITION_DURATION, Easing.OutQuint); + return; + } + + SwitchContainer.FadeColour(Colour4.White, TRANSITION_DURATION, Easing.OutQuint); + base.UpdateState(); + } + + protected override bool OnMouseDown(MouseDownEvent e) + { + if (incompatible.Value) + return true; // bypasses base call purposely in order to not play out the intermediate state animation. + + return base.OnMouseDown(e); + } + + #region IHasCustomTooltip + + public ITooltip GetCustomTooltip() => new IncompatibilityDisplayingTooltip(); + + public Mod TooltipContent => Mod; + + #endregion + } +}