diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 1b06aa4d17..6444127594 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -14,8 +14,8 @@
"jb"
]
},
- "smoogipoo.nvika": {
- "version": "1.0.3",
+ "nvika": {
+ "version": "2.2.0",
"commands": [
"nvika"
]
diff --git a/osu.Android.props b/osu.Android.props
index 4887e3a95f..6d2e8428a7 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,7 +52,7 @@
-
+
diff --git a/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs b/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs
index c8848ab7d8..656e333073 100644
--- a/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs
+++ b/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using NUnit.Framework;
@@ -67,9 +68,11 @@ namespace osu.Game.Tests.Online
var deserialised = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(apiMod));
var converted = (TestModTimeRamp)deserialised?.ToMod(new TestRuleset());
- Assert.That(converted?.AdjustPitch.Value, Is.EqualTo(false));
- Assert.That(converted?.InitialRate.Value, Is.EqualTo(1.25));
- Assert.That(converted?.FinalRate.Value, Is.EqualTo(0.25));
+ Assert.That(converted, Is.Not.Null);
+
+ Assert.That(converted.AdjustPitch.Value, Is.EqualTo(false));
+ Assert.That(converted.InitialRate.Value, Is.EqualTo(1.25));
+ Assert.That(converted.FinalRate.Value, Is.EqualTo(0.25));
}
[Test]
@@ -121,11 +124,11 @@ namespace osu.Game.Tests.Online
new TestModDifficultyAdjust()
};
- public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) => throw new System.NotImplementedException();
+ public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) => throw new NotImplementedException();
- public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new System.NotImplementedException();
+ public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new NotImplementedException();
- public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => throw new System.NotImplementedException();
+ public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => throw new NotImplementedException();
public override string Description { get; } = string.Empty;
public override string ShortName { get; } = string.Empty;
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneComposerSelection.cs b/osu.Game.Tests/Visual/Editing/TestSceneComposerSelection.cs
index a2a7b72283..dddd9f07ab 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneComposerSelection.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneComposerSelection.cs
@@ -5,7 +5,10 @@ using System;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Testing;
+using osu.Framework.Graphics.Cursor;
+using osu.Framework.Graphics.UserInterface;
using osu.Game.Beatmaps;
+using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu;
@@ -29,6 +32,9 @@ namespace osu.Game.Tests.Visual.Editing
private ComposeBlueprintContainer blueprintContainer
=> Editor.ChildrenOfType().First();
+ private ContextMenuContainer contextMenuContainer
+ => Editor.ChildrenOfType().First();
+
private void moveMouseToObject(Func targetFunc)
{
AddStep("move mouse to object", () =>
@@ -42,6 +48,19 @@ namespace osu.Game.Tests.Visual.Editing
});
}
+ [Test]
+ public void TestSelectAndShowContextMenu()
+ {
+ var addedObject = new HitCircle { StartTime = 100, Position = new Vector2(100, 100) };
+ AddStep("add hitobject", () => EditorBeatmap.Add(addedObject));
+
+ moveMouseToObject(() => addedObject);
+ AddStep("right click", () => InputManager.Click(MouseButton.Right));
+
+ AddUntilStep("hitobject selected", () => EditorBeatmap.SelectedHitObjects.Single() == addedObject);
+ AddUntilStep("context menu is visible", () => contextMenuContainer.ChildrenOfType().Single().State == MenuState.Open);
+ }
+
[Test]
public void TestNudgeSelection()
{
diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs
index d7d4642a39..29e3f12d03 100644
--- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs
@@ -108,11 +108,20 @@ namespace osu.Game.Screens.Edit.Compose.Components
protected override bool OnMouseDown(MouseDownEvent e)
{
bool selectionPerformed = performMouseDownActions(e);
-
- // even if a selection didn't occur, a drag event may still move the selection.
bool movementPossible = prepareSelectionMovement();
- return selectionPerformed || (e.Button == MouseButton.Left && movementPossible);
+ // check if selection has occurred
+ if (selectionPerformed)
+ {
+ // only unmodified right click should show context menu
+ bool shouldShowContextMenu = e.Button == MouseButton.Right && !e.ShiftPressed && !e.AltPressed && !e.SuperPressed;
+
+ // stop propagation if not showing context menu
+ return !shouldShowContextMenu;
+ }
+
+ // even if a selection didn't occur, a drag event may still move the selection.
+ return e.Button == MouseButton.Left && movementPossible;
}
protected SelectionBlueprint ClickedBlueprint { get; private set; }
diff --git a/osu.Game/Screens/Select/BeatmapDeleteDialog.cs b/osu.Game/Screens/Select/BeatmapDeleteDialog.cs
index 5fb72e4151..307c2352e3 100644
--- a/osu.Game/Screens/Select/BeatmapDeleteDialog.cs
+++ b/osu.Game/Screens/Select/BeatmapDeleteDialog.cs
@@ -29,7 +29,7 @@ namespace osu.Game.Screens.Select
new PopupDialogOkButton
{
Text = @"Yes. Totally. Delete it.",
- Action = () => manager.Delete(beatmap),
+ Action = () => manager?.Delete(beatmap),
},
new PopupDialogCancelButton
{
diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs
index 99123627bd..9e3d3df915 100644
--- a/osu.Game/Storyboards/Storyboard.cs
+++ b/osu.Game/Storyboards/Storyboard.cs
@@ -77,10 +77,14 @@ namespace osu.Game.Storyboards
{
get
{
- string backgroundPath = BeatmapInfo.BeatmapSet?.Metadata?.BackgroundFile.ToLowerInvariant();
+ string backgroundPath = BeatmapInfo.BeatmapSet?.Metadata?.BackgroundFile;
+
if (string.IsNullOrEmpty(backgroundPath))
return false;
+ // Importantly, do this after the NullOrEmpty because EF may have stored the non-nullable value as null to the database, bypassing compile-time constraints.
+ backgroundPath = backgroundPath.ToLowerInvariant();
+
return GetLayer("Background").Elements.Any(e => e.Path.ToLowerInvariant() == backgroundPath);
}
}
@@ -93,7 +97,7 @@ namespace osu.Game.Storyboards
Drawable drawable = null;
string storyboardPath = BeatmapInfo.BeatmapSet?.Files.Find(f => f.Filename.Equals(path, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath;
- if (storyboardPath != null)
+ if (!string.IsNullOrEmpty(storyboardPath))
drawable = new Sprite { Texture = textureStore.Get(storyboardPath) };
// if the texture isn't available locally in the beatmap, some storyboards choose to source from the underlying skin lookup hierarchy.
else if (UseSkinSprites)
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 972d64a997..6dda1f77c6 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -36,7 +36,7 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index f6e4f61fde..df24a57e90 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -70,7 +70,7 @@
-
+
@@ -93,7 +93,7 @@
-
+