mirror of
https://github.com/ppy/osu.git
synced 2025-02-13 15:03:13 +08:00
Merge branch 'master' into beatmap-update-test
This commit is contained in:
commit
7f75184a01
@ -1,8 +1,6 @@
|
||||
// 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 System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Utils;
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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 System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Utils;
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Game.Rulesets.Catch.Mods;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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 System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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 System.Collections.Generic;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Replays;
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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 System.Collections.Generic;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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 osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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 osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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 System.Linq;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Beatmaps;
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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 osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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 osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
|
@ -1,9 +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 osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
@ -37,9 +36,9 @@ namespace osu.Game.Rulesets.Catch.Mods
|
||||
|
||||
public override float DefaultFlashlightSize => 350;
|
||||
|
||||
protected override Flashlight CreateFlashlight() => new CatchFlashlight(this, playfield);
|
||||
protected override Flashlight CreateFlashlight() => new CatchFlashlight(this, playfield.AsNonNull());
|
||||
|
||||
private CatchPlayfield playfield;
|
||||
private CatchPlayfield? playfield;
|
||||
|
||||
public override void ApplyToDrawableRuleset(DrawableRuleset<CatchHitObject> drawableRuleset)
|
||||
{
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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 osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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 osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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 osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Beatmaps;
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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 System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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 System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Beatmaps;
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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 osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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 osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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 osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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 System;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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 osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
|
@ -1,8 +1,7 @@
|
||||
// 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 System.Diagnostics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.Bindings;
|
||||
@ -20,7 +19,7 @@ namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public override string Description => @"Use the mouse to control the catcher.";
|
||||
|
||||
private DrawableRuleset<CatchHitObject> drawableRuleset;
|
||||
private DrawableRuleset<CatchHitObject>? drawableRuleset;
|
||||
|
||||
public void ApplyToDrawableRuleset(DrawableRuleset<CatchHitObject> drawableRuleset)
|
||||
{
|
||||
@ -29,6 +28,8 @@ namespace osu.Game.Rulesets.Catch.Mods
|
||||
|
||||
public void ApplyToPlayer(Player player)
|
||||
{
|
||||
Debug.Assert(drawableRuleset != null);
|
||||
|
||||
if (!drawableRuleset.HasReplayLoaded.Value)
|
||||
drawableRuleset.Cursor.Add(new MouseInputHelper((CatchPlayfield)drawableRuleset.Playfield));
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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 osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
|
@ -142,7 +142,6 @@ namespace osu.Game.Tests.Database
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
// ReSharper disable once AccessToDisposedClosure
|
||||
var beatmapSet = await importer.Import(new ImportTask(TestResources.GetTestBeatmapStream(), "renatus.osz"));
|
||||
|
||||
Assert.NotNull(beatmapSet);
|
||||
@ -311,6 +310,7 @@ namespace osu.Game.Tests.Database
|
||||
}
|
||||
finally
|
||||
{
|
||||
File.Delete(temp);
|
||||
Directory.Delete(extractedFolder, true);
|
||||
}
|
||||
});
|
||||
|
@ -32,31 +32,29 @@ namespace osu.Game.Tests.Database
|
||||
[Test]
|
||||
public void TestAccessAfterStorageMigrate()
|
||||
{
|
||||
RunTestWithRealm((realm, storage) =>
|
||||
using (var migratedStorage = new TemporaryNativeStorage("realm-test-migration-target"))
|
||||
{
|
||||
var beatmap = new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata());
|
||||
|
||||
Live<BeatmapInfo>? liveBeatmap = null;
|
||||
|
||||
realm.Run(r =>
|
||||
RunTestWithRealm((realm, storage) =>
|
||||
{
|
||||
r.Write(_ => r.Add(beatmap));
|
||||
var beatmap = new BeatmapInfo(CreateRuleset(), new BeatmapDifficulty(), new BeatmapMetadata());
|
||||
|
||||
liveBeatmap = beatmap.ToLive(realm);
|
||||
});
|
||||
Live<BeatmapInfo>? liveBeatmap = null;
|
||||
|
||||
realm.Run(r =>
|
||||
{
|
||||
r.Write(_ => r.Add(beatmap));
|
||||
|
||||
liveBeatmap = beatmap.ToLive(realm);
|
||||
});
|
||||
|
||||
using (var migratedStorage = new TemporaryNativeStorage("realm-test-migration-target"))
|
||||
{
|
||||
migratedStorage.DeleteDirectory(string.Empty);
|
||||
|
||||
using (realm.BlockAllOperations("testing"))
|
||||
{
|
||||
storage.Migrate(migratedStorage);
|
||||
}
|
||||
|
||||
Assert.IsFalse(liveBeatmap?.PerformRead(l => l.Hidden));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -341,14 +339,12 @@ namespace osu.Game.Tests.Database
|
||||
liveBeatmap.PerformRead(resolved =>
|
||||
{
|
||||
// retrieval causes an implicit refresh. even changes that aren't related to the retrieval are fired at this point.
|
||||
// ReSharper disable once AccessToDisposedClosure
|
||||
Assert.AreEqual(2, outerRealm.All<BeatmapInfo>().Count());
|
||||
Assert.AreEqual(1, changesTriggered);
|
||||
|
||||
// can access properties without a crash.
|
||||
Assert.IsFalse(resolved.Hidden);
|
||||
|
||||
// ReSharper disable once AccessToDisposedClosure
|
||||
outerRealm.Write(r =>
|
||||
{
|
||||
// can use with the main context.
|
||||
|
@ -4,11 +4,11 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.IO;
|
||||
@ -20,22 +20,15 @@ namespace osu.Game.Tests.Database
|
||||
[TestFixture]
|
||||
public abstract class RealmTest
|
||||
{
|
||||
private static readonly TemporaryNativeStorage storage;
|
||||
|
||||
static RealmTest()
|
||||
{
|
||||
storage = new TemporaryNativeStorage("realm-test");
|
||||
storage.DeleteDirectory(string.Empty);
|
||||
}
|
||||
|
||||
protected void RunTestWithRealm(Action<RealmAccess, OsuStorage> testAction, [CallerMemberName] string caller = "")
|
||||
protected void RunTestWithRealm([InstantHandle] Action<RealmAccess, OsuStorage> testAction, [CallerMemberName] string caller = "")
|
||||
{
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(callingMethodName: caller))
|
||||
{
|
||||
host.Run(new RealmTestGame(() =>
|
||||
{
|
||||
// ReSharper disable once AccessToDisposedClosure
|
||||
var testStorage = new OsuStorage(host, storage.GetStorageForDirectory(caller));
|
||||
var defaultStorage = host.Storage;
|
||||
|
||||
var testStorage = new OsuStorage(host, defaultStorage);
|
||||
|
||||
using (var realm = new RealmAccess(testStorage, OsuGameBase.CLIENT_DATABASE_FILENAME))
|
||||
{
|
||||
@ -58,7 +51,7 @@ namespace osu.Game.Tests.Database
|
||||
{
|
||||
host.Run(new RealmTestGame(async () =>
|
||||
{
|
||||
var testStorage = storage.GetStorageForDirectory(caller);
|
||||
var testStorage = host.Storage;
|
||||
|
||||
using (var realm = new RealmAccess(testStorage, OsuGameBase.CLIENT_DATABASE_FILENAME))
|
||||
{
|
||||
@ -116,7 +109,7 @@ namespace osu.Game.Tests.Database
|
||||
|
||||
private class RealmTestGame : Framework.Game
|
||||
{
|
||||
public RealmTestGame(Func<Task> work)
|
||||
public RealmTestGame([InstantHandle] Func<Task> work)
|
||||
{
|
||||
// ReSharper disable once AsyncVoidLambda
|
||||
Scheduler.Add(async () =>
|
||||
@ -126,7 +119,7 @@ namespace osu.Game.Tests.Database
|
||||
});
|
||||
}
|
||||
|
||||
public RealmTestGame(Action work)
|
||||
public RealmTestGame([InstantHandle] Action work)
|
||||
{
|
||||
Scheduler.Add(() =>
|
||||
{
|
||||
|
@ -12,7 +12,6 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Online.Solo;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Difficulty;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
@ -110,30 +109,30 @@ namespace osu.Game.Tests.Online
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDeserialiseSubmittableScoreWithEmptyMods()
|
||||
public void TestDeserialiseSoloScoreWithEmptyMods()
|
||||
{
|
||||
var score = new SubmittableScore(new ScoreInfo
|
||||
var score = SoloScoreInfo.ForSubmission(new ScoreInfo
|
||||
{
|
||||
User = new APIUser(),
|
||||
Ruleset = new OsuRuleset().RulesetInfo,
|
||||
});
|
||||
|
||||
var deserialised = JsonConvert.DeserializeObject<SubmittableScore>(JsonConvert.SerializeObject(score));
|
||||
var deserialised = JsonConvert.DeserializeObject<SoloScoreInfo>(JsonConvert.SerializeObject(score));
|
||||
|
||||
Assert.That(deserialised?.Mods.Length, Is.Zero);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDeserialiseSubmittableScoreWithCustomModSetting()
|
||||
public void TestDeserialiseSoloScoreWithCustomModSetting()
|
||||
{
|
||||
var score = new SubmittableScore(new ScoreInfo
|
||||
var score = SoloScoreInfo.ForSubmission(new ScoreInfo
|
||||
{
|
||||
Mods = new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 2 } } },
|
||||
User = new APIUser(),
|
||||
Ruleset = new OsuRuleset().RulesetInfo,
|
||||
});
|
||||
|
||||
var deserialised = JsonConvert.DeserializeObject<SubmittableScore>(JsonConvert.SerializeObject(score));
|
||||
var deserialised = JsonConvert.DeserializeObject<SoloScoreInfo>(JsonConvert.SerializeObject(score));
|
||||
|
||||
Assert.That((deserialised?.Mods[0])?.Settings["speed_change"], Is.EqualTo(2));
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
using Newtonsoft.Json;
|
||||
using NUnit.Framework;
|
||||
using osu.Game.IO.Serialization;
|
||||
using osu.Game.Online.Solo;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Tests.Resources;
|
||||
|
||||
namespace osu.Game.Tests.Online
|
||||
@ -15,12 +15,12 @@ namespace osu.Game.Tests.Online
|
||||
/// Basic testing to ensure our attribute-based naming is correctly working.
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class TestSubmittableScoreJsonSerialization
|
||||
public class TestSoloScoreInfoJsonSerialization
|
||||
{
|
||||
[Test]
|
||||
public void TestScoreSerialisationViaExtensionMethod()
|
||||
{
|
||||
var score = new SubmittableScore(TestResources.CreateTestScoreInfo());
|
||||
var score = SoloScoreInfo.ForSubmission(TestResources.CreateTestScoreInfo());
|
||||
|
||||
string serialised = score.Serialize();
|
||||
|
||||
@ -31,7 +31,7 @@ namespace osu.Game.Tests.Online
|
||||
[Test]
|
||||
public void TestScoreSerialisationWithoutSettings()
|
||||
{
|
||||
var score = new SubmittableScore(TestResources.CreateTestScoreInfo());
|
||||
var score = SoloScoreInfo.ForSubmission(TestResources.CreateTestScoreInfo());
|
||||
|
||||
string serialised = JsonConvert.SerializeObject(score);
|
||||
|
@ -8,26 +8,17 @@ using osu.Framework.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Editing
|
||||
{
|
||||
[Ignore("Timeline initialisation is kinda broken.")] // Initial work to rectify this was done in https://github.com/ppy/osu/pull/19297, but needs more massaging to work.
|
||||
public class TestSceneTimelineZoom : TimelineTestScene
|
||||
{
|
||||
public override Drawable CreateTestComponent() => Empty();
|
||||
|
||||
[Test]
|
||||
[FlakyTest]
|
||||
/*
|
||||
* Fail rate around 0.3%
|
||||
*
|
||||
* TearDown : osu.Framework.Testing.Drawables.Steps.AssertButton+TracedException : range halved
|
||||
* --TearDown
|
||||
* at osu.Framework.Threading.ScheduledDelegate.RunTaskInternal()
|
||||
* at osu.Framework.Threading.Scheduler.Update()
|
||||
* at osu.Framework.Graphics.Drawable.UpdateSubTree()
|
||||
*/
|
||||
public void TestVisibleRangeUpdatesOnZoomChange()
|
||||
{
|
||||
double initialVisibleRange = 0;
|
||||
|
||||
AddUntilStep("wait for load", () => MusicController.TrackLoaded);
|
||||
|
||||
AddStep("reset zoom", () => TimelineArea.Timeline.Zoom = 100);
|
||||
AddStep("get initial range", () => initialVisibleRange = TimelineArea.Timeline.VisibleRange);
|
||||
|
||||
@ -45,6 +36,8 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
{
|
||||
double initialVisibleRange = 0;
|
||||
|
||||
AddUntilStep("wait for load", () => MusicController.TrackLoaded);
|
||||
|
||||
AddStep("reset timeline size", () => TimelineArea.Timeline.Width = 1);
|
||||
AddStep("get initial range", () => initialVisibleRange = TimelineArea.Timeline.VisibleRange);
|
||||
|
||||
|
@ -46,7 +46,7 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.Gray(30)
|
||||
},
|
||||
scrollContainer = new ZoomableScrollContainer
|
||||
scrollContainer = new ZoomableScrollContainer(1, 60, 1)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
@ -80,21 +80,6 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
AddAssert("Inner container width matches scroll container", () => innerBox.DrawWidth == scrollContainer.DrawWidth);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestZoomRangeUpdate()
|
||||
{
|
||||
AddStep("set zoom to 2", () => scrollContainer.Zoom = 2);
|
||||
AddStep("set min zoom to 5", () => scrollContainer.MinZoom = 5);
|
||||
AddAssert("zoom = 5", () => scrollContainer.Zoom == 5);
|
||||
|
||||
AddStep("set max zoom to 10", () => scrollContainer.MaxZoom = 10);
|
||||
AddAssert("zoom = 5", () => scrollContainer.Zoom == 5);
|
||||
|
||||
AddStep("set min zoom to 20", () => scrollContainer.MinZoom = 20);
|
||||
AddStep("set max zoom to 40", () => scrollContainer.MaxZoom = 40);
|
||||
AddAssert("zoom = 20", () => scrollContainer.Zoom == 20);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestZoom0()
|
||||
{
|
||||
|
@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
public TestScenePause()
|
||||
{
|
||||
base.Content.Add(content = new MenuCursorContainer { RelativeSizeAxes = Axes.Both });
|
||||
base.Content.Add(content = new GlobalCursorDisplay { RelativeSizeAxes = Axes.Both });
|
||||
}
|
||||
|
||||
[SetUpSteps]
|
||||
|
@ -7,7 +7,6 @@ using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Online;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
@ -15,7 +14,6 @@ using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Ranking;
|
||||
@ -30,9 +28,6 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
private const long online_score_id = 2553163309;
|
||||
|
||||
[Resolved]
|
||||
private RulesetStore rulesets { get; set; }
|
||||
|
||||
private TestReplayDownloadButton downloadButton;
|
||||
|
||||
[Resolved]
|
||||
@ -211,21 +206,18 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddAssert("button is not enabled", () => !downloadButton.ChildrenOfType<DownloadButton>().First().Enabled.Value);
|
||||
}
|
||||
|
||||
private ScoreInfo getScoreInfo(bool replayAvailable, bool hasOnlineId = true)
|
||||
private ScoreInfo getScoreInfo(bool replayAvailable, bool hasOnlineId = true) => new ScoreInfo
|
||||
{
|
||||
return new APIScore
|
||||
OnlineID = hasOnlineId ? online_score_id : 0,
|
||||
Ruleset = new OsuRuleset().RulesetInfo,
|
||||
BeatmapInfo = beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps.First(),
|
||||
Hash = replayAvailable ? "online" : string.Empty,
|
||||
User = new APIUser
|
||||
{
|
||||
OnlineID = hasOnlineId ? online_score_id : 0,
|
||||
RulesetID = 0,
|
||||
Beatmap = CreateAPIBeatmapSet(new OsuRuleset().RulesetInfo).Beatmaps.First(),
|
||||
HasReplay = replayAvailable,
|
||||
User = new APIUser
|
||||
{
|
||||
Id = 39828,
|
||||
Username = @"WubWoofWolf",
|
||||
}
|
||||
}.CreateScoreInfo(rulesets, beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps.First());
|
||||
}
|
||||
Id = 39828,
|
||||
Username = @"WubWoofWolf",
|
||||
}
|
||||
};
|
||||
|
||||
private class TestReplayDownloadButton : ReplayDownloadButton
|
||||
{
|
||||
|
@ -21,12 +21,12 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
[TestFixture]
|
||||
public class TestSceneCursors : OsuManualInputManagerTestScene
|
||||
{
|
||||
private readonly MenuCursorContainer menuCursorContainer;
|
||||
private readonly GlobalCursorDisplay globalCursorDisplay;
|
||||
private readonly CustomCursorBox[] cursorBoxes = new CustomCursorBox[6];
|
||||
|
||||
public TestSceneCursors()
|
||||
{
|
||||
Child = menuCursorContainer = new MenuCursorContainer
|
||||
Child = globalCursorDisplay = new GlobalCursorDisplay
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new[]
|
||||
@ -96,11 +96,11 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
private void testUserCursor()
|
||||
{
|
||||
AddStep("Move to green area", () => InputManager.MoveMouseTo(cursorBoxes[0]));
|
||||
AddAssert("Check green cursor visible", () => checkVisible(cursorBoxes[0].Cursor));
|
||||
AddAssert("Check green cursor at mouse", () => checkAtMouse(cursorBoxes[0].Cursor));
|
||||
AddAssert("Check green cursor visible", () => checkVisible(cursorBoxes[0].MenuCursor));
|
||||
AddAssert("Check green cursor at mouse", () => checkAtMouse(cursorBoxes[0].MenuCursor));
|
||||
AddStep("Move out", moveOut);
|
||||
AddAssert("Check green cursor invisible", () => !checkVisible(cursorBoxes[0].Cursor));
|
||||
AddAssert("Check global cursor visible", () => checkVisible(menuCursorContainer.Cursor));
|
||||
AddAssert("Check green cursor invisible", () => !checkVisible(cursorBoxes[0].MenuCursor));
|
||||
AddAssert("Check global cursor visible", () => checkVisible(globalCursorDisplay.MenuCursor));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -111,13 +111,13 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
private void testLocalCursor()
|
||||
{
|
||||
AddStep("Move to purple area", () => InputManager.MoveMouseTo(cursorBoxes[3]));
|
||||
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor));
|
||||
AddAssert("Check purple cursor at mouse", () => checkAtMouse(cursorBoxes[3].Cursor));
|
||||
AddAssert("Check global cursor visible", () => checkVisible(menuCursorContainer.Cursor));
|
||||
AddAssert("Check global cursor at mouse", () => checkAtMouse(menuCursorContainer.Cursor));
|
||||
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].MenuCursor));
|
||||
AddAssert("Check purple cursor at mouse", () => checkAtMouse(cursorBoxes[3].MenuCursor));
|
||||
AddAssert("Check global cursor visible", () => checkVisible(globalCursorDisplay.MenuCursor));
|
||||
AddAssert("Check global cursor at mouse", () => checkAtMouse(globalCursorDisplay.MenuCursor));
|
||||
AddStep("Move out", moveOut);
|
||||
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor));
|
||||
AddAssert("Check global cursor visible", () => checkVisible(menuCursorContainer.Cursor));
|
||||
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].MenuCursor));
|
||||
AddAssert("Check global cursor visible", () => checkVisible(globalCursorDisplay.MenuCursor));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -128,12 +128,12 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
private void testUserCursorOverride()
|
||||
{
|
||||
AddStep("Move to blue-green boundary", () => InputManager.MoveMouseTo(cursorBoxes[1].ScreenSpaceDrawQuad.BottomRight - new Vector2(10)));
|
||||
AddAssert("Check blue cursor visible", () => checkVisible(cursorBoxes[1].Cursor));
|
||||
AddAssert("Check green cursor invisible", () => !checkVisible(cursorBoxes[0].Cursor));
|
||||
AddAssert("Check blue cursor at mouse", () => checkAtMouse(cursorBoxes[1].Cursor));
|
||||
AddAssert("Check blue cursor visible", () => checkVisible(cursorBoxes[1].MenuCursor));
|
||||
AddAssert("Check green cursor invisible", () => !checkVisible(cursorBoxes[0].MenuCursor));
|
||||
AddAssert("Check blue cursor at mouse", () => checkAtMouse(cursorBoxes[1].MenuCursor));
|
||||
AddStep("Move out", moveOut);
|
||||
AddAssert("Check blue cursor not visible", () => !checkVisible(cursorBoxes[1].Cursor));
|
||||
AddAssert("Check green cursor not visible", () => !checkVisible(cursorBoxes[0].Cursor));
|
||||
AddAssert("Check blue cursor not visible", () => !checkVisible(cursorBoxes[1].MenuCursor));
|
||||
AddAssert("Check green cursor not visible", () => !checkVisible(cursorBoxes[0].MenuCursor));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -143,13 +143,13 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
private void testMultipleLocalCursors()
|
||||
{
|
||||
AddStep("Move to yellow-purple boundary", () => InputManager.MoveMouseTo(cursorBoxes[5].ScreenSpaceDrawQuad.BottomRight - new Vector2(10)));
|
||||
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor));
|
||||
AddAssert("Check purple cursor at mouse", () => checkAtMouse(cursorBoxes[3].Cursor));
|
||||
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].Cursor));
|
||||
AddAssert("Check yellow cursor at mouse", () => checkAtMouse(cursorBoxes[5].Cursor));
|
||||
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].MenuCursor));
|
||||
AddAssert("Check purple cursor at mouse", () => checkAtMouse(cursorBoxes[3].MenuCursor));
|
||||
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].MenuCursor));
|
||||
AddAssert("Check yellow cursor at mouse", () => checkAtMouse(cursorBoxes[5].MenuCursor));
|
||||
AddStep("Move out", moveOut);
|
||||
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor));
|
||||
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].Cursor));
|
||||
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].MenuCursor));
|
||||
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].MenuCursor));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -159,13 +159,13 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
private void testUserOverrideWithLocal()
|
||||
{
|
||||
AddStep("Move to yellow-blue boundary", () => InputManager.MoveMouseTo(cursorBoxes[5].ScreenSpaceDrawQuad.TopRight - new Vector2(10)));
|
||||
AddAssert("Check blue cursor visible", () => checkVisible(cursorBoxes[1].Cursor));
|
||||
AddAssert("Check blue cursor at mouse", () => checkAtMouse(cursorBoxes[1].Cursor));
|
||||
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].Cursor));
|
||||
AddAssert("Check yellow cursor at mouse", () => checkAtMouse(cursorBoxes[5].Cursor));
|
||||
AddAssert("Check blue cursor visible", () => checkVisible(cursorBoxes[1].MenuCursor));
|
||||
AddAssert("Check blue cursor at mouse", () => checkAtMouse(cursorBoxes[1].MenuCursor));
|
||||
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].MenuCursor));
|
||||
AddAssert("Check yellow cursor at mouse", () => checkAtMouse(cursorBoxes[5].MenuCursor));
|
||||
AddStep("Move out", moveOut);
|
||||
AddAssert("Check blue cursor invisible", () => !checkVisible(cursorBoxes[1].Cursor));
|
||||
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].Cursor));
|
||||
AddAssert("Check blue cursor invisible", () => !checkVisible(cursorBoxes[1].MenuCursor));
|
||||
AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].MenuCursor));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -191,7 +191,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public bool SmoothTransition;
|
||||
|
||||
public CursorContainer Cursor { get; }
|
||||
public CursorContainer MenuCursor { get; }
|
||||
public bool ProvidingUserCursor { get; }
|
||||
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) || (SmoothTransition && !ProvidingUserCursor);
|
||||
@ -218,7 +218,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
Origin = Anchor.Centre,
|
||||
Text = providesUserCursor ? "User cursor" : "Local cursor"
|
||||
},
|
||||
Cursor = new TestCursorContainer
|
||||
MenuCursor = new TestCursorContainer
|
||||
{
|
||||
State = { Value = providesUserCursor ? Visibility.Hidden : Visibility.Visible },
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
@ -27,7 +28,6 @@ namespace osu.Game.Tournament.Tests.NonVisual
|
||||
{
|
||||
var osu = new TestTournament(runOnLoadComplete: () =>
|
||||
{
|
||||
// ReSharper disable once AccessToDisposedClosure
|
||||
var storage = host.Storage.GetStorageForDirectory(Path.Combine("tournaments", "default"));
|
||||
|
||||
using (var stream = storage.CreateFileSafely("bracket.json"))
|
||||
@ -85,7 +85,7 @@ namespace osu.Game.Tournament.Tests.NonVisual
|
||||
|
||||
public new Task BracketLoadTask => base.BracketLoadTask;
|
||||
|
||||
public TestTournament(bool resetRuleset = false, Action runOnLoadComplete = null)
|
||||
public TestTournament(bool resetRuleset = false, [InstantHandle] Action runOnLoadComplete = null)
|
||||
{
|
||||
this.resetRuleset = resetRuleset;
|
||||
this.runOnLoadComplete = runOnLoadComplete;
|
||||
|
@ -70,10 +70,10 @@ namespace osu.Game.Tournament
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
MenuCursorContainer.Cursor.AlwaysPresent = true; // required for tooltip display
|
||||
GlobalCursorDisplay.MenuCursor.AlwaysPresent = true; // required for tooltip display
|
||||
|
||||
// we don't want to show the menu cursor as it would appear on stream output.
|
||||
MenuCursorContainer.Cursor.Alpha = 0;
|
||||
GlobalCursorDisplay.MenuCursor.Alpha = 0;
|
||||
|
||||
base.LoadComplete();
|
||||
|
||||
|
@ -91,6 +91,7 @@ namespace osu.Game.Configuration
|
||||
// Input
|
||||
SetDefault(OsuSetting.MenuCursorSize, 1.0f, 0.5f, 2f, 0.01f);
|
||||
SetDefault(OsuSetting.GameplayCursorSize, 1.0f, 0.1f, 2f, 0.01f);
|
||||
SetDefault(OsuSetting.GameplayCursorDuringTouch, false);
|
||||
SetDefault(OsuSetting.AutoCursorSize, false);
|
||||
|
||||
SetDefault(OsuSetting.MouseDisableButtons, false);
|
||||
@ -292,6 +293,7 @@ namespace osu.Game.Configuration
|
||||
MenuCursorSize,
|
||||
GameplayCursorSize,
|
||||
AutoCursorSize,
|
||||
GameplayCursorDuringTouch,
|
||||
DimLevel,
|
||||
BlurLevel,
|
||||
LightenDuringBreaks,
|
||||
|
92
osu.Game/Graphics/Cursor/GlobalCursorDisplay.cs
Normal file
92
osu.Game/Graphics/Cursor/GlobalCursorDisplay.cs
Normal file
@ -0,0 +1,92 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.StateChanges;
|
||||
using osu.Game.Configuration;
|
||||
|
||||
namespace osu.Game.Graphics.Cursor
|
||||
{
|
||||
/// <summary>
|
||||
/// A container which provides the main <see cref="Cursor.MenuCursor"/>.
|
||||
/// Also handles cases where a more localised cursor is provided by another component (via <see cref="IProvideCursor"/>).
|
||||
/// </summary>
|
||||
public class GlobalCursorDisplay : Container, IProvideCursor
|
||||
{
|
||||
/// <summary>
|
||||
/// Control whether any cursor should be displayed.
|
||||
/// </summary>
|
||||
internal bool ShowCursor = true;
|
||||
|
||||
public CursorContainer MenuCursor { get; }
|
||||
|
||||
public bool ProvidingUserCursor => true;
|
||||
|
||||
protected override Container<Drawable> Content { get; } = new Container { RelativeSizeAxes = Axes.Both };
|
||||
|
||||
private Bindable<bool> showDuringTouch = null!;
|
||||
|
||||
private InputManager inputManager = null!;
|
||||
|
||||
private IProvideCursor? currentOverrideProvider;
|
||||
|
||||
[Resolved]
|
||||
private OsuConfigManager config { get; set; } = null!;
|
||||
|
||||
public GlobalCursorDisplay()
|
||||
{
|
||||
AddRangeInternal(new Drawable[]
|
||||
{
|
||||
MenuCursor = new MenuCursor { State = { Value = Visibility.Hidden } },
|
||||
Content = new Container { RelativeSizeAxes = Axes.Both }
|
||||
});
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
inputManager = GetContainingInputManager();
|
||||
showDuringTouch = config.GetBindable<bool>(OsuSetting.GameplayCursorDuringTouch);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
var lastMouseSource = inputManager.CurrentState.Mouse.LastSource;
|
||||
bool hasValidInput = lastMouseSource != null && (showDuringTouch.Value || lastMouseSource is not ISourcedFromTouch);
|
||||
|
||||
if (!hasValidInput || !ShowCursor)
|
||||
{
|
||||
currentOverrideProvider?.MenuCursor?.Hide();
|
||||
currentOverrideProvider = null;
|
||||
return;
|
||||
}
|
||||
|
||||
IProvideCursor newOverrideProvider = this;
|
||||
|
||||
foreach (var d in inputManager.HoveredDrawables)
|
||||
{
|
||||
if (d is IProvideCursor p && p.ProvidingUserCursor)
|
||||
{
|
||||
newOverrideProvider = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentOverrideProvider == newOverrideProvider)
|
||||
return;
|
||||
|
||||
currentOverrideProvider?.MenuCursor?.Hide();
|
||||
newOverrideProvider.MenuCursor?.Show();
|
||||
|
||||
currentOverrideProvider = newOverrideProvider;
|
||||
}
|
||||
}
|
||||
}
|
@ -17,10 +17,10 @@ namespace osu.Game.Graphics.Cursor
|
||||
/// The cursor provided by this <see cref="IDrawable"/>.
|
||||
/// May be null if no cursor should be visible.
|
||||
/// </summary>
|
||||
CursorContainer Cursor { get; }
|
||||
CursorContainer MenuCursor { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether <see cref="Cursor"/> should be displayed as the singular user cursor. This will temporarily hide any other user cursor.
|
||||
/// Whether <see cref="MenuCursor"/> should be displayed as the singular user cursor. This will temporarily hide any other user cursor.
|
||||
/// This value is checked every frame and may be used to control whether multiple cursors are displayed (e.g. watching replays).
|
||||
/// </summary>
|
||||
bool ProvidingUserCursor { get; }
|
||||
|
@ -1,83 +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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.StateChanges;
|
||||
|
||||
namespace osu.Game.Graphics.Cursor
|
||||
{
|
||||
/// <summary>
|
||||
/// A container which provides a <see cref="MenuCursor"/> which can be overridden by hovered <see cref="Drawable"/>s.
|
||||
/// </summary>
|
||||
public class MenuCursorContainer : Container, IProvideCursor
|
||||
{
|
||||
protected override Container<Drawable> Content => content;
|
||||
private readonly Container content;
|
||||
|
||||
/// <summary>
|
||||
/// Whether any cursors can be displayed.
|
||||
/// </summary>
|
||||
internal bool CanShowCursor = true;
|
||||
|
||||
public CursorContainer Cursor { get; }
|
||||
public bool ProvidingUserCursor => true;
|
||||
|
||||
public MenuCursorContainer()
|
||||
{
|
||||
AddRangeInternal(new Drawable[]
|
||||
{
|
||||
Cursor = new MenuCursor { State = { Value = Visibility.Hidden } },
|
||||
content = new Container { RelativeSizeAxes = Axes.Both }
|
||||
});
|
||||
}
|
||||
|
||||
private InputManager inputManager;
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
inputManager = GetContainingInputManager();
|
||||
}
|
||||
|
||||
private IProvideCursor currentTarget;
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
var lastMouseSource = inputManager.CurrentState.Mouse.LastSource;
|
||||
bool hasValidInput = lastMouseSource != null && !(lastMouseSource is ISourcedFromTouch);
|
||||
|
||||
if (!hasValidInput || !CanShowCursor)
|
||||
{
|
||||
currentTarget?.Cursor?.Hide();
|
||||
currentTarget = null;
|
||||
return;
|
||||
}
|
||||
|
||||
IProvideCursor newTarget = this;
|
||||
|
||||
foreach (var d in inputManager.HoveredDrawables)
|
||||
{
|
||||
if (d is IProvideCursor p && p.ProvidingUserCursor)
|
||||
{
|
||||
newTarget = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentTarget == newTarget)
|
||||
return;
|
||||
|
||||
currentTarget?.Cursor?.Hide();
|
||||
newTarget.Cursor?.Show();
|
||||
|
||||
currentTarget = newTarget;
|
||||
}
|
||||
}
|
||||
}
|
@ -34,6 +34,11 @@ namespace osu.Game.Localisation
|
||||
/// </summary>
|
||||
public static LocalisableString AutoCursorSize => new TranslatableString(getKey(@"auto_cursor_size"), @"Adjust gameplay cursor size based on current beatmap");
|
||||
|
||||
/// <summary>
|
||||
/// "Show gameplay cursor during touch input"
|
||||
/// </summary>
|
||||
public static LocalisableString GameplayCursorDuringTouch => new TranslatableString(getKey(@"gameplay_cursor_during_touch"), @"Show gameplay cursor during touch input");
|
||||
|
||||
/// <summary>
|
||||
/// "Beatmap skins"
|
||||
/// </summary>
|
||||
|
@ -1,162 +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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Scoring.Legacy;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Online.API.Requests.Responses
|
||||
{
|
||||
public class APIScore : IScoreInfo
|
||||
{
|
||||
[JsonProperty(@"score")]
|
||||
public long TotalScore { get; set; }
|
||||
|
||||
[JsonProperty(@"max_combo")]
|
||||
public int MaxCombo { get; set; }
|
||||
|
||||
[JsonProperty(@"user")]
|
||||
public APIUser User { get; set; }
|
||||
|
||||
[JsonProperty(@"id")]
|
||||
public long OnlineID { get; set; }
|
||||
|
||||
[JsonProperty(@"replay")]
|
||||
public bool HasReplay { get; set; }
|
||||
|
||||
[JsonProperty(@"created_at")]
|
||||
public DateTimeOffset Date { get; set; }
|
||||
|
||||
[JsonProperty(@"beatmap")]
|
||||
[CanBeNull]
|
||||
public APIBeatmap Beatmap { get; set; }
|
||||
|
||||
[JsonProperty("accuracy")]
|
||||
public double Accuracy { get; set; }
|
||||
|
||||
[JsonProperty(@"pp")]
|
||||
public double? PP { get; set; }
|
||||
|
||||
[JsonProperty(@"beatmapset")]
|
||||
[CanBeNull]
|
||||
public APIBeatmapSet BeatmapSet
|
||||
{
|
||||
set
|
||||
{
|
||||
// in the deserialisation case we need to ferry this data across.
|
||||
// the order of properties returned by the API guarantees that the beatmap is populated by this point.
|
||||
if (!(Beatmap is APIBeatmap apiBeatmap))
|
||||
throw new InvalidOperationException("Beatmap set metadata arrived before beatmap metadata in response");
|
||||
|
||||
apiBeatmap.BeatmapSet = value;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty("statistics")]
|
||||
public Dictionary<string, int> Statistics { get; set; }
|
||||
|
||||
[JsonProperty(@"mode_int")]
|
||||
public int RulesetID { get; set; }
|
||||
|
||||
[JsonProperty(@"mods")]
|
||||
private string[] mods { set => Mods = value.Select(acronym => new APIMod { Acronym = acronym }); }
|
||||
|
||||
[NotNull]
|
||||
public IEnumerable<APIMod> Mods { get; set; } = Array.Empty<APIMod>();
|
||||
|
||||
[JsonProperty("rank")]
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public ScoreRank Rank { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="ScoreInfo"/> from an API score instance.
|
||||
/// </summary>
|
||||
/// <param name="rulesets">A ruleset store, used to populate a ruleset instance in the returned score.</param>
|
||||
/// <param name="beatmap">An optional beatmap, copied into the returned score (for cases where the API does not populate the beatmap).</param>
|
||||
/// <returns></returns>
|
||||
public ScoreInfo CreateScoreInfo(RulesetStore rulesets, BeatmapInfo beatmap = null)
|
||||
{
|
||||
var ruleset = rulesets.GetRuleset(RulesetID) ?? throw new InvalidOperationException($"Ruleset with ID of {RulesetID} not found locally");
|
||||
|
||||
var rulesetInstance = ruleset.CreateInstance();
|
||||
|
||||
var modInstances = Mods.Select(apiMod => rulesetInstance.CreateModFromAcronym(apiMod.Acronym)).Where(m => m != null).ToArray();
|
||||
|
||||
// all API scores provided by this class are considered to be legacy.
|
||||
modInstances = modInstances.Append(rulesetInstance.CreateMod<ModClassic>()).ToArray();
|
||||
|
||||
var scoreInfo = new ScoreInfo
|
||||
{
|
||||
TotalScore = TotalScore,
|
||||
MaxCombo = MaxCombo,
|
||||
BeatmapInfo = beatmap ?? new BeatmapInfo(),
|
||||
User = User,
|
||||
Accuracy = Accuracy,
|
||||
OnlineID = OnlineID,
|
||||
Date = Date,
|
||||
PP = PP,
|
||||
Hash = HasReplay ? "online" : string.Empty, // todo: temporary?
|
||||
Rank = Rank,
|
||||
Ruleset = ruleset,
|
||||
Mods = modInstances,
|
||||
};
|
||||
|
||||
if (Statistics != null)
|
||||
{
|
||||
foreach (var kvp in Statistics)
|
||||
{
|
||||
switch (kvp.Key)
|
||||
{
|
||||
case @"count_geki":
|
||||
scoreInfo.SetCountGeki(kvp.Value);
|
||||
break;
|
||||
|
||||
case @"count_300":
|
||||
scoreInfo.SetCount300(kvp.Value);
|
||||
break;
|
||||
|
||||
case @"count_katu":
|
||||
scoreInfo.SetCountKatu(kvp.Value);
|
||||
break;
|
||||
|
||||
case @"count_100":
|
||||
scoreInfo.SetCount100(kvp.Value);
|
||||
break;
|
||||
|
||||
case @"count_50":
|
||||
scoreInfo.SetCount50(kvp.Value);
|
||||
break;
|
||||
|
||||
case @"count_miss":
|
||||
scoreInfo.SetCountMiss(kvp.Value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return scoreInfo;
|
||||
}
|
||||
|
||||
public IRulesetInfo Ruleset => new RulesetInfo { OnlineID = RulesetID };
|
||||
IEnumerable<INamedFileUsage> IHasNamedFiles.Files => throw new NotImplementedException();
|
||||
|
||||
#region Implementation of IScoreInfo
|
||||
|
||||
IBeatmapInfo IScoreInfo.Beatmap => Beatmap;
|
||||
IUser IScoreInfo.User => User;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -151,6 +151,23 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
PP = PP,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="SoloScoreInfo"/> from a local score for score submission.
|
||||
/// </summary>
|
||||
/// <param name="score">The local score.</param>
|
||||
public static SoloScoreInfo ForSubmission(ScoreInfo score) => new SoloScoreInfo
|
||||
{
|
||||
Rank = score.Rank,
|
||||
TotalScore = (int)score.TotalScore,
|
||||
Accuracy = score.Accuracy,
|
||||
PP = score.PP,
|
||||
MaxCombo = score.MaxCombo,
|
||||
RulesetID = score.RulesetID,
|
||||
Passed = score.Passed,
|
||||
Mods = score.APIMods,
|
||||
Statistics = score.Statistics,
|
||||
};
|
||||
|
||||
public long OnlineID => ID ?? -1;
|
||||
}
|
||||
}
|
||||
|
@ -7,20 +7,20 @@ using System.Net.Http;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Framework.IO.Network;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.Solo;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Scoring;
|
||||
|
||||
namespace osu.Game.Online.Rooms
|
||||
{
|
||||
public abstract class SubmitScoreRequest : APIRequest<MultiplayerScore>
|
||||
{
|
||||
public readonly SubmittableScore Score;
|
||||
public readonly SoloScoreInfo Score;
|
||||
|
||||
protected readonly long ScoreId;
|
||||
|
||||
protected SubmitScoreRequest(ScoreInfo scoreInfo, long scoreId)
|
||||
{
|
||||
Score = new SubmittableScore(scoreInfo);
|
||||
Score = SoloScoreInfo.ForSubmission(scoreInfo);
|
||||
ScoreId = scoreId;
|
||||
}
|
||||
|
||||
|
@ -1,72 +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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
|
||||
namespace osu.Game.Online.Solo
|
||||
{
|
||||
/// <summary>
|
||||
/// A class specifically for sending scores to the API during score submission.
|
||||
/// This is used instead of <see cref="APIScore"/> due to marginally different serialisation naming requirements.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SubmittableScore
|
||||
{
|
||||
[JsonProperty("rank")]
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public ScoreRank Rank { get; set; }
|
||||
|
||||
[JsonProperty("total_score")]
|
||||
public long TotalScore { get; set; }
|
||||
|
||||
[JsonProperty("accuracy")]
|
||||
public double Accuracy { get; set; }
|
||||
|
||||
[JsonProperty(@"pp")]
|
||||
public double? PP { get; set; }
|
||||
|
||||
[JsonProperty("max_combo")]
|
||||
public int MaxCombo { get; set; }
|
||||
|
||||
[JsonProperty("ruleset_id")]
|
||||
public int RulesetID { get; set; }
|
||||
|
||||
[JsonProperty("passed")]
|
||||
public bool Passed { get; set; }
|
||||
|
||||
// Used for API serialisation/deserialisation.
|
||||
[JsonProperty("mods")]
|
||||
public APIMod[] Mods { get; set; }
|
||||
|
||||
[JsonProperty("statistics")]
|
||||
public Dictionary<HitResult, int> Statistics { get; set; }
|
||||
|
||||
[UsedImplicitly]
|
||||
public SubmittableScore()
|
||||
{
|
||||
}
|
||||
|
||||
public SubmittableScore(ScoreInfo score)
|
||||
{
|
||||
Rank = score.Rank;
|
||||
TotalScore = score.TotalScore;
|
||||
Accuracy = score.Accuracy;
|
||||
PP = score.PP;
|
||||
MaxCombo = score.MaxCombo;
|
||||
RulesetID = score.RulesetID;
|
||||
Passed = score.Passed;
|
||||
Mods = score.APIMods;
|
||||
Statistics = score.Statistics;
|
||||
}
|
||||
}
|
||||
}
|
@ -716,7 +716,7 @@ namespace osu.Game
|
||||
// The next time this is updated is in UpdateAfterChildren, which occurs too late and results
|
||||
// in the cursor being shown for a few frames during the intro.
|
||||
// This prevents the cursor from showing until we have a screen with CursorVisible = true
|
||||
MenuCursorContainer.CanShowCursor = menuScreen?.CursorVisible ?? false;
|
||||
GlobalCursorDisplay.ShowCursor = menuScreen?.CursorVisible ?? false;
|
||||
|
||||
// todo: all archive managers should be able to be looped here.
|
||||
SkinManager.PostNotification = n => Notifications.Post(n);
|
||||
@ -1231,7 +1231,7 @@ namespace osu.Game
|
||||
ScreenOffsetContainer.X = horizontalOffset;
|
||||
overlayContent.X = horizontalOffset * 1.2f;
|
||||
|
||||
MenuCursorContainer.CanShowCursor = (ScreenStack.CurrentScreen as IOsuScreen)?.CursorVisible ?? false;
|
||||
GlobalCursorDisplay.ShowCursor = (ScreenStack.CurrentScreen as IOsuScreen)?.CursorVisible ?? false;
|
||||
}
|
||||
|
||||
private void screenChanged(IScreen current, IScreen newScreen)
|
||||
|
@ -138,7 +138,7 @@ namespace osu.Game
|
||||
|
||||
protected RealmKeyBindingStore KeyBindingStore { get; private set; }
|
||||
|
||||
protected MenuCursorContainer MenuCursorContainer { get; private set; }
|
||||
protected GlobalCursorDisplay GlobalCursorDisplay { get; private set; }
|
||||
|
||||
protected MusicController MusicController { get; private set; }
|
||||
|
||||
@ -340,10 +340,10 @@ namespace osu.Game
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = CreateScalingContainer().WithChildren(new Drawable[]
|
||||
{
|
||||
(MenuCursorContainer = new MenuCursorContainer
|
||||
(GlobalCursorDisplay = new GlobalCursorDisplay
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
}).WithChild(content = new OsuTooltipContainer(MenuCursorContainer.Cursor)
|
||||
}).WithChild(content = new OsuTooltipContainer(GlobalCursorDisplay.MenuCursor)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
}),
|
||||
|
@ -32,6 +32,11 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
||||
LabelText = SkinSettingsStrings.AutoCursorSize,
|
||||
Current = config.GetBindable<bool>(OsuSetting.AutoCursorSize)
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = SkinSettingsStrings.GameplayCursorDuringTouch,
|
||||
Current = config.GetBindable<bool>(OsuSetting.GameplayCursorDuringTouch)
|
||||
},
|
||||
};
|
||||
|
||||
if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows)
|
||||
|
@ -380,7 +380,7 @@ namespace osu.Game.Rulesets.UI
|
||||
// only show the cursor when within the playfield, by default.
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Playfield.ReceivePositionalInputAt(screenSpacePos);
|
||||
|
||||
CursorContainer IProvideCursor.Cursor => Playfield.Cursor;
|
||||
CursorContainer IProvideCursor.MenuCursor => Playfield.Cursor;
|
||||
|
||||
public override GameplayCursorContainer Cursor => Playfield.Cursor;
|
||||
|
||||
|
@ -146,13 +146,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
waveform.Waveform = b.NewValue.Waveform;
|
||||
track = b.NewValue.Track;
|
||||
|
||||
// todo: i don't think this is safe, the track may not be loaded yet.
|
||||
if (track.Length > 0)
|
||||
{
|
||||
MaxZoom = getZoomLevelForVisibleMilliseconds(500);
|
||||
MinZoom = getZoomLevelForVisibleMilliseconds(10000);
|
||||
defaultTimelineZoom = getZoomLevelForVisibleMilliseconds(6000);
|
||||
}
|
||||
setupTimelineZoom();
|
||||
}, true);
|
||||
|
||||
Zoom = (float)(defaultTimelineZoom * editorBeatmap.BeatmapInfo.TimelineZoom);
|
||||
@ -205,6 +199,20 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
scrollToTrackTime();
|
||||
}
|
||||
|
||||
private void setupTimelineZoom()
|
||||
{
|
||||
if (!track.IsLoaded)
|
||||
{
|
||||
Scheduler.AddOnce(setupTimelineZoom);
|
||||
return;
|
||||
}
|
||||
|
||||
defaultTimelineZoom = getZoomLevelForVisibleMilliseconds(6000);
|
||||
|
||||
float initialZoom = (float)(defaultTimelineZoom * editorBeatmap.BeatmapInfo.TimelineZoom);
|
||||
SetupZoom(initialZoom, getZoomLevelForVisibleMilliseconds(10000), getZoomLevelForVisibleMilliseconds(500));
|
||||
}
|
||||
|
||||
protected override bool OnScroll(ScrollEvent e)
|
||||
{
|
||||
// if this is not a precision scroll event, let the editor handle the seek itself (for snapping support)
|
||||
|
@ -32,20 +32,28 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
|
||||
private readonly Container zoomedContent;
|
||||
protected override Container<Drawable> Content => zoomedContent;
|
||||
private float currentZoom = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The current zoom level of <see cref="ZoomableScrollContainer" />.
|
||||
/// It may differ from <see cref="Zoom" /> during transitions.
|
||||
/// The current zoom level of <see cref="ZoomableScrollContainer"/>.
|
||||
/// It may differ from <see cref="Zoom"/> during transitions.
|
||||
/// </summary>
|
||||
public float CurrentZoom => currentZoom;
|
||||
public float CurrentZoom { get; private set; } = 1;
|
||||
|
||||
private bool isZoomSetUp;
|
||||
|
||||
[Resolved(canBeNull: true)]
|
||||
private IFrameBasedClock editorClock { get; set; }
|
||||
|
||||
private readonly LayoutValue zoomedContentWidthCache = new LayoutValue(Invalidation.DrawSize);
|
||||
|
||||
public ZoomableScrollContainer()
|
||||
private float minZoom;
|
||||
private float maxZoom;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="ZoomableScrollContainer"/> with no zoom range.
|
||||
/// Functionality will be disabled until zoom is set up via <see cref="SetupZoom"/>.
|
||||
/// </summary>
|
||||
protected ZoomableScrollContainer()
|
||||
: base(Direction.Horizontal)
|
||||
{
|
||||
base.Content.Add(zoomedContent = new Container { RelativeSizeAxes = Axes.Y });
|
||||
@ -53,46 +61,36 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
AddLayout(zoomedContentWidthCache);
|
||||
}
|
||||
|
||||
private float minZoom = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum zoom level allowed.
|
||||
/// Creates a <see cref="ZoomableScrollContainer"/> with a defined zoom range.
|
||||
/// </summary>
|
||||
public float MinZoom
|
||||
public ZoomableScrollContainer(float minimum, float maximum, float initial)
|
||||
: this()
|
||||
{
|
||||
get => minZoom;
|
||||
set
|
||||
{
|
||||
if (value < 1)
|
||||
throw new ArgumentException($"{nameof(MinZoom)} must be >= 1.", nameof(value));
|
||||
|
||||
minZoom = value;
|
||||
|
||||
// ensure zoom range is in valid state before updating zoom.
|
||||
if (MinZoom < MaxZoom)
|
||||
updateZoom();
|
||||
}
|
||||
SetupZoom(initial, minimum, maximum);
|
||||
}
|
||||
|
||||
private float maxZoom = 60;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum zoom level allowed.
|
||||
/// Sets up the minimum and maximum range of this zoomable scroll container, along with the initial zoom value.
|
||||
/// </summary>
|
||||
public float MaxZoom
|
||||
/// <param name="initial">The initial zoom value, applied immediately.</param>
|
||||
/// <param name="minimum">The minimum zoom value.</param>
|
||||
/// <param name="maximum">The maximum zoom value.</param>
|
||||
protected void SetupZoom(float initial, float minimum, float maximum)
|
||||
{
|
||||
get => maxZoom;
|
||||
set
|
||||
{
|
||||
if (value < 1)
|
||||
throw new ArgumentException($"{nameof(MaxZoom)} must be >= 1.", nameof(value));
|
||||
if (minimum < 1)
|
||||
throw new ArgumentException($"{nameof(minimum)} ({minimum}) must be >= 1.", nameof(maximum));
|
||||
|
||||
maxZoom = value;
|
||||
if (maximum < 1)
|
||||
throw new ArgumentException($"{nameof(maximum)} ({maximum}) must be >= 1.", nameof(maximum));
|
||||
|
||||
// ensure zoom range is in valid state before updating zoom.
|
||||
if (MaxZoom > MinZoom)
|
||||
updateZoom();
|
||||
}
|
||||
if (minimum > maximum)
|
||||
throw new ArgumentException($"{nameof(minimum)} ({minimum}) must be less than {nameof(maximum)} ({maximum})");
|
||||
|
||||
minZoom = minimum;
|
||||
maxZoom = maximum;
|
||||
CurrentZoom = zoomTarget = initial;
|
||||
isZoomSetUp = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -104,14 +102,17 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
set => updateZoom(value);
|
||||
}
|
||||
|
||||
private void updateZoom(float? value = null)
|
||||
private void updateZoom(float value)
|
||||
{
|
||||
float newZoom = Math.Clamp(value ?? Zoom, MinZoom, MaxZoom);
|
||||
if (!isZoomSetUp)
|
||||
return;
|
||||
|
||||
float newZoom = Math.Clamp(value, minZoom, maxZoom);
|
||||
|
||||
if (IsLoaded)
|
||||
setZoomTarget(newZoom, ToSpaceOfOtherDrawable(new Vector2(DrawWidth / 2, 0), zoomedContent).X);
|
||||
else
|
||||
currentZoom = zoomTarget = newZoom;
|
||||
CurrentZoom = zoomTarget = newZoom;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
@ -141,22 +142,25 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
|
||||
private void updateZoomedContentWidth()
|
||||
{
|
||||
zoomedContent.Width = DrawWidth * currentZoom;
|
||||
zoomedContent.Width = DrawWidth * CurrentZoom;
|
||||
zoomedContentWidthCache.Validate();
|
||||
}
|
||||
|
||||
public void AdjustZoomRelatively(float change, float? focusPoint = null)
|
||||
{
|
||||
if (!isZoomSetUp)
|
||||
return;
|
||||
|
||||
const float zoom_change_sensitivity = 0.02f;
|
||||
|
||||
setZoomTarget(zoomTarget + change * (MaxZoom - minZoom) * zoom_change_sensitivity, focusPoint);
|
||||
setZoomTarget(zoomTarget + change * (maxZoom - minZoom) * zoom_change_sensitivity, focusPoint);
|
||||
}
|
||||
|
||||
private float zoomTarget = 1;
|
||||
|
||||
private void setZoomTarget(float newZoom, float? focusPoint = null)
|
||||
{
|
||||
zoomTarget = Math.Clamp(newZoom, MinZoom, MaxZoom);
|
||||
zoomTarget = Math.Clamp(newZoom, minZoom, maxZoom);
|
||||
focusPoint ??= zoomedContent.ToLocalSpace(ToScreenSpace(new Vector2(DrawWidth / 2, 0))).X;
|
||||
|
||||
transformZoomTo(zoomTarget, focusPoint.Value, ZoomDuration, ZoomEasing);
|
||||
@ -192,7 +196,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
private readonly float scrollOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Transforms <see cref="ZoomableScrollContainer.currentZoom"/> to a new value.
|
||||
/// Transforms <see cref="ZoomableScrollContainer.CurrentZoom"/> to a new value.
|
||||
/// </summary>
|
||||
/// <param name="focusPoint">The focus point in absolute coordinates local to the content.</param>
|
||||
/// <param name="contentSize">The size of the content.</param>
|
||||
@ -204,7 +208,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
this.scrollOffset = scrollOffset;
|
||||
}
|
||||
|
||||
public override string TargetMember => nameof(currentZoom);
|
||||
public override string TargetMember => nameof(CurrentZoom);
|
||||
|
||||
private float valueAt(double time)
|
||||
{
|
||||
@ -222,7 +226,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
float expectedWidth = d.DrawWidth * newZoom;
|
||||
float targetOffset = expectedWidth * (focusPoint / contentSize) - focusOffset;
|
||||
|
||||
d.currentZoom = newZoom;
|
||||
d.CurrentZoom = newZoom;
|
||||
d.updateZoomedContentWidth();
|
||||
|
||||
// Temporarily here to make sure ScrollTo gets the correct DrawSize for scrollable area.
|
||||
@ -231,7 +235,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
d.ScrollTo(targetOffset, false);
|
||||
}
|
||||
|
||||
protected override void ReadIntoStartValue(ZoomableScrollContainer d) => StartValue = d.currentZoom;
|
||||
protected override void ReadIntoStartValue(ZoomableScrollContainer d) => StartValue = d.CurrentZoom;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input.Events;
|
||||
@ -90,18 +91,16 @@ namespace osu.Game.Screens.Ranking.Statistics
|
||||
spinner.Show();
|
||||
|
||||
var localCancellationSource = loadCancellation = new CancellationTokenSource();
|
||||
IBeatmap playableBeatmap = null;
|
||||
|
||||
var workingBeatmap = beatmapManager.GetWorkingBeatmap(newScore.BeatmapInfo);
|
||||
|
||||
// Todo: The placement of this is temporary. Eventually we'll both generate the playable beatmap _and_ run through it in a background task to generate the hit events.
|
||||
Task.Run(() =>
|
||||
{
|
||||
playableBeatmap = beatmapManager.GetWorkingBeatmap(newScore.BeatmapInfo).GetPlayableBeatmap(newScore.Ruleset, newScore.Mods);
|
||||
}, loadCancellation.Token).ContinueWith(_ => Schedule(() =>
|
||||
Task.Run(() => workingBeatmap.GetPlayableBeatmap(newScore.Ruleset, newScore.Mods), loadCancellation.Token).ContinueWith(task => Schedule(() =>
|
||||
{
|
||||
bool hitEventsAvailable = newScore.HitEvents.Count != 0;
|
||||
Container<Drawable> container;
|
||||
|
||||
var statisticRows = newScore.Ruleset.CreateInstance().CreateStatisticsForScore(newScore, playableBeatmap);
|
||||
var statisticRows = newScore.Ruleset.CreateInstance().CreateStatisticsForScore(newScore, task.GetResultSafely());
|
||||
|
||||
if (!hitEventsAvailable && statisticRows.SelectMany(r => r.Columns).All(c => c.RequiresHitEvents))
|
||||
{
|
||||
|
@ -36,7 +36,7 @@ namespace osu.Game.Screens.Utility
|
||||
|
||||
public readonly Bindable<LatencyVisualMode> VisualMode = new Bindable<LatencyVisualMode>();
|
||||
|
||||
public CursorContainer? Cursor { get; private set; }
|
||||
public CursorContainer? MenuCursor { get; private set; }
|
||||
|
||||
public bool ProvidingUserCursor => IsActiveArea.Value;
|
||||
|
||||
@ -91,7 +91,7 @@ namespace osu.Game.Screens.Utility
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
Cursor = new LatencyCursorContainer
|
||||
MenuCursor = new LatencyCursorContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
@ -105,7 +105,7 @@ namespace osu.Game.Screens.Utility
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
Cursor = new LatencyCursorContainer
|
||||
MenuCursor = new LatencyCursorContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
@ -119,7 +119,7 @@ namespace osu.Game.Screens.Utility
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
Cursor = new LatencyCursorContainer
|
||||
MenuCursor = new LatencyCursorContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
|
@ -38,11 +38,11 @@ namespace osu.Game.Tests.Visual
|
||||
|
||||
protected OsuManualInputManagerTestScene()
|
||||
{
|
||||
MenuCursorContainer cursorContainer;
|
||||
GlobalCursorDisplay cursorDisplay;
|
||||
|
||||
CompositeDrawable mainContent = cursorContainer = new MenuCursorContainer { RelativeSizeAxes = Axes.Both };
|
||||
CompositeDrawable mainContent = cursorDisplay = new GlobalCursorDisplay { RelativeSizeAxes = Axes.Both };
|
||||
|
||||
cursorContainer.Child = content = new OsuTooltipContainer(cursorContainer.Cursor)
|
||||
cursorDisplay.Child = content = new OsuTooltipContainer(cursorDisplay.MenuCursor)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user