diff --git a/osu.Desktop.slnf b/osu.Desktop.slnf index 68541dbcfc..503e5935f5 100644 --- a/osu.Desktop.slnf +++ b/osu.Desktop.slnf @@ -24,7 +24,7 @@ "Templates\\Rulesets\\ruleset-scrolling-empty\\osu.Game.Rulesets.EmptyScrolling\\osu.Game.Rulesets.EmptyScrolling.csproj", "Templates\\Rulesets\\ruleset-scrolling-empty\\osu.Game.Rulesets.EmptyScrolling.Tests\\osu.Game.Rulesets.EmptyScrolling.Tests.csproj", "Templates\\Rulesets\\ruleset-scrolling-example\\osu.Game.Rulesets.Pippidon\\osu.Game.Rulesets.Pippidon.csproj", - "Templates\\Rulesets\\ruleset-scrolling-example\\osu.Game.Rulesets.Pippidon.Tests\\osu.Game.Rulesets.Pippidon.Tests.csproj", + "Templates\\Rulesets\\ruleset-scrolling-example\\osu.Game.Rulesets.Pippidon.Tests\\osu.Game.Rulesets.Pippidon.Tests.csproj" ] } -} \ No newline at end of file +} diff --git a/osu.Game.Rulesets.Osu.Tests/OsuSkinnableTestScene.cs b/osu.Game.Rulesets.Osu.Tests/OsuSkinnableTestScene.cs index cad98185ce..233aaf2ed9 100644 --- a/osu.Game.Rulesets.Osu.Tests/OsuSkinnableTestScene.cs +++ b/osu.Game.Rulesets.Osu.Tests/OsuSkinnableTestScene.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Osu.Tests get { if (content == null) - base.Content.Add(content = new OsuInputManager(new RulesetInfo { ID = 0 })); + base.Content.Add(content = new OsuInputManager(new OsuRuleset().RulesetInfo)); return content; } diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneInputDrum.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneInputDrum.cs index fa6c9da174..9b36b064bc 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneInputDrum.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneInputDrum.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning [BackgroundDependencyLoader] private void load() { - SetContents(() => new TaikoInputManager(new RulesetInfo { ID = 1 }) + SetContents(() => new TaikoInputManager(new TaikoRuleset().RulesetInfo) { RelativeSizeAxes = Axes.Both, Child = new Container diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index fb18be3ae1..0f82492e51 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -740,6 +740,36 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.That(fifth.ControlPoints[5].Type.Value, Is.EqualTo(PathType.Bezier)); Assert.That(fifth.ControlPoints[6].Position.Value, Is.EqualTo(new Vector2(5, 5))); Assert.That(fifth.ControlPoints[6].Type.Value, Is.EqualTo(null)); + + // Implicit perfect-curve multi-segment(Should convert to bezier to match stable) + var sixth = ((IHasPath)decoded.HitObjects[5]).Path; + + Assert.That(sixth.ControlPoints[0].Position.Value, Is.EqualTo(Vector2.Zero)); + Assert.That(sixth.ControlPoints[0].Type.Value == PathType.Bezier); + Assert.That(sixth.ControlPoints[1].Position.Value, Is.EqualTo(new Vector2(75, 145))); + Assert.That(sixth.ControlPoints[1].Type.Value == null); + Assert.That(sixth.ControlPoints[2].Position.Value, Is.EqualTo(new Vector2(170, 75))); + + Assert.That(sixth.ControlPoints[2].Type.Value == PathType.Bezier); + Assert.That(sixth.ControlPoints[3].Position.Value, Is.EqualTo(new Vector2(300, 145))); + Assert.That(sixth.ControlPoints[3].Type.Value == null); + Assert.That(sixth.ControlPoints[4].Position.Value, Is.EqualTo(new Vector2(410, 20))); + Assert.That(sixth.ControlPoints[4].Type.Value == null); + + // Explicit perfect-curve multi-segment(Should not convert to bezier) + var seventh = ((IHasPath)decoded.HitObjects[6]).Path; + + Assert.That(seventh.ControlPoints[0].Position.Value, Is.EqualTo(Vector2.Zero)); + Assert.That(seventh.ControlPoints[0].Type.Value == PathType.PerfectCurve); + Assert.That(seventh.ControlPoints[1].Position.Value, Is.EqualTo(new Vector2(75, 145))); + Assert.That(seventh.ControlPoints[1].Type.Value == null); + Assert.That(seventh.ControlPoints[2].Position.Value, Is.EqualTo(new Vector2(170, 75))); + + Assert.That(seventh.ControlPoints[2].Type.Value == PathType.PerfectCurve); + Assert.That(seventh.ControlPoints[3].Position.Value, Is.EqualTo(new Vector2(300, 145))); + Assert.That(seventh.ControlPoints[3].Type.Value == null); + Assert.That(seventh.ControlPoints[4].Position.Value, Is.EqualTo(new Vector2(410, 20))); + Assert.That(seventh.ControlPoints[4].Type.Value == null); } } } diff --git a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs index 8c30802ce3..8dab570e30 100644 --- a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs +++ b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs @@ -38,7 +38,7 @@ namespace osu.Game.Tests.Online private BeatmapSetInfo testBeatmapSet; private readonly Bindable selectedItem = new Bindable(); - private OnlinePlayBeatmapAvailablilityTracker availablilityTracker; + private OnlinePlayBeatmapAvailabilityTracker availabilityTracker; [BackgroundDependencyLoader] private void load(AudioManager audio, GameHost host) @@ -67,7 +67,7 @@ namespace osu.Game.Tests.Online Ruleset = { Value = testBeatmapInfo.Ruleset }, }; - Child = availablilityTracker = new OnlinePlayBeatmapAvailablilityTracker + Child = availabilityTracker = new OnlinePlayBeatmapAvailabilityTracker { SelectedItem = { BindTarget = selectedItem, } }; @@ -118,7 +118,7 @@ namespace osu.Game.Tests.Online }); addAvailabilityCheckStep("state still not downloaded", BeatmapAvailability.NotDownloaded); - AddStep("recreate tracker", () => Child = availablilityTracker = new OnlinePlayBeatmapAvailablilityTracker + AddStep("recreate tracker", () => Child = availabilityTracker = new OnlinePlayBeatmapAvailabilityTracker { SelectedItem = { BindTarget = selectedItem } }); @@ -127,7 +127,7 @@ namespace osu.Game.Tests.Online private void addAvailabilityCheckStep(string description, Func expected) { - AddAssert(description, () => availablilityTracker.Availability.Value.Equals(expected.Invoke())); + AddAssert(description, () => availabilityTracker.Availability.Value.Equals(expected.Invoke())); } private static BeatmapInfo getTestBeatmapInfo(string archiveFile) diff --git a/osu.Game.Tests/Resources/multi-segment-slider.osu b/osu.Game.Tests/Resources/multi-segment-slider.osu index cc86710067..135132e35c 100644 --- a/osu.Game.Tests/Resources/multi-segment-slider.osu +++ b/osu.Game.Tests/Resources/multi-segment-slider.osu @@ -15,3 +15,10 @@ osu file format v128 // Last control point in segment duplicated 0,0,5000,2,0,B|1:1|2:2|3:3|3:3|B|4:4|5:5,2,200 + +// Implicit perfect-curve multi-segment (Should convert to bezier to match stable) +0,0,6000,2,0,P|75:145|170:75|170:75|300:145|410:20,1,475,0:0:0:0: + +// Explicit perfect-curve multi-segment (Should not convert to bezier) +0,0,7000,2,0,P|75:145|P|170:75|300:145|410:20,1,650,0:0:0:0: + diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs index b44e5b1e5b..dad1237991 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs @@ -27,7 +27,7 @@ namespace osu.Game.Tests.Visual.Multiplayer public class TestSceneMultiplayerReadyButton : MultiplayerTestScene { private MultiplayerReadyButton button; - private OnlinePlayBeatmapAvailablilityTracker beatmapTracker; + private OnlinePlayBeatmapAvailabilityTracker beatmapTracker; private BeatmapSetInfo importedSet; private readonly Bindable selectedItem = new Bindable(); @@ -44,7 +44,7 @@ namespace osu.Game.Tests.Visual.Multiplayer Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).Wait(); - Add(beatmapTracker = new OnlinePlayBeatmapAvailablilityTracker + Add(beatmapTracker = new OnlinePlayBeatmapAvailabilityTracker { SelectedItem = { BindTarget = selectedItem } }); diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooter.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooter.cs new file mode 100644 index 0000000000..0ac65b357c --- /dev/null +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooter.cs @@ -0,0 +1,35 @@ +// 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.Graphics; +using osu.Game.Screens.Select; + +namespace osu.Game.Tests.Visual.SongSelect +{ + public class TestSceneSongSelectFooter : OsuManualInputManagerTestScene + { + public TestSceneSongSelectFooter() + { + AddStep("Create footer", () => + { + Footer footer; + AddRange(new Drawable[] + { + footer = new Footer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + }); + + footer.AddButton(new FooterButtonMods(), null); + footer.AddButton(new FooterButtonRandom + { + NextRandom = () => { }, + PreviousRandom = () => { }, + }, null); + footer.AddButton(new FooterButtonOptions(), null); + }); + } + } +} diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs index 5eb5fcdfa0..da44b96ed3 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs @@ -333,9 +333,10 @@ namespace osu.Game.Beatmaps.Formats // Explicit segments have a new format in which the type is injected into the middle of the control point string. // To preserve compatibility with osu-stable as much as possible, explicit segments with the same type are converted to use implicit segments by duplicating the control point. - bool needsExplicitSegment = point.Type.Value != lastType; + // One exception are consecutive perfect curves, which aren't supported in osu!stable and can lead to decoding issues if encoded as implicit segments + bool needsExplicitSegment = point.Type.Value != lastType || point.Type.Value == PathType.PerfectCurve; - // One exception to this is when the last two control points of the last segment were duplicated. This is not a scenario supported by osu!stable. + // Another exception to this is when the last two control points of the last segment were duplicated. This is not a scenario supported by osu!stable. // Lazer does not add implicit segments for the last two control points of _any_ explicit segment, so an explicit segment is forced in order to maintain consistency with the decoder. if (i > 1) { diff --git a/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs b/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs index d12eaa10f6..cd8b486f23 100644 --- a/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs +++ b/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs @@ -64,12 +64,20 @@ namespace osu.Game.Input.Bindings protected override void ReloadMappings() { + var defaults = DefaultKeyBindings.ToList(); + if (ruleset != null && !ruleset.ID.HasValue) // if the provided ruleset is not stored to the database, we have no way to retrieve custom bindings. // fallback to defaults instead. - KeyBindings = DefaultKeyBindings; + KeyBindings = defaults; else - KeyBindings = store.Query(ruleset?.ID, variant).ToList(); + { + KeyBindings = store.Query(ruleset?.ID, variant) + // this ordering is important to ensure that we read entries from the database in the order + // enforced by DefaultKeyBindings. allow for song select to handle actions that may otherwise + // have been eaten by the music controller due to query order. + .OrderBy(b => defaults.FindIndex(d => (int)d.Action == b.IntAction)).ToList(); + } } } } diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index cda962f0ab..042960d54c 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -27,7 +27,11 @@ namespace osu.Game.Input.Bindings handler = game; } - public override IEnumerable DefaultKeyBindings => GlobalKeyBindings.Concat(InGameKeyBindings).Concat(AudioControlKeyBindings).Concat(EditorKeyBindings); + public override IEnumerable DefaultKeyBindings => GlobalKeyBindings + .Concat(EditorKeyBindings) + .Concat(InGameKeyBindings) + .Concat(SongSelectKeyBindings) + .Concat(AudioControlKeyBindings); public IEnumerable GlobalKeyBindings => new[] { @@ -80,6 +84,14 @@ namespace osu.Game.Input.Bindings new KeyBinding(InputKey.Control, GlobalAction.HoldForHUD), }; + public IEnumerable SongSelectKeyBindings => new[] + { + new KeyBinding(InputKey.F1, GlobalAction.ToggleModSelection), + new KeyBinding(InputKey.F2, GlobalAction.SelectNextRandom), + new KeyBinding(new[] { InputKey.Shift, InputKey.F2 }, GlobalAction.SelectPreviousRandom), + new KeyBinding(InputKey.F3, GlobalAction.ToggleBeatmapOptions) + }; + public IEnumerable AudioControlKeyBindings => new[] { new KeyBinding(new[] { InputKey.Alt, InputKey.Up }, GlobalAction.IncreaseVolume), @@ -217,5 +229,18 @@ namespace osu.Game.Input.Bindings [Description("Toggle in-game interface")] ToggleInGameInterface, + + // Song select keybindings + [Description("Toggle Mod Select")] + ToggleModSelection, + + [Description("Random")] + SelectNextRandom, + + [Description("Rewind")] + SelectPreviousRandom, + + [Description("Beatmap Options")] + ToggleBeatmapOptions, } } diff --git a/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailablilityTracker.cs b/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs similarity index 97% rename from osu.Game/Online/Rooms/OnlinePlayBeatmapAvailablilityTracker.cs rename to osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs index 8278162353..72ea84d4a8 100644 --- a/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailablilityTracker.cs +++ b/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs @@ -16,7 +16,7 @@ namespace osu.Game.Online.Rooms /// This differs from a regular download tracking composite as this accounts for the /// databased beatmap set's checksum, to disallow from playing with an altered version of the beatmap. /// - public class OnlinePlayBeatmapAvailablilityTracker : DownloadTrackingComposite + public class OnlinePlayBeatmapAvailabilityTracker : DownloadTrackingComposite { public readonly IBindable SelectedItem = new Bindable(); diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index b2bbd0b48b..21313d0596 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -308,17 +308,15 @@ namespace osu.Game AddInternal(RulesetConfigCache); - MenuCursorContainer = new MenuCursorContainer { RelativeSizeAxes = Axes.Both }; - - GlobalInputManager globalInput; - - MenuCursorContainer.Child = globalInput = new GlobalInputManager(this) + var globalInput = new GlobalInputManager(this) { RelativeSizeAxes = Axes.Both, - Child = content = new OsuTooltipContainer(MenuCursorContainer.Cursor) { RelativeSizeAxes = Axes.Both } + Child = MenuCursorContainer = new MenuCursorContainer { RelativeSizeAxes = Axes.Both } }; - base.Content.Add(CreateScalingContainer().WithChild(MenuCursorContainer)); + MenuCursorContainer.Child = content = new OsuTooltipContainer(MenuCursorContainer.Cursor) { RelativeSizeAxes = Axes.Both }; + + base.Content.Add(CreateScalingContainer().WithChild(globalInput)); KeyBindingStore.Register(globalInput.GlobalBindings); dependencies.Cache(globalInput.GlobalBindings); diff --git a/osu.Game/Overlays/KeyBinding/GlobalKeyBindingsSection.cs b/osu.Game/Overlays/KeyBinding/GlobalKeyBindingsSection.cs index 9a27c55c53..c905397e77 100644 --- a/osu.Game/Overlays/KeyBinding/GlobalKeyBindingsSection.cs +++ b/osu.Game/Overlays/KeyBinding/GlobalKeyBindingsSection.cs @@ -21,6 +21,7 @@ namespace osu.Game.Overlays.KeyBinding { Add(new DefaultBindingsSubsection(manager)); Add(new AudioControlKeyBindingsSubsection(manager)); + Add(new SongSelectKeyBindingSubsection(manager)); Add(new InGameKeyBindingsSubsection(manager)); Add(new EditorKeyBindingsSubsection(manager)); } @@ -36,6 +37,17 @@ namespace osu.Game.Overlays.KeyBinding } } + private class SongSelectKeyBindingSubsection : KeyBindingsSubsection + { + protected override string Header => "Song Select"; + + public SongSelectKeyBindingSubsection(GlobalActionContainer manager) + : base(null) + { + Defaults = manager.SongSelectKeyBindings; + } + } + private class InGameKeyBindingsSubsection : KeyBindingsSubsection { protected override string Header => "In Game"; diff --git a/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs b/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs index 6eb675976a..8f85608b29 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs @@ -16,7 +16,7 @@ namespace osu.Game.Screens.OnlinePlay.Components private IBindable availability; [BackgroundDependencyLoader] - private void load(OnlinePlayBeatmapAvailablilityTracker beatmapTracker) + private void load(OnlinePlayBeatmapAvailabilityTracker beatmapTracker) { availability = beatmapTracker.Availability.GetBoundCopy(); diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 4a689314db..706da05d15 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -56,15 +56,15 @@ namespace osu.Game.Screens.OnlinePlay.Match private IBindable> managerUpdated; [Cached] - protected OnlinePlayBeatmapAvailablilityTracker BeatmapAvailablilityTracker { get; } + protected OnlinePlayBeatmapAvailabilityTracker BeatmapAvailabilityTracker { get; } - protected IBindable BeatmapAvailability => BeatmapAvailablilityTracker.Availability; + protected IBindable BeatmapAvailability => BeatmapAvailabilityTracker.Availability; protected RoomSubScreen() { AddRangeInternal(new Drawable[] { - BeatmapAvailablilityTracker = new OnlinePlayBeatmapAvailablilityTracker + BeatmapAvailabilityTracker = new OnlinePlayBeatmapAvailabilityTracker { SelectedItem = { BindTarget = SelectedItem } }, diff --git a/osu.Game/Screens/Select/FooterButton.cs b/osu.Game/Screens/Select/FooterButton.cs index cd7c1c449f..7528651fd9 100644 --- a/osu.Game/Screens/Select/FooterButton.cs +++ b/osu.Game/Screens/Select/FooterButton.cs @@ -4,7 +4,6 @@ using System; using osuTK; using osuTK.Graphics; -using osuTK.Input; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -13,10 +12,12 @@ using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Containers; +using osu.Game.Input.Bindings; +using osu.Framework.Input.Bindings; namespace osu.Game.Screens.Select { - public class FooterButton : OsuClickableContainer + public class FooterButton : OsuClickableContainer, IKeyBindingHandler { public const float SHEAR_WIDTH = 7.5f; @@ -105,6 +106,7 @@ namespace osu.Game.Screens.Select AutoSizeAxes = Axes.Both, Child = SpriteText = new OsuSpriteText { + AlwaysPresent = true, Anchor = Anchor.Centre, Origin = Anchor.Centre, } @@ -118,7 +120,7 @@ namespace osu.Game.Screens.Select public Action Hovered; public Action HoverLost; - public Key? Hotkey; + public GlobalAction? Hotkey; protected override void UpdateAfterChildren() { @@ -168,15 +170,17 @@ namespace osu.Game.Screens.Select return base.OnClick(e); } - protected override bool OnKeyDown(KeyDownEvent e) + public virtual bool OnPressed(GlobalAction action) { - if (!e.Repeat && e.Key == Hotkey) + if (action == Hotkey) { Click(); return true; } - return base.OnKeyDown(e); + return false; } + + public virtual void OnReleased(GlobalAction action) { } } } diff --git a/osu.Game/Screens/Select/FooterButtonMods.cs b/osu.Game/Screens/Select/FooterButtonMods.cs index 02333da0dc..b98b48a0c0 100644 --- a/osu.Game/Screens/Select/FooterButtonMods.cs +++ b/osu.Game/Screens/Select/FooterButtonMods.cs @@ -14,7 +14,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osuTK; using osuTK.Graphics; -using osuTK.Input; +using osu.Game.Input.Bindings; namespace osu.Game.Screens.Select { @@ -57,7 +57,7 @@ namespace osu.Game.Screens.Select lowMultiplierColour = colours.Red; highMultiplierColour = colours.Green; Text = @"mods"; - Hotkey = Key.F1; + Hotkey = GlobalAction.ToggleModSelection; } protected override void LoadComplete() diff --git a/osu.Game/Screens/Select/FooterButtonOptions.cs b/osu.Game/Screens/Select/FooterButtonOptions.cs index c000d8a8c8..e549656785 100644 --- a/osu.Game/Screens/Select/FooterButtonOptions.cs +++ b/osu.Game/Screens/Select/FooterButtonOptions.cs @@ -4,7 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Game.Graphics; -using osuTK.Input; +using osu.Game.Input.Bindings; namespace osu.Game.Screens.Select { @@ -16,7 +16,7 @@ namespace osu.Game.Screens.Select SelectedColour = colours.Blue; DeselectedColour = SelectedColour.Opacity(0.5f); Text = @"options"; - Hotkey = Key.F3; + Hotkey = GlobalAction.ToggleBeatmapOptions; } } } diff --git a/osu.Game/Screens/Select/FooterButtonRandom.cs b/osu.Game/Screens/Select/FooterButtonRandom.cs index a42e6721db..2d14111137 100644 --- a/osu.Game/Screens/Select/FooterButtonRandom.cs +++ b/osu.Game/Screens/Select/FooterButtonRandom.cs @@ -1,35 +1,23 @@ // 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.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osuTK.Input; +using osu.Game.Input.Bindings; +using osuTK; namespace osu.Game.Screens.Select { public class FooterButtonRandom : FooterButton { - private readonly SpriteText secondaryText; - private bool secondaryActive; + public Action NextRandom { get; set; } + public Action PreviousRandom { get; set; } - public FooterButtonRandom() - { - TextContainer.Add(secondaryText = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = @"rewind", - Alpha = 0, - }); - - // force both text sprites to always be present to avoid width flickering while they're being swapped out - SpriteText.AlwaysPresent = secondaryText.AlwaysPresent = true; - } + private bool rewindSearch; [BackgroundDependencyLoader] private void load(OsuColour colours) @@ -37,34 +25,57 @@ namespace osu.Game.Screens.Select SelectedColour = colours.Green; DeselectedColour = SelectedColour.Opacity(0.5f); Text = @"random"; - Hotkey = Key.F2; - } - protected override bool OnKeyDown(KeyDownEvent e) - { - secondaryActive = e.ShiftPressed; - updateText(); - return base.OnKeyDown(e); - } - - protected override void OnKeyUp(KeyUpEvent e) - { - secondaryActive = e.ShiftPressed; - updateText(); - base.OnKeyUp(e); - } - - private void updateText() - { - if (secondaryActive) + Action = () => { - SpriteText.FadeOut(120, Easing.InQuad); - secondaryText.FadeIn(120, Easing.InQuad); + if (rewindSearch) + { + const double fade_time = 500; + + OsuSpriteText rewindSpriteText; + + TextContainer.Add(rewindSpriteText = new OsuSpriteText + { + Alpha = 0, + Text = @"rewind", + AlwaysPresent = true, // make sure the button is sized large enough to always show this + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }); + + rewindSpriteText.FadeOutFromOne(fade_time, Easing.In); + rewindSpriteText.MoveTo(Vector2.Zero).MoveTo(new Vector2(0, 10), fade_time, Easing.In); + rewindSpriteText.Expire(); + + SpriteText.FadeInFromZero(fade_time, Easing.In); + + PreviousRandom.Invoke(); + } + else + { + NextRandom.Invoke(); + } + }; + } + + public override bool OnPressed(GlobalAction action) + { + rewindSearch = action == GlobalAction.SelectPreviousRandom; + + if (action != GlobalAction.SelectNextRandom && action != GlobalAction.SelectPreviousRandom) + { + return false; } - else + + Click(); + return true; + } + + public override void OnReleased(GlobalAction action) + { + if (action == GlobalAction.SelectPreviousRandom) { - SpriteText.FadeIn(120, Easing.InQuad); - secondaryText.FadeOut(120, Easing.InQuad); + rewindSearch = false; } } } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index b7f7c40539..215700d87c 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -307,7 +307,11 @@ namespace osu.Game.Screens.Select protected virtual IEnumerable<(FooterButton, OverlayContainer)> CreateFooterButtons() => new (FooterButton, OverlayContainer)[] { (new FooterButtonMods { Current = Mods }, ModSelect), - (new FooterButtonRandom { Action = triggerRandom }, null), + (new FooterButtonRandom + { + NextRandom = () => Carousel.SelectNextRandom(), + PreviousRandom = Carousel.SelectPreviousRandom + }, null), (new FooterButtonOptions(), BeatmapOptions) }; @@ -522,14 +526,6 @@ namespace osu.Game.Screens.Select } } - private void triggerRandom() - { - if (GetContainingInputManager().CurrentState.Keyboard.ShiftPressed) - Carousel.SelectPreviousRandom(); - else - Carousel.SelectNextRandom(); - } - public override void OnEntering(IScreen last) { base.OnEntering(last);