diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBackButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBackButton.cs new file mode 100644 index 0000000000..867b3130c9 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBackButton.cs @@ -0,0 +1,52 @@ +// 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.Collections.Generic; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics.UserInterface; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneBackButton : OsuTestScene + { + private readonly BackButton button; + + public override IReadOnlyList RequiredTypes => new[] + { + typeof(TwoLayerButton) + }; + + public TestSceneBackButton() + { + Child = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(300), + Masking = true, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.SlateGray + }, + button = new BackButton + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Action = () => button.Hide(), + } + } + }; + + AddStep("show button", () => button.Show()); + AddStep("hide button", () => button.Hide()); + } + } +} diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneTwoLayerButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneTwoLayerButton.cs index b9ed1a71cc..849577186d 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneTwoLayerButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneTwoLayerButton.cs @@ -1,17 +1,26 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.ComponentModel; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osuTK; +using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { - [Description("mostly back button")] public class TestSceneTwoLayerButton : OsuTestScene { public TestSceneTwoLayerButton() { - Add(new BackButton()); + Add(new TwoLayerButton + { + Position = new Vector2(100), + Text = "button", + Icon = FontAwesome.Solid.Check, + BackgroundColour = Color4.SlateGray, + HoverColour = Color4.SlateGray.Darken(0.2f) + }); } } } diff --git a/osu.Game/Graphics/UserInterface/BackButton.cs b/osu.Game/Graphics/UserInterface/BackButton.cs index 10e8227f16..48bf0848ae 100644 --- a/osu.Game/Graphics/UserInterface/BackButton.cs +++ b/osu.Game/Graphics/UserInterface/BackButton.cs @@ -1,26 +1,65 @@ // 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.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Input.Bindings; +using osu.Game.Input.Bindings; namespace osu.Game.Graphics.UserInterface { - public class BackButton : TwoLayerButton + public class BackButton : VisibilityContainer, IKeyBindingHandler { + public Action Action; + + private readonly TwoLayerButton button; + public BackButton() { - Text = @"back"; - Icon = OsuIcon.LeftCircle; - Anchor = Anchor.BottomLeft; - Origin = Anchor.BottomLeft; + Size = TwoLayerButton.SIZE_EXTENDED; + + Child = button = new TwoLayerButton + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Text = @"back", + Icon = OsuIcon.LeftCircle, + Action = () => Action?.Invoke() + }; } [BackgroundDependencyLoader] private void load(OsuColour colours) { - BackgroundColour = colours.Pink; - HoverColour = colours.PinkDark; + button.BackgroundColour = colours.Pink; + button.HoverColour = colours.PinkDark; + } + + public bool OnPressed(GlobalAction action) + { + if (action == GlobalAction.Back) + { + Action?.Invoke(); + return true; + } + + return false; + } + + public bool OnReleased(GlobalAction action) => action == GlobalAction.Back; + + protected override void PopIn() + { + button.MoveToX(0, 400, Easing.OutQuint); + button.FadeIn(150, Easing.OutQuint); + } + + protected override void PopOut() + { + button.MoveToX(-TwoLayerButton.SIZE_EXTENDED.X / 2, 400, Easing.OutQuint); + button.FadeOut(400, Easing.OutQuint); } } } diff --git a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs index 36a9aca412..c74d00cd1e 100644 --- a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs +++ b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs @@ -165,7 +165,8 @@ namespace osu.Game.Graphics.UserInterface protected override bool OnHover(HoverEvent e) { this.ResizeTo(SIZE_EXTENDED, transform_time, Easing.OutElastic); - IconLayer.FadeColour(HoverColour, transform_time, Easing.OutElastic); + + IconLayer.FadeColour(HoverColour, transform_time / 2f, Easing.OutQuint); bouncingIcon.ScaleTo(1.1f, transform_time, Easing.OutElastic); @@ -174,16 +175,13 @@ namespace osu.Game.Graphics.UserInterface protected override void OnHoverLost(HoverLostEvent e) { - this.ResizeTo(SIZE_RETRACTED, transform_time, Easing.OutElastic); - IconLayer.FadeColour(TextLayer.Colour, transform_time, Easing.OutElastic); + this.ResizeTo(SIZE_RETRACTED, transform_time, Easing.Out); + IconLayer.FadeColour(TextLayer.Colour, transform_time, Easing.Out); - bouncingIcon.ScaleTo(1, transform_time, Easing.OutElastic); + bouncingIcon.ScaleTo(1, transform_time, Easing.Out); } - protected override bool OnMouseDown(MouseDownEvent e) - { - return true; - } + protected override bool OnMouseDown(MouseDownEvent e) => true; protected override bool OnClick(ClickEvent e) { diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 35684849a3..f7f2e1b451 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -29,6 +29,7 @@ using osu.Framework.Threading; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; using osu.Game.Input; using osu.Game.Overlays.Notifications; using osu.Game.Screens.Play; @@ -82,6 +83,7 @@ namespace osu.Game private OsuScreenStack screenStack; private VolumeOverlay volume; private OsuLogo osuLogo; + private BackButton backButton; private MainMenu menuScreen; private Intro introScreen; @@ -399,6 +401,16 @@ namespace osu.Game Children = new Drawable[] { screenStack = new OsuScreenStack { RelativeSizeAxes = Axes.Both }, + backButton = new BackButton + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Action = () => + { + if ((screenStack.CurrentScreen as IOsuScreen)?.AllowBackButton == true) + screenStack.Exit(); + } + }, logoContainer = new Container { RelativeSizeAxes = Axes.Both }, } }, @@ -795,6 +807,11 @@ namespace osu.Game CloseAllOverlays(); else Toolbar.Show(); + + if (newOsuScreen.AllowBackButton) + backButton.Show(); + else + backButton.Hide(); } } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index de0f3870c6..660c1235d1 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -32,6 +32,8 @@ namespace osu.Game.Screens.Edit { protected override BackgroundScreen CreateBackground() => new BackgroundScreenCustom(@"Backgrounds/bg4"); + public override bool AllowBackButton => false; + public override bool HideOverlaysOnEnter => true; public override bool DisallowExternalBeatmapRulesetChanges => true; diff --git a/osu.Game/Screens/IOsuScreen.cs b/osu.Game/Screens/IOsuScreen.cs index b25bcdeab1..9fc907c2a4 100644 --- a/osu.Game/Screens/IOsuScreen.cs +++ b/osu.Game/Screens/IOsuScreen.cs @@ -17,6 +17,11 @@ namespace osu.Game.Screens /// bool DisallowExternalBeatmapRulesetChanges { get; } + /// + /// Whether the user can exit this this by pressing the back button. + /// + bool AllowBackButton { get; } + /// /// Whether a top-level component should be allowed to exit the current screen to, for example, /// complete an import. Note that this can be overridden by a user if they specifically request. diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index fbe4b6311e..e4956bc8ab 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -23,7 +23,7 @@ namespace osu.Game.Screens public override bool CursorVisible => false; - protected override bool AllowBackButton => false; + public override bool AllowBackButton => false; public Loader() { diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs index 88537322ad..eec92e3080 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/Intro.cs @@ -32,6 +32,8 @@ namespace osu.Game.Screens.Menu private SampleChannel welcome; private SampleChannel seeya; + public override bool AllowBackButton => false; + public override bool HideOverlaysOnEnter => true; public override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled; diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 65db2973de..7e6de54d1b 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -27,7 +27,7 @@ namespace osu.Game.Screens.Menu public override bool HideOverlaysOnEnter => buttons == null || buttons.State == ButtonSystemState.Initial; - protected override bool AllowBackButton => buttons.State != ButtonSystemState.Initial && host.CanExit; + public override bool AllowBackButton => false; public override bool AllowExternalScreenChange => true; diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs index a56d153646..9ffd620e55 100644 --- a/osu.Game/Screens/Multi/Multiplayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer.cs @@ -212,6 +212,12 @@ namespace osu.Game.Screens.Multi public override bool OnExiting(IScreen next) { + if (!(screenStack.CurrentScreen is LoungeSubScreen)) + { + screenStack.Exit(); + return true; + } + waves.Hide(); this.Delay(WaveContainer.DISAPPEAR_DURATION).FadeOut(); diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index e2aeb41de1..328631ff9c 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -8,10 +8,8 @@ using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Input.Bindings; using osu.Framework.Screens; using osu.Game.Beatmaps; -using osu.Game.Input.Bindings; using osu.Game.Rulesets; using osu.Game.Screens.Menu; using osu.Game.Overlays; @@ -21,7 +19,7 @@ using osu.Game.Rulesets.Mods; namespace osu.Game.Screens { - public abstract class OsuScreen : Screen, IOsuScreen, IKeyBindingHandler, IHasDescription + public abstract class OsuScreen : Screen, IOsuScreen, IHasDescription { /// /// The amount of negative padding that should be applied to game background content which touches both the left and right sides of the screen. @@ -36,7 +34,7 @@ namespace osu.Game.Screens public string Description => Title; - protected virtual bool AllowBackButton => true; + public virtual bool AllowBackButton => true; public virtual bool AllowExternalScreenChange => false; @@ -131,21 +129,6 @@ namespace osu.Game.Screens sampleExit = audio.Samples.Get(@"UI/screen-back"); } - public virtual bool OnPressed(GlobalAction action) - { - if (!this.IsCurrentScreen()) return false; - - if (action == GlobalAction.Back && AllowBackButton) - { - this.Exit(); - return true; - } - - return false; - } - - public bool OnReleased(GlobalAction action) => action == GlobalAction.Back && AllowBackButton; - public override void OnResuming(IScreen last) { if (PlayResumeSound) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index c3a9ffdaba..8c2c653c5b 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -33,7 +33,7 @@ namespace osu.Game.Screens.Play { public class Player : ScreenWithBeatmapBackground { - protected override bool AllowBackButton => false; // handled by HoldForMenuButton + public override bool AllowBackButton => false; // handled by HoldForMenuButton protected override UserActivity InitialActivity => new UserActivity.SoloGame(Beatmap.Value.BeatmapInfo, Ruleset.Value); diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index 370c856d1d..f53fb75e1a 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -16,7 +16,6 @@ using osu.Game.Screens.Backgrounds; using osuTK; using osuTK.Graphics; using osu.Game.Graphics; -using osu.Game.Graphics.UserInterface; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Sprites; using osu.Game.Scoring; @@ -254,13 +253,7 @@ namespace osu.Game.Screens.Ranking } } } - }, - new BackButton - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Action = this.Exit - }, + } }; foreach (var t in CreateResultPages()) diff --git a/osu.Game/Screens/ScreenWhiteBox.cs b/osu.Game/Screens/ScreenWhiteBox.cs index d6766c2b49..5648dd997b 100644 --- a/osu.Game/Screens/ScreenWhiteBox.cs +++ b/osu.Game/Screens/ScreenWhiteBox.cs @@ -20,8 +20,6 @@ namespace osu.Game.Screens { public class ScreenWhiteBox : OsuScreen { - private readonly BackButton popButton; - private const double transition_time = 1000; protected virtual IEnumerable PossibleChildren => null; @@ -35,10 +33,6 @@ namespace osu.Game.Screens { base.OnEntering(last); - //only show the pop button if we are entered form another screen. - if (last != null) - popButton.Alpha = 1; - Alpha = 0; textContainer.Position = new Vector2(DrawSize.X / 16, 0); @@ -144,13 +138,6 @@ namespace osu.Game.Screens }, } }, - popButton = new BackButton - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Alpha = 0, - Action = this.Exit - }, childModeButtons = new FillFlowContainer { Direction = FillDirection.Vertical, diff --git a/osu.Game/Screens/Select/Footer.cs b/osu.Game/Screens/Select/Footer.cs index 6ba29751b0..0680711f1c 100644 --- a/osu.Game/Screens/Select/Footer.cs +++ b/osu.Game/Screens/Select/Footer.cs @@ -1,7 +1,6 @@ // 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.Collections.Generic; using System.Linq; using osuTK; @@ -25,8 +24,6 @@ namespace osu.Game.Screens.Select private const float padding = 80; - public Action OnBack; - private readonly FillFlowContainer buttons; private readonly List overlays = new List(); @@ -83,12 +80,6 @@ namespace osu.Game.Screens.Select Height = 3, Position = new Vector2(0, -3), }, - new BackButton - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Action = () => OnBack?.Invoke() - }, new FillFlowContainer { Anchor = Anchor.BottomLeft, diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index f9df8c3a39..dfda252deb 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -34,10 +34,11 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using osu.Framework.Graphics.Sprites; +using osu.Framework.Input.Bindings; namespace osu.Game.Screens.Select { - public abstract class SongSelect : OsuScreen + public abstract class SongSelect : OsuScreen, IKeyBindingHandler { private static readonly Vector2 wedged_container_size = new Vector2(0.5f, 245); @@ -186,31 +187,27 @@ namespace osu.Game.Screens.Select if (ShowFooter) { - AddInternal(FooterPanels = new Container + AddRangeInternal(new[] { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Margin = new MarginPadding - { - Bottom = Footer.HEIGHT, - }, - }); - AddInternal(Footer = new Footer - { - OnBack = ExitFromBack, - }); - - FooterPanels.AddRange(new Drawable[] - { - BeatmapOptions = new BeatmapOptionsOverlay(), - ModSelect = new ModSelectOverlay + FooterPanels = new Container { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, RelativeSizeAxes = Axes.X, - Origin = Anchor.BottomCentre, - Anchor = Anchor.BottomCentre, - } + AutoSizeAxes = Axes.Y, + Margin = new MarginPadding { Bottom = Footer.HEIGHT }, + Children = new Drawable[] + { + BeatmapOptions = new BeatmapOptionsOverlay(), + ModSelect = new ModSelectOverlay + { + RelativeSizeAxes = Axes.X, + Origin = Anchor.BottomCentre, + Anchor = Anchor.BottomCentre, + } + } + }, + Footer = new Footer() }); } @@ -277,17 +274,6 @@ namespace osu.Game.Screens.Select return dependencies; } - protected virtual void ExitFromBack() - { - if (ModSelect.State.Value == Visibility.Visible) - { - ModSelect.Hide(); - return; - } - - this.Exit(); - } - public void Edit(BeatmapInfo beatmap = null) { Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap ?? beatmapNoDebounce); @@ -518,6 +504,12 @@ namespace osu.Game.Screens.Select public override bool OnExiting(IScreen next) { + if (ModSelect.State.Value == Visibility.Visible) + { + ModSelect.Hide(); + return true; + } + if (base.OnExiting(next)) return true; @@ -649,7 +641,7 @@ namespace osu.Game.Screens.Select Schedule(() => BeatmapDetails.Leaderboard.RefreshScores()))); } - public override bool OnPressed(GlobalAction action) + public virtual bool OnPressed(GlobalAction action) { if (!this.IsCurrentScreen()) return false; @@ -660,9 +652,11 @@ namespace osu.Game.Screens.Select return true; } - return base.OnPressed(action); + return false; } + public bool OnReleased(GlobalAction action) => action == GlobalAction.Select; + protected override bool OnKeyDown(KeyDownEvent e) { if (e.Repeat) return false;