1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-18 05:39:53 +08:00

Merge branch 'master' into song-select-v2-single-items-arent-shown

This commit is contained in:
Bartłomiej Dach
2025-05-30 11:37:47 +02:00
Unverified
20 changed files with 412 additions and 217 deletions
@@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
..beatmap4.Beatmaps
];
var results = await runGrouping(GroupMode.NoGrouping, beatmapSets);
var results = await runGrouping(GroupMode.None, beatmapSets);
Assert.That(results.Select(r => r.Model).OfType<BeatmapSetInfo>(), Is.EquivalentTo(beatmapSets));
Assert.That(results.Select(r => r.Model).OfType<BeatmapInfo>(), Is.EquivalentTo(allBeatmaps));
assertTotal(results, beatmapSets.Count + allBeatmaps.Length);
@@ -130,7 +130,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
SelectedMods.SetDefault();
Config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.Title);
Config.SetValue(OsuSetting.SongSelectGroupMode, GroupMode.NoGrouping);
Config.SetValue(OsuSetting.SongSelectGroupMode, GroupMode.None);
SongSelect = null!;
});
@@ -37,7 +37,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
[Explicit]
public void TestSorting()
{
SortAndGroupBy(SortMode.Artist, GroupMode.NoGrouping);
SortAndGroupBy(SortMode.Artist, GroupMode.None);
SortAndGroupBy(SortMode.Difficulty, GroupMode.Difficulty);
SortAndGroupBy(SortMode.Artist, GroupMode.Artist);
}
@@ -55,7 +55,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
public void TestLoadingDisplay()
{
AddStep("induce slow filtering", () => Carousel.FilterDelay = 2000);
SortAndGroupBy(SortMode.Artist, GroupMode.NoGrouping);
SortAndGroupBy(SortMode.Artist, GroupMode.None);
}
[Test]
@@ -125,7 +125,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
CreateCarousel();
RemoveAllBeatmaps();
SortAndGroupBy(SortMode.Difficulty, GroupMode.NoGrouping);
SortAndGroupBy(SortMode.Difficulty, GroupMode.None);
AddBeatmaps(1, fixedDifficultiesPerSet: 1);
AddUntilStep("single item is shown", () => this.ChildrenOfType<PanelBeatmapStandalone>().Count(), () => Is.EqualTo(1));
}
@@ -243,7 +243,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
AddBeatmaps(2, 3);
WaitForDrawablePanels();
SortAndGroupBy(SortMode.Difficulty, GroupMode.NoGrouping);
SortAndGroupBy(SortMode.Difficulty, GroupMode.None);
WaitForFiltering();
AddUntilStep("standalone panels displayed", () => GetVisiblePanels<PanelBeatmapStandalone>().Any());
@@ -30,7 +30,7 @@ namespace osu.Game.Tests.Visual.UserInterface
Position = new Vector2(275, 5)
});
filter.PinItem(GroupMode.NoGrouping);
filter.PinItem(GroupMode.None);
filter.PinItem(GroupMode.LastPlayed);
filter.Current.ValueChanged += grouping =>
+1 -1
View File
@@ -47,7 +47,7 @@ namespace osu.Game.Configuration
SetDefault(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10, 0.1);
SetDefault(OsuSetting.DisplayStarsMaximum, 10.1, 0, 10.1, 0.1);
SetDefault(OsuSetting.SongSelectGroupMode, GroupMode.NoGrouping);
SetDefault(OsuSetting.SongSelectGroupMode, GroupMode.None);
SetDefault(OsuSetting.SongSelectSortingMode, SortMode.Title);
SetDefault(OsuSetting.RandomSelectAlgorithm, RandomSelectAlgorithm.RandomPermutation);
+2 -2
View File
@@ -617,13 +617,13 @@ namespace osu.Game.Graphics.Carousel
{
var item = carouselItems[i];
updateItemYPosition(item, ref lastVisible, ref yPos);
if (CheckModelEquality(item.Model, currentKeyboardSelection.Model!))
currentKeyboardSelection = new Selection(currentKeyboardSelection.Model, item, item.CarouselYPosition, i);
if (CheckModelEquality(item.Model, currentSelection.Model!))
currentSelection = new Selection(currentSelection.Model, item, item.CarouselYPosition, i);
updateItemYPosition(item, ref lastVisible, ref yPos);
}
// If a keyboard selection is currently made, we want to keep the view stable around the selection.
+10 -1
View File
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@@ -49,8 +50,13 @@ namespace osu.Game.Screens.Footer
private Container<ScreenFooterButton> hiddenButtonsContainer = null!;
private LogoTrackingContainer logoTrackingContainer = null!;
// TODO: This has some weird update logic local in this class, but it only works for overlay containers.
// This is not what we want. The footer is to be displayed on *screens* with different colour schemes.
// It needs to update on screen switch.
//
// For now it's locked to Blue to match song select (the most prominent usage).
[Cached]
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine);
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
public ScreenFooter(BackReceptor? receptor = null)
{
@@ -167,6 +173,7 @@ namespace osu.Game.Screens.Footer
temporarilyHiddenButtons.Clear();
overlays.Clear();
this.HidePopover();
clearActiveOverlayContainer();
var oldButtons = buttonsFlow.ToArray();
@@ -312,6 +319,8 @@ namespace osu.Game.Screens.Footer
private void showOverlay(OverlayContainer overlay)
{
this.HidePopover();
foreach (var o in overlays.Where(o => o != overlay))
o.Hide();
+10 -10
View File
@@ -7,8 +7,8 @@ namespace osu.Game.Screens.Select.Filter
{
public enum GroupMode
{
[Description("No Grouping")]
NoGrouping,
[Description("None")]
None,
[Description("Artist")]
Artist,
@@ -19,8 +19,8 @@ namespace osu.Game.Screens.Select.Filter
[Description("BPM")]
BPM,
[Description("Collections")]
Collections,
// [Description("Collections")]
// Collections,
[Description("Date Added")]
DateAdded,
@@ -31,17 +31,17 @@ namespace osu.Game.Screens.Select.Filter
[Description("Difficulty")]
Difficulty,
[Description("Favourites")]
Favourites,
// [Description("Favourites")]
// Favourites,
[Description("Length")]
Length,
[Description("My Maps")]
MyMaps,
// [Description("My Maps")]
// MyMaps,
[Description("Rank Achieved")]
RankAchieved,
// [Description("Rank Achieved")]
// RankAchieved,
[Description("Ranked Status")]
RankedStatus,
+19 -3
View File
@@ -60,9 +60,25 @@ namespace osu.Game.Screens.SelectV2
if ((top.Model is GroupDefinition) ^ (bottom.Model is GroupDefinition))
return SPACING * 2;
// Beatmap difficulty panels do not overlap with themselves or any other panel.
if (grouping.BeatmapSetsGroupedTogether && (top.Model is BeatmapInfo || bottom.Model is BeatmapInfo))
return SPACING;
if (grouping.BeatmapSetsGroupedTogether)
{
// Give some space around the expanded beatmap set, at the top..
if (bottom.Model is BeatmapSetInfo && bottom.IsExpanded)
return SPACING * 2;
// ..and the bottom.
if (top.Model is BeatmapInfo && bottom.Model is BeatmapSetInfo)
return SPACING * 2;
// Beatmap difficulty panels do not overlap with themselves or any other panel.
if (top.Model is BeatmapInfo || bottom.Model is BeatmapInfo)
return SPACING;
}
else
{
if (top == CurrentSelectionItem || bottom == CurrentSelectionItem)
return SPACING * 2;
}
return -SPACING;
}
@@ -139,7 +139,7 @@ namespace osu.Game.Screens.SelectV2
{
switch (criteria.Group)
{
case GroupMode.NoGrouping:
case GroupMode.None:
return new List<GroupMapping> { new GroupMapping(null, items) };
case GroupMode.Artist:
@@ -199,21 +199,19 @@ namespace osu.Game.Screens.SelectV2
return defineGroupByLength(length);
}, items);
case GroupMode.Collections:
// TODO: needs implementation
goto case GroupMode.NoGrouping;
case GroupMode.Favourites:
// TODO: needs implementation
goto case GroupMode.NoGrouping;
case GroupMode.MyMaps:
// TODO: needs implementation
goto case GroupMode.NoGrouping;
case GroupMode.RankAchieved:
// TODO: needs implementation
goto case GroupMode.NoGrouping;
// TODO: need implementation
//
// case GroupMode.Collections:
// goto case GroupMode.None;
//
// case GroupMode.Favourites:
// goto case GroupMode.None;
//
// case GroupMode.MyMaps:
// goto case GroupMode.None;
//
// case GroupMode.RankAchieved:
// goto case GroupMode.None;
default:
throw new ArgumentOutOfRangeException();
@@ -117,6 +117,15 @@ namespace osu.Game.Screens.SelectV2
private readonly bool sheared;
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos)
{
var inputRectangle = DrawRectangle;
inputRectangle = inputRectangle.Inflate(new MarginPadding { Vertical = BeatmapLeaderboardWedge.SPACING_BETWEEN_SCORES / 2 });
return inputRectangle.Contains(ToLocalSpace(screenSpacePos));
}
public BeatmapLeaderboardScore(ScoreInfo score, bool sheared = true)
{
this.score = score;
@@ -3,12 +3,15 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Extensions.PolygonExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Beatmaps;
@@ -26,11 +29,14 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Scoring;
using osu.Game.Screens.Select.Leaderboards;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Screens.SelectV2
{
public partial class BeatmapLeaderboardWedge : VisibilityContainer
{
public const float SPACING_BETWEEN_SCORES = 4;
public IBindable<BeatmapLeaderboardScope> Scope { get; } = new Bindable<BeatmapLeaderboardScope>();
public IBindable<bool> FilterBySelectedMods { get; } = new BindableBool();
@@ -254,10 +260,10 @@ namespace osu.Game.Screens.SelectV2
foreach (var d in loadedScores)
{
d.Y = (BeatmapLeaderboardScore.HEIGHT + 4f) * i;
d.Y = (BeatmapLeaderboardScore.HEIGHT + SPACING_BETWEEN_SCORES) * i;
// This is a bit of a weird one. We're already in a sheared state and don't want top-level
// shear applied, but still need the `BeatmapLeadeboardScore` to be in "sheared" mode (see ctor).
// shear applied, but still need the `BeatmapLeaderboardScore` to be in "sheared" mode (see ctor).
d.Shear = Vector2.Zero;
scoresContainer.Add(d);
@@ -350,6 +356,59 @@ namespace osu.Game.Screens.SelectV2
placeholder.FadeInFromZero(300, Easing.OutQuint);
}
#region Fade handling
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
const int height = BeatmapLeaderboardScore.HEIGHT;
float fadeBottom = (float)(scoresScroll.Current + scoresScroll.DrawHeight);
float fadeTop = (float)(scoresScroll.Current);
if (!scoresScroll.IsScrolledToStart())
fadeTop += height;
foreach (var c in scoresContainer)
{
float topY = c.ToSpaceOfOtherDrawable(Vector2.Zero, scoresContainer).Y;
float bottomY = topY + height;
bool requireBottomFade = bottomY >= fadeBottom;
bool requireTopFade = topY < fadeTop;
if (!requireBottomFade && !requireTopFade)
{
c.Colour = Color4.White;
continue;
}
if (topY > fadeBottom + height || bottomY < fadeTop - height)
{
c.Colour = Color4.Transparent;
continue;
}
if (requireBottomFade)
{
c.Colour = ColourInfo.GradientVertical(
Color4.White.Opacity(Math.Min(1 - (topY - fadeBottom) / height, 1)),
Color4.White.Opacity(Math.Min(1 - (bottomY - fadeBottom) / height, 1)));
}
else
{
Debug.Assert(requireTopFade);
c.Colour = ColourInfo.GradientVertical(
Color4.White.Opacity(Math.Min(1 - (fadeTop - topY) / height, 1)),
Color4.White.Opacity(Math.Min(1 - (fadeTop - bottomY) / height, 1)));
}
}
}
#endregion
private Placeholder? getPlaceholderFor(LeaderboardState state)
{
switch (state)
@@ -253,7 +253,7 @@ namespace osu.Game.Screens.SelectV2
mapperText.Text = beatmap.Value.Metadata.Author.Username;
}
starRatingDisplay.Current = (Bindable<StarDifficulty>)difficultyCache.GetBindableDifficulty(beatmap.Value.BeatmapInfo, cancellationSource.Token, 200);
starRatingDisplay.Current = (Bindable<StarDifficulty>)difficultyCache.GetBindableDifficulty(beatmap.Value.BeatmapInfo, cancellationSource.Token, SongSelect.SELECTION_DEBOUNCE);
updateCountStatistics(cancellationSource.Token);
updateDifficultyStatistics();
+4 -5
View File
@@ -17,7 +17,6 @@ using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Localisation;
using osu.Game.Resources.Localisation.Web;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Select;
@@ -142,9 +141,9 @@ namespace osu.Game.Screens.SelectV2
RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) },
ColumnDimensions = new[]
{
new Dimension(maxSize: 210),
new Dimension(maxSize: 180),
new Dimension(GridSizeMode.Absolute, 5),
new Dimension(maxSize: 230),
new Dimension(maxSize: 180),
new Dimension(GridSizeMode.Absolute, 5),
new Dimension(),
},
@@ -152,14 +151,14 @@ namespace osu.Game.Screens.SelectV2
{
new[]
{
sortDropdown = new ShearedDropdown<SortMode>(SortStrings.Default)
sortDropdown = new ShearedDropdown<SortMode>("Sort")
{
RelativeSizeAxes = Axes.X,
Items = Enum.GetValues<SortMode>(),
},
Empty(),
// todo: pending localisation
groupDropdown = new ShearedDropdown<GroupMode>("Group by")
groupDropdown = new ShearedDropdown<GroupMode>("Group")
{
RelativeSizeAxes = Axes.X,
Items = Enum.GetValues<GroupMode>(),
@@ -1,6 +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.
using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -20,10 +21,14 @@ namespace osu.Game.Screens.SelectV2
{
public partial class NoResultsPlaceholder : VisibilityContainer
{
public Action? RequestClearFilterText { get; init; }
private FilterCriteria? filter;
private LinkFlowContainer textFlow = null!;
private SpriteIcon icon = null!;
[Resolved]
private BeatmapManager beatmaps { get; set; } = null!;
@@ -50,8 +55,7 @@ namespace osu.Game.Screens.SelectV2
[BackgroundDependencyLoader]
private void load()
{
Width = 400;
AutoSizeAxes = Axes.Y;
RelativeSizeAxes = Axes.Both;
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
@@ -61,11 +65,13 @@ namespace osu.Game.Screens.SelectV2
new FillFlowContainer
{
Direction = FillDirection.Vertical,
RelativeSizeAxes = Axes.X,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Width = 300,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
new SpriteIcon
icon = new SpriteIcon
{
Icon = FontAwesome.Solid.Ghost,
Anchor = Anchor.TopCentre,
@@ -78,7 +84,7 @@ namespace osu.Game.Screens.SelectV2
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Font = OsuFont.Style.Title,
Text = "No beatmaps found"
Text = "No matching beatmaps"
},
textFlow = new LinkFlowContainer
{
@@ -115,6 +121,9 @@ namespace osu.Game.Screens.SelectV2
this.ScaleTo(0.9f)
.ScaleTo(1f, 1000, Easing.OutQuint);
icon.ScaleTo(new Vector2(-1, 1))
.ScaleTo(new Vector2(1, 1), 500, Easing.InOutSine);
textFlow.FadeInFromZero(800, Easing.OutQuint);
textFlow.Clear();
@@ -131,6 +140,18 @@ namespace osu.Game.Screens.SelectV2
textFlow.AddParagraph("No beatmaps match your filter criteria!");
textFlow.AddParagraph(string.Empty);
if (!string.IsNullOrEmpty(filter?.SearchText))
{
addBulletPoint();
textFlow.AddText("Try ");
textFlow.AddLink("clearing", () =>
{
RequestClearFilterText?.Invoke();
});
textFlow.AddText(" your current search criteria.");
}
if (filter?.UserStarDifficulty.HasFilter == true)
{
addBulletPoint();
+9 -11
View File
@@ -26,7 +26,7 @@ namespace osu.Game.Screens.SelectV2
{
private const float corner_radius = 10;
private const float active_x_offset = 50f;
private const float active_x_offset = 25f;
protected const float DURATION = 400;
@@ -34,7 +34,6 @@ namespace osu.Game.Screens.SelectV2
private Box backgroundBorder = null!;
private Box backgroundGradient = null!;
private Box backgroundAccentGradient = null!;
private Container backgroundLayerHorizontalPadding = null!;
private Container backgroundContainer = null!;
private Container iconContainer = null!;
@@ -61,6 +60,7 @@ namespace osu.Game.Screens.SelectV2
public Color4? AccentColour
{
get => accentColour;
set
{
accentColour = value;
@@ -123,12 +123,6 @@ namespace osu.Game.Screens.SelectV2
{
RelativeSizeAxes = Axes.Both,
},
// TODO: this is only used by beatmap panels and should NOT be in this class.
// it's wasting fill rate.
backgroundAccentGradient = new Box
{
RelativeSizeAxes = Axes.Both,
},
backgroundContainer = new Container
{
RelativeSizeAxes = Axes.Both,
@@ -243,7 +237,6 @@ namespace osu.Game.Screens.SelectV2
{
var backgroundColour = accentColour ?? Color4.White;
backgroundAccentGradient.Colour = ColourInfo.GradientHorizontal(backgroundColour.Opacity(0.25f), backgroundColour.Opacity(0f));
backgroundBorder.Colour = backgroundColour;
selectionLayer.Colour = ColourInfo.GradientHorizontal(backgroundColour.Opacity(0), backgroundColour.Opacity(0.5f));
@@ -269,10 +262,15 @@ namespace osu.Game.Screens.SelectV2
float x = PanelXOffset + corner_radius;
if (!Expanded.Value && !Selected.Value)
x += active_x_offset;
{
if (this is PanelBeatmap)
x += active_x_offset * 2;
else
x += active_x_offset * 4;
}
if (!KeyboardSelected.Value)
x += active_x_offset * 0.5f;
x += active_x_offset;
TopLevelContent.MoveToX(x, DURATION, Easing.OutQuint);
}
+114 -67
View File
@@ -7,12 +7,16 @@ using System.Diagnostics;
using System.Threading;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Carousel;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
@@ -36,10 +40,15 @@ namespace osu.Game.Screens.SelectV2
private PanelLocalRankDisplay localRank = null!;
private OsuSpriteText difficultyText = null!;
private OsuSpriteText authorText = null!;
private FillFlowContainer mainFill = null!;
private IBindable<StarDifficulty>? starDifficultyBindable;
private CancellationTokenSource? starDifficultyCancellationSource;
private Box backgroundAccentGradient = null!;
private TrianglesV2 triangles = null!;
[Resolved]
private OverlayColourProvider colourProvider { get; set; } = null!;
@@ -58,6 +67,11 @@ namespace osu.Game.Screens.SelectV2
[Resolved]
private ISongSelect? songSelect { get; set; }
public PanelBeatmap()
{
PanelXOffset = 60;
}
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos)
{
var inputRectangle = TopLevelContent.DrawRectangle;
@@ -78,80 +92,108 @@ namespace osu.Game.Screens.SelectV2
Icon = difficultyIcon = new ConstrainedIconContainer
{
Size = new Vector2(16f),
Margin = new MarginPadding { Horizontal = 5f },
Size = new Vector2(9f),
Margin = new MarginPadding { Left = 2.5f, Right = 1.5f },
Colour = colourProvider.Background5,
};
Content.Children = new[]
Background = new Container
{
new FillFlowContainer
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Padding = new MarginPadding { Left = 10f },
Direction = FillDirection.Vertical,
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
backgroundAccentGradient = new Box
{
new FillFlowContainer
RelativeSizeAxes = Axes.Both,
},
triangles = new TrianglesV2
{
ScaleAdjust = 1.2f,
Thickness = 0.01f,
Velocity = 0.3f,
RelativeSizeAxes = Axes.Both,
},
}
};
Content.Child = new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Spacing = new Vector2(3),
Margin = new MarginPadding { Left = 5 },
Direction = FillDirection.Horizontal,
Children = new Drawable[]
{
localRank = new PanelLocalRankDisplay
{
Scale = new Vector2(0.8f),
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
},
mainFill = new FillFlowContainer
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Direction = FillDirection.Vertical,
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
Direction = FillDirection.Horizontal,
Spacing = new Vector2(3, 0),
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
new FillFlowContainer
{
localRank = new PanelLocalRankDisplay
Direction = FillDirection.Horizontal,
AutoSizeAxes = Axes.Both,
Padding = new MarginPadding { Bottom = 4 },
Children = new Drawable[]
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Scale = new Vector2(0.65f)
},
starRatingDisplay = new StarRatingDisplay(default, StarRatingDisplaySize.Small, animated: true)
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Scale = new Vector2(0.875f),
},
starCounter = new StarCounter
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Scale = new Vector2(0.4f)
keyCountText = new OsuSpriteText
{
Font = OsuFont.Style.Body.With(weight: FontWeight.SemiBold),
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Alpha = 0,
},
difficultyText = new OsuSpriteText
{
Font = OsuFont.Style.Body.With(weight: FontWeight.SemiBold),
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Margin = new MarginPadding { Right = 3f },
},
authorText = new OsuSpriteText
{
Colour = colourProvider.Content2,
Font = OsuFont.Style.Caption1.With(weight: FontWeight.SemiBold),
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft
}
}
}
},
new FillFlowContainer
{
Direction = FillDirection.Horizontal,
AutoSizeAxes = Axes.Both,
Children = new[]
},
new FillFlowContainer
{
keyCountText = new OsuSpriteText
Direction = FillDirection.Horizontal,
Spacing = new Vector2(3),
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
Font = OsuFont.Style.Body.With(weight: FontWeight.SemiBold),
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Alpha = 0,
starRatingDisplay = new StarRatingDisplay(default, StarRatingDisplaySize.Small, animated: true)
{
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
Scale = new Vector2(0.875f),
},
starCounter = new StarCounter
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Scale = new Vector2(0.4f)
}
},
difficultyText = new OsuSpriteText
{
Font = OsuFont.Style.Body.With(weight: FontWeight.SemiBold),
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Margin = new MarginPadding { Right = 3f },
},
authorText = new OsuSpriteText
{
Colour = colourProvider.Content2,
Font = OsuFont.Style.Caption1.With(weight: FontWeight.SemiBold),
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft
}
}
}
}
},
}
};
}
@@ -210,12 +252,10 @@ namespace osu.Game.Screens.SelectV2
var beatmap = (BeatmapInfo)Item.Model;
starDifficultyBindable = difficultyCache.GetBindableDifficulty(beatmap, starDifficultyCancellationSource.Token, SongSelect.SELECTION_DEBOUNCE);
starDifficultyBindable.BindValueChanged(_ =>
starDifficultyBindable.BindValueChanged(starDifficulty =>
{
var starDifficulty = starDifficultyBindable?.Value ?? default;
starRatingDisplay.Current.Value = starDifficulty;
starCounter.Current = (float)starDifficulty.Stars;
starRatingDisplay.Current.Value = starDifficulty.NewValue;
starCounter.Current = (float)starDifficulty.NewValue.Stars;
}, true);
}
@@ -231,14 +271,21 @@ namespace osu.Game.Screens.SelectV2
// Dirty hack to make sure we don't take up spacing in parent fill flow when not displaying a rank.
// I can't find a better way to do this.
starRatingDisplay.Margin = new MarginPadding { Left = 1 / starRatingDisplay.Scale.X * (localRank.HasRank ? 0 : -3) };
mainFill.Margin = new MarginPadding { Left = 1 / starRatingDisplay.Scale.X * (localRank.HasRank ? 0 : -3) };
var diffColour = starRatingDisplay.DisplayedDifficultyColour;
AccentColour = diffColour;
starCounter.Colour = diffColour;
if (AccentColour != diffColour)
{
AccentColour = diffColour;
starCounter.Colour = diffColour;
difficultyIcon.Colour = starRatingDisplay.DisplayedStars.Value > OsuColour.STAR_DIFFICULTY_DEFINED_COLOUR_CUTOFF ? colours.Orange1 : colourProvider.Background5;
backgroundAccentGradient.Colour = ColourInfo.GradientHorizontal(diffColour.Opacity(0.25f), diffColour.Opacity(0f));
difficultyIcon.Colour = starRatingDisplay.DisplayedStars.Value > OsuColour.STAR_DIFFICULTY_DEFINED_COLOUR_CUTOFF ? colours.Orange1 : colourProvider.Background5;
triangles.Colour = ColourInfo.GradientVertical(diffColour.Opacity(0.25f), diffColour.Opacity(0f));
}
}
private void updateKeyCount()
@@ -63,13 +63,29 @@ namespace osu.Game.Screens.SelectV2
private BeatmapSetOnlineStatusPill statusPill = null!;
private ConstrainedIconContainer difficultyIcon = null!;
private FillFlowContainer difficultyLine = null!;
private StarRatingDisplay starRatingDisplay = null!;
private StarCounter starCounter = null!;
private PanelLocalRankDisplay localRank = null!;
private OsuSpriteText keyCountText = null!;
private OsuSpriteText difficultyText = null!;
private OsuSpriteText authorText = null!;
private FillFlowContainer mainFill = null!;
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos)
{
var inputRectangle = TopLevelContent.DrawRectangle;
if (Selected.Value)
{
// Cover the gaps introduced by the spacing between BeatmapPanels so that clicks will not fall through the carousel.
//
// Caveat is that for simplicity, we are covering the full spacing, so panels with frontmost depth will have a slightly
// larger hit target.
inputRectangle = inputRectangle.Inflate(new MarginPadding { Vertical = BeatmapCarousel.SPACING * 2 });
}
return inputRectangle.Contains(TopLevelContent.ToLocalSpace(screenSpacePos));
}
public PanelBeatmapStandalone()
{
@@ -83,8 +99,8 @@ namespace osu.Game.Screens.SelectV2
Icon = difficultyIcon = new ConstrainedIconContainer
{
Size = new Vector2(16),
Margin = new MarginPadding { Horizontal = 5f },
Size = new Vector2(12),
Margin = new MarginPadding { Left = 4f, Right = 3f },
Colour = colourProvider.Background5,
};
@@ -95,93 +111,105 @@ namespace osu.Game.Screens.SelectV2
Content.Child = new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Padding = new MarginPadding { Left = 10f },
Direction = FillDirection.Vertical,
AutoSizeAxes = Axes.Both,
Spacing = new Vector2(3),
Margin = new MarginPadding { Left = 5 },
Direction = FillDirection.Horizontal,
Children = new Drawable[]
{
titleText = new OsuSpriteText
localRank = new PanelLocalRankDisplay
{
Font = OsuFont.Style.Heading2.With(typeface: Typeface.TorusAlternate, weight: FontWeight.Bold),
Scale = new Vector2(0.8f),
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
},
artistText = new OsuSpriteText
mainFill = new FillFlowContainer
{
Font = OsuFont.Style.Caption1.With(weight: FontWeight.SemiBold),
Padding = new MarginPadding { Top = -2 },
},
difficultyLine = new FillFlowContainer
{
Direction = FillDirection.Horizontal,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Direction = FillDirection.Vertical,
Padding = new MarginPadding { Bottom = 2 },
AutoSizeAxes = Axes.Both,
Padding = new MarginPadding { Top = 4 },
Children = new Drawable[]
{
statusPill = new BeatmapSetOnlineStatusPill
titleText = new OsuSpriteText
{
Animated = false,
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
TextSize = OsuFont.Style.Caption2.Size,
Margin = new MarginPadding { Right = 5f },
Font = OsuFont.Style.Heading2.With(typeface: Typeface.TorusAlternate, weight: FontWeight.Bold),
},
updateButton = new PanelUpdateBeatmapButton
artistText = new OsuSpriteText
{
Scale = new Vector2(0.7f),
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Margin = new MarginPadding { Right = 5f, Top = -2f },
},
keyCountText = new OsuSpriteText
{
Font = OsuFont.Style.Body.With(weight: FontWeight.SemiBold),
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Alpha = 0,
},
difficultyText = new OsuSpriteText
{
Font = OsuFont.Style.Body.With(weight: FontWeight.SemiBold),
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Margin = new MarginPadding { Right = 3f },
},
authorText = new OsuSpriteText
{
Colour = colourProvider.Content2,
Font = OsuFont.Style.Caption1.With(weight: FontWeight.SemiBold),
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft
Padding = new MarginPadding { Top = -2 },
},
new FillFlowContainer
{
Direction = FillDirection.Horizontal,
AutoSizeAxes = Axes.Both,
Padding = new MarginPadding { Top = 2, Bottom = 2 },
Children = new Drawable[]
{
statusPill = new BeatmapSetOnlineStatusPill
{
Animated = false,
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
TextSize = OsuFont.Style.Caption2.Size,
Margin = new MarginPadding { Right = 4f },
},
updateButton = new PanelUpdateBeatmapButton
{
Scale = new Vector2(0.8f),
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Margin = new MarginPadding { Right = 4f, Bottom = -1f },
},
keyCountText = new OsuSpriteText
{
Font = OsuFont.Style.Body.With(weight: FontWeight.SemiBold),
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Alpha = 0,
},
difficultyText = new OsuSpriteText
{
Font = OsuFont.Style.Body.With(weight: FontWeight.SemiBold),
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Margin = new MarginPadding { Right = 3f },
},
authorText = new OsuSpriteText
{
Colour = colourProvider.Content2,
Font = OsuFont.Style.Caption1.With(weight: FontWeight.SemiBold),
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft
}
}
},
new FillFlowContainer
{
Direction = FillDirection.Horizontal,
Spacing = new Vector2(3),
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
starRatingDisplay = new StarRatingDisplay(default, StarRatingDisplaySize.Small, animated: true)
{
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
Scale = new Vector2(0.875f),
},
starCounter = new StarCounter
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Scale = new Vector2(0.4f)
}
},
}
}
},
new FillFlowContainer
{
Direction = FillDirection.Horizontal,
Spacing = new Vector2(3),
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
localRank = new PanelLocalRankDisplay
{
Scale = new Vector2(0.65f),
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
},
starRatingDisplay = new StarRatingDisplay(default, StarRatingDisplaySize.Small, animated: true)
{
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
Scale = new Vector2(0.875f),
},
starCounter = new StarCounter
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Scale = new Vector2(0.4f)
}
},
}
}
};
@@ -229,9 +257,9 @@ namespace osu.Game.Screens.SelectV2
localRank.Beatmap = beatmap;
difficultyText.Text = beatmap.DifficultyName;
authorText.Text = BeatmapsetsStrings.ShowDetailsMappedBy(beatmap.Metadata.Author.Username);
difficultyLine.Show();
computeStarRating();
updateKeyCount();
}
protected override void FreeAfterUse()
@@ -257,12 +285,10 @@ namespace osu.Game.Screens.SelectV2
var beatmap = (BeatmapInfo)Item.Model;
starDifficultyBindable = difficultyCache.GetBindableDifficulty(beatmap, starDifficultyCancellationSource.Token, SongSelect.SELECTION_DEBOUNCE);
starDifficultyBindable.BindValueChanged(_ =>
starDifficultyBindable.BindValueChanged(starDifficulty =>
{
var starDifficulty = starDifficultyBindable?.Value ?? default;
starRatingDisplay.Current.Value = starDifficulty;
starCounter.Current = (float)starDifficulty.Stars;
starRatingDisplay.Current.Value = starDifficulty.NewValue;
starCounter.Current = (float)starDifficulty.NewValue.Stars;
}, true);
}
@@ -278,7 +304,7 @@ namespace osu.Game.Screens.SelectV2
// Dirty hack to make sure we don't take up spacing in parent fill flow when not displaying a rank.
// I can't find a better way to do this.
starRatingDisplay.Margin = new MarginPadding { Left = 1 / starRatingDisplay.Scale.X * (localRank.HasRank ? 0 : -3) };
mainFill.Margin = new MarginPadding { Left = 1 / starRatingDisplay.Scale.X * (localRank.HasRank ? 0 : -3) };
var diffColour = starRatingDisplay.DisplayedDifficultyColour;
+18 -5
View File
@@ -71,15 +71,20 @@ namespace osu.Game.Screens.SelectV2
/// </summary>
protected bool ControlGlobalMusic { get; init; } = true;
private readonly ModSelectOverlay modSelectOverlay = new UserModSelectOverlay(OverlayColourScheme.Aquamarine)
// Colour scheme for mod overlay is left as default (green) to match mods button.
// Not sure about this, but we'll iterate based on feedback.
private readonly ModSelectOverlay modSelectOverlay = new UserModSelectOverlay
{
ShowPresets = true,
};
private ModSpeedHotkeyHandler modSpeedHotkeyHandler = null!;
// Blue is the most neutral choice, so I'm using that for now.
// Purple makes the most sense to match the "gameplay" flow, but it's a bit too strong for the current design.
// TODO: Colour scheme choice should probably be customisable by the user.
[Cached]
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine);
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
private BeatmapCarousel carousel = null!;
@@ -149,7 +154,7 @@ namespace osu.Game.Screens.SelectV2
{
new Dimension(GridSizeMode.Relative, 0.5f, maxSize: 660),
new Dimension(),
new Dimension(GridSizeMode.Relative, 0.5f, maxSize: 580),
new Dimension(GridSizeMode.Relative, 0.5f, maxSize: 620),
},
Content = new[]
{
@@ -197,8 +202,13 @@ namespace osu.Game.Screens.SelectV2
new Container
{
RelativeSizeAxes = Axes.Both,
Children = new CompositeDrawable[]
Children = new Drawable[]
{
new Box
{
Colour = ColourInfo.GradientHorizontal(Color4.Black.Opacity(0.0f), Color4.Black.Opacity(0.5f)),
RelativeSizeAxes = Axes.Both,
},
new Container
{
RelativeSizeAxes = Axes.Both,
@@ -219,7 +229,10 @@ namespace osu.Game.Screens.SelectV2
RequestRecommendedSelection = selectRecommendedBeatmap,
NewItemsPresented = newItemsPresented,
},
noResultsPlaceholder = new NoResultsPlaceholder(),
noResultsPlaceholder = new NoResultsPlaceholder
{
RequestClearFilterText = () => filterControl.Search(string.Empty)
}
}
},
filterControl = new FilterControl