1
0
mirror of https://github.com/ppy/osu.git synced 2026-06-05 19:36:03 +08:00

Merge pull request #35429 from bdach/scrolling-song-select-wedge-text

Scroll song select title wedge text if it overflows
This commit is contained in:
Dean Herbert
2025-10-24 21:40:03 +09:00
committed by GitHub
Unverified
4 changed files with 78 additions and 36 deletions
+44 -9
View File
@@ -3,8 +3,10 @@
using System;
using osu.Framework.Allocation;
using osu.Framework.Caching;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Layout;
using osuTK;
namespace osu.Game.Overlays
@@ -21,7 +23,7 @@ namespace osu.Game.Overlays
set
{
allowScrolling = value;
ScheduleAfterChildren(updateScrolling);
scrollCached.Invalidate();
}
}
@@ -49,15 +51,27 @@ namespace osu.Game.Overlays
private Func<Drawable>? createContent;
public new MarginPadding Padding
{
get => base.Padding;
set => base.Padding = value;
}
public float OverflowSpacing { get; init; } = 15;
private const float pixels_per_second = 50;
private const float padding = 15;
private Drawable mainContent = null!;
private Drawable fillerContent = null!;
private FillFlowContainer flow = null!;
private readonly Cached scrollCached = new Cached();
private readonly LayoutValue drawSizeLayout = new LayoutValue(Invalidation.DrawSize);
public MarqueeContainer()
{
AddLayout(drawSizeLayout);
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
}
@@ -65,14 +79,14 @@ namespace osu.Game.Overlays
[BackgroundDependencyLoader]
private void load()
{
InternalChild = flow = new FillFlowContainer
InternalChild = flow = new MarqueeFlow
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Anchor = NonOverflowingContentAnchor,
Origin = NonOverflowingContentAnchor,
Spacing = new Vector2(padding),
Padding = new MarginPadding { Horizontal = padding },
Spacing = new Vector2(OverflowSpacing),
OnRequiredParentSizeInvalidated = () => scrollCached.Invalidate(),
};
}
@@ -92,12 +106,17 @@ namespace osu.Game.Overlays
flow.Add(mainContent = createContent());
flow.Add(fillerContent = createContent().With(d => d.Alpha = 0));
ScheduleAfterChildren(updateScrolling);
scrollCached.Invalidate();
}
private void updateScrolling()
protected override void UpdateAfterChildren()
{
float overflowWidth = mainContent.DrawWidth + padding - DrawWidth;
base.UpdateAfterChildren();
if (scrollCached.IsValid && drawSizeLayout.IsValid)
return;
float overflowWidth = mainContent.DrawWidth - DrawWidth;
if (overflowWidth > 0 && AllowScrolling)
{
@@ -105,7 +124,7 @@ namespace osu.Game.Overlays
flow.Anchor = Anchor.TopLeft;
flow.Origin = Anchor.TopLeft;
float targetX = mainContent.DrawWidth + padding;
float targetX = mainContent.DrawWidth + OverflowSpacing;
flow.MoveToX(0)
.Delay(InitialMoveDelay)
@@ -120,6 +139,22 @@ namespace osu.Game.Overlays
flow.Anchor = NonOverflowingContentAnchor;
flow.Origin = NonOverflowingContentAnchor;
}
scrollCached.Validate();
drawSizeLayout.Validate();
}
private partial class MarqueeFlow : FillFlowContainer
{
public required Action OnRequiredParentSizeInvalidated { get; init; }
protected override bool OnInvalidate(Invalidation invalidation, InvalidationSource source)
{
if (invalidation.HasFlag(Invalidation.RequiredParentSizeToFit))
OnRequiredParentSizeInvalidated.Invoke();
return base.OnInvalidate(invalidation, source);
}
}
}
}
+1
View File
@@ -49,6 +49,7 @@ namespace osu.Game.Overlays.Music
RelativeSizeAxes = Axes.X,
InitialMoveDelay = 0,
AllowScrolling = false,
Padding = new MarginPadding { Horizontal = 15 },
};
selectedSet.BindTo(playlistOverlay.SelectedSet);
+2
View File
@@ -121,6 +121,7 @@ namespace osu.Game.Overlays
Origin = Anchor.Centre,
},
NonOverflowingContentAnchor = Anchor.Centre,
Padding = new MarginPadding { Horizontal = 15 },
},
artist = new MarqueeContainer
{
@@ -136,6 +137,7 @@ namespace osu.Game.Overlays
Origin = Anchor.Centre,
},
NonOverflowingContentAnchor = Anchor.Centre,
Padding = new MarginPadding { Horizontal = 15 },
},
new Container
{
+31 -27
View File
@@ -20,6 +20,7 @@ using osu.Game.Extensions;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Overlays;
using osu.Game.Resources.Localisation.Web;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
@@ -49,15 +50,13 @@ namespace osu.Game.Screens.SelectV2
private ModSettingChangeTracker? settingChangeTracker;
private BeatmapSetOnlineStatusPill statusPill = null!;
private Container titleContainer = null!;
private OsuHoverContainer titleLink = null!;
private OsuSpriteText titleLabel = null!;
private Container artistContainer = null!;
private MarqueeContainer titleLabel = null!;
private OsuHoverContainer artistLink = null!;
private OsuSpriteText artistLabel = null!;
private MarqueeContainer artistLabel = null!;
internal string DisplayedTitle => titleLabel.Text.ToString();
internal string DisplayedArtist => artistLabel.Text.ToString();
internal string DisplayedTitle { get; private set; } = string.Empty;
internal string DisplayedArtist { get; private set; } = string.Empty;
private StatisticPlayCount playCount = null!;
private FavouriteButton favouriteButton = null!;
@@ -110,7 +109,7 @@ namespace osu.Game.Screens.SelectV2
TextSize = OsuFont.Style.Caption1.Size,
TextPadding = new MarginPadding { Horizontal = 6, Vertical = 1 },
}),
new ShearAligningWrapper(titleContainer = new Container
new ShearAligningWrapper(new Container
{
Shear = -OsuGame.SHEAR,
RelativeSizeAxes = Axes.X,
@@ -118,15 +117,15 @@ namespace osu.Game.Screens.SelectV2
Margin = new MarginPadding { Bottom = -4f },
Child = titleLink = new OsuHoverContainer
{
AutoSizeAxes = Axes.Both,
Child = titleLabel = new TruncatingSpriteText
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Child = titleLabel = new MarqueeContainer
{
Shadow = true,
Font = OsuFont.Style.Title,
},
OverflowSpacing = 50,
}
}
}),
new ShearAligningWrapper(artistContainer = new Container
new ShearAligningWrapper(new Container
{
Shear = -OsuGame.SHEAR,
RelativeSizeAxes = Axes.X,
@@ -134,12 +133,12 @@ namespace osu.Game.Screens.SelectV2
Margin = new MarginPadding { Left = 1f },
Child = artistLink = new OsuHoverContainer
{
AutoSizeAxes = Axes.Both,
Child = artistLabel = new TruncatingSpriteText
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Child = artistLabel = new MarqueeContainer
{
Shadow = true,
Font = OsuFont.Style.Heading2,
},
OverflowSpacing = 50,
}
}
}),
new ShearAligningWrapper(statisticsFlow = new FillFlowContainer
@@ -214,13 +213,6 @@ namespace osu.Game.Screens.SelectV2
.FadeOut(SongSelect.ENTER_DURATION / 3, Easing.In);
}
protected override void Update()
{
base.Update();
titleLabel.MaxWidth = titleContainer.DrawWidth - 20;
artistLabel.MaxWidth = artistContainer.DrawWidth - 20;
}
private void updateDisplay()
{
var metadata = working.Value.Metadata;
@@ -229,12 +221,24 @@ namespace osu.Game.Screens.SelectV2
statusPill.Status = beatmapInfo.Status;
var titleText = new RomanisableString(metadata.TitleUnicode, metadata.Title);
titleLabel.Text = titleText;
titleLabel.CreateContent = () => new OsuSpriteText
{
Text = titleText,
Shadow = true,
Font = OsuFont.Style.Title,
};
titleLink.Action = () => songSelect?.Search(titleText.GetPreferred(localisation.CurrentParameters.Value.PreferOriginalScript));
DisplayedTitle = titleText.ToString();
var artistText = new RomanisableString(metadata.ArtistUnicode, metadata.Artist);
artistLabel.Text = artistText;
artistLabel.CreateContent = () => new OsuSpriteText
{
Text = artistText,
Shadow = true,
Font = OsuFont.Style.Heading2,
};
artistLink.Action = () => songSelect?.Search(artistText.GetPreferred(localisation.CurrentParameters.Value.PreferOriginalScript));
DisplayedArtist = artistText.ToString();
updateLengthAndBpmStatistics();
updateOnlineDisplay();