diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs index 405461eec8..54cdeaf956 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs @@ -1,10 +1,12 @@ // 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.Threading; using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; -using osu.Framework.Testing; using osu.Game.Overlays; using osu.Game.Overlays.Dialog; @@ -15,15 +17,11 @@ namespace osu.Game.Tests.Visual.UserInterface { private DialogOverlay overlay; - [SetUpSteps] - public void SetUpSteps() - { - AddStep("create dialog overlay", () => Child = overlay = new DialogOverlay()); - } - [Test] public void TestBasic() { + AddStep("create dialog overlay", () => Child = overlay = new DialogOverlay()); + TestPopupDialog firstDialog = null; TestPopupDialog secondDialog = null; @@ -37,12 +35,12 @@ namespace osu.Game.Tests.Visual.UserInterface new PopupDialogOkButton { Text = @"I never want to see this again.", - Action = () => System.Console.WriteLine(@"OK"), + Action = () => Console.WriteLine(@"OK"), }, new PopupDialogCancelButton { Text = @"Firetruck, I still want quick ranks!", - Action = () => System.Console.WriteLine(@"Cancel"), + Action = () => Console.WriteLine(@"Cancel"), }, }, })); @@ -87,9 +85,49 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("first dialog is not part of hierarchy", () => firstDialog.Parent == null); } + [Test] + public void TestPushBeforeLoad() + { + PopupDialog dialog = null; + + AddStep("create dialog overlay", () => overlay = new SlowLoadingDialogOverlay()); + + AddStep("start loading overlay", () => LoadComponentAsync(overlay, Add)); + + AddStep("push dialog before loaded", () => + { + overlay.Push(dialog = new TestPopupDialog + { + Buttons = new PopupDialogButton[] + { + new PopupDialogOkButton { Text = @"OK" }, + }, + }); + }); + + AddStep("complete load", () => ((SlowLoadingDialogOverlay)overlay).LoadEvent.Set()); + + AddUntilStep("wait for load", () => overlay.IsLoaded); + + AddAssert("dialog displayed", () => overlay.CurrentDialog == dialog); + } + + public class SlowLoadingDialogOverlay : DialogOverlay + { + public ManualResetEventSlim LoadEvent = new ManualResetEventSlim(); + + [BackgroundDependencyLoader] + private void load() + { + LoadEvent.Wait(10000); + } + } + [Test] public void TestDismissBeforePush() { + AddStep("create dialog overlay", () => Child = overlay = new DialogOverlay()); + TestPopupDialog testDialog = null; AddStep("dismissed dialog push", () => { @@ -106,6 +144,8 @@ namespace osu.Game.Tests.Visual.UserInterface [Test] public void TestDismissBeforePushViaButtonPress() { + AddStep("create dialog overlay", () => Child = overlay = new DialogOverlay()); + TestPopupDialog testDialog = null; AddStep("dismissed dialog push", () => { diff --git a/osu.Game/Beatmaps/BeatmapOnlineLookupQueue.cs b/osu.Game/Beatmaps/BeatmapOnlineLookupQueue.cs index a24b6b315a..46f5b418bd 100644 --- a/osu.Game/Beatmaps/BeatmapOnlineLookupQueue.cs +++ b/osu.Game/Beatmaps/BeatmapOnlineLookupQueue.cs @@ -153,7 +153,7 @@ namespace osu.Game.Beatmaps } }; - cacheDownloadRequest.PerformAsync(); + Task.Run(() => cacheDownloadRequest.PerformAsync()); } private bool checkLocalCache(BeatmapSetInfo set, BeatmapInfo beatmapInfo) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 3e7051cbf5..13a3f006fb 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -59,6 +59,9 @@ namespace osu.Game.Input.Bindings new KeyBinding(InputKey.Up, GlobalAction.SelectPrevious), new KeyBinding(InputKey.Down, GlobalAction.SelectNext), + new KeyBinding(InputKey.Left, GlobalAction.SelectPreviousGroup), + new KeyBinding(InputKey.Right, GlobalAction.SelectNextGroup), + new KeyBinding(InputKey.Space, GlobalAction.Select), new KeyBinding(InputKey.Enter, GlobalAction.Select), new KeyBinding(InputKey.KeypadEnter, GlobalAction.Select), @@ -105,7 +108,7 @@ namespace osu.Game.Input.Bindings 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) + new KeyBinding(InputKey.F3, GlobalAction.ToggleBeatmapOptions), }; public IEnumerable AudioControlKeyBindings => new[] @@ -309,5 +312,11 @@ namespace osu.Game.Input.Bindings [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorDecreaseDistanceSpacing))] EditorDecreaseDistanceSpacing, + + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.SelectPreviousGroup))] + SelectPreviousGroup, + + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.SelectNextGroup))] + SelectNextGroup, } } diff --git a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs index 58afb284b5..b2f25de7f2 100644 --- a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs +++ b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs @@ -129,6 +129,16 @@ namespace osu.Game.Localisation /// public static LocalisableString SelectNext => new TranslatableString(getKey(@"select_next"), @"Next selection"); + /// + /// "Select previous group" + /// + public static LocalisableString SelectPreviousGroup => new TranslatableString(getKey(@"select_previous_group"), @"Select previous group"); + + /// + /// "Select next group" + /// + public static LocalisableString SelectNextGroup => new TranslatableString(getKey(@"select_next_group"), @"Select next group"); + /// /// "Home" /// diff --git a/osu.Game/Overlays/DialogOverlay.cs b/osu.Game/Overlays/DialogOverlay.cs index 15d89a561a..5a69562e82 100644 --- a/osu.Game/Overlays/DialogOverlay.cs +++ b/osu.Game/Overlays/DialogOverlay.cs @@ -49,18 +49,24 @@ namespace osu.Game.Overlays { if (dialog == CurrentDialog || dialog.State.Value != Visibility.Visible) return; - // if any existing dialog is being displayed, dismiss it before showing a new one. - CurrentDialog?.Hide(); + var lastDialog = CurrentDialog; + // Immediately update the externally accessible property as this may be used for checks even before + // a DialogOverlay instance has finished loading. CurrentDialog = dialog; - CurrentDialog.State.ValueChanged += state => onDialogOnStateChanged(dialog, state.NewValue); - dialogContainer.Add(CurrentDialog); + Scheduler.Add(() => + { + // if any existing dialog is being displayed, dismiss it before showing a new one. + lastDialog?.Hide(); + dialog.State.ValueChanged += state => onDialogOnStateChanged(dialog, state.NewValue); + dialogContainer.Add(dialog); - Show(); + Show(); + }, false); } - public override bool IsPresent => dialogContainer.Children.Count > 0; + public override bool IsPresent => Scheduler.HasPendingTasks || dialogContainer.Children.Count > 0; protected override bool BlockNonPositionalInput => true; @@ -81,23 +87,16 @@ namespace osu.Game.Overlays protected override void PopIn() { base.PopIn(); - this.FadeIn(PopupDialog.ENTER_DURATION, Easing.OutQuint); lowPassFilter.CutoffTo(300, 100, Easing.OutCubic); } protected override void PopOut() { base.PopOut(); - lowPassFilter.CutoffTo(AudioFilter.MAX_LOWPASS_CUTOFF, 100, Easing.InCubic); if (CurrentDialog?.State.Value == Visibility.Visible) - { CurrentDialog.Hide(); - return; - } - - this.FadeOut(PopupDialog.EXIT_DURATION, Easing.InSine); } public override bool OnPressed(KeyBindingPressEvent e) diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index e2afd46c18..46b8b35da2 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -372,12 +372,12 @@ namespace osu.Game.Overlays.Volume switch (e.Action) { - case GlobalAction.SelectPrevious: + case GlobalAction.SelectPreviousGroup: State = SelectionState.Selected; adjust(1, false); return true; - case GlobalAction.SelectNext: + case GlobalAction.SelectNextGroup: State = SelectionState.Selected; adjust(-1, false); return true; diff --git a/osu.Game/Rulesets/Edit/IPositionSnapProvider.cs b/osu.Game/Rulesets/Edit/IPositionSnapProvider.cs index 87842673d8..837b04424a 100644 --- a/osu.Game/Rulesets/Edit/IPositionSnapProvider.cs +++ b/osu.Game/Rulesets/Edit/IPositionSnapProvider.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Edit SnapResult FindSnappedPositionAndTime(Vector2 screenSpacePosition); /// - /// Given a position, find a value position snap, restricting time to its input value. + /// Given a position, find a valid position snap, without changing the time value. /// /// The screen-space position to be snapped. /// The position post-snapping. Time will always be null. diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index c3d340ac61..a59f14647d 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -604,34 +604,20 @@ namespace osu.Game.Screens.Select public void ScrollToSelected(bool immediate = false) => pendingScrollOperation = immediate ? PendingScrollOperation.Immediate : PendingScrollOperation.Standard; - #region Key / button selection logic - - protected override bool OnKeyDown(KeyDownEvent e) - { - switch (e.Key) - { - case Key.Left: - SelectNext(-1); - return true; - - case Key.Right: - SelectNext(); - return true; - } - - return false; - } + #region Button selection logic public bool OnPressed(KeyBindingPressEvent e) { switch (e.Action) { case GlobalAction.SelectNext: - SelectNext(1, false); + case GlobalAction.SelectNextGroup: + SelectNext(1, e.Action == GlobalAction.SelectNextGroup); return true; case GlobalAction.SelectPrevious: - SelectNext(-1, false); + case GlobalAction.SelectPreviousGroup: + SelectNext(-1, e.Action == GlobalAction.SelectPreviousGroup); return true; }