diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetailArea.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetailArea.cs deleted file mode 100644 index 66144cbfe4..0000000000 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetailArea.cs +++ /dev/null @@ -1,237 +0,0 @@ -// 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 NUnit.Framework; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Game.Beatmaps; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Mods; -using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.Select; -using osu.Game.Tests.Beatmaps; -using osuTK; - -namespace osu.Game.Tests.Visual.SongSelect -{ - [TestFixture] - [System.ComponentModel.Description("PlaySongSelect leaderboard/details area")] - public class TestSceneBeatmapDetailArea : OsuTestScene - { - public override IReadOnlyList RequiredTypes => new[] { typeof(BeatmapDetails) }; - - private ModDisplay modDisplay; - - [BackgroundDependencyLoader] - private void load(OsuGameBase game, RulesetStore rulesets) - { - BeatmapDetailArea detailsArea; - Add(detailsArea = new BeatmapDetailArea - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(550f, 450f), - }); - - Add(modDisplay = new ModDisplay - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - AutoSizeAxes = Axes.Both, - Position = new Vector2(0, 25), - }); - - modDisplay.Current.BindTo(SelectedMods); - - AddStep("all metrics", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap - { - BeatmapInfo = - { - BeatmapSet = new BeatmapSetInfo - { - Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() } - }, - Version = "All Metrics", - Metadata = new BeatmapMetadata - { - Source = "osu!lazer", - Tags = "this beatmap has all the metrics", - }, - BaseDifficulty = new BeatmapDifficulty - { - CircleSize = 7, - DrainRate = 1, - OverallDifficulty = 5.7f, - ApproachRate = 3.5f, - }, - StarDifficulty = 5.3f, - Metrics = new BeatmapMetrics - { - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), - }, - } - })); - - AddStep("all except source", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap - { - BeatmapInfo = - { - BeatmapSet = new BeatmapSetInfo - { - Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() } - }, - Version = "All Metrics", - Metadata = new BeatmapMetadata - { - Tags = "this beatmap has all the metrics", - }, - BaseDifficulty = new BeatmapDifficulty - { - CircleSize = 7, - DrainRate = 1, - OverallDifficulty = 5.7f, - ApproachRate = 3.5f, - }, - StarDifficulty = 5.3f, - Metrics = new BeatmapMetrics - { - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), - }, - } - })); - - AddStep("ratings", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap - { - BeatmapInfo = - { - BeatmapSet = new BeatmapSetInfo - { - Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() } - }, - Version = "Only Ratings", - Metadata = new BeatmapMetadata - { - Source = "osu!lazer", - Tags = "this beatmap has ratings metrics but not retries or fails", - }, - BaseDifficulty = new BeatmapDifficulty - { - CircleSize = 6, - DrainRate = 9, - OverallDifficulty = 6, - ApproachRate = 6, - }, - StarDifficulty = 4.8f - } - })); - - AddStep("fails+retries", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap - { - BeatmapInfo = - { - Version = "Only Retries and Fails", - Metadata = new BeatmapMetadata - { - Source = "osu!lazer", - Tags = "this beatmap has retries and fails but no ratings", - }, - BaseDifficulty = new BeatmapDifficulty - { - CircleSize = 3.7f, - DrainRate = 6, - OverallDifficulty = 6, - ApproachRate = 7, - }, - StarDifficulty = 2.91f, - Metrics = new BeatmapMetrics - { - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), - }, - } - })); - - AddStep("null metrics", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap - { - BeatmapInfo = - { - Version = "No Metrics", - Metadata = new BeatmapMetadata - { - Source = "osu!lazer", - Tags = "this beatmap has no metrics", - }, - BaseDifficulty = new BeatmapDifficulty - { - CircleSize = 5, - DrainRate = 5, - OverallDifficulty = 5.5f, - ApproachRate = 6.5f, - }, - StarDifficulty = 1.97f, - } - })); - - AddStep("null beatmap", () => detailsArea.Beatmap = null); - - Ruleset ruleset = rulesets.AvailableRulesets.First().CreateInstance(); - - AddStep("with EZ mod", () => - { - detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap - { - BeatmapInfo = - { - Version = "Has Easy Mod", - Metadata = new BeatmapMetadata - { - Source = "osu!lazer", - Tags = "this beatmap has the easy mod enabled", - }, - BaseDifficulty = new BeatmapDifficulty - { - CircleSize = 3, - DrainRate = 3, - OverallDifficulty = 3, - ApproachRate = 3, - }, - StarDifficulty = 1f, - } - }); - - SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModEasy) }; - }); - - AddStep("with HR mod", () => - { - detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap - { - BeatmapInfo = - { - Version = "Has Hard Rock Mod", - Metadata = new BeatmapMetadata - { - Source = "osu!lazer", - Tags = "this beatmap has the hard rock mod enabled", - }, - BaseDifficulty = new BeatmapDifficulty - { - CircleSize = 3, - DrainRate = 3, - OverallDifficulty = 3, - ApproachRate = 3, - }, - StarDifficulty = 1f, - } - }); - - SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModHardRock) }; - }); - } - } -} diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs index acf037198f..6aa5a76490 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs @@ -3,8 +3,14 @@ using System.Linq; using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; using osu.Game.Screens.Select; namespace osu.Game.Tests.Visual.SongSelect @@ -174,5 +180,27 @@ namespace osu.Game.Tests.Visual.SongSelect OnlineBeatmapID = 162, }); } + + [Resolved] + private RulesetStore rulesets { get; set; } + + [Resolved] + private OsuColour colours { get; set; } + + [Test] + public void TestModAdjustments() + { + TestAllMetrics(); + + Ruleset ruleset = rulesets.AvailableRulesets.First().CreateInstance(); + + AddStep("with EZ mod", () => SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModEasy) }); + + AddAssert("first bar coloured blue", () => details.ChildrenOfType().Skip(1).First().AccentColour == colours.BlueDark); + + AddStep("with HR mod", () => SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModHardRock) }); + + AddAssert("first bar coloured red", () => details.ChildrenOfType().Skip(1).First().AccentColour == colours.Red); + } } } diff --git a/osu.Game/Overlays/Settings/ISettingsItem.cs b/osu.Game/Overlays/Settings/ISettingsItem.cs new file mode 100644 index 0000000000..e7afa48502 --- /dev/null +++ b/osu.Game/Overlays/Settings/ISettingsItem.cs @@ -0,0 +1,13 @@ +// 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 osu.Framework.Graphics; + +namespace osu.Game.Overlays.Settings +{ + public interface ISettingsItem : IDrawable, IDisposable + { + event Action SettingChanged; + } +} diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index 31fcb7abd8..35f28ab1b2 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -1,6 +1,7 @@ // 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 osu.Framework.Allocation; using osu.Framework.Bindables; @@ -20,7 +21,7 @@ using osuTK; namespace osu.Game.Overlays.Settings { - public abstract class SettingsItem : Container, IFilterable + public abstract class SettingsItem : Container, IFilterable, ISettingsItem { protected abstract Drawable CreateControl(); @@ -34,8 +35,6 @@ namespace osu.Game.Overlays.Settings private SpriteText text; - private readonly RestoreDefaultValueButton restoreDefaultButton; - public bool ShowsDefaultIndicator = true; public virtual string LabelText @@ -70,8 +69,12 @@ namespace osu.Game.Overlays.Settings public bool FilteringActive { get; set; } + public event Action SettingChanged; + protected SettingsItem() { + RestoreDefaultValueButton restoreDefaultButton; + RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; Padding = new MarginPadding { Right = SettingsPanel.CONTENT_MARGINS }; @@ -87,13 +90,12 @@ namespace osu.Game.Overlays.Settings Child = Control = CreateControl() }, }; - } - [BackgroundDependencyLoader] - private void load() - { + // all bindable logic is in constructor intentionally to support "CreateSettingsControls" being used in a context it is + // never loaded, but requires bindable storage. if (controlWithCurrent != null) { + controlWithCurrent.Current.ValueChanged += _ => SettingChanged?.Invoke(); controlWithCurrent.Current.DisabledChanged += disabled => { Colour = disabled ? Color4.Gray : Color4.White; }; if (ShowsDefaultIndicator) diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs index 9c9c33274f..a147527f6c 100644 --- a/osu.Game/Screens/Select/Details/AdvancedStats.cs +++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs @@ -16,6 +16,9 @@ using osu.Framework.Bindables; using System.Collections.Generic; using osu.Game.Rulesets.Mods; using System.Linq; +using osu.Framework.Threading; +using osu.Game.Configuration; +using osu.Game.Overlays.Settings; namespace osu.Game.Screens.Select.Details { @@ -69,7 +72,37 @@ namespace osu.Game.Screens.Select.Details { base.LoadComplete(); - mods.BindValueChanged(_ => updateStatistics(), true); + mods.BindValueChanged(modsChanged, true); + } + + private readonly List references = new List(); + + private void modsChanged(ValueChangedEvent> mods) + { + // TODO: find a more permanent solution for this if/when it is needed in other components. + // this is generating drawables for the only purpose of storing bindable references. + foreach (var r in references) + r.Dispose(); + + references.Clear(); + + ScheduledDelegate debounce = null; + + foreach (var mod in mods.NewValue.OfType()) + { + foreach (var setting in mod.CreateSettingsControls().OfType()) + { + setting.SettingChanged += () => + { + debounce?.Cancel(); + debounce = Scheduler.AddDelayed(updateStatistics, 100); + }; + + references.Add(setting); + } + } + + updateStatistics(); } private void updateStatistics()