1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-15 01:02:55 +08:00

Merge branch 'master' into pause-screen-progress

This commit is contained in:
Bartłomiej Dach 2023-05-24 21:57:26 +02:00
commit 133c954c93
No known key found for this signature in database
7 changed files with 160 additions and 59 deletions

View File

@ -1,57 +0,0 @@
// 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 System.Linq;
using NUnit.Framework;
using osu.Framework.Extensions;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.GameplayTest;
using osu.Game.Screens.Select;
using osu.Game.Tests.Resources;
namespace osu.Game.Tests.Visual.Editing
{
public partial class TestSceneEditorNavigation : OsuGameTestScene
{
[Test]
public void TestEditorGameplayTestAlwaysUsesOriginalRuleset()
{
BeatmapSetInfo beatmapSet = null!;
AddStep("import test beatmap", () => Game.BeatmapManager.Import(TestResources.GetTestBeatmapForImport()).WaitSafely());
AddStep("retrieve beatmap", () => beatmapSet = Game.BeatmapManager.QueryBeatmapSet(set => !set.Protected).AsNonNull().Value.Detach());
AddStep("present beatmap", () => Game.PresentBeatmap(beatmapSet));
AddUntilStep("wait for song select",
() => Game.Beatmap.Value.BeatmapSetInfo.Equals(beatmapSet)
&& Game.ScreenStack.CurrentScreen is PlaySongSelect songSelect
&& songSelect.IsLoaded);
AddStep("switch ruleset", () => Game.Ruleset.Value = new ManiaRuleset().RulesetInfo);
AddStep("open editor", () => ((PlaySongSelect)Game.ScreenStack.CurrentScreen).Edit(beatmapSet.Beatmaps.First(beatmap => beatmap.Ruleset.OnlineID == 0)));
AddUntilStep("wait for editor open", () => Game.ScreenStack.CurrentScreen is Editor editor && editor.ReadyForUse);
AddStep("test gameplay", () => ((Editor)Game.ScreenStack.CurrentScreen).TestGameplay());
AddUntilStep("wait for player", () =>
{
// notifications may fire at almost any inopportune time and cause annoying test failures.
// relentlessly attempt to dismiss any and all interfering overlays, which includes notifications.
// this is theoretically not foolproof, but it's the best that can be done here.
Game.CloseAllOverlays();
return Game.ScreenStack.CurrentScreen is EditorPlayer editorPlayer && editorPlayer.IsLoaded;
});
AddAssert("current ruleset is osu!", () => Game.Ruleset.Value.Equals(new OsuRuleset().RulesetInfo));
AddStep("exit to song select", () => Game.PerformFromScreen(_ => { }, typeof(PlaySongSelect).Yield()));
AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is PlaySongSelect);
AddAssert("previous ruleset restored", () => Game.Ruleset.Value.Equals(new ManiaRuleset().RulesetInfo));
}
}
}

View File

