1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 08:43:01 +08:00

Share code with HoldToConfirm implementations elsewhere

This commit is contained in:
Dean Herbert 2018-05-22 01:44:06 +09:00
parent f9c162dee9
commit ebda287e81
6 changed files with 135 additions and 112 deletions

@ -1 +1 @@
Subproject commit fac688633b8fcf34ae5d0514c26b03e217161eb4
Subproject commit b4d5c766f5698540a7b1bbbae7290ac7dafc2813

View File

@ -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<SpriteText>().Single();
AddStep("Trigger text fade in/out", () =>
{
exitAction = false;
innerButton.TriggerOnMouseDown();
innerButton.TriggerOnMouseUp();
Action = () => exitAction = true
});
var text = quitButton.Children.OfType<SpriteText>().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");
}
}
}

View File

@ -0,0 +1,52 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// 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;
/// <summary>
/// Whether the overlay should be allowed to return from a fired state.
/// </summary>
protected virtual bool AllowMultipleFires => false;
public Bindable<double> 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);
}
}
}

View File

@ -1,11 +1,10 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// 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 <see cref="BeginConfirm"/> and <see cref="AbortConfirm"/> from a user event).
/// </summary>
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;
/// <summary>
/// Whether the overlay should be allowed to return from a fired state.
/// </summary>
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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -219,7 +219,7 @@ namespace osu.Game.Screens.Play
}
};
hudOverlay.HoldToQuit.ExitAction = Exit;
hudOverlay.HoldToQuit.Action = Exit;
if (ShowStoryboard)
initializeStoryboard(false);