diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedgeV2.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedgeV2.cs new file mode 100644 index 0000000000..98e9d803ca --- /dev/null +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedgeV2.cs @@ -0,0 +1,187 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + +using System.Collections.Generic; +using JetBrains.Annotations; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Legacy; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Screens.Select; +using osuTK; + +namespace osu.Game.Tests.Visual.SongSelect +{ + [TestFixture] + public partial class TestSceneBeatmapInfoWedgeV2 : OsuTestScene + { + private RulesetStore rulesets; + private TestBeatmapInfoWedgeV2 infoWedge; + private readonly List beatmaps = new List(); + + [BackgroundDependencyLoader] + private void load(RulesetStore rulesets) + { + this.rulesets = rulesets; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Add(infoWedge = new TestBeatmapInfoWedgeV2 + { + Size = new Vector2(0.6f, 120), + RelativeSizeAxes = Axes.X, + Margin = new MarginPadding { Top = 20 } + }); + + AddStep("show", () => infoWedge.Show()); + + selectBeatmap(Beatmap.Value.Beatmap); + + AddWaitStep("wait for select", 3); + + AddStep("hide", () => { infoWedge.Hide(); }); + + AddWaitStep("wait for hide", 3); + + AddStep("show", () => { infoWedge.Show(); }); + + AddSliderStep("change star difficulty", 0, 11.9, 5.55, v => + { + foreach (var hasCurrentValue in infoWedge.Info.ChildrenOfType>()) + hasCurrentValue.Current.Value = new StarDifficulty(v, 0); + }); + + foreach (var rulesetInfo in rulesets.AvailableRulesets) + { + var instance = rulesetInfo.CreateInstance(); + var testBeatmap = createTestBeatmap(rulesetInfo); + + beatmaps.Add(testBeatmap); + + setRuleset(rulesetInfo); + + selectBeatmap(testBeatmap); + + testBeatmapLabels(instance); + } + } + + private void testBeatmapLabels(Ruleset ruleset) + { + AddAssert("check title", () => infoWedge.Info.TitleLabel.Current.Value == $"{ruleset.ShortName}Title"); + AddAssert("check artist", () => infoWedge.Info.ArtistLabel.Current.Value == $"{ruleset.ShortName}Artist"); + } + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("reset mods", () => SelectedMods.SetDefault()); + } + + [Test] + public void TestTruncation() + { + selectBeatmap(createLongMetadata()); + } + + private void setRuleset(RulesetInfo rulesetInfo) + { + Container containerBefore = null; + + AddStep("set ruleset", () => + { + // wedge content is only refreshed if the ruleset changes, so only wait for load in that case. + if (!rulesetInfo.Equals(Ruleset.Value)) + containerBefore = infoWedge.DisplayedContent; + + Ruleset.Value = rulesetInfo; + }); + + AddUntilStep("wait for async load", () => infoWedge.DisplayedContent != containerBefore); + } + + private void selectBeatmap([CanBeNull] IBeatmap b) + { + Container containerBefore = null; + + AddStep($"select {b?.Metadata.Title ?? "null"} beatmap", () => + { + containerBefore = infoWedge.DisplayedContent; + infoWedge.Beatmap = Beatmap.Value = b == null ? Beatmap.Default : CreateWorkingBeatmap(b); + }); + + AddUntilStep("wait for async load", () => infoWedge.DisplayedContent != containerBefore); + } + + private IBeatmap createTestBeatmap(RulesetInfo ruleset) + { + List objects = new List(); + for (double i = 0; i < 50000; i += 1000) + objects.Add(new TestHitObject { StartTime = i }); + + return new Beatmap + { + BeatmapInfo = new BeatmapInfo + { + Metadata = new BeatmapMetadata + { + Author = { Username = $"{ruleset.ShortName}Author" }, + Artist = $"{ruleset.ShortName}Artist", + Source = $"{ruleset.ShortName}Source", + Title = $"{ruleset.ShortName}Title" + }, + Ruleset = ruleset, + StarRating = 6, + DifficultyName = $"{ruleset.ShortName}Version", + Difficulty = new BeatmapDifficulty() + }, + HitObjects = objects + }; + } + + private IBeatmap createLongMetadata() + { + return new Beatmap + { + BeatmapInfo = new BeatmapInfo + { + Metadata = new BeatmapMetadata + { + Author = { Username = "WWWWWWWWWWWWWWW" }, + Artist = "Verrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrry long Artist", + Source = "Verrrrry long Source", + Title = "Verrrrry long Title" + }, + DifficultyName = "Verrrrrrrrrrrrrrrrrrrrrrrrrrrrry long Version", + Status = BeatmapOnlineStatus.Graveyard, + }, + }; + } + + private partial class TestBeatmapInfoWedgeV2 : BeatmapInfoWedgeV2 + { + public new Container DisplayedContent => base.DisplayedContent; + + public new WedgeInfoText Info => base.Info; + } + + private class TestHitObject : ConvertHitObject, IHasPosition + { + public float X => 0; + public float Y => 0; + public Vector2 Position { get; } = Vector2.Zero; + } + } +} diff --git a/osu.Game/Screens/Select/BeatmapInfoWedgeV2.cs b/osu.Game/Screens/Select/BeatmapInfoWedgeV2.cs index 104fa8787b..5583ad11f7 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedgeV2.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedgeV2.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Threading; using osuTK; -using osuTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -16,18 +15,16 @@ using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Effects; using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; -using osu.Game.Graphics.Containers; namespace osu.Game.Screens.Select { + [Cached] public partial class BeatmapInfoWedgeV2 : VisibilityContainer { - public const float BORDER_THICKNESS = 2.5f; private const float shear_width = 36.75f; private const float transition_duration = 250; @@ -44,22 +41,25 @@ namespace osu.Game.Screens.Select protected WedgeInfoText Info { get; private set; } - private IBindable starDifficulty; + private IBindable starDifficulty = new Bindable(); private CancellationTokenSource cancellationSource; + private readonly Container difficultyColourBar; + public BeatmapInfoWedgeV2() { + CornerRadius = 10; Shear = wedged_container_shear; Masking = true; - BorderColour = new Color4(221, 255, 255, 255); - BorderThickness = BORDER_THICKNESS; Alpha = 0; - EdgeEffect = new EdgeEffectParameters + Child = difficultyColourBar = new Container { - Type = EdgeEffectType.Glow, - Colour = new Color4(130, 204, 255, 150), - Radius = 20, - Roundness = 15, + Depth = float.MaxValue, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + RelativeSizeAxes = Axes.Y, + Width = 40, + Child = new Box { RelativeSizeAxes = Axes.Both } }; } @@ -95,6 +95,7 @@ namespace osu.Game.Screens.Select if (beatmap == value) return; beatmap = value; + starDifficulty = difficultyCache.GetBindableDifficulty(value.BeatmapInfo, (cancellationSource = new CancellationTokenSource()).Token); updateDisplay(); } @@ -104,12 +105,6 @@ namespace osu.Game.Screens.Select private Container loadingInfo; - protected override void LoadComplete() - { - base.LoadComplete(); - starDifficulty = difficultyCache.GetBindableDifficulty(beatmap.BeatmapInfo, (cancellationSource = new CancellationTokenSource()).Token); - } - protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); @@ -140,13 +135,15 @@ namespace osu.Game.Screens.Select LoadComponentAsync(loadingInfo = new Container { + Masking = true, + X = -30, + CornerRadius = 10, RelativeSizeAxes = Axes.Both, - Shear = -Shear, Depth = DisplayedContent?.Depth + 1 ?? 0, Children = new Drawable[] { - new BeatmapInfoWedgeBackground(beatmap), - Info = new WedgeInfoText(beatmap, starDifficulty), + new BeatmapInfoWedgeBackground(beatmap) { Shear = -Shear }, + Info = new WedgeInfoText(beatmap, starDifficulty) { Shear = -Shear } } }, loaded => { @@ -161,12 +158,9 @@ namespace osu.Game.Screens.Select public partial class WedgeInfoText : Container { - public OsuSpriteText VersionLabel { get; private set; } public OsuSpriteText TitleLabel { get; private set; } public OsuSpriteText ArtistLabel { get; private set; } - public FillFlowContainer MapperContainer { get; private set; } - private Container difficultyColourBar; private StarRatingDisplay starRatingDisplay; private ILocalisedBindableString titleBinding; @@ -178,6 +172,9 @@ namespace osu.Game.Screens.Select [Resolved] private IBindable> mods { get; set; } + [Resolved] + private BeatmapInfoWedgeV2 wedge { get; set; } + [Resolved] private OsuColour colours { get; set; } @@ -200,51 +197,8 @@ namespace osu.Game.Screens.Select titleBinding = localisation.GetLocalisedBindableString(new RomanisableString(metadata.TitleUnicode, metadata.Title)); artistBinding = localisation.GetLocalisedBindableString(new RomanisableString(metadata.ArtistUnicode, metadata.Artist)); - const float top_height = 0.7f; - Children = new Drawable[] { - difficultyColourBar = new Container - { - RelativeSizeAxes = Axes.Y, - Width = 20f, - Children = new[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Width = top_height, - }, - new Box - { - RelativeSizeAxes = Axes.Both, - RelativePositionAxes = Axes.Both, - Alpha = 0.5f, - X = top_height, - Width = 1 - top_height, - } - } - }, - new FillFlowContainer - { - Name = "Topleft-aligned metadata", - Anchor = Anchor.TopLeft, - Origin = Anchor.TopLeft, - Direction = FillDirection.Vertical, - Padding = new MarginPadding { Top = 10, Left = 25, Right = shear_width * 2.5f }, - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Children = new Drawable[] - { - VersionLabel = new OsuSpriteText - { - Text = beatmapInfo.DifficultyName, - Font = OsuFont.GetFont(size: 24, italics: true), - RelativeSizeAxes = Axes.X, - Truncate = true, - }, - } - }, new FillFlowContainer { Name = "Topright-aligned metadata", @@ -279,12 +233,10 @@ namespace osu.Game.Screens.Select }, new FillFlowContainer { - Name = "Centre-aligned metadata", - Anchor = Anchor.CentreLeft, - Origin = Anchor.TopLeft, - Y = -7, + Name = "Top-left aligned metadata", Direction = FillDirection.Vertical, - Padding = new MarginPadding { Left = 25, Right = shear_width }, + Position = new Vector2(50, 12), + Width = .8f, AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, Children = new Drawable[] @@ -292,23 +244,17 @@ namespace osu.Game.Screens.Select TitleLabel = new OsuSpriteText { Current = { BindTarget = titleBinding }, - Font = OsuFont.GetFont(size: 28, italics: true), + Font = OsuFont.TorusAlternate.With(size: 40, weight: FontWeight.SemiBold), RelativeSizeAxes = Axes.X, - Truncate = true, + Truncate = true }, ArtistLabel = new OsuSpriteText { Current = { BindTarget = artistBinding }, - Font = OsuFont.GetFont(size: 17, italics: true), + //Not sure if this should be semi bold or medium + Font = OsuFont.Torus.With(size: 20, weight: FontWeight.SemiBold), RelativeSizeAxes = Axes.X, - Truncate = true, - }, - MapperContainer = new FillFlowContainer - { - Margin = new MarginPadding { Top = 10 }, - Direction = FillDirection.Horizontal, - AutoSizeAxes = Axes.Both, - Child = getMapper(metadata), + Truncate = true } } } @@ -321,9 +267,8 @@ namespace osu.Game.Screens.Select starRatingDisplay.DisplayedStars.BindValueChanged(s => { - difficultyColourBar.Colour = colours.ForStarDifficulty(s.NewValue); + wedge.difficultyColourBar.FadeColour(colours.ForStarDifficulty(s.NewValue)); }, true); - starDifficulty.BindValueChanged(s => { starRatingDisplay.Current.Value = s.NewValue ?? default; @@ -343,22 +288,6 @@ namespace osu.Game.Screens.Select }, true); } - private Drawable getMapper(BeatmapMetadata metadata) - { - if (string.IsNullOrEmpty(metadata.Author.Username)) - return Empty(); - - return new LinkFlowContainer(s => - { - s.Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 15); - }).With(d => - { - d.AutoSizeAxes = Axes.Both; - d.AddText("mapped by "); - d.AddUserLink(metadata.Author); - }); - } - protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing);