diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index 586217a05f..1c9696901c 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -264,7 +264,8 @@ namespace osu.Game.Tests.Beatmaps.IO private string createTemporaryBeatmap() { - var temp = new FileInfo(osz_path).CopyTo(Path.GetTempFileName(), true).FullName; + var temp = Path.GetTempFileName() + ".osz"; + File.Copy(osz_path, temp, true); Assert.IsTrue(File.Exists(temp)); return temp; } @@ -344,12 +345,12 @@ namespace osu.Game.Tests.Beatmaps.IO private void waitForOrAssert(Func result, string failureMessage, int timeout = 60000) { - Action waitAction = () => + Task task = Task.Run(() => { while (!result()) Thread.Sleep(200); - }; + }); - Assert.IsTrue(waitAction.BeginInvoke(null, null).AsyncWaitHandle.WaitOne(timeout), failureMessage); + Assert.IsTrue(task.Wait(timeout), failureMessage); } } } diff --git a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs index 11a2034a8f..0186a170c9 100644 --- a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs +++ b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Input; using OpenTK; using osu.Framework.Configuration; +using osu.Game.Overlays; namespace osu.Game.Graphics.Containers { @@ -16,13 +17,13 @@ namespace osu.Game.Graphics.Containers private SampleChannel samplePopIn; private SampleChannel samplePopOut; - private readonly BindableBool allowOpeningOverlays = new BindableBool(true); + protected readonly Bindable OverlayActivationMode = new Bindable(OverlayActivation.All); [BackgroundDependencyLoader(true)] private void load(OsuGame osuGame, AudioManager audio) { if (osuGame != null) - allowOpeningOverlays.BindTo(osuGame.AllowOpeningOverlays); + OverlayActivationMode.BindTo(osuGame.OverlayActivationMode); samplePopIn = audio.Sample.Get(@"UI/overlay-pop-in"); samplePopOut = audio.Sample.Get(@"UI/overlay-pop-out"); @@ -52,20 +53,18 @@ namespace osu.Game.Graphics.Containers private void onStateChanged(Visibility visibility) { - if (allowOpeningOverlays) + switch (visibility) { - switch (visibility) - { - case Visibility.Visible: + case Visibility.Visible: + if (OverlayActivationMode != OverlayActivation.Disabled) samplePopIn?.Play(); - break; - case Visibility.Hidden: - samplePopOut?.Play(); - break; - } + else + State = Visibility.Hidden; + break; + case Visibility.Hidden: + samplePopOut?.Play(); + break; } - else - State = Visibility.Hidden; } } } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index a43c1507b6..36c76851c6 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -77,8 +77,7 @@ namespace osu.Game public float ToolbarOffset => Toolbar.Position.Y + Toolbar.DrawHeight; - public readonly BindableBool HideOverlaysOnEnter = new BindableBool(); - public readonly BindableBool AllowOpeningOverlays = new BindableBool(true); + public readonly Bindable OverlayActivationMode = new Bindable(); private OsuScreen screenStack; @@ -94,6 +93,8 @@ namespace osu.Game private SettingsOverlay settings; + private readonly List overlays = new List(); + // todo: move this to SongSelect once Screen has the ability to unsuspend. public readonly Bindable> SelectedMods = new Bindable>(new List()); @@ -106,6 +107,17 @@ namespace osu.Game public void ToggleDirect() => direct.ToggleVisibility(); + /// + /// Close all game-wide overlays. + /// + /// Whether the toolbar should also be hidden. + public void CloseAllOverlays(bool toolbar = true) + { + foreach (var o in overlays) + o.State = Visibility.Hidden; + if (toolbar) Toolbar.State = Visibility.Hidden; + } + private DependencyContainer dependencies; protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => @@ -251,7 +263,7 @@ namespace osu.Game Depth = -5, OnHome = delegate { - hideAllOverlays(); + CloseAllOverlays(false); intro?.ChildScreen?.MakeCurrent(); }, }, overlayContent.Add); @@ -308,6 +320,8 @@ namespace osu.Game // ensure only one of these overlays are open at once. var singleDisplayOverlays = new OverlayContainer[] { chat, social, direct }; + overlays.AddRange(singleDisplayOverlays); + foreach (var overlay in singleDisplayOverlays) { overlay.StateChanged += state => @@ -323,6 +337,8 @@ namespace osu.Game } var singleDisplaySideOverlays = new OverlayContainer[] { settings, notifications }; + overlays.AddRange(singleDisplaySideOverlays); + foreach (var overlay in singleDisplaySideOverlays) { overlay.StateChanged += state => @@ -339,6 +355,8 @@ namespace osu.Game // eventually informational overlays should be displayed in a stack, but for now let's only allow one to stay open at a time. var informationalOverlays = new OverlayContainer[] { beatmapSetOverlay, userProfile }; + overlays.AddRange(informationalOverlays); + foreach (var overlay in informationalOverlays) { overlay.StateChanged += state => @@ -353,6 +371,11 @@ namespace osu.Game }; } + OverlayActivationMode.ValueChanged += v => + { + if (v != OverlayActivation.All) CloseAllOverlays(); + }; + void updateScreenOffset() { float offset = 0; @@ -367,21 +390,6 @@ namespace osu.Game settings.StateChanged += _ => updateScreenOffset(); notifications.StateChanged += _ => updateScreenOffset(); - - notifications.Enabled.BindTo(AllowOpeningOverlays); - - HideOverlaysOnEnter.ValueChanged += hide => - { - //central game screen change logic. - if (hide) - { - hideAllOverlays(); - musicController.State = Visibility.Hidden; - Toolbar.State = Visibility.Hidden; - } - else - Toolbar.State = Visibility.Visible; - }; } private void forwardLoggedErrorsToNotifications() @@ -498,16 +506,6 @@ namespace osu.Game private OsuScreen currentScreen; private FrameworkConfigManager frameworkConfig; - private void hideAllOverlays() - { - settings.State = Visibility.Hidden; - chat.State = Visibility.Hidden; - direct.State = Visibility.Hidden; - social.State = Visibility.Hidden; - userProfile.State = Visibility.Hidden; - notifications.State = Visibility.Hidden; - } - protected override bool OnExiting() { if (screenStack.ChildScreen == null) return false; diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index 09b6022ac5..3dc8f5ec15 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -22,11 +22,6 @@ namespace osu.Game.Overlays public const float TRANSITION_LENGTH = 600; - /// - /// Whether posted notifications should be processed. - /// - public readonly BindableBool Enabled = new BindableBool(true); - private FlowContainer sections; /// @@ -34,27 +29,6 @@ namespace osu.Game.Overlays /// public Func GetToolbarHeight; - public NotificationOverlay() - { - ScheduledDelegate notificationsEnabler = null; - Enabled.ValueChanged += v => - { - if (!IsLoaded) - { - processingPosts = v; - return; - } - - notificationsEnabler?.Cancel(); - - if (v) - // we want a slight delay before toggling notifications on to avoid the user becoming overwhelmed. - notificationsEnabler = Scheduler.AddDelayed(() => processingPosts = true, 1000); - else - processingPosts = false; - }; - } - [BackgroundDependencyLoader] private void load() { @@ -103,6 +77,29 @@ namespace osu.Game.Overlays }; } + private ScheduledDelegate notificationsEnabler; + private void updateProcessingMode() + { + bool enabled = OverlayActivationMode == OverlayActivation.All || State == Visibility.Visible; + + notificationsEnabler?.Cancel(); + + if (enabled) + // we want a slight delay before toggling notifications on to avoid the user becoming overwhelmed. + notificationsEnabler = Scheduler.AddDelayed(() => processingPosts = true, State == Visibility.Visible ? 0 : 1000); + else + processingPosts = false; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + StateChanged += _ => updateProcessingMode(); + OverlayActivationMode.ValueChanged += _ => updateProcessingMode(); + OverlayActivationMode.TriggerChange(); + } + private int totalCount => sections.Select(c => c.DisplayedCount).Sum(); private int unreadCount => sections.Select(c => c.UnreadCount).Sum(); diff --git a/osu.Game/Overlays/OverlayActivation.cs b/osu.Game/Overlays/OverlayActivation.cs new file mode 100644 index 0000000000..da4e153ce9 --- /dev/null +++ b/osu.Game/Overlays/OverlayActivation.cs @@ -0,0 +1,12 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Overlays +{ + public enum OverlayActivation + { + Disabled, + UserTriggered, + All + } +} diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index 424a457110..48d0674b3d 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -10,6 +10,8 @@ using osu.Framework.Input; using osu.Game.Graphics; using OpenTK; using osu.Framework.Graphics.Shapes; +using osu.Framework.Allocation; +using osu.Framework.Configuration; namespace osu.Game.Overlays.Toolbar { @@ -29,6 +31,8 @@ namespace osu.Game.Overlays.Toolbar private const float alpha_hovering = 0.8f; private const float alpha_normal = 0.6f; + private readonly Bindable overlayActivationMode = new Bindable(OverlayActivation.All); + public Toolbar() { Children = new Drawable[] @@ -76,6 +80,19 @@ namespace osu.Game.Overlays.Toolbar Size = new Vector2(1, HEIGHT); } + [BackgroundDependencyLoader(true)] + private void load(OsuGame osuGame) + { + if (osuGame != null) + overlayActivationMode.BindTo(osuGame.OverlayActivationMode); + + StateChanged += visibility => + { + if (overlayActivationMode == OverlayActivation.Disabled) + State = Visibility.Hidden; + }; + } + public class ToolbarBackground : Container { private readonly Box solidBackground; diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index f212bfabf3..42e25aad43 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -8,7 +8,6 @@ using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; -using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -17,6 +16,7 @@ using osu.Framework.Input.Bindings; using osu.Framework.Threading; using osu.Game.Graphics; using osu.Game.Input.Bindings; +using osu.Game.Overlays; using OpenTK; using OpenTK.Graphics; using OpenTK.Input; @@ -27,9 +27,6 @@ namespace osu.Game.Screens.Menu { public event Action StateChanged; - private readonly BindableBool hideOverlaysOnEnter = new BindableBool(); - private readonly BindableBool allowOpeningOverlays = new BindableBool(); - public Action OnEdit; public Action OnExit; public Action OnDirect; @@ -133,15 +130,12 @@ namespace osu.Game.Screens.Menu buttonFlow.AddRange(buttonsTopLevel); } + private OsuGame game; + [BackgroundDependencyLoader(true)] private void load(AudioManager audio, OsuGame game) { - if (game != null) - { - hideOverlaysOnEnter.BindTo(game.HideOverlaysOnEnter); - allowOpeningOverlays.BindTo(game.AllowOpeningOverlays); - } - + this.game = game; sampleBack = audio.Sample.Get(@"Menu/button-back-select"); } @@ -328,18 +322,18 @@ namespace osu.Game.Screens.Menu case MenuState.Initial: logoDelayedAction?.Cancel(); logoDelayedAction = Scheduler.AddDelayed(() => - { - logoTracking = false; + { + logoTracking = false; - hideOverlaysOnEnter.Value = true; - allowOpeningOverlays.Value = false; + if (game != null) + game.OverlayActivationMode.Value = state == MenuState.Exit ? OverlayActivation.Disabled : OverlayActivation.UserTriggered; - logo.ClearTransforms(targetMember: nameof(Position)); - logo.RelativePositionAxes = Axes.Both; + logo.ClearTransforms(targetMember: nameof(Position)); + logo.RelativePositionAxes = Axes.Both; - logo.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo); - logo.ScaleTo(1, 800, Easing.OutExpo); - }, buttonArea.Alpha * 150); + logo.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo); + logo.ScaleTo(1, 800, Easing.OutExpo); + }, buttonArea.Alpha * 150); break; case MenuState.TopLevel: case MenuState.Play: @@ -366,8 +360,11 @@ namespace osu.Game.Screens.Menu if (impact) logo.Impact(); - hideOverlaysOnEnter.Value = false; - allowOpeningOverlays.Value = true; + if (game != null) + { + game.OverlayActivationMode.Value = OverlayActivation.All; + game.Toolbar.State = Visibility.Visible; + } }, 200); break; default: diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index b8cb7f2a4a..0c70dbf570 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.cs @@ -9,6 +9,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using OpenTK; using OpenTK.Graphics; +using osu.Game.Overlays; namespace osu.Game.Screens.Menu { @@ -19,7 +20,7 @@ namespace osu.Game.Screens.Menu private Color4 iconColour; protected override bool HideOverlaysOnEnter => true; - protected override bool AllowOpeningOverlays => false; + protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled; public override bool CursorVisible => false; diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs index 5aca184d24..c5bd345a31 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/Intro.cs @@ -15,6 +15,7 @@ using osu.Game.IO.Archives; using osu.Game.Screens.Backgrounds; using OpenTK; using OpenTK.Graphics; +using osu.Game.Overlays; namespace osu.Game.Screens.Menu { @@ -32,7 +33,7 @@ namespace osu.Game.Screens.Menu private SampleChannel seeya; protected override bool HideOverlaysOnEnter => true; - protected override bool AllowOpeningOverlays => false; + protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled; public override bool CursorVisible => false; diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index d5f3b11467..cbdd8b4e8b 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -25,7 +25,6 @@ namespace osu.Game.Screens.Menu private readonly ButtonSystem buttons; protected override bool HideOverlaysOnEnter => buttons.State == MenuState.Initial; - protected override bool AllowOpeningOverlays => buttons.State != MenuState.Initial; protected override bool AllowBackButton => buttons.State != MenuState.Initial; diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index 7f68e5144b..d98aac8f84 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -18,6 +18,8 @@ using osu.Game.Rulesets; using osu.Game.Screens.Menu; using OpenTK; using OpenTK.Input; +using osu.Game.Overlays; +using osu.Framework.Graphics.Containers; namespace osu.Game.Screens { @@ -40,19 +42,19 @@ namespace osu.Game.Screens /// protected virtual BackgroundScreen CreateBackground() => null; - private readonly BindableBool hideOverlaysOnEnter = new BindableBool(); + private Action updateOverlayStates; /// - /// Whether overlays should be hidden when this screen is entered or resumed. + /// Whether all overlays should be hidden when this screen is entered or resumed. /// protected virtual bool HideOverlaysOnEnter => false; - private readonly BindableBool allowOpeningOverlays = new BindableBool(); + protected readonly Bindable OverlayActivationMode = new Bindable(); /// - /// Whether overlays should be able to be opened while this screen is active. + /// Whether overlays should be able to be opened once this screen is entered or resumed. /// - protected virtual bool AllowOpeningOverlays => true; + protected virtual OverlayActivation InitialOverlayActivationMode => OverlayActivation.All; /// /// Whether this allows the cursor to be displayed. @@ -103,8 +105,15 @@ namespace osu.Game.Screens if (osuGame != null) { Ruleset.BindTo(osuGame.Ruleset); - hideOverlaysOnEnter.BindTo(osuGame.HideOverlaysOnEnter); - allowOpeningOverlays.BindTo(osuGame.AllowOpeningOverlays); + OverlayActivationMode.BindTo(osuGame.OverlayActivationMode); + + updateOverlayStates = () => + { + if (HideOverlaysOnEnter) + osuGame.CloseAllOverlays(); + else + osuGame.Toolbar.State = Visibility.Visible; + }; } sampleExit = audio.Sample.Get(@"UI/screen-back"); @@ -240,8 +249,9 @@ namespace osu.Game.Screens if (backgroundParallaxContainer != null) backgroundParallaxContainer.ParallaxAmount = ParallaxContainer.DEFAULT_PARALLAX_AMOUNT * BackgroundParallaxAmount; - hideOverlaysOnEnter.Value = HideOverlaysOnEnter; - allowOpeningOverlays.Value = AllowOpeningOverlays; + OverlayActivationMode.Value = InitialOverlayActivationMode; + + updateOverlayStates?.Invoke(); } private void onExitingLogo() diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index c93e4b7b40..54f65e3991 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -21,6 +21,7 @@ using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Cursor; using osu.Game.Online.API; +using osu.Game.Overlays; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; @@ -37,6 +38,8 @@ namespace osu.Game.Screens.Play protected override bool HideOverlaysOnEnter => true; + protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.UserTriggered; + public Action RestartRequested; public bool HasFailed { get; private set; }