mirror of
https://github.com/ppy/osu.git
synced 2025-01-13 08:02:54 +08:00
Refactor game-wide layout order of footer to fix depth issues with overlays and improve UX
With this new order, the logo can be easily moved to display in front of the footer in `SongSelectV2` without breaking experience when footer-based overlays are present. Such overlays (i.e. mod select overlay) will also be dimmed alongside the current screen when a game-wide overlay is open (e.g. settings).
This commit is contained in:
parent
900d15e777
commit
467d7c4f54
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
/// <summary>
|
||||
@ -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;
|
||||
|
||||
|
@ -1,10 +1,8 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. 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
|
||||
/// <summary>
|
||||
/// The overlay's header.
|
||||
/// </summary>
|
||||
protected ShearedOverlayHeader Header { get; private set; }
|
||||
protected ShearedOverlayHeader Header { get; private set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The overlay's footer.
|
||||
/// </summary>
|
||||
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.
|
||||
/// </summary>
|
||||
protected Container TopLevelContent { get; private set; }
|
||||
protected Container TopLevelContent { get; private set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// A container for content that is to be displayed between the header and footer.
|
||||
/// </summary>
|
||||
protected Container MainAreaContent { get; private set; }
|
||||
protected Container MainAreaContent { get; private set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 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,
|
||||
|
@ -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<ScreenFooterButton> buttons)
|
||||
|
@ -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
|
||||
/// </summary>
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user