diff --git a/osu-framework b/osu-framework index fac688633b..b4d5c766f5 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit fac688633b8fcf34ae5d0514c26b03e217161eb4 +Subproject commit b4d5c766f5698540a7b1bbbae7290ac7dafc2813 diff --git a/osu.Game.Tests/Visual/TestCaseQuitButton.cs b/osu.Game.Tests/Visual/TestCaseQuitButton.cs index 545a8ff57b..f0f8d41074 100644 --- a/osu.Game.Tests/Visual/TestCaseQuitButton.cs +++ b/osu.Game.Tests/Visual/TestCaseQuitButton.cs @@ -3,49 +3,55 @@ using System.Linq; using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Game.Screens.Play.HUD; +using OpenTK; +using OpenTK.Input; namespace osu.Game.Tests.Visual { [Description("'Hold to Quit' UI element")] - public class TestCaseQuitButton : OsuTestCase + public class TestCaseQuitButton : ManualInputManagerTestCase { - private readonly QuitButton quitButton; - private Drawable innerButton => quitButton.Children.Single(child => child is CircularContainer); private bool exitAction; - public TestCaseQuitButton() + [BackgroundDependencyLoader] + private void load() { + QuitButton quitButton; + Add(quitButton = new QuitButton { Origin = Anchor.BottomRight, Anchor = Anchor.BottomRight, - }); - quitButton.ExitAction = () => exitAction = true; - - var text = quitButton.Children.OfType().Single(); - - AddStep("Trigger text fade in/out", () => - { - exitAction = false; - - innerButton.TriggerOnMouseDown(); - innerButton.TriggerOnMouseUp(); + Action = () => exitAction = true }); + var text = quitButton.Children.OfType().First(); + + // initial display AddUntilStep(() => text.IsPresent && !exitAction, "Text visible"); AddUntilStep(() => !text.IsPresent && !exitAction, "Text is not visible"); + AddStep("Trigger text fade in", () => InputManager.MoveMouseTo(quitButton)); + AddUntilStep(() => text.IsPresent && !exitAction, "Text visible"); + AddStep("Trigger text fade out", () => InputManager.MoveMouseTo(Vector2.One)); + AddUntilStep(() => !text.IsPresent && !exitAction, "Text is not visible"); + AddStep("Trigger exit action", () => { exitAction = false; - innerButton.TriggerOnMouseDown(); + InputManager.MoveMouseTo(quitButton); + InputManager.ButtonDown(MouseButton.Left); }); - AddUntilStep(() => exitAction, $"{nameof(quitButton.ExitAction)} was triggered"); + AddStep("Early release", () => InputManager.ButtonUp(MouseButton.Left)); + AddAssert("action not triggered", () => !exitAction); + + AddStep("Trigger exit action", () => InputManager.ButtonDown(MouseButton.Left)); + AddUntilStep(() => exitAction, $"{nameof(quitButton.Action)} was triggered"); } } } diff --git a/osu.Game/Graphics/Containers/HoldToCofirmContainer.cs b/osu.Game/Graphics/Containers/HoldToCofirmContainer.cs new file mode 100644 index 0000000000..eb2b2ca51b --- /dev/null +++ b/osu.Game/Graphics/Containers/HoldToCofirmContainer.cs @@ -0,0 +1,52 @@ +// 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.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; + +namespace osu.Game.Graphics.Containers +{ + public abstract class HoldToCofirmContainer : Container + { + public Action Action; + + private const int activate_delay = 400; + private const int fadeout_delay = 200; + + private bool fired; + private bool confirming; + + /// + /// Whether the overlay should be allowed to return from a fired state. + /// + protected virtual bool AllowMultipleFires => false; + + public Bindable Progress = new BindableDouble(); + + protected void BeginConfirm() + { + if (confirming || !AllowMultipleFires && fired) return; + + confirming = true; + + this.TransformBindableTo(Progress, 1, activate_delay * (1 - Progress.Value), Easing.Out).OnComplete(_ => Confirm()); + } + + protected virtual void Confirm() + { + Action?.Invoke(); + fired = true; + } + + protected void AbortConfirm() + { + if (!AllowMultipleFires && fired) return; + + confirming = false; + + this.TransformBindableTo(Progress, 0, fadeout_delay, Easing.Out); + } + } +} diff --git a/osu.Game/Overlays/HoldToConfirmOverlay.cs b/osu.Game/Overlays/HoldToConfirmOverlay.cs index a0e4bf1a39..afd3e2016f 100644 --- a/osu.Game/Overlays/HoldToConfirmOverlay.cs +++ b/osu.Game/Overlays/HoldToConfirmOverlay.cs @@ -1,11 +1,10 @@ // 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 osu.Game.Graphics.Containers; using OpenTK.Graphics; namespace osu.Game.Overlays @@ -14,22 +13,10 @@ 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 abstract class HoldToConfirmOverlay : HoldToCofirmContainer { - public Action Action; - private Box overlay; - private const int activate_delay = 400; - private const int fadeout_delay = 200; - - private bool fired; - - /// - /// Whether the overlay should be allowed to return from a fired state. - /// - protected virtual bool AllowMultipleFires => false; - [BackgroundDependencyLoader] private void load() { @@ -45,22 +32,8 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.Both, } }; - } - protected void BeginConfirm() - { - if (!AllowMultipleFires && fired) return; - overlay.FadeIn(activate_delay * (1 - overlay.Alpha), Easing.Out).OnComplete(_ => - { - Action?.Invoke(); - fired = true; - }); - } - - protected void AbortConfirm() - { - if (!AllowMultipleFires && fired) return; - overlay.FadeOut(fadeout_delay, Easing.Out); + Progress.ValueChanged += v => overlay.Alpha = (float)v; } } } diff --git a/osu.Game/Screens/Play/HUD/QuitButton.cs b/osu.Game/Screens/Play/HUD/QuitButton.cs index 939966f0e5..867558ad93 100644 --- a/osu.Game/Screens/Play/HUD/QuitButton.cs +++ b/osu.Game/Screens/Play/HUD/QuitButton.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Input; using osu.Framework.MathUtils; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using OpenTK; @@ -21,10 +22,9 @@ namespace osu.Game.Screens.Play.HUD private readonly Button button; - public Action ExitAction + public Action Action { - get => button.ExitAction; - set => button.ExitAction = value; + set => button.Action = value; } private readonly OsuSpriteText text; @@ -73,88 +73,80 @@ namespace osu.Game.Screens.Play.HUD float adjust = Vector2.Distance(GetContainingInputManager().CurrentState.Mouse.NativeState.Position, button.ScreenSpaceDrawQuad.Centre) / 200; double elapsed = MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 1000); - bool stayVisible = text.Alpha > 0 || button.Progress > 0 || IsHovered; + bool stayVisible = text.Alpha > 0 || button.Progress.Value > 0 || IsHovered; Alpha = stayVisible ? 1 : Interpolation.ValueAt(elapsed, Alpha, MathHelper.Clamp(1 - adjust, 0.04f, 1), 0, 200, Easing.OutQuint); } - private class Button : CircularContainer + private class Button : HoldToCofirmContainer { private SpriteIcon icon; private CircularProgress progress; private Circle innerCircle; - private bool triggered; - - public Action ExitAction { get; set; } - - public double Progress => progress.Current.Value; - - private const int fade_duration = 200; - private const int progress_duration = 600; - [BackgroundDependencyLoader] private void load(OsuColour colours) { - Masking = true; Size = new Vector2(60); - AddRange(new Drawable[] + + Child = new CircularContainer { - new Box + Masking = true, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Colour = colours.Gray1, - Alpha = 0.5f, - }, - progress = new CircularProgress - { - RelativeSizeAxes = Axes.Both, - InnerRadius = 1 - }, - innerCircle = new Circle - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Colour = colours.Gray1, - Size = new Vector2(0.9f), - }, - icon = new SpriteIcon - { - Shadow = false, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(15), - Icon = FontAwesome.fa_close - }, - }); + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.Gray1, + Alpha = 0.5f, + }, + progress = new CircularProgress + { + RelativeSizeAxes = Axes.Both, + InnerRadius = 1 + }, + innerCircle = new Circle + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = colours.Gray1, + Size = new Vector2(0.9f), + }, + icon = new SpriteIcon + { + Shadow = false, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(15), + Icon = FontAwesome.fa_close + }, + } + }; + + Progress.BindTo(progress.Current); + Progress.ValueChanged += v => icon.Scale = new Vector2(1 + (float)v * 0.4f); + } + + protected override void Confirm() + { + base.Confirm(); + innerCircle.ScaleTo(0, 100).Then().FadeOut().ScaleTo(1).FadeIn(500); } protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) { - if (state.Mouse.Buttons.Count > 1 || triggered) - return true; - - icon.ScaleTo(1.4f, progress_duration); - progress.FillTo(1, progress_duration, Easing.OutSine).OnComplete(_ => - { - innerCircle.ScaleTo(0, 100).Then().FadeOut().ScaleTo(1).FadeIn(500); - triggered = true; - ExitAction(); - }); - - return base.OnMouseDown(state, args); + if (state.Mouse.Buttons.Count == 1) + BeginConfirm(); + return true; } protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) { - if (state.Mouse.Buttons.Count > 0 || triggered) - return true; - - icon.ScaleTo(1, 800, Easing.OutElastic); - progress.FillTo(0, progress_duration, Easing.OutQuint).OnComplete(cp => progress.Current.SetDefault()); - - return base.OnMouseUp(state, args); + if (state.Mouse.Buttons.Count == 0) + AbortConfirm(); + return true; } } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 5fb3fb778c..37176aa327 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -219,7 +219,7 @@ namespace osu.Game.Screens.Play } }; - hudOverlay.HoldToQuit.ExitAction = Exit; + hudOverlay.HoldToQuit.Action = Exit; if (ShowStoryboard) initializeStoryboard(false);