1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-14 17:52:56 +08:00

Merge pull request #14150 from frenzibyte/improve-screen-offsetting

Improve overlay screen offsetting logic to be position-based
This commit is contained in:
Dean Herbert 2021-08-13 17:59:41 +09:00 committed by GitHub
commit 72268d3e8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 102 additions and 41 deletions

View File

@ -0,0 +1,42 @@
// 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.
using NUnit.Framework;
using osu.Framework.Testing;
using osu.Game.Overlays;
using osu.Game.Tests.Visual.Navigation;
namespace osu.Game.Tests.Visual.Menus
{
public class TestSceneSideOverlays : OsuGameTestScene
{
[SetUpSteps]
public override void SetUpSteps()
{
base.SetUpSteps();
AddAssert("no screen offset applied", () => Game.ScreenOffsetContainer.X == 0f);
AddUntilStep("wait for overlays", () => Game.Settings.IsLoaded && Game.Notifications.IsLoaded);
}
[Test]
public void TestScreenOffsettingOnSettingsOverlay()
{
AddStep("open settings", () => Game.Settings.Show());
AddUntilStep("right screen offset applied", () => Game.ScreenOffsetContainer.X == SettingsPanel.WIDTH * TestOsuGame.SIDE_OVERLAY_OFFSET_RATIO);
AddStep("hide settings", () => Game.Settings.Hide());
AddUntilStep("screen offset removed", () => Game.ScreenOffsetContainer.X == 0f);
}
[Test]
public void TestScreenOffsettingOnNotificationOverlay()
{
AddStep("open notifications", () => Game.Notifications.Show());
AddUntilStep("right screen offset applied", () => Game.ScreenOffsetContainer.X == -NotificationOverlay.WIDTH * TestOsuGame.SIDE_OVERLAY_OFFSET_RATIO);
AddStep("hide notifications", () => Game.Notifications.Hide());
AddUntilStep("screen offset removed", () => Game.ScreenOffsetContainer.X == 0f);
}
}
}

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Platform;
using osu.Framework.Screens;
@ -95,6 +96,8 @@ namespace osu.Game.Tests.Visual.Navigation
public class TestOsuGame : OsuGame
{
public new const float SIDE_OVERLAY_OFFSET_RATIO = OsuGame.SIDE_OVERLAY_OFFSET_RATIO;
public new ScreenStack ScreenStack => base.ScreenStack;
public new BackButton BackButton => base.BackButton;
@ -103,7 +106,11 @@ namespace osu.Game.Tests.Visual.Navigation
public new ScoreManager ScoreManager => base.ScoreManager;
public new SettingsPanel Settings => base.Settings;
public new Container ScreenOffsetContainer => base.ScreenOffsetContainer;
public new SettingsOverlay Settings => base.Settings;
public new NotificationOverlay Notifications => base.Notifications;
public new MusicController MusicController => base.MusicController;

View File

@ -27,7 +27,7 @@ namespace osu.Game.Tests.Visual.Settings
new TabletSettings(tabletHandler)
{
RelativeSizeAxes = Axes.None,
Width = SettingsPanel.WIDTH,
Width = SettingsPanel.PANEL_WIDTH,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
}

View File

@ -64,6 +64,11 @@ namespace osu.Game
/// </summary>
public class OsuGame : OsuGameBase, IKeyBindingHandler<GlobalAction>
{
/// <summary>
/// The amount of global offset to apply when a left/right anchored overlay is displayed (ie. settings or notifications).
/// </summary>
protected const float SIDE_OVERLAY_OFFSET_RATIO = 0.05f;
public Toolbar Toolbar;
private ChatOverlay chatOverlay;
@ -71,7 +76,7 @@ namespace osu.Game
private ChannelManager channelManager;
[NotNull]
private readonly NotificationOverlay notifications = new NotificationOverlay();
protected readonly NotificationOverlay Notifications = new NotificationOverlay();
private BeatmapListingOverlay beatmapListing;
@ -97,7 +102,7 @@ namespace osu.Game
private ScalingContainer screenContainer;
private Container screenOffsetContainer;
protected Container ScreenOffsetContainer { get; private set; }
[Resolved]
private FrameworkConfigManager frameworkConfig { get; set; }
@ -312,7 +317,7 @@ namespace osu.Game
case LinkAction.OpenEditorTimestamp:
case LinkAction.JoinMultiplayerMatch:
case LinkAction.Spectate:
waitForReady(() => notifications, _ => notifications.Post(new SimpleNotification
waitForReady(() => Notifications, _ => Notifications.Post(new SimpleNotification
{
Text = @"This link type is not yet supported!",
Icon = FontAwesome.Solid.LifeRing,
@ -611,12 +616,12 @@ namespace osu.Game
MenuCursorContainer.CanShowCursor = menuScreen?.CursorVisible ?? false;
// todo: all archive managers should be able to be looped here.
SkinManager.PostNotification = n => notifications.Post(n);
SkinManager.PostNotification = n => Notifications.Post(n);
BeatmapManager.PostNotification = n => notifications.Post(n);
BeatmapManager.PostNotification = n => Notifications.Post(n);
BeatmapManager.PresentImport = items => PresentBeatmap(items.First());
ScoreManager.PostNotification = n => notifications.Post(n);
ScoreManager.PostNotification = n => Notifications.Post(n);
ScoreManager.PresentImport = items => PresentScore(items.First());
// make config aware of how to lookup skins for on-screen display purposes.
@ -655,7 +660,7 @@ namespace osu.Game
ActionRequested = action => volume.Adjust(action),
ScrollActionRequested = (action, amount, isPrecise) => volume.Adjust(action, amount, isPrecise),
},
screenOffsetContainer = new Container
ScreenOffsetContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
@ -724,7 +729,7 @@ namespace osu.Game
loadComponentSingleFile(onScreenDisplay, Add, true);
loadComponentSingleFile(notifications.With(d =>
loadComponentSingleFile(Notifications.With(d =>
{
d.GetToolbarHeight = () => ToolbarOffset;
d.Anchor = Anchor.TopRight;
@ -733,7 +738,7 @@ namespace osu.Game
loadComponentSingleFile(new CollectionManager(Storage)
{
PostNotification = n => notifications.Post(n),
PostNotification = n => Notifications.Post(n),
}, Add, true);
loadComponentSingleFile(stableImportManager, Add);
@ -785,7 +790,7 @@ namespace osu.Game
Add(new MusicKeyBindingHandler());
// side overlays which cancel each other.
var singleDisplaySideOverlays = new OverlayContainer[] { Settings, notifications };
var singleDisplaySideOverlays = new OverlayContainer[] { Settings, Notifications };
foreach (var overlay in singleDisplaySideOverlays)
{
@ -828,21 +833,6 @@ namespace osu.Game
{
if (mode.NewValue != OverlayActivation.All) CloseAllOverlays();
};
void updateScreenOffset()
{
float offset = 0;
if (Settings.State.Value == Visibility.Visible)
offset += Toolbar.HEIGHT / 2;
if (notifications.State.Value == Visibility.Visible)
offset -= Toolbar.HEIGHT / 2;
screenOffsetContainer.MoveToX(offset, SettingsPanel.TRANSITION_LENGTH, Easing.OutQuint);
}
Settings.State.ValueChanged += _ => updateScreenOffset();
notifications.State.ValueChanged += _ => updateScreenOffset();
}
private void showOverlayAboveOthers(OverlayContainer overlay, OverlayContainer[] otherOverlays)
@ -874,7 +864,7 @@ namespace osu.Game
if (recentLogCount < short_term_display_limit)
{
Schedule(() => notifications.Post(new SimpleErrorNotification
Schedule(() => Notifications.Post(new SimpleErrorNotification
{
Icon = entry.Level == LogLevel.Important ? FontAwesome.Solid.ExclamationCircle : FontAwesome.Solid.Bomb,
Text = entry.Message.Truncate(256) + (entry.Exception != null && IsDeployedBuild ? "\n\nThis error has been automatically reported to the devs." : string.Empty),
@ -882,7 +872,7 @@ namespace osu.Game
}
else if (recentLogCount == short_term_display_limit)
{
Schedule(() => notifications.Post(new SimpleNotification
Schedule(() => Notifications.Post(new SimpleNotification
{
Icon = FontAwesome.Solid.EllipsisH,
Text = "Subsequent messages have been logged. Click to view log files.",
@ -1023,9 +1013,18 @@ namespace osu.Game
{
base.UpdateAfterChildren();
screenOffsetContainer.Padding = new MarginPadding { Top = ToolbarOffset };
ScreenOffsetContainer.Padding = new MarginPadding { Top = ToolbarOffset };
overlayContent.Padding = new MarginPadding { Top = ToolbarOffset };
var horizontalOffset = 0f;
if (Settings.IsLoaded && Settings.IsPresent)
horizontalOffset += ToLocalSpace(Settings.ScreenSpaceDrawQuad.TopRight).X * SIDE_OVERLAY_OFFSET_RATIO;
if (Notifications.IsLoaded && Notifications.IsPresent)
horizontalOffset += (ToLocalSpace(Notifications.ScreenSpaceDrawQuad.TopLeft).X - DrawWidth) * SIDE_OVERLAY_OFFSET_RATIO;
ScreenOffsetContainer.X = horizontalOffset;
MenuCursorContainer.CanShowCursor = (ScreenStack.CurrentScreen as IOsuScreen)?.CursorVisible ?? false;
}

View File

@ -24,7 +24,7 @@ namespace osu.Game.Overlays
public LocalisableString Title => NotificationsStrings.HeaderTitle;
public LocalisableString Description => NotificationsStrings.HeaderDescription;
private const float width = 320;
public const float WIDTH = 320;
public const float TRANSITION_LENGTH = 600;
@ -38,7 +38,8 @@ namespace osu.Game.Overlays
[BackgroundDependencyLoader]
private void load()
{
Width = width;
X = WIDTH;
Width = WIDTH;
RelativeSizeAxes = Axes.Y;
Children = new Drawable[]
@ -152,7 +153,7 @@ namespace osu.Game.Overlays
markAllRead();
this.MoveToX(width, TRANSITION_LENGTH, Easing.OutQuint);
this.MoveToX(WIDTH, TRANSITION_LENGTH, Easing.OutQuint);
this.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint);
}

View File

@ -9,7 +9,6 @@ using osu.Game.Overlays.Settings.Sections;
using osu.Game.Overlays.Settings.Sections.Input;
using osuTK.Graphics;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Localisation;
using osu.Game.Localisation;
@ -38,6 +37,8 @@ namespace osu.Game.Overlays
private readonly List<SettingsSubPanel> subPanels = new List<SettingsSubPanel>();
private SettingsSubPanel lastOpenedSubPanel;
protected override Drawable CreateHeader() => new SettingsHeader(Title, Description);
protected override Drawable CreateFooter() => new SettingsFooter();
@ -46,21 +47,21 @@ namespace osu.Game.Overlays
{
}
public override bool AcceptsFocus => subPanels.All(s => s.State.Value != Visibility.Visible);
public override bool AcceptsFocus => lastOpenedSubPanel == null || lastOpenedSubPanel.State.Value == Visibility.Hidden;
private T createSubPanel<T>(T subPanel)
where T : SettingsSubPanel
{
subPanel.Depth = 1;
subPanel.Anchor = Anchor.TopRight;
subPanel.State.ValueChanged += subPanelStateChanged;
subPanel.State.ValueChanged += e => subPanelStateChanged(subPanel, e);
subPanels.Add(subPanel);
return subPanel;
}
private void subPanelStateChanged(ValueChangedEvent<Visibility> state)
private void subPanelStateChanged(SettingsSubPanel panel, ValueChangedEvent<Visibility> state)
{
switch (state.NewValue)
{
@ -68,7 +69,9 @@ namespace osu.Game.Overlays
Sidebar?.FadeColour(Color4.DarkGray, 300, Easing.OutQuint);
SectionsContainer.FadeOut(300, Easing.OutQuint);
ContentContainer.MoveToX(-WIDTH, 500, Easing.OutQuint);
ContentContainer.MoveToX(-PANEL_WIDTH, 500, Easing.OutQuint);
lastOpenedSubPanel = panel;
break;
case Visibility.Hidden:
@ -80,7 +83,7 @@ namespace osu.Game.Overlays
}
}
protected override float ExpandedPosition => subPanels.Any(s => s.State.Value == Visibility.Visible) ? -WIDTH : base.ExpandedPosition;
protected override float ExpandedPosition => lastOpenedSubPanel?.State.Value == Visibility.Visible ? -PANEL_WIDTH : base.ExpandedPosition;
[BackgroundDependencyLoader]
private void load()

View File

@ -28,7 +28,15 @@ namespace osu.Game.Overlays
private const float sidebar_width = Sidebar.DEFAULT_WIDTH;
public const float WIDTH = 400;
/// <summary>
/// The width of the settings panel content, excluding the sidebar.
/// </summary>
public const float PANEL_WIDTH = 400;
/// <summary>
/// The full width of the settings panel, including the sidebar.
/// </summary>
public const float WIDTH = sidebar_width + PANEL_WIDTH;
protected Container<Drawable> ContentContainer;
@ -64,7 +72,8 @@ namespace osu.Game.Overlays
{
InternalChild = ContentContainer = new NonMaskedContent
{
Width = WIDTH,
X = -WIDTH + ExpandedPosition,
Width = PANEL_WIDTH,
RelativeSizeAxes = Axes.Y,
Children = new Drawable[]
{