mirror of
https://github.com/ppy/osu.git
synced 2024-09-22 00:47:24 +08:00
Merge pull request #19621 from bdach/mod-overlay/mod-preset-selection-logic
Implement selection logic for mod preset panels
This commit is contained in:
commit
c622b31f8d
@ -1,12 +1,15 @@
|
|||||||
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Overlays.Mods;
|
using osu.Game.Overlays.Mods;
|
||||||
@ -23,6 +26,12 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
[Cached]
|
[Cached]
|
||||||
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
|
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
|
||||||
|
|
||||||
|
[SetUpSteps]
|
||||||
|
public void SetUpSteps()
|
||||||
|
{
|
||||||
|
AddStep("reset selected mods", () => SelectedMods.SetDefault());
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestVariousModPresets()
|
public void TestVariousModPresets()
|
||||||
{
|
{
|
||||||
@ -37,6 +46,78 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPresetSelectionStateAfterExternalModChanges()
|
||||||
|
{
|
||||||
|
ModPresetPanel? panel = null;
|
||||||
|
|
||||||
|
AddStep("create panel", () => Child = panel = new ModPresetPanel(createTestPresets().First().ToLiveUnmanaged())
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Width = 0.5f
|
||||||
|
});
|
||||||
|
AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value);
|
||||||
|
|
||||||
|
AddStep("set mods to HR", () => SelectedMods.Value = new[] { new OsuModHardRock() });
|
||||||
|
AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value);
|
||||||
|
|
||||||
|
AddStep("set mods to DT", () => SelectedMods.Value = new[] { new OsuModDoubleTime() });
|
||||||
|
AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value);
|
||||||
|
|
||||||
|
AddStep("set mods to HR+DT", () => SelectedMods.Value = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() });
|
||||||
|
AddAssert("panel is active", () => panel.AsNonNull().Active.Value);
|
||||||
|
|
||||||
|
AddStep("set mods to HR+customised DT", () => SelectedMods.Value = new Mod[]
|
||||||
|
{
|
||||||
|
new OsuModHardRock(),
|
||||||
|
new OsuModDoubleTime
|
||||||
|
{
|
||||||
|
SpeedChange = { Value = 1.25 }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value);
|
||||||
|
|
||||||
|
AddStep("set mods to HR+DT", () => SelectedMods.Value = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() });
|
||||||
|
AddAssert("panel is active", () => panel.AsNonNull().Active.Value);
|
||||||
|
|
||||||
|
AddStep("customise mod in place", () => SelectedMods.Value.OfType<OsuModDoubleTime>().Single().SpeedChange.Value = 1.33);
|
||||||
|
AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value);
|
||||||
|
|
||||||
|
AddStep("set mods to HD+HR+DT", () => SelectedMods.Value = new Mod[] { new OsuModHidden(), new OsuModHardRock(), new OsuModDoubleTime() });
|
||||||
|
AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestActivatingPresetTogglesIncludedMods()
|
||||||
|
{
|
||||||
|
ModPresetPanel? panel = null;
|
||||||
|
|
||||||
|
AddStep("create panel", () => Child = panel = new ModPresetPanel(createTestPresets().First().ToLiveUnmanaged())
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Width = 0.5f
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("activate panel", () => panel.AsNonNull().TriggerClick());
|
||||||
|
assertSelectedModsEquivalentTo(new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() });
|
||||||
|
|
||||||
|
AddStep("deactivate panel", () => panel.AsNonNull().TriggerClick());
|
||||||
|
assertSelectedModsEquivalentTo(Array.Empty<Mod>());
|
||||||
|
|
||||||
|
AddStep("set different mod", () => SelectedMods.Value = new[] { new OsuModHidden() });
|
||||||
|
AddStep("activate panel", () => panel.AsNonNull().TriggerClick());
|
||||||
|
assertSelectedModsEquivalentTo(new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() });
|
||||||
|
|
||||||
|
AddStep("set customised mod", () => SelectedMods.Value = new[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } });
|
||||||
|
AddStep("activate panel", () => panel.AsNonNull().TriggerClick());
|
||||||
|
assertSelectedModsEquivalentTo(new Mod[] { new OsuModHardRock(), new OsuModDoubleTime { SpeedChange = { Value = 1.5 } } });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertSelectedModsEquivalentTo(IEnumerable<Mod> mods)
|
||||||
|
=> AddAssert("selected mods changed correctly", () => new HashSet<Mod>(SelectedMods.Value).SetEquals(mods));
|
||||||
|
|
||||||
private static IEnumerable<ModPreset> createTestPresets() => new[]
|
private static IEnumerable<ModPreset> createTestPresets() => new[]
|
||||||
{
|
{
|
||||||
new ModPreset
|
new ModPreset
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
// 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.
|
// 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.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
@ -22,12 +26,19 @@ namespace osu.Game.Overlays.Mods
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private IDialogOverlay? dialogOverlay { get; set; }
|
private IDialogOverlay? dialogOverlay { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private Bindable<IReadOnlyList<Mod>> selectedMods { get; set; } = null!;
|
||||||
|
|
||||||
|
private ModSettingChangeTracker? settingChangeTracker;
|
||||||
|
|
||||||
public ModPresetPanel(Live<ModPreset> preset)
|
public ModPresetPanel(Live<ModPreset> preset)
|
||||||
{
|
{
|
||||||
Preset = preset;
|
Preset = preset;
|
||||||
|
|
||||||
Title = preset.Value.Name;
|
Title = preset.Value.Name;
|
||||||
Description = preset.Value.Description;
|
Description = preset.Value.Description;
|
||||||
|
|
||||||
|
Action = toggleRequestedByUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -36,6 +47,37 @@ namespace osu.Game.Overlays.Mods
|
|||||||
AccentColour = colours.Orange1;
|
AccentColour = colours.Orange1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
selectedMods.BindValueChanged(_ => selectedModsChanged(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void toggleRequestedByUser()
|
||||||
|
{
|
||||||
|
// if the preset is not active at the point of the user click, then set the mods using the preset directly, discarding any previous selections.
|
||||||
|
// if the preset is active when the user has clicked it, then it means that the set of active mods is exactly equal to the set of mods in the preset
|
||||||
|
// (there are no other active mods than what the preset specifies, and the mod settings match exactly).
|
||||||
|
// therefore it's safe to just clear selected mods, since it will have the effect of toggling the preset off.
|
||||||
|
selectedMods.Value = !Active.Value
|
||||||
|
? Preset.Value.Mods.ToArray()
|
||||||
|
: Array.Empty<Mod>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void selectedModsChanged()
|
||||||
|
{
|
||||||
|
settingChangeTracker?.Dispose();
|
||||||
|
settingChangeTracker = new ModSettingChangeTracker(selectedMods.Value);
|
||||||
|
settingChangeTracker.SettingChanged = _ => updateActiveState();
|
||||||
|
updateActiveState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateActiveState()
|
||||||
|
{
|
||||||
|
Active.Value = new HashSet<Mod>(Preset.Value.Mods).SetEquals(selectedMods.Value);
|
||||||
|
}
|
||||||
|
|
||||||
#region IHasCustomTooltip
|
#region IHasCustomTooltip
|
||||||
|
|
||||||
public ModPreset TooltipContent => Preset.Value;
|
public ModPreset TooltipContent => Preset.Value;
|
||||||
@ -51,5 +93,12 @@ namespace osu.Game.Overlays.Mods
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
|
||||||
|
settingChangeTracker?.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user