diff --git a/README.md b/README.md
index 7ace47a74f..f64240f67a 100644
--- a/README.md
+++ b/README.md
@@ -50,7 +50,7 @@ Please make sure you have the following prerequisites:
- A desktop platform with the [.NET 6.0 SDK](https://dotnet.microsoft.com/download) installed.
- When developing with mobile, [Xamarin](https://docs.microsoft.com/en-us/xamarin/) is required, which is shipped together with Visual Studio or [Visual Studio for Mac](https://visualstudio.microsoft.com/vs/mac/).
-- When working with the codebase, we recommend using an IDE with intelligent code completion and syntax highlighting, such as [Visual Studio 2019+](https://visualstudio.microsoft.com/vs/), [JetBrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/).
+- When working with the codebase, we recommend using an IDE with intelligent code completion and syntax highlighting, such as the latest version of [Visual Studio](https://visualstudio.microsoft.com/vs/), [JetBrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/).
- When running on Linux, please have a system-wide FFmpeg installation available to support video decoding.
### Downloading the source code
@@ -72,7 +72,7 @@ git pull
Build configurations for the recommended IDEs (listed above) are included. You should use the provided Build/Run functionality of your IDE to get things going. When testing or building new components, it's highly encouraged you use the `VisualTests` project/configuration. More information on this is provided [below](#contributing).
-- Visual Studio / Rider users should load the project via one of the platform-specific `.slnf` files, rather than the main `.sln.` This will allow access to template run configurations.
+- Visual Studio / Rider users should load the project via one of the platform-specific `.slnf` files, rather than the main `.sln`. This will allow access to template run configurations.
You can also build and run *osu!* from the command-line with a single command:
diff --git a/osu.Android.props b/osu.Android.props
index 526ce959a6..d418dcaccf 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -51,7 +51,7 @@
-
+
diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs
index 3642f70a56..d87b25a4c7 100644
--- a/osu.Desktop/DiscordRichPresence.cs
+++ b/osu.Desktop/DiscordRichPresence.cs
@@ -10,6 +10,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Logging;
using osu.Game.Configuration;
+using osu.Game.Extensions;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets;
@@ -108,10 +109,7 @@ namespace osu.Desktop
presence.Assets.LargeImageText = $"{user.Value.Username}" + (user.Value.Statistics?.GlobalRank > 0 ? $" (rank #{user.Value.Statistics.GlobalRank:N0})" : string.Empty);
// update ruleset
- int onlineID = ruleset.Value.OnlineID;
- bool isLegacyRuleset = onlineID >= 0 && onlineID <= ILegacyRuleset.MAX_LEGACY_RULESET_ID;
-
- presence.Assets.SmallImageKey = isLegacyRuleset ? $"mode_{onlineID}" : "mode_custom";
+ presence.Assets.SmallImageKey = ruleset.Value.IsLegacyRuleset() ? $"mode_{ruleset.Value.OnlineID}" : "mode_custom";
presence.Assets.SmallImageText = ruleset.Value.Name;
client.SetPresence(presence);
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapOffsetControl.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapOffsetControl.cs
index 67f5db548b..4b079cbb2c 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapOffsetControl.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapOffsetControl.cs
@@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual.Gameplay
}
[Test]
- public void TestDisplay()
+ public void TestCalibrationFromZero()
{
const double average_error = -4.5;
@@ -70,5 +70,33 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("Remove reference score", () => offsetControl.ReferenceScore.Value = null);
AddAssert("No calibration button", () => !offsetControl.ChildrenOfType().Any());
}
+
+ ///
+ /// When a beatmap offset was already set, the calibration should take it into account.
+ ///
+ [Test]
+ public void TestCalibrationFromNonZero()
+ {
+ const double average_error = -4.5;
+ const double initial_offset = -2;
+
+ AddStep("Set offset non-neutral", () => offsetControl.Current.Value = initial_offset);
+ AddAssert("No calibration button", () => !offsetControl.ChildrenOfType().Any());
+ AddStep("Set reference score", () =>
+ {
+ offsetControl.ReferenceScore.Value = new ScoreInfo
+ {
+ HitEvents = TestSceneHitEventTimingDistributionGraph.CreateDistributedHitEvents(average_error)
+ };
+ });
+
+ AddAssert("Has calibration button", () => offsetControl.ChildrenOfType().Any());
+ AddStep("Press button", () => offsetControl.ChildrenOfType().Single().TriggerClick());
+ AddAssert("Offset is adjusted", () => offsetControl.Current.Value == initial_offset - average_error);
+
+ AddAssert("Button is disabled", () => !offsetControl.ChildrenOfType().Single().Enabled.Value);
+ AddStep("Remove reference score", () => offsetControl.ReferenceScore.Value = null);
+ AddAssert("No calibration button", () => !offsetControl.ChildrenOfType().Any());
+ }
}
}
diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs b/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs
index 221001e40b..f31aec8975 100644
--- a/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs
+++ b/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs
@@ -23,6 +23,12 @@ namespace osu.Game.Tests.Visual.Ranking
createTest(CreateDistributedHitEvents());
}
+ [Test]
+ public void TestManyDistributedEventsOffset()
+ {
+ createTest(CreateDistributedHitEvents(-3.5));
+ }
+
[Test]
public void TestAroundCentre()
{
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
index 31bd3a203c..1ed6648131 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
@@ -119,7 +119,8 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep(@"Network failure", () => leaderboard.SetErrorState(LeaderboardState.NetworkFailure));
AddStep(@"No supporter", () => leaderboard.SetErrorState(LeaderboardState.NotSupporter));
AddStep(@"Not logged in", () => leaderboard.SetErrorState(LeaderboardState.NotLoggedIn));
- AddStep(@"Unavailable", () => leaderboard.SetErrorState(LeaderboardState.Unavailable));
+ AddStep(@"Ruleset unavailable", () => leaderboard.SetErrorState(LeaderboardState.RulesetUnavailable));
+ AddStep(@"Beatmap unavailable", () => leaderboard.SetErrorState(LeaderboardState.BeatmapUnavailable));
AddStep(@"None selected", () => leaderboard.SetErrorState(LeaderboardState.NoneSelected));
}
diff --git a/osu.Game/Beatmaps/DifficultyRecommender.cs b/osu.Game/Beatmaps/DifficultyRecommender.cs
index 3949e84f4a..93c2fccbc7 100644
--- a/osu.Game/Beatmaps/DifficultyRecommender.cs
+++ b/osu.Game/Beatmaps/DifficultyRecommender.cs
@@ -9,6 +9,7 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
+using osu.Game.Extensions;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Rulesets;
@@ -83,7 +84,7 @@ namespace osu.Game.Beatmaps
requestedUserId = api.LocalUser.Value.Id;
// only query API for built-in rulesets
- rulesets.AvailableRulesets.Where(ruleset => ruleset.OnlineID >= 0 && ruleset.OnlineID <= ILegacyRuleset.MAX_LEGACY_RULESET_ID).ForEach(rulesetInfo =>
+ rulesets.AvailableRulesets.Where(ruleset => ruleset.IsLegacyRuleset()).ForEach(rulesetInfo =>
{
var req = new GetUserRequest(api.LocalUser.Value.Id, rulesetInfo);
diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs
index 35638a025c..450fec4a4d 100644
--- a/osu.Game/Configuration/OsuConfigManager.cs
+++ b/osu.Game/Configuration/OsuConfigManager.cs
@@ -240,9 +240,9 @@ namespace osu.Game.Configuration
};
}
- public Func LookupSkinName { private get; set; }
+ public Func LookupSkinName { private get; set; } = _ => @"unknown";
- public Func LookupKeyBindings { get; set; }
+ public Func LookupKeyBindings { get; set; } = _ => @"unknown";
}
// IMPORTANT: These are used in user configuration files.
diff --git a/osu.Game/Extensions/ModelExtensions.cs b/osu.Game/Extensions/ModelExtensions.cs
index f178a5c97b..13c25e45c8 100644
--- a/osu.Game/Extensions/ModelExtensions.cs
+++ b/osu.Game/Extensions/ModelExtensions.cs
@@ -72,6 +72,11 @@ namespace osu.Game.Extensions
return result;
}
+ ///
+ /// Check whether this 's online ID is within the range that defines it as a legacy ruleset (ie. either osu!, osu!taiko, osu!catch or osu!mania).
+ ///
+ public static bool IsLegacyRuleset(this IRulesetInfo ruleset) => ruleset.OnlineID >= 0 && ruleset.OnlineID <= ILegacyRuleset.MAX_LEGACY_RULESET_ID;
+
///
/// Check whether the online ID of two s match.
///
diff --git a/osu.Game/Graphics/Containers/ScalingContainer.cs b/osu.Game/Graphics/Containers/ScalingContainer.cs
index 0d543bdbc8..d331b818a1 100644
--- a/osu.Game/Graphics/Containers/ScalingContainer.cs
+++ b/osu.Game/Graphics/Containers/ScalingContainer.cs
@@ -5,6 +5,7 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Primitives;
using osu.Framework.Screens;
using osu.Game.Configuration;
using osu.Game.Screens;
@@ -38,24 +39,24 @@ namespace osu.Game.Graphics.Containers
private BackgroundScreenStack backgroundStack;
- private bool allowScaling = true;
+ private RectangleF? customRect;
+ private bool customRectIsRelativePosition;
///
- /// Whether user scaling preferences should be applied. Enabled by default.
+ /// Set a custom position and scale which overrides any user specification.
///
- public bool AllowScaling
+ /// A rectangle with positional and sizing information for this container to conform to. null will clear the custom rect and revert to user settings.
+ /// Whether the position portion of the provided rect is in relative coordinate space or not.
+ public void SetCustomRect(RectangleF? rect, bool relativePosition = false)
{
- get => allowScaling;
- set
- {
- if (value == allowScaling)
- return;
+ customRect = rect;
+ customRectIsRelativePosition = relativePosition;
- allowScaling = value;
- if (IsLoaded) Scheduler.AddOnce(updateSize);
- }
+ if (IsLoaded) Scheduler.AddOnce(updateSize);
}
+ private const float corner_radius = 10;
+
///
/// Create a new instance.
///
@@ -69,7 +70,7 @@ namespace osu.Game.Graphics.Containers
{
RelativeSizeAxes = Axes.Both,
RelativePositionAxes = Axes.Both,
- CornerRadius = 10,
+ CornerRadius = corner_radius,
Child = content = new ScalingDrawSizePreservingFillContainer(targetMode != ScalingMode.Gameplay)
};
}
@@ -137,7 +138,7 @@ namespace osu.Game.Graphics.Containers
private void updateSize()
{
- const float fade_time = 500;
+ const float duration = 500;
if (targetMode == ScalingMode.Everything)
{
@@ -156,17 +157,31 @@ namespace osu.Game.Graphics.Containers
backgroundStack.Push(new ScalingBackgroundScreen());
}
- backgroundStack.FadeIn(fade_time);
+ backgroundStack.FadeIn(duration);
}
else
- backgroundStack?.FadeOut(fade_time);
+ backgroundStack?.FadeOut(duration);
}
- bool scaling = AllowScaling && (targetMode == null || scalingMode.Value == targetMode);
+ RectangleF targetRect = new RectangleF(Vector2.Zero, Vector2.One);
- var targetSize = scaling ? new Vector2(sizeX.Value, sizeY.Value) : Vector2.One;
- var targetPosition = scaling ? new Vector2(posX.Value, posY.Value) * (Vector2.One - targetSize) : Vector2.Zero;
- bool requiresMasking = (scaling && targetSize != Vector2.One)
+ if (customRect != null)
+ {
+ sizableContainer.RelativePositionAxes = customRectIsRelativePosition ? Axes.Both : Axes.None;
+
+ targetRect = customRect.Value;
+ }
+ else if (targetMode == null || scalingMode.Value == targetMode)
+ {
+ sizableContainer.RelativePositionAxes = Axes.Both;
+
+ Vector2 scale = new Vector2(sizeX.Value, sizeY.Value);
+ Vector2 pos = new Vector2(posX.Value, posY.Value) * (Vector2.One - scale);
+
+ targetRect = new RectangleF(pos, scale);
+ }
+
+ bool requiresMasking = targetRect.Size != Vector2.One
// For the top level scaling container, for now we apply masking if safe areas are in use.
// In the future this can likely be removed as more of the actual UI supports overflowing into the safe areas.
|| (targetMode == ScalingMode.Everything && safeAreaPadding.Value.Total != Vector2.Zero);
@@ -174,8 +189,14 @@ namespace osu.Game.Graphics.Containers
if (requiresMasking)
sizableContainer.Masking = true;
- sizableContainer.MoveTo(targetPosition, 500, Easing.OutQuart);
- sizableContainer.ResizeTo(targetSize, 500, Easing.OutQuart).OnComplete(_ => { sizableContainer.Masking = requiresMasking; });
+ sizableContainer.MoveTo(targetRect.Location, duration, Easing.OutQuart);
+ sizableContainer.ResizeTo(targetRect.Size, duration, Easing.OutQuart);
+
+ // Of note, this will not work great in the case of nested ScalingContainers where multiple are applying corner radius.
+ // Masking and corner radius should likely only be applied at one point in the full game stack to fix this.
+ // An example of how this can occur is when the skin editor is visible and the game screen scaling is set to "Everything".
+ sizableContainer.TransformTo(nameof(CornerRadius), requiresMasking ? corner_radius : 0, duration, requiresMasking ? Easing.OutQuart : Easing.None)
+ .OnComplete(_ => { sizableContainer.Masking = requiresMasking; });
}
private class ScalingBackgroundScreen : BackgroundScreenDefault
diff --git a/osu.Game/Graphics/Cursor/MenuCursor.cs b/osu.Game/Graphics/Cursor/MenuCursor.cs
index 0cc751ea21..03fad00e41 100644
--- a/osu.Game/Graphics/Cursor/MenuCursor.cs
+++ b/osu.Game/Graphics/Cursor/MenuCursor.cs
@@ -140,6 +140,7 @@ namespace osu.Game.Graphics.Cursor
// Scale to [-0.75, 0.75] so that the sample isn't fully panned left or right (sounds weird)
channel.Balance.Value = ((activeCursor.X / DrawWidth) * 2 - 1) * 0.75;
channel.Frequency.Value = baseFrequency - (random_range / 2f) + RNG.NextDouble(random_range);
+ channel.Volume.Value = baseFrequency;
channel.Play();
}
diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs
index 747a56f636..21c8dfcfa4 100644
--- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs
+++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs
@@ -40,7 +40,7 @@ namespace osu.Game.Graphics.UserInterface
private readonly Box rightBox;
private readonly Container nubContainer;
- public LocalisableString TooltipText { get; private set; }
+ public virtual LocalisableString TooltipText { get; private set; }
///
/// Whether to format the tooltip as a percentage or the actual value.
@@ -148,7 +148,7 @@ namespace osu.Game.Graphics.UserInterface
protected override void LoadComplete()
{
base.LoadComplete();
- CurrentNumber.BindValueChanged(current => TooltipText = GetTooltipText(current.NewValue), true);
+ CurrentNumber.BindValueChanged(current => TooltipText = getTooltipText(current.NewValue), true);
}
protected override bool OnHover(HoverEvent e)
@@ -178,7 +178,7 @@ namespace osu.Game.Graphics.UserInterface
{
base.OnUserChange(value);
playSample(value);
- TooltipText = GetTooltipText(value);
+ TooltipText = getTooltipText(value);
}
private void playSample(T value)
@@ -203,7 +203,7 @@ namespace osu.Game.Graphics.UserInterface
channel.Play();
}
- protected virtual LocalisableString GetTooltipText(T value)
+ private LocalisableString getTooltipText(T value)
{
if (CurrentNumber.IsInteger)
return value.ToInt32(NumberFormatInfo.InvariantInfo).ToString("N0");
diff --git a/osu.Game/Graphics/UserInterface/TimeSlider.cs b/osu.Game/Graphics/UserInterface/TimeSlider.cs
index e99345f147..82b02f1b48 100644
--- a/osu.Game/Graphics/UserInterface/TimeSlider.cs
+++ b/osu.Game/Graphics/UserInterface/TimeSlider.cs
@@ -10,6 +10,6 @@ namespace osu.Game.Graphics.UserInterface
///
public class TimeSlider : OsuSliderBar
{
- protected override LocalisableString GetTooltipText(double value) => $"{value:N0} ms";
+ public override LocalisableString TooltipText => $"{Current.Value:N0} ms";
}
}
diff --git a/osu.Game/Localisation/LeaderboardStrings.cs b/osu.Game/Localisation/LeaderboardStrings.cs
new file mode 100644
index 0000000000..8e53f8e88c
--- /dev/null
+++ b/osu.Game/Localisation/LeaderboardStrings.cs
@@ -0,0 +1,49 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Localisation;
+
+namespace osu.Game.Localisation
+{
+ public static class LeaderboardStrings
+ {
+ private const string prefix = @"osu.Game.Resources.Localisation.Leaderboard";
+
+ ///
+ /// "Couldn't fetch scores!"
+ ///
+ public static LocalisableString CouldntFetchScores => new TranslatableString(getKey(@"couldnt_fetch_scores"), @"Couldn't fetch scores!");
+
+ ///
+ /// "Please select a beatmap!"
+ ///
+ public static LocalisableString PleaseSelectABeatmap => new TranslatableString(getKey(@"please_select_a_beatmap"), @"Please select a beatmap!");
+
+ ///
+ /// "Leaderboards are not available for this ruleset!"
+ ///
+ public static LocalisableString LeaderboardsAreNotAvailableForThisRuleset => new TranslatableString(getKey(@"leaderboards_are_not_available_for_this_ruleset"), @"Leaderboards are not available for this ruleset!");
+
+ ///
+ /// "Leaderboards are not available for this beatmap!"
+ ///
+ public static LocalisableString LeaderboardsAreNotAvailableForThisBeatmap => new TranslatableString(getKey(@"leaderboards_are_not_available_for_this_beatmap"), @"Leaderboards are not available for this beatmap!");
+
+ ///
+ /// "No records yet!"
+ ///
+ public static LocalisableString NoRecordsYet => new TranslatableString(getKey(@"no_records_yet"), @"No records yet!");
+
+ ///
+ /// "Please sign in to view online leaderboards!"
+ ///
+ public static LocalisableString PleaseSignInToViewOnlineLeaderboards => new TranslatableString(getKey(@"please_sign_in_to_view_online_leaderboards"), @"Please sign in to view online leaderboards!");
+
+ ///
+ /// "Please invest in an osu!supporter tag to view this leaderboard!"
+ ///
+ public static LocalisableString PleaseInvestInAnOsuSupporterTagToViewThisLeaderboard => new TranslatableString(getKey(@"please_invest_in_an_osu_supporter_tag_to_view_this_leaderboard"), @"Please invest in an osu!supporter tag to view this leaderboard!");
+
+ private static string getKey(string key) => $@"{prefix}:{key}";
+ }
+}
diff --git a/osu.Game/Online/API/Requests/GetWikiRequest.cs b/osu.Game/Online/API/Requests/GetWikiRequest.cs
index 248fcc03e3..09571ab0a8 100644
--- a/osu.Game/Online/API/Requests/GetWikiRequest.cs
+++ b/osu.Game/Online/API/Requests/GetWikiRequest.cs
@@ -1,6 +1,8 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using osu.Game.Extensions;
+using osu.Game.Localisation;
using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Online.API.Requests
@@ -8,14 +10,14 @@ namespace osu.Game.Online.API.Requests
public class GetWikiRequest : APIRequest
{
private readonly string path;
- private readonly string locale;
+ private readonly Language language;
- public GetWikiRequest(string path, string locale = "en")
+ public GetWikiRequest(string path, Language language = Language.en)
{
this.path = path;
- this.locale = locale;
+ this.language = language;
}
- protected override string Target => $"wiki/{locale}/{path}";
+ protected override string Target => $"wiki/{language.ToCultureCode()}/{path}";
}
}
diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs
index 5dd3e46b4a..c94a6d3361 100644
--- a/osu.Game/Online/Leaderboards/Leaderboard.cs
+++ b/osu.Game/Online/Leaderboards/Leaderboard.cs
@@ -22,6 +22,7 @@ using osu.Game.Online.API;
using osu.Game.Online.Placeholders;
using osuTK;
using osuTK.Graphics;
+using osu.Game.Localisation;
namespace osu.Game.Online.Leaderboards
{
@@ -311,25 +312,28 @@ namespace osu.Game.Online.Leaderboards
switch (state)
{
case LeaderboardState.NetworkFailure:
- return new ClickablePlaceholder(@"Couldn't fetch scores!", FontAwesome.Solid.Sync)
+ return new ClickablePlaceholder(LeaderboardStrings.CouldntFetchScores, FontAwesome.Solid.Sync)
{
Action = RefetchScores
};
case LeaderboardState.NoneSelected:
- return new MessagePlaceholder(@"Please select a beatmap!");
+ return new MessagePlaceholder(LeaderboardStrings.PleaseSelectABeatmap);
- case LeaderboardState.Unavailable:
- return new MessagePlaceholder(@"Leaderboards are not available for this beatmap!");
+ case LeaderboardState.RulesetUnavailable:
+ return new MessagePlaceholder(LeaderboardStrings.LeaderboardsAreNotAvailableForThisRuleset);
+
+ case LeaderboardState.BeatmapUnavailable:
+ return new MessagePlaceholder(LeaderboardStrings.LeaderboardsAreNotAvailableForThisBeatmap);
case LeaderboardState.NoScores:
- return new MessagePlaceholder(@"No records yet!");
+ return new MessagePlaceholder(LeaderboardStrings.NoRecordsYet);
case LeaderboardState.NotLoggedIn:
- return new LoginPlaceholder(@"Please sign in to view online leaderboards!");
+ return new LoginPlaceholder(LeaderboardStrings.PleaseSignInToViewOnlineLeaderboards);
case LeaderboardState.NotSupporter:
- return new MessagePlaceholder(@"Please invest in an osu!supporter tag to view this leaderboard!");
+ return new MessagePlaceholder(LeaderboardStrings.PleaseInvestInAnOsuSupporterTagToViewThisLeaderboard);
case LeaderboardState.Retrieving:
return null;
diff --git a/osu.Game/Online/Leaderboards/LeaderboardState.cs b/osu.Game/Online/Leaderboards/LeaderboardState.cs
index 75e2c6e6db..6b07500a98 100644
--- a/osu.Game/Online/Leaderboards/LeaderboardState.cs
+++ b/osu.Game/Online/Leaderboards/LeaderboardState.cs
@@ -8,7 +8,8 @@ namespace osu.Game.Online.Leaderboards
Success,
Retrieving,
NetworkFailure,
- Unavailable,
+ BeatmapUnavailable,
+ RulesetUnavailable,
NoneSelected,
NoScores,
NotLoggedIn,
diff --git a/osu.Game/Online/Placeholders/LoginPlaceholder.cs b/osu.Game/Online/Placeholders/LoginPlaceholder.cs
index f8a326a52e..d03b3d8ffc 100644
--- a/osu.Game/Online/Placeholders/LoginPlaceholder.cs
+++ b/osu.Game/Online/Placeholders/LoginPlaceholder.cs
@@ -3,6 +3,7 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics.Sprites;
+using osu.Framework.Localisation;
using osu.Game.Overlays;
namespace osu.Game.Online.Placeholders
@@ -12,7 +13,7 @@ namespace osu.Game.Online.Placeholders
[Resolved(CanBeNull = true)]
private LoginOverlay login { get; set; }
- public LoginPlaceholder(string actionMessage)
+ public LoginPlaceholder(LocalisableString actionMessage)
: base(actionMessage, FontAwesome.Solid.UserLock)
{
Action = () => login?.Show();
diff --git a/osu.Game/Overlays/Profile/Header/MedalHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/MedalHeaderContainer.cs
index 5f513582e5..922f3832e4 100644
--- a/osu.Game/Overlays/Profile/Header/MedalHeaderContainer.cs
+++ b/osu.Game/Overlays/Profile/Header/MedalHeaderContainer.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.Threading;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
@@ -63,11 +64,17 @@ namespace osu.Game.Overlays.Profile.Header
};
}
+ private CancellationTokenSource cancellationTokenSource;
+
private void updateDisplay(APIUser user)
{
- var badges = user.Badges;
+ cancellationTokenSource?.Cancel();
+ cancellationTokenSource = new CancellationTokenSource();
+
badgeFlowContainer.Clear();
+ var badges = user.Badges;
+
if (badges?.Length > 0)
{
Show();
@@ -79,7 +86,7 @@ namespace osu.Game.Overlays.Profile.Header
{
// load in stable order regardless of async load order.
badgeFlowContainer.Insert(displayIndex, asyncBadge);
- });
+ }, cancellationTokenSource.Token);
}
}
else
@@ -87,5 +94,11 @@ namespace osu.Game.Overlays.Profile.Header
Hide();
}
}
+
+ protected override void Dispose(bool isDisposing)
+ {
+ cancellationTokenSource?.Cancel();
+ base.Dispose(isDisposing);
+ }
}
}
diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs
index b572f1c6a0..adf1453d1a 100644
--- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs
@@ -240,7 +240,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
private class UIScaleSlider : OsuSliderBar
{
- protected override LocalisableString GetTooltipText(float value) => $"{base.GetTooltipText(value)}x";
+ public override LocalisableString TooltipText => base.TooltipText + "x";
}
private class ResolutionSettingsDropdown : SettingsDropdown
diff --git a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs
index 971b19ca6c..4235dc0a05 100644
--- a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs
@@ -135,9 +135,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
private class SensitivitySlider : OsuSliderBar
{
- protected override LocalisableString GetTooltipText(double value) => Current.Disabled
- ? MouseSettingsStrings.EnableHighPrecisionForSensitivityAdjust
- : $"{base.GetTooltipText(value)}x";
+ public override LocalisableString TooltipText => Current.Disabled ? MouseSettingsStrings.EnableHighPrecisionForSensitivityAdjust : $"{base.TooltipText}x";
}
}
}
diff --git a/osu.Game/Overlays/Settings/Sections/SizeSlider.cs b/osu.Game/Overlays/Settings/Sections/SizeSlider.cs
index c80b330db6..8aeb440be1 100644
--- a/osu.Game/Overlays/Settings/Sections/SizeSlider.cs
+++ b/osu.Game/Overlays/Settings/Sections/SizeSlider.cs
@@ -11,6 +11,6 @@ namespace osu.Game.Overlays.Settings.Sections
///
internal class SizeSlider : OsuSliderBar
{
- protected override LocalisableString GetTooltipText(float value) => value.ToString(@"0.##x");
+ public override LocalisableString TooltipText => Current.Value.ToString(@"0.##x");
}
}
diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs
index c24513e7b4..6290046987 100644
--- a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs
@@ -64,14 +64,12 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
private class MaximumStarsSlider : StarsSlider
{
- protected override LocalisableString GetTooltipText(double value) => Current.IsDefault
- ? UserInterfaceStrings.NoLimit
- : base.GetTooltipText(value);
+ public override LocalisableString TooltipText => Current.IsDefault ? UserInterfaceStrings.NoLimit : base.TooltipText;
}
private class StarsSlider : OsuSliderBar
{
- protected override LocalisableString GetTooltipText(double value) => $"{value:0.##} stars";
+ public override LocalisableString TooltipText => Current.Value.ToString(@"0.## stars");
}
}
}
diff --git a/osu.Game/Overlays/SettingsToolboxGroup.cs b/osu.Game/Overlays/SettingsToolboxGroup.cs
index 08321f68fe..b4178359a4 100644
--- a/osu.Game/Overlays/SettingsToolboxGroup.cs
+++ b/osu.Game/Overlays/SettingsToolboxGroup.cs
@@ -22,8 +22,9 @@ namespace osu.Game.Overlays
{
public class SettingsToolboxGroup : Container, IExpandable
{
+ public const int CONTAINER_WIDTH = 270;
+
private const float transition_duration = 250;
- private const int container_width = 270;
private const int border_thickness = 2;
private const int header_height = 30;
private const int corner_radius = 5;
@@ -49,7 +50,7 @@ namespace osu.Game.Overlays
public SettingsToolboxGroup(string title)
{
AutoSizeAxes = Axes.Y;
- Width = container_width;
+ Width = CONTAINER_WIDTH;
Masking = true;
CornerRadius = corner_radius;
BorderColour = Color4.Black;
@@ -201,7 +202,5 @@ namespace osu.Game.Overlays
}
protected override Container Content => content;
-
- protected override bool OnMouseDown(MouseDownEvent e) => true;
}
}
diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs
index 44713d637d..4015d8e196 100644
--- a/osu.Game/Overlays/WikiOverlay.cs
+++ b/osu.Game/Overlays/WikiOverlay.cs
@@ -7,6 +7,7 @@ using System.Threading;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
+using osu.Game.Extensions;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
@@ -100,7 +101,12 @@ namespace osu.Game.Overlays
cancellationToken?.Cancel();
request?.Cancel();
- request = new GetWikiRequest(e.NewValue);
+ string[] values = e.NewValue.Split('/', 2);
+
+ if (values.Length > 1 && LanguageExtensions.TryParseCultureCode(values[0], out var language))
+ request = new GetWikiRequest(values[1], language);
+ else
+ request = new GetWikiRequest(e.NewValue);
Loading.Show();
diff --git a/osu.Game/Rulesets/Mods/IUpdatableByPlayfield.cs b/osu.Game/Rulesets/Mods/IUpdatableByPlayfield.cs
index 9baa252caf..7cf480a11b 100644
--- a/osu.Game/Rulesets/Mods/IUpdatableByPlayfield.cs
+++ b/osu.Game/Rulesets/Mods/IUpdatableByPlayfield.cs
@@ -5,8 +5,19 @@ using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mods
{
+ ///
+ /// An interface for s that are updated every frame by a .
+ ///
public interface IUpdatableByPlayfield : IApplicableMod
{
+ ///
+ /// Update this .
+ ///
+ /// The main
+ ///
+ /// This method is called once per frame during gameplay by the main only.
+ /// To access nested s, use .
+ ///
void Update(Playfield playfield);
}
}
diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs
index e528d8214e..1d33b44812 100644
--- a/osu.Game/Rulesets/Mods/ModMuted.cs
+++ b/osu.Game/Rulesets/Mods/ModMuted.cs
@@ -111,6 +111,6 @@ namespace osu.Game.Rulesets.Mods
public class MuteComboSlider : OsuSliderBar
{
- protected override LocalisableString GetTooltipText(int value) => value == 0 ? "always muted" : base.GetTooltipText(value);
+ public override LocalisableString TooltipText => Current.Value == 0 ? "always muted" : base.TooltipText;
}
}
diff --git a/osu.Game/Rulesets/Mods/ModNoScope.cs b/osu.Game/Rulesets/Mods/ModNoScope.cs
index c71239ea5a..7a935eb38f 100644
--- a/osu.Game/Rulesets/Mods/ModNoScope.cs
+++ b/osu.Game/Rulesets/Mods/ModNoScope.cs
@@ -57,6 +57,6 @@ namespace osu.Game.Rulesets.Mods
public class HiddenComboSlider : OsuSliderBar
{
- protected override LocalisableString GetTooltipText(int value) => value == 0 ? "always hidden" : base.GetTooltipText(value);
+ public override LocalisableString TooltipText => Current.Value == 0 ? "always hidden" : base.TooltipText;
}
}
diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs
index d0bbf859af..30e71dde1c 100644
--- a/osu.Game/Rulesets/UI/Playfield.cs
+++ b/osu.Game/Rulesets/UI/Playfield.cs
@@ -79,6 +79,11 @@ namespace osu.Game.Rulesets.UI
private readonly List nestedPlayfields = new List();
+ ///
+ /// Whether this is nested in another .
+ ///
+ public bool IsNested { get; private set; }
+
///
/// Whether judgements should be displayed by this and and all nested s.
///
@@ -206,6 +211,8 @@ namespace osu.Game.Rulesets.UI
/// The to add.
protected void AddNested(Playfield otherPlayfield)
{
+ otherPlayfield.IsNested = true;
+
otherPlayfield.DisplayJudgements.BindTo(DisplayJudgements);
otherPlayfield.NewResult += (d, r) => NewResult?.Invoke(d, r);
@@ -229,7 +236,7 @@ namespace osu.Game.Rulesets.UI
{
base.Update();
- if (mods != null)
+ if (!IsNested && mods != null)
{
foreach (var mod in mods)
{
diff --git a/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs b/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs
index 1326395695..f0ead05280 100644
--- a/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs
+++ b/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs
@@ -7,9 +7,9 @@ using System.Linq;
using System.Text;
using osu.Framework.Extensions;
using osu.Game.Beatmaps;
+using osu.Game.Extensions;
using osu.Game.IO.Legacy;
using osu.Game.Replays.Legacy;
-using osu.Game.Rulesets;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Replays.Types;
using SharpCompress.Compressors.LZMA;
@@ -48,7 +48,7 @@ namespace osu.Game.Scoring.Legacy
if (beatmap == null && !score.Replay.Frames.All(f => f is LegacyReplayFrame))
throw new ArgumentException(@"Beatmap must be provided if frames are not already legacy frames.", nameof(beatmap));
- if (score.ScoreInfo.Ruleset.OnlineID < 0 || score.ScoreInfo.Ruleset.OnlineID > ILegacyRuleset.MAX_LEGACY_RULESET_ID)
+ if (!score.ScoreInfo.Ruleset.IsLegacyRuleset())
throw new ArgumentException(@"Only scores in the osu, taiko, catch, or mania rulesets can be encoded to the legacy score format.", nameof(score));
}
diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs
index f6d63a8ec5..41eb822e39 100644
--- a/osu.Game/Screens/Play/PlayerLoader.cs
+++ b/osu.Game/Screens/Play/PlayerLoader.cs
@@ -143,6 +143,8 @@ namespace osu.Game.Screens.Play
muteWarningShownOnce = sessionStatics.GetBindable(Static.MutedAudioNotificationShownOnce);
batteryWarningShownOnce = sessionStatics.GetBindable(Static.LowBatteryNotificationShownOnce);
+ const float padding = 25;
+
InternalChildren = new Drawable[]
{
(content = new LogoTrackingContainer
@@ -158,20 +160,27 @@ namespace osu.Game.Screens.Play
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
},
- PlayerSettings = new FillFlowContainer
+ new OsuScrollContainer
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
- AutoSizeAxes = Axes.Both,
- Direction = FillDirection.Vertical,
- Spacing = new Vector2(0, 20),
- Margin = new MarginPadding(25),
- Children = new PlayerSettingsGroup[]
+ RelativeSizeAxes = Axes.Y,
+ Width = SettingsToolboxGroup.CONTAINER_WIDTH + padding * 2,
+ Padding = new MarginPadding { Vertical = padding },
+ Masking = false,
+ Child = PlayerSettings = new FillFlowContainer
{
- VisualSettings = new VisualSettings(),
- AudioSettings = new AudioSettings(),
- new InputSettings()
- }
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Vertical,
+ Spacing = new Vector2(0, 20),
+ Padding = new MarginPadding { Horizontal = padding },
+ Children = new PlayerSettingsGroup[]
+ {
+ VisualSettings = new VisualSettings(),
+ AudioSettings = new AudioSettings(),
+ new InputSettings()
+ }
+ },
},
idleTracker = new IdleTracker(750),
}),
diff --git a/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs b/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs
index 201e431367..bb8dcf566d 100644
--- a/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs
+++ b/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs
@@ -53,6 +53,7 @@ namespace osu.Game.Screens.Play.PlayerSettings
private OsuColour colours { get; set; } = null!;
private double lastPlayAverage;
+ private double lastPlayBeatmapOffset;
private SettingsButton? useAverageButton;
@@ -96,12 +97,10 @@ namespace osu.Game.Screens.Play.PlayerSettings
protected class CustomSliderBar : SliderBar
{
- protected override LocalisableString GetTooltipText(double value)
- {
- return value == 0
- ? new TranslatableString("_", @"{0} ms", base.GetTooltipText(value))
- : new TranslatableString("_", @"{0} ms {1}", base.GetTooltipText(value), getEarlyLateText(value));
- }
+ public override LocalisableString TooltipText =>
+ Current.Value == 0
+ ? new TranslatableString("_", @"{0} ms", base.TooltipText)
+ : new TranslatableString("_", @"{0} ms {1}", base.TooltipText, getEarlyLateText(Current.Value));
private LocalisableString getEarlyLateText(double value)
{
@@ -156,7 +155,7 @@ namespace osu.Game.Screens.Play.PlayerSettings
}
if (useAverageButton != null)
- useAverageButton.Enabled.Value = !Precision.AlmostEquals(lastPlayAverage, -Current.Value, Current.Precision / 2);
+ useAverageButton.Enabled.Value = !Precision.AlmostEquals(Current.Value, lastPlayBeatmapOffset - lastPlayAverage, Current.Precision / 2);
realmWriteTask = realm.WriteAsync(r =>
{
@@ -213,6 +212,7 @@ namespace osu.Game.Screens.Play.PlayerSettings
}
lastPlayAverage = average;
+ lastPlayBeatmapOffset = Current.Value;
referenceScoreContainer.AddRange(new Drawable[]
{
@@ -225,7 +225,7 @@ namespace osu.Game.Screens.Play.PlayerSettings
useAverageButton = new SettingsButton
{
Text = BeatmapOffsetControlStrings.CalibrateUsingLastPlay,
- Action = () => Current.Value = -lastPlayAverage
+ Action = () => Current.Value = lastPlayBeatmapOffset - lastPlayAverage
},
});
}
diff --git a/osu.Game/Screens/Play/SoloPlayer.cs b/osu.Game/Screens/Play/SoloPlayer.cs
index 824c0072e3..a935ce49eb 100644
--- a/osu.Game/Screens/Play/SoloPlayer.cs
+++ b/osu.Game/Screens/Play/SoloPlayer.cs
@@ -4,10 +4,10 @@
using System;
using System.Diagnostics;
using osu.Game.Beatmaps;
+using osu.Game.Extensions;
using osu.Game.Online.API;
using osu.Game.Online.Rooms;
using osu.Game.Online.Solo;
-using osu.Game.Rulesets;
using osu.Game.Scoring;
namespace osu.Game.Screens.Play
@@ -32,7 +32,7 @@ namespace osu.Game.Screens.Play
if (beatmapId <= 0)
return null;
- if (rulesetId < 0 || rulesetId > ILegacyRuleset.MAX_LEGACY_RULESET_ID)
+ if (!Ruleset.Value.IsLegacyRuleset())
return null;
return new CreateSoloScoreRequest(beatmapId, rulesetId, Game.VersionHash);
diff --git a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs
index 93885b6e02..b32b11c028 100644
--- a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs
+++ b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs
@@ -64,10 +64,22 @@ namespace osu.Game.Screens.Ranking.Statistics
// Prevent div-by-0 by enforcing a minimum bin size
binSize = Math.Max(1, binSize);
+ bool roundUp = true;
+
foreach (var e in hitEvents)
{
- int binOffset = (int)Math.Round(e.TimeOffset / binSize, MidpointRounding.AwayFromZero);
- bins[timing_distribution_centre_bin_index + binOffset]++;
+ double binOffset = e.TimeOffset / binSize;
+
+ // .NET's round midpoint handling doesn't provide a behaviour that works amazingly for display
+ // purposes here. We want midpoint rounding to roughly distribute evenly to each adjacent bucket
+ // so the easiest way is to cycle between downwards and upwards rounding as we process events.
+ if (Math.Abs(binOffset - (int)binOffset) == 0.5)
+ {
+ binOffset = (int)binOffset + Math.Sign(binOffset) * (roundUp ? 1 : 0);
+ roundUp = !roundUp;
+ }
+
+ bins[timing_distribution_centre_bin_index + (int)Math.Round(binOffset, MidpointRounding.AwayFromZero)]++;
}
int maxCount = bins.Max();
@@ -160,8 +172,6 @@ namespace osu.Game.Screens.Ranking.Statistics
RelativeSizeAxes = Axes.Both;
- Padding = new MarginPadding { Horizontal = 1 };
-
InternalChild = new Circle
{
RelativeSizeAxes = Axes.Both,
diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
index 907a2c9bda..eb0addd377 100644
--- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
+++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
@@ -11,6 +11,7 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Game.Beatmaps;
using osu.Game.Database;
+using osu.Game.Extensions;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.Leaderboards;
@@ -98,6 +99,7 @@ namespace osu.Game.Screens.Select.Leaderboards
protected override APIRequest FetchScores(CancellationToken cancellationToken)
{
var fetchBeatmapInfo = BeatmapInfo;
+ var fetchRuleset = ruleset.Value ?? fetchBeatmapInfo.Ruleset;
if (fetchBeatmapInfo == null)
{
@@ -117,9 +119,15 @@ namespace osu.Game.Screens.Select.Leaderboards
return null;
}
+ if (!fetchRuleset.IsLegacyRuleset())
+ {
+ SetErrorState(LeaderboardState.RulesetUnavailable);
+ return null;
+ }
+
if (fetchBeatmapInfo.OnlineID <= 0 || fetchBeatmapInfo.Status <= BeatmapOnlineStatus.Pending)
{
- SetErrorState(LeaderboardState.Unavailable);
+ SetErrorState(LeaderboardState.BeatmapUnavailable);
return null;
}
@@ -137,7 +145,7 @@ namespace osu.Game.Screens.Select.Leaderboards
else if (filterMods)
requestMods = mods.Value;
- var req = new GetScoresRequest(fetchBeatmapInfo, ruleset.Value ?? fetchBeatmapInfo.Ruleset, Scope, requestMods);
+ var req = new GetScoresRequest(fetchBeatmapInfo, fetchRuleset, Scope, requestMods);
req.Success += r =>
{
diff --git a/osu.Game/Skinning/Editor/SkinComponentToolbox.cs b/osu.Game/Skinning/Editor/SkinComponentToolbox.cs
index 935d2756fb..ce9afd650a 100644
--- a/osu.Game/Skinning/Editor/SkinComponentToolbox.cs
+++ b/osu.Game/Skinning/Editor/SkinComponentToolbox.cs
@@ -23,6 +23,8 @@ namespace osu.Game.Skinning.Editor
{
public class SkinComponentToolbox : ScrollingToolboxGroup
{
+ public const float WIDTH = 200;
+
public Action RequestPlacement;
private const float component_display_scale = 0.8f;
@@ -41,7 +43,7 @@ namespace osu.Game.Skinning.Editor
: base("Components", height)
{
RelativeSizeAxes = Axes.None;
- Width = 200;
+ Width = WIDTH;
}
[BackgroundDependencyLoader]
diff --git a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs
index 86854ab6ff..61c363b019 100644
--- a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs
+++ b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs
@@ -5,6 +5,7 @@ using JetBrains.Annotations;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Primitives;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Game.Graphics.Containers;
@@ -100,30 +101,14 @@ namespace osu.Game.Skinning.Editor
{
if (visibility.NewValue == Visibility.Visible)
{
- updateMasking();
- target.AllowScaling = false;
- target.RelativePositionAxes = Axes.Both;
-
- target.ScaleTo(VISIBLE_TARGET_SCALE, SkinEditor.TRANSITION_DURATION, Easing.OutQuint);
- target.MoveToX(0.095f, SkinEditor.TRANSITION_DURATION, Easing.OutQuint);
+ target.SetCustomRect(new RectangleF(0.18f, 0.1f, VISIBLE_TARGET_SCALE, VISIBLE_TARGET_SCALE), true);
}
else
{
- target.AllowScaling = true;
-
- target.ScaleTo(1, SkinEditor.TRANSITION_DURATION, Easing.OutQuint).OnComplete(_ => updateMasking());
- target.MoveToX(0f, SkinEditor.TRANSITION_DURATION, Easing.OutQuint);
+ target.SetCustomRect(null);
}
}
- private void updateMasking()
- {
- if (skinEditor == null)
- return;
-
- target.Masking = skinEditor.State.Value == Visibility.Visible;
- }
-
public void OnReleased(KeyBindingReleaseEvent e)
{
}
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 7dfd099df1..64785ab566 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -37,7 +37,7 @@
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index 80600655aa..a7bffd28b5 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -62,7 +62,7 @@
-
+