From 5df9f126d162ea33a8eb1af68746ec5291d4f21d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 10 May 2018 17:07:19 +0900 Subject: [PATCH 1/4] Implement a hold-to-confirm screen when exiting game using escape key --- osu.Game/Overlays/HoldToConfirmOverlay.cs | 59 +++++++++++++++++++++ osu.Game/Screens/Menu/ExitConfirmOverlay.cs | 34 ++++++++++++ osu.Game/Screens/Menu/MainMenu.cs | 4 ++ osu.Game/Screens/Play/HotkeyRetryOverlay.cs | 49 ++--------------- 4 files changed, 101 insertions(+), 45 deletions(-) create mode 100644 osu.Game/Overlays/HoldToConfirmOverlay.cs create mode 100644 osu.Game/Screens/Menu/ExitConfirmOverlay.cs diff --git a/osu.Game/Overlays/HoldToConfirmOverlay.cs b/osu.Game/Overlays/HoldToConfirmOverlay.cs new file mode 100644 index 0000000000..4bc7154ce8 --- /dev/null +++ b/osu.Game/Overlays/HoldToConfirmOverlay.cs @@ -0,0 +1,59 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using OpenTK.Graphics; + +namespace osu.Game.Overlays +{ + /// + /// An overlay which will display a black screen that dims over a period before confirming an exit action. + /// Action is BYO (derived class will need to call and from a user event). + /// + public abstract class HoldToConfirmOverlay : Container + { + public Action Action; + + private Box overlay; + + private const int activate_delay = 400; + private const int fadeout_delay = 200; + + private bool fired; + + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.Both; + AlwaysPresent = true; + + Children = new Drawable[] + { + overlay = new Box + { + Alpha = 0, + Colour = Color4.Black, + RelativeSizeAxes = Axes.Both, + } + }; + } + + protected void BeginConfirm() => overlay.FadeIn(activate_delay, Easing.Out); + + protected void AbortConfirm() => overlay.FadeOut(fadeout_delay, Easing.Out); + + protected override void Update() + { + base.Update(); + if (!fired && overlay.Alpha == 1) + { + fired = true; + Action?.Invoke(); + } + } + } +} diff --git a/osu.Game/Screens/Menu/ExitConfirmOverlay.cs b/osu.Game/Screens/Menu/ExitConfirmOverlay.cs new file mode 100644 index 0000000000..62605da5a4 --- /dev/null +++ b/osu.Game/Screens/Menu/ExitConfirmOverlay.cs @@ -0,0 +1,34 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Input; +using osu.Game.Overlays; +using OpenTK.Input; + +namespace osu.Game.Screens.Menu +{ + public class ExitConfirmOverlay : HoldToConfirmOverlay + { + protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) + { + if (args.Key == Key.Escape && !args.Repeat) + { + BeginConfirm(); + return true; + } + + return base.OnKeyDown(state, args); + } + + protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) + { + if (args.Key == Key.Escape) + { + AbortConfirm(); + return true; + } + + return base.OnKeyUp(state, args); + } + } +} diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index f2ea6d85a8..ce5aace50b 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -39,6 +39,10 @@ namespace osu.Game.Screens.Menu Children = new Drawable[] { + new ExitConfirmOverlay + { + Action = Exit, + }, new ParallaxContainer { ParallaxAmount = 0.01f, diff --git a/osu.Game/Screens/Play/HotkeyRetryOverlay.cs b/osu.Game/Screens/Play/HotkeyRetryOverlay.cs index a018a2697a..926a96eb6c 100644 --- a/osu.Game/Screens/Play/HotkeyRetryOverlay.cs +++ b/osu.Game/Screens/Play/HotkeyRetryOverlay.cs @@ -1,50 +1,19 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Allocation; -using System; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Bindings; using osu.Game.Input.Bindings; -using OpenTK.Graphics; +using osu.Game.Overlays; namespace osu.Game.Screens.Play { - public class HotkeyRetryOverlay : Container, IKeyBindingHandler + public class HotkeyRetryOverlay : HoldToConfirmOverlay, IKeyBindingHandler { - public Action Action; - - private Box overlay; - - private const int activate_delay = 400; - private const int fadeout_delay = 200; - - private bool fired; - - [BackgroundDependencyLoader] - private void load() - { - RelativeSizeAxes = Axes.Both; - AlwaysPresent = true; - - Children = new Drawable[] - { - overlay = new Box - { - Alpha = 0, - Colour = Color4.Black, - RelativeSizeAxes = Axes.Both, - } - }; - } - public bool OnPressed(GlobalAction action) { if (action != GlobalAction.QuickRetry) return false; - overlay.FadeIn(activate_delay, Easing.Out); + BeginConfirm(); return true; } @@ -52,18 +21,8 @@ namespace osu.Game.Screens.Play { if (action != GlobalAction.QuickRetry) return false; - overlay.FadeOut(fadeout_delay, Easing.Out); + AbortConfirm(); return true; } - - protected override void Update() - { - base.Update(); - if (!fired && overlay.Alpha == 1) - { - fired = true; - Action?.Invoke(); - } - } } } From 63e10ec3c2d2844e13e7e2b47b86984be5e4547a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 10 May 2018 17:10:42 +0900 Subject: [PATCH 2/4] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 96ef8c43b5..e793a08417 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 96ef8c43b5e6b6ae14b01c3550c480c8d9a78518 +Subproject commit e793a084177f53920645c4f6f70cfef91e7fd19e From fadb1a5e0b44c85b2ff132aa0ab91b9c34285621 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 10 May 2018 17:30:24 +0900 Subject: [PATCH 3/4] Add tests and expand functionality to ensure single fire --- .../Visual/TestCaseHoldToConfirmOverlay.cs | 62 +++++++++++++++++++ osu.Game/Overlays/HoldToConfirmOverlay.cs | 25 +++++--- 2 files changed, 78 insertions(+), 9 deletions(-) create mode 100644 osu.Game.Tests/Visual/TestCaseHoldToConfirmOverlay.cs diff --git a/osu.Game.Tests/Visual/TestCaseHoldToConfirmOverlay.cs b/osu.Game.Tests/Visual/TestCaseHoldToConfirmOverlay.cs new file mode 100644 index 0000000000..ef6f44b42e --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseHoldToConfirmOverlay.cs @@ -0,0 +1,62 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using osu.Framework.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Screens.Menu; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseHoldToConfirmOverlay : OsuTestCase + { + public override IReadOnlyList RequiredTypes => new[] { typeof(ExitConfirmOverlay) }; + + public TestCaseHoldToConfirmOverlay() + { + bool fired = false; + + var abortText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = "Aborted!", + TextSize = 50, + Alpha = 0, + }; + + var overlay = new TestHoldToConfirmOverlay + { + Action = () => + { + fired = true; + abortText.FadeTo(1).Then().FadeOut(1000); + } + }; + + Children = new Drawable[] + { + overlay, + abortText + }; + + AddStep("start confirming", () => overlay.Begin()); + AddStep("abort confirming", () => overlay.Abort()); + + AddAssert("ensure aborted", () => !fired); + + AddStep("start confirming", () => overlay.Begin()); + + AddUntilStep(() => fired, "wait until confirmed"); + } + + private class TestHoldToConfirmOverlay : ExitConfirmOverlay + { + protected override bool AllowMultipleFires => true; + + public void Begin() => BeginConfirm(); + public void Abort() => AbortConfirm(); + } + } +} diff --git a/osu.Game/Overlays/HoldToConfirmOverlay.cs b/osu.Game/Overlays/HoldToConfirmOverlay.cs index 4bc7154ce8..a0e4bf1a39 100644 --- a/osu.Game/Overlays/HoldToConfirmOverlay.cs +++ b/osu.Game/Overlays/HoldToConfirmOverlay.cs @@ -25,6 +25,11 @@ namespace osu.Game.Overlays private bool fired; + /// + /// Whether the overlay should be allowed to return from a fired state. + /// + protected virtual bool AllowMultipleFires => false; + [BackgroundDependencyLoader] private void load() { @@ -42,18 +47,20 @@ namespace osu.Game.Overlays }; } - protected void BeginConfirm() => overlay.FadeIn(activate_delay, Easing.Out); - - protected void AbortConfirm() => overlay.FadeOut(fadeout_delay, Easing.Out); - - protected override void Update() + protected void BeginConfirm() { - base.Update(); - if (!fired && overlay.Alpha == 1) + if (!AllowMultipleFires && fired) return; + overlay.FadeIn(activate_delay * (1 - overlay.Alpha), Easing.Out).OnComplete(_ => { - fired = true; Action?.Invoke(); - } + fired = true; + }); + } + + protected void AbortConfirm() + { + if (!AllowMultipleFires && fired) return; + overlay.FadeOut(fadeout_delay, Easing.Out); } } } From 9536c324fa3853bfeff8c29b54d3258ad1998509 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 14 May 2018 19:08:00 +0900 Subject: [PATCH 4/4] Rename aborted -> fired --- osu.Game.Tests/Visual/TestCaseHoldToConfirmOverlay.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseHoldToConfirmOverlay.cs b/osu.Game.Tests/Visual/TestCaseHoldToConfirmOverlay.cs index ef6f44b42e..6fa49c4edb 100644 --- a/osu.Game.Tests/Visual/TestCaseHoldToConfirmOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseHoldToConfirmOverlay.cs @@ -17,11 +17,11 @@ namespace osu.Game.Tests.Visual { bool fired = false; - var abortText = new OsuSpriteText + var firedText = new OsuSpriteText { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Text = "Aborted!", + Text = "Fired!", TextSize = 50, Alpha = 0, }; @@ -31,14 +31,14 @@ namespace osu.Game.Tests.Visual Action = () => { fired = true; - abortText.FadeTo(1).Then().FadeOut(1000); + firedText.FadeTo(1).Then().FadeOut(1000); } }; Children = new Drawable[] { overlay, - abortText + firedText }; AddStep("start confirming", () => overlay.Begin());