@ -3,15 +3,61 @@
using System.Linq;
using NUnit.Framework;
using osu.Framework.Extensions;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.GameplayTest;
using osu.Game.Screens.Menu;
using osu.Game.Screens.Select;
using osu.Game.Tests.Resources;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Navigation
{
public partial class TestSceneBeatmapEditorNavigation : OsuGameTestScene
{
[Test]
public void TestEditorGameplayTestAlwaysUsesOriginalRuleset()
{
BeatmapSetInfo beatmapSet = null!;
AddStep("import test beatmap", () => Game.BeatmapManager.Import(TestResources.GetTestBeatmapForImport()).WaitSafely());
AddStep("retrieve beatmap", () => beatmapSet = Game.BeatmapManager.QueryBeatmapSet(set => !set.Protected).AsNonNull().Value.Detach());
AddStep("present beatmap", () => Game.PresentBeatmap(beatmapSet));
AddUntilStep("wait for song select",
() => Game.Beatmap.Value.BeatmapSetInfo.Equals(beatmapSet)
&& Game.ScreenStack.CurrentScreen is PlaySongSelect songSelect
&& songSelect.IsLoaded);
AddStep("switch ruleset", () => Game.Ruleset.Value = new ManiaRuleset().RulesetInfo);
AddStep("open editor", () => ((PlaySongSelect)Game.ScreenStack.CurrentScreen).Edit(beatmapSet.Beatmaps.First(beatmap => beatmap.Ruleset.OnlineID == 0)));
AddUntilStep("wait for editor open", () => Game.ScreenStack.CurrentScreen is Editor editor && editor.ReadyForUse);
AddStep("test gameplay", () => ((Editor)Game.ScreenStack.CurrentScreen).TestGameplay());
AddUntilStep("wait for player", () =>
{
// notifications may fire at almost any inopportune time and cause annoying test failures.
// relentlessly attempt to dismiss any and all interfering overlays, which includes notifications.
// this is theoretically not foolproof, but it's the best that can be done here.
Game.CloseAllOverlays();
return Game.ScreenStack.CurrentScreen is EditorPlayer editorPlayer && editorPlayer.IsLoaded;
});
AddAssert("current ruleset is osu!", () => Game.Ruleset.Value.Equals(new OsuRuleset().RulesetInfo));
AddStep("exit to song select", () => Game.PerformFromScreen(_ => { }, typeof(PlaySongSelect).Yield()));
AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is PlaySongSelect);
AddAssert("previous ruleset restored", () => Game.Ruleset.Value.Equals(new ManiaRuleset().RulesetInfo));
}
/// <summary>
/// When entering the editor, a new beatmap is created as part of the asynchronous load process.
/// This test ensures that in the case of an early exit from the editor (ie. while it's still loading)
@ -38,5 +84,63 @@ namespace osu.Game.Tests.Visual.Navigation
BeatmapSetInfo[] allBeatmapSets() => Game.Realm.Run(realm => realm.All<BeatmapSetInfo>().Where(x => !x.DeletePending).ToArray());
}
[Test]
public void TestExitEditorWithoutSelection()
{
BeatmapSetInfo beatmapSet = null!;
AddStep("import test beatmap", () => Game.BeatmapManager.Import(TestResources.GetTestBeatmapForImport()).WaitSafely());
AddStep("retrieve beatmap", () => beatmapSet = Game.BeatmapManager.QueryBeatmapSet(set => !set.Protected).AsNonNull().Value.Detach());
AddStep("present beatmap", () => Game.PresentBeatmap(beatmapSet));
AddUntilStep("wait for song select",
() => Game.Beatmap.Value.BeatmapSetInfo.Equals(beatmapSet)
&& Game.ScreenStack.CurrentScreen is PlaySongSelect songSelect
&& songSelect.IsLoaded);
AddStep("open editor", () => ((PlaySongSelect)Game.ScreenStack.CurrentScreen).Edit(beatmapSet.Beatmaps.First(beatmap => beatmap.Ruleset.OnlineID == 0)));
AddUntilStep("wait for editor open", () => Game.ScreenStack.CurrentScreen is Editor editor && editor.ReadyForUse);
AddStep("escape once", () => InputManager.Key(Key.Escape));
AddUntilStep("wait for editor exit", () => Game.ScreenStack.CurrentScreen is not Editor);
}
[Test]
public void TestExitEditorWithSelection()
{
BeatmapSetInfo beatmapSet = null!;
AddStep("import test beatmap", () => Game.BeatmapManager.Import(TestResources.GetTestBeatmapForImport()).WaitSafely());
AddStep("retrieve beatmap", () => beatmapSet = Game.BeatmapManager.QueryBeatmapSet(set => !set.Protected).AsNonNull().Value.Detach());
AddStep("present beatmap", () => Game.PresentBeatmap(beatmapSet));
AddUntilStep("wait for song select",
() => Game.Beatmap.Value.BeatmapSetInfo.Equals(beatmapSet)
&& Game.ScreenStack.CurrentScreen is PlaySongSelect songSelect
&& songSelect.IsLoaded);
AddStep("open editor", () => ((PlaySongSelect)Game.ScreenStack.CurrentScreen).Edit(beatmapSet.Beatmaps.First(beatmap => beatmap.Ruleset.OnlineID == 0)));
AddUntilStep("wait for editor open", () => Game.ScreenStack.CurrentScreen is Editor editor && editor.ReadyForUse);
AddStep("make selection", () =>
{
var beatmap = getEditorBeatmap();
beatmap.SelectedHitObjects.AddRange(beatmap.HitObjects.Take(5));
});
AddAssert("selection exists", () => getEditorBeatmap().SelectedHitObjects, () => Has.Count.GreaterThan(0));
AddStep("escape once", () => InputManager.Key(Key.Escape));
AddAssert("selection empty", () => getEditorBeatmap().SelectedHitObjects, () => Has.Count.Zero);
AddStep("escape again", () => InputManager.Key(Key.Escape));
AddUntilStep("wait for editor exit", () => Game.ScreenStack.CurrentScreen is not Editor);
}
private EditorBeatmap getEditorBeatmap() => ((Editor)Game.ScreenStack.CurrentScreen).ChildrenOfType<EditorBeatmap>().Single();
}
}

View File

