diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectV2.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectV2.cs index 674eaa2ff8..0a632793cc 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectV2.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectV2.cs @@ -181,12 +181,6 @@ namespace osu.Game.Tests.Visual.SongSelect #endregion - protected override void Update() - { - base.Update(); - Stack.Padding = new MarginPadding { Bottom = screenScreenFooter.DrawHeight - screenScreenFooter.Y }; - } - private void updateFooter(IScreen? _, IScreen? newScreen) { if (newScreen is IOsuScreen osuScreen && osuScreen.ShowFooter) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index cf32daab00..3862fea0e2 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -51,6 +51,7 @@ using osu.Game.Online.Chat; using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Overlays.BeatmapListing; +using osu.Game.Overlays.Mods; using osu.Game.Overlays.Music; using osu.Game.Overlays.Notifications; using osu.Game.Overlays.SkinEditor; @@ -132,8 +133,12 @@ namespace osu.Game private Container topMostOverlayContent; + private Container footerBasedOverlayContent; + protected ScalingContainer ScreenContainer { get; private set; } + private Container logoContainer; + protected Container ScreenOffsetContainer { get; private set; } private Container overlayOffsetContainer; @@ -156,8 +161,6 @@ namespace osu.Game private float toolbarOffset => (Toolbar?.Position.Y ?? 0) + (Toolbar?.DrawHeight ?? 0); - private float screenFooterOffset => (ScreenFooter?.DrawHeight ?? 0) - (ScreenFooter?.Position.Y ?? 0); - private IdleTracker idleTracker; /// @@ -242,7 +245,11 @@ namespace osu.Game throw new ArgumentException($@"{overlayContainer} has already been registered via {nameof(IOverlayManager.RegisterBlockingOverlay)} once."); externalOverlays.Add(overlayContainer); - overlayContent.Add(overlayContainer); + + if (overlayContainer is ShearedOverlayContainer) + footerBasedOverlayContent.Add(overlayContainer); + else + overlayContent.Add(overlayContainer); if (overlayContainer is OsuFocusedOverlayContainer focusedOverlayContainer) focusedOverlays.Add(focusedOverlayContainer); @@ -290,6 +297,8 @@ namespace osu.Game if (hideToolbar) Toolbar.Hide(); } + public void ChangeLogoDepth(bool inFrontOfFooter) => ScreenContainer.ChangeChildDepth(logoContainer, inFrontOfFooter ? float.MinValue : 0); + protected override UserInputManager CreateUserInputManager() { var userInputManager = base.CreateUserInputManager(); @@ -934,7 +943,6 @@ namespace osu.Game return string.Join(" / ", combinations); }; - Container logoContainer; ScreenFooter.BackReceptor backReceptor; dependencies.CacheAs(idleTracker = new GameIdleTracker(6000)); @@ -976,8 +984,15 @@ namespace osu.Game Origin = Anchor.BottomLeft, Action = () => ScreenFooter.OnBack?.Invoke(), }, + logoContainer = new Container { RelativeSizeAxes = Axes.Both }, + footerBasedOverlayContent = new Container + { + Depth = -1, + RelativeSizeAxes = Axes.Both, + }, new PopoverContainer { + Depth = -1, RelativeSizeAxes = Axes.Both, Child = ScreenFooter = new ScreenFooter(backReceptor) { @@ -991,7 +1006,6 @@ namespace osu.Game } }, }, - logoContainer = new Container { RelativeSizeAxes = Axes.Both }, } }, } @@ -1025,7 +1039,7 @@ namespace osu.Game if (!IsDeployedBuild) { - dependencies.Cache(versionManager = new VersionManager { Depth = int.MinValue }); + dependencies.Cache(versionManager = new VersionManager()); loadComponentSingleFile(versionManager, ScreenContainer.Add); } @@ -1072,7 +1086,7 @@ namespace osu.Game loadComponentSingleFile(CreateUpdateManager(), Add, true); // overlay elements - loadComponentSingleFile(FirstRunOverlay = new FirstRunSetupOverlay(), overlayContent.Add, true); + loadComponentSingleFile(FirstRunOverlay = new FirstRunSetupOverlay(), footerBasedOverlayContent.Add, true); loadComponentSingleFile(new ManageCollectionsDialog(), overlayContent.Add, true); loadComponentSingleFile(beatmapListing = new BeatmapListingOverlay(), overlayContent.Add, true); loadComponentSingleFile(dashboard = new DashboardOverlay(), overlayContent.Add, true); @@ -1137,7 +1151,7 @@ namespace osu.Game } // ensure only one of these overlays are open at once. - var singleDisplayOverlays = new OverlayContainer[] { FirstRunOverlay, chatOverlay, news, dashboard, beatmapListing, changelogOverlay, rankingsOverlay, wikiOverlay }; + var singleDisplayOverlays = new OverlayContainer[] { chatOverlay, news, dashboard, beatmapListing, changelogOverlay, rankingsOverlay, wikiOverlay }; foreach (var overlay in singleDisplayOverlays) { @@ -1485,7 +1499,6 @@ namespace osu.Game ScreenOffsetContainer.Padding = new MarginPadding { Top = toolbarOffset }; overlayOffsetContainer.Padding = new MarginPadding { Top = toolbarOffset }; - ScreenStack.Padding = new MarginPadding { Bottom = screenFooterOffset }; float horizontalOffset = 0f; diff --git a/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs b/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs index c9c3c62404..b5435e7e58 100644 --- a/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs +++ b/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs @@ -1,10 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using JetBrains.Annotations; using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -30,16 +28,15 @@ namespace osu.Game.Overlays.Mods /// /// The overlay's header. /// - protected ShearedOverlayHeader Header { get; private set; } + protected ShearedOverlayHeader Header { get; private set; } = null!; /// /// The overlay's footer. /// protected Container Footer { get; private set; } - [Resolved(canBeNull: true)] - [CanBeNull] - private ScreenFooter footer { get; set; } + [Resolved] + private ScreenFooter? footer { get; set; } // todo: very temporary property that will be removed once ModSelectOverlay and FirstRunSetupOverlay are updated to use new footer. public virtual bool UseNewFooter => false; @@ -48,12 +45,12 @@ namespace osu.Game.Overlays.Mods /// A container containing all content, including the header and footer. /// May be used for overlay-wide animations. /// - protected Container TopLevelContent { get; private set; } + protected Container TopLevelContent { get; private set; } = null!; /// /// A container for content that is to be displayed between the header and footer. /// - protected Container MainAreaContent { get; private set; } + protected Container MainAreaContent { get; private set; } = null!; /// /// A container for content that is to be displayed inside the footer. @@ -64,6 +61,10 @@ namespace osu.Game.Overlays.Mods protected override bool BlockNonPositionalInput => true; + // ShearedOverlayContainers are placed at a layer within the screen container as they rely on ScreenFooter which must be placed there. + // Therefore, dimming must be managed locally, since DimMainContent dims the entire screen layer. + protected sealed override bool DimMainContent => false; + protected ShearedOverlayContainer(OverlayColourScheme colourScheme) { RelativeSizeAxes = Axes.Both; @@ -81,6 +82,11 @@ namespace osu.Game.Overlays.Mods RelativeSizeAxes = Axes.Both, Children = new Drawable[] { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourProvider.Background6.Opacity(0.75f), + }, Header = new ShearedOverlayHeader { Anchor = Anchor.TopCentre, diff --git a/osu.Game/Screens/Footer/ScreenFooter.cs b/osu.Game/Screens/Footer/ScreenFooter.cs index cef891f8c0..dcf64e9291 100644 --- a/osu.Game/Screens/Footer/ScreenFooter.cs +++ b/osu.Game/Screens/Footer/ScreenFooter.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Framework.Threading; using osu.Game.Graphics.Containers; using osu.Game.Input.Bindings; using osu.Game.Overlays; @@ -24,6 +25,7 @@ namespace osu.Game.Screens.Footer { private const int padding = 60; private const float delay_per_button = 30; + private const double transition_duration = 400; public const int HEIGHT = 50; @@ -37,6 +39,9 @@ namespace osu.Game.Screens.Footer [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine); + [Resolved] + private OsuGame? game { get; set; } + public ScreenBackButton BackButton { get; private set; } = null!; public Action? OnBack; @@ -101,19 +106,35 @@ namespace osu.Game.Screens.Footer }; } - public void StartTrackingLogo(OsuLogo logo, float duration = 0, Easing easing = Easing.None) => logoTrackingContainer.StartTracking(logo, duration, easing); - public void StopTrackingLogo() => logoTrackingContainer.StopTracking(); + private ScheduledDelegate? changeLogoDepthDelegate; + + public void StartTrackingLogo(OsuLogo logo, float duration = 0, Easing easing = Easing.None) + { + changeLogoDepthDelegate?.Cancel(); + changeLogoDepthDelegate = null; + + logoTrackingContainer.StartTracking(logo, duration, easing); + game?.ChangeLogoDepth(inFrontOfFooter: true); + } + + public void StopTrackingLogo() + { + logoTrackingContainer.StopTracking(); + + if (game != null) + changeLogoDepthDelegate = Scheduler.AddDelayed(() => game.ChangeLogoDepth(inFrontOfFooter: false), transition_duration); + } protected override void PopIn() { - this.MoveToY(0, 400, Easing.OutQuint) - .FadeIn(400, Easing.OutQuint); + this.MoveToY(0, transition_duration, Easing.OutQuint) + .FadeIn(transition_duration, Easing.OutQuint); } protected override void PopOut() { - this.MoveToY(HEIGHT, 400, Easing.OutQuint) - .FadeOut(400, Easing.OutQuint); + this.MoveToY(HEIGHT, transition_duration, Easing.OutQuint) + .FadeOut(transition_duration, Easing.OutQuint); } public void SetButtons(IReadOnlyList buttons) diff --git a/osu.Game/Screens/SelectV2/SongSelectV2.cs b/osu.Game/Screens/SelectV2/SongSelectV2.cs index 10ed7783c4..a8730ad808 100644 --- a/osu.Game/Screens/SelectV2/SongSelectV2.cs +++ b/osu.Game/Screens/SelectV2/SongSelectV2.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; using osu.Framework.Screens; using osu.Game.Overlays; using osu.Game.Overlays.Mods; @@ -23,6 +22,8 @@ namespace osu.Game.Screens.SelectV2 /// public partial class SongSelectV2 : OsuScreen { + private const float logo_scale = 0.4f; + private readonly ModSelectOverlay modSelectOverlay = new SoloModSelectOverlay(); [Cached] @@ -30,15 +31,14 @@ namespace osu.Game.Screens.SelectV2 public override bool ShowFooter => true; + [Resolved] + private OsuLogo? logo { get; set; } + [BackgroundDependencyLoader] private void load() { AddRangeInternal(new Drawable[] { - new PopoverContainer - { - RelativeSizeAxes = Axes.Both, - }, modSelectOverlay, }); } @@ -50,6 +50,17 @@ namespace osu.Game.Screens.SelectV2 new ScreenFooterButtonOptions(), }; + protected override void LoadComplete() + { + base.LoadComplete(); + + modSelectOverlay.State.BindValueChanged(v => + { + logo?.ScaleTo(v.NewValue == Visibility.Visible ? 0f : logo_scale, 400, Easing.OutQuint) + .FadeTo(v.NewValue == Visibility.Visible ? 0f : 1f, 200, Easing.OutQuint); + }, true); + } + public override void OnEntering(ScreenTransitionEvent e) { this.FadeIn(); @@ -74,17 +85,6 @@ namespace osu.Game.Screens.SelectV2 return base.OnExiting(e); } - public override bool OnBackButton() - { - if (modSelectOverlay.State.Value == Visibility.Visible) - { - modSelectOverlay.Hide(); - return true; - } - - return false; - } - protected override void LogoArriving(OsuLogo logo, bool resuming) { base.LogoArriving(logo, resuming); @@ -99,7 +99,7 @@ namespace osu.Game.Screens.SelectV2 } logo.FadeIn(240, Easing.OutQuint); - logo.ScaleTo(0.4f, 240, Easing.OutQuint); + logo.ScaleTo(logo_scale, 240, Easing.OutQuint); logo.Action = () => { @@ -122,14 +122,9 @@ namespace osu.Game.Screens.SelectV2 logo.FadeOut(120, Easing.Out); } - private partial class SoloModSelectOverlay : ModSelectOverlay + private partial class SoloModSelectOverlay : UserModSelectOverlay { protected override bool ShowPresets => true; - - public SoloModSelectOverlay() - : base(OverlayColourScheme.Aquamarine) - { - } } private partial class PlayerLoaderV2 : PlayerLoader