@ -17,6 +17,7 @@ namespace osu.Game.Graphics.Containers
{
public const float APPEAR_DURATION = 800;
public const float DISAPPEAR_DURATION = 500;
public const float SHADOW_OPACITY = 0.2f;
private const Easing easing_show = Easing.OutSine;
private const Easing easing_hide = Easing.InSine;

View File

@ -56,6 +56,7 @@ namespace osu.Game.Overlays
{
Colour = Color4.Black.Opacity(0),
Type = EdgeEffectType.Shadow,
Hollow = true,
Radius = 10
};
@ -101,7 +102,7 @@ namespace osu.Game.Overlays
protected override void PopIn()
{
base.PopIn();
FadeEdgeEffectTo(0.4f, WaveContainer.APPEAR_DURATION, Easing.Out);
FadeEdgeEffectTo(WaveContainer.SHADOW_OPACITY, WaveContainer.APPEAR_DURATION, Easing.Out);
}
protected override void PopOut()

View File

@ -5,9 +5,11 @@ using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Localisation;
using osu.Framework.Logging;
@ -16,6 +18,7 @@ using osu.Game.Graphics.Containers;
using osu.Game.Overlays.Notifications;
using osu.Game.Resources.Localisation.Web;
using osuTK;
using osuTK.Graphics;
using NotificationsStrings = osu.Game.Localisation.NotificationsStrings;
namespace osu.Game.Overlays
@ -72,6 +75,14 @@ namespace osu.Game.Overlays
mainContent = new Container
{
RelativeSizeAxes = Axes.Both,
Masking = true,
EdgeEffect = new EdgeEffectParameters
{
Colour = Color4.Black.Opacity(0),
Type = EdgeEffectType.Shadow,
Radius = 10,
Hollow = true,
},
Children = new Drawable[]
{
new Box
@ -199,6 +210,7 @@ namespace osu.Game.Overlays
this.MoveToX(0, TRANSITION_LENGTH, Easing.OutQuint);
mainContent.FadeTo(1, TRANSITION_LENGTH, Easing.OutQuint);
mainContent.FadeEdgeEffectTo(WaveContainer.SHADOW_OPACITY, WaveContainer.APPEAR_DURATION, Easing.Out);
toastTray.FlushAllToasts();
}
@ -211,6 +223,7 @@ namespace osu.Game.Overlays
this.MoveToX(WIDTH, TRANSITION_LENGTH, Easing.OutQuint);
mainContent.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint);
mainContent.FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.In);
}
private void notificationClosed() => Schedule(() =>

View File

@ -10,15 +10,18 @@ using System.Threading.Tasks;
using osuTK;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.Settings;
using osuTK.Graphics;
namespace osu.Game.Overlays
{
@ -105,6 +108,14 @@ namespace osu.Game.Overlays
Add(SectionsContainer = new SettingsSectionsContainer
{
Masking = true,
EdgeEffect = new EdgeEffectParameters
{
Colour = Color4.Black.Opacity(0),
Type = EdgeEffectType.Shadow,
Hollow = true,
Radius = 10
},
MaskingSmoothness = 0,
RelativeSizeAxes = Axes.Both,
ExpandableHeader = CreateHeader(),
SelectedSection = { BindTarget = CurrentSection },
@ -156,6 +167,8 @@ namespace osu.Game.Overlays
ContentContainer.MoveToX(ExpandedPosition, TRANSITION_LENGTH, Easing.OutQuint);
SectionsContainer.FadeEdgeEffectTo(WaveContainer.SHADOW_OPACITY, WaveContainer.APPEAR_DURATION, Easing.Out);
// delay load enough to ensure it doesn't overlap with the initial animation.
// this is done as there is still a brief stutter during load completion which is more visible if the transition is in progress.
// the eventual goal would be to remove the need for this by splitting up load into smaller work pieces, or fixing the remaining
@ -175,6 +188,7 @@ namespace osu.Game.Overlays
{
base.PopOut();
SectionsContainer.FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.In);
ContentContainer.MoveToX(-WIDTH + ExpandedPosition, TRANSITION_LENGTH, Easing.OutQuint);
Sidebar?.MoveToX(-sidebar_width, TRANSITION_LENGTH, Easing.OutQuint);

View File

@ -16,6 +16,7 @@ using osu.Framework.Input;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Game.Graphics.UserInterface;
using osu.Game.Input.Bindings;
using osu.Game.Rulesets.Edit;
using osuTK;
using osuTK.Input;
@ -26,7 +27,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
/// A container which provides a "blueprint" display of items.
/// Includes selection and manipulation support via a <see cref="Components.SelectionHandler{T}"/>.
/// </summary>
public abstract partial class BlueprintContainer<T> : CompositeDrawable, IKeyBindingHandler<PlatformAction>
public abstract partial class BlueprintContainer<T> : CompositeDrawable, IKeyBindingHandler<PlatformAction>, IKeyBindingHandler<GlobalAction>
where T : class
{
protected DragBox DragBox { get; private set; }
@ -279,6 +280,30 @@ namespace osu.Game.Screens.Edit.Compose.Components
{
}
public bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
{
if (e.Repeat)
return false;
switch (e.Action)
{
case GlobalAction.Back:
if (SelectedItems.Count > 0)
{
DeselectAll();
return true;
}
break;
}
return false;
}
public void OnReleased(KeyBindingReleaseEvent<GlobalAction> e)
{
}
#region Blueprint Addition/Removal
protected virtual void AddBlueprintFor(T item)