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

Make overflowing playlist items scroll

This commit is contained in:
Bartłomiej Dach
2025-04-04 12:06:55 +02:00
Unverified
parent f5b849b4f3
commit 52d71d7f6e
3 changed files with 150 additions and 147 deletions
+21 -31
View File
@@ -31,32 +31,22 @@ namespace osu.Game.Overlays.Music
private readonly Bindable<Live<BeatmapSetInfo>?> selectedSet = new Bindable<Live<BeatmapSetInfo>?>();
private Action<Live<BeatmapSetInfo>>? requestSelection;
private TextFlowContainer text = null!;
private ITextPart? titlePart;
private OverflowScrollingContainer text = null!;
[Resolved]
private OsuColour colours { get; set; } = null!;
[Resolved]
private PlaylistOverlay playlistOverlay { get; set; } = null!;
public PlaylistItem()
{
Padding = new MarginPadding { Horizontal = 10 };
}
[BackgroundDependencyLoader]
private void load(PlaylistOverlay playlistOverlay)
{
RelativeSizeAxes = Axes.X;
Height = 20;
InternalChild = text = new OsuTextFlowContainer
InternalChild = text = new OverflowScrollingContainer
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
RelativeSizeAxes = Axes.X,
};
selectedSet.BindTo(playlistOverlay.SelectedSet);
@@ -77,22 +67,26 @@ namespace osu.Game.Overlays.Music
var title = new RomanisableString(metadata.TitleUnicode, metadata.Title);
var artist = new RomanisableString(metadata.ArtistUnicode, metadata.Artist);
text.Clear();
titlePart = text.AddText(title, sprite => sprite.Font = OsuFont.GetFont(weight: FontWeight.Regular));
titlePart.DrawablePartsRecreated += _ =>
text.CreateContent.Value = () =>
{
selectedSet.TriggerChange();
FinishTransforms(true);
var flow = new OsuTextFlowContainer
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
};
flow.AddText(title, sprite => sprite.Font = OsuFont.GetFont(weight: FontWeight.Regular));
flow.AddText(@" "); // to separate the title from the artist.
flow.AddText(artist, sprite =>
{
sprite.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold);
sprite.Colour = colours.Gray9;
});
return flow;
};
text.AddText(@" "); // to separate the title from the artist.
text.AddText(artist, sprite =>
{
sprite.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold);
sprite.Colour = colours.Gray9;
});
selectedSet.TriggerChange();
FinishTransforms(true);
});
@@ -107,11 +101,7 @@ namespace osu.Game.Overlays.Music
if (wasSelected == this.selected)
return;
if (titlePart != null)
{
foreach (Drawable s in titlePart.Drawables)
s.FadeColour(this.selected == true ? colours.Yellow : Color4.White, 100);
}
text.FadeColour(this.selected == true ? colours.Yellow : Color4.White, 100);
}
protected override bool OnClick(ClickEvent e)
+42 -116
View File
@@ -5,7 +5,6 @@ using System;
using System.Threading;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Configuration;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
@@ -50,7 +49,7 @@ namespace osu.Game.Overlays
private MusicIconButton shuffleButton = null!;
private IconButton playlistButton = null!;
private ScrollingTextContainer title = null!, artist = null!;
private OverflowScrollingContainer title = null!, artist = null!;
private PlaylistOverlay? playlist;
@@ -72,6 +71,9 @@ namespace osu.Game.Overlays
private Bindable<bool> allowTrackControl = null!;
private readonly BindableBool shuffle = new BindableBool(true);
private static readonly FontUsage title_font = OsuFont.GetFont(size: 25, italics: true);
private static readonly FontUsage artist_font = OsuFont.GetFont(size: 15, weight: FontWeight.Bold, italics: true);
public NowPlayingOverlay()
{
Width = player_width;
@@ -105,23 +107,41 @@ namespace osu.Game.Overlays
Children = new[]
{
background = Empty(),
title = new ScrollingTextContainer
title = new OverflowScrollingContainer
{
Origin = Anchor.BottomCentre,
Anchor = Anchor.TopCentre,
Position = new Vector2(0, 40),
Font = OsuFont.GetFont(size: 25, italics: true),
Colour = Color4.White,
Text = @"Nothing to play",
CreateContent =
{
Value = () => new OsuSpriteText
{
Font = title_font,
Text = @"Nothing to play",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}
},
NonOverflowingContentAnchor = Anchor.Centre,
},
artist = new ScrollingTextContainer
artist = new OverflowScrollingContainer
{
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Position = new Vector2(0, 45),
Font = OsuFont.GetFont(size: 15, weight: FontWeight.Bold, italics: true),
Colour = Color4.White,
Text = @"Nothing to play",
CreateContent =
{
Value = () => new OsuSpriteText
{
Font = artist_font,
Text = @"Nothing to play",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}
},
NonOverflowingContentAnchor = Anchor.Centre,
},
new Container
{
@@ -318,8 +338,20 @@ namespace osu.Game.Overlays
{
BeatmapMetadata metadata = beatmap.Metadata;
title.Text = new RomanisableString(metadata.TitleUnicode, metadata.Title);
artist.Text = new RomanisableString(metadata.ArtistUnicode, metadata.Artist);
title.CreateContent.Value = () => new OsuSpriteText
{
Text = new RomanisableString(metadata.TitleUnicode, metadata.Title),
Font = title_font,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
};
artist.CreateContent.Value = () => new OsuSpriteText
{
Text = new RomanisableString(metadata.ArtistUnicode, metadata.Artist),
Font = artist_font,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
};
backgroundLoadCancellation?.Cancel();
@@ -484,111 +516,5 @@ namespace osu.Game.Overlays
base.OnHoverLost(e);
}
}
private partial class ScrollingTextContainer : CompositeDrawable
{
private const float initial_move_delay = 1000;
private const float pixels_per_second = 50;
private OsuSpriteText mainSpriteText = null!;
private OsuSpriteText fillerSpriteText = null!;
private Bindable<bool> showUnicode = null!;
[Resolved]
private FrameworkConfigManager frameworkConfig { get; set; } = null!;
private LocalisableString text;
public LocalisableString Text
{
get => text;
set
{
text = value;
if (IsLoaded)
updateText();
}
}
private FontUsage font = OsuFont.Default;
public FontUsage Font
{
get => font;
set
{
font = value;
if (IsLoaded)
updateFontAndText();
}
}
public ScrollingTextContainer()
{
AutoSizeAxes = Axes.Both;
}
[BackgroundDependencyLoader]
private void load()
{
InternalChild = new FillFlowContainer<OsuSpriteText>
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Children = new[]
{
mainSpriteText = new OsuSpriteText { Padding = new MarginPadding { Horizontal = margin } },
fillerSpriteText = new OsuSpriteText { Padding = new MarginPadding { Horizontal = margin }, Alpha = 0 },
}
};
}
protected override void LoadComplete()
{
base.LoadComplete();
showUnicode = frameworkConfig.GetBindable<bool>(FrameworkSetting.ShowUnicode);
showUnicode.BindValueChanged(_ => updateText());
updateFontAndText();
}
private void updateFontAndText()
{
mainSpriteText.Font = font;
fillerSpriteText.Font = font;
updateText();
}
private void updateText()
{
mainSpriteText.Text = text;
fillerSpriteText.Alpha = 0;
ClearTransforms();
X = 0;
float textOverflowWidth = mainSpriteText.Width - player_width;
// apply half margin of tolerance on both sides before the text scrolls
if (textOverflowWidth > margin)
{
fillerSpriteText.Alpha = 1;
fillerSpriteText.Text = text;
float initialX = (textOverflowWidth + mainSpriteText.Width) / 2;
float targetX = (textOverflowWidth - mainSpriteText.Width) / 2;
this.MoveToX(initialX)
.Delay(initial_move_delay)
.MoveToX(targetX, mainSpriteText.Width * 1000 / pixels_per_second)
.Loop();
}
}
}
}
}
@@ -0,0 +1,87 @@
// 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.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osuTK;
namespace osu.Game.Overlays
{
public partial class OverflowScrollingContainer : CompositeDrawable
{
public Anchor NonOverflowingContentAnchor { get; init; } = Anchor.TopLeft;
public Bindable<Func<Drawable>> CreateContent = new Bindable<Func<Drawable>>();
private const float initial_move_delay = 1000;
private const float pixels_per_second = 50;
private const float padding = 15;
private Drawable mainContent = null!;
private Drawable fillerContent = null!;
private FillFlowContainer flow = null!;
public OverflowScrollingContainer()
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
}
[BackgroundDependencyLoader]
private void load()
{
InternalChild = flow = new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(padding),
Padding = new MarginPadding { Horizontal = padding },
};
}
protected override void LoadComplete()
{
base.LoadComplete();
CreateContent.BindValueChanged(_ =>
{
flow.Clear();
flow.Add(mainContent = CreateContent.Value.Invoke());
flow.Add(fillerContent = CreateContent.Value.Invoke().With(d => d.Alpha = 0));
ScheduleAfterChildren(updateText);
}, true);
}
private void updateText()
{
fillerContent.Alpha = 0;
flow.ClearTransforms();
flow.X = 0;
float overflowWidth = mainContent.DrawWidth + padding - DrawWidth;
if (overflowWidth > 0)
{
fillerContent.Alpha = 1;
float targetX = mainContent.DrawWidth + padding;
flow.MoveToX(0)
.Delay(initial_move_delay)
.MoveToX(-targetX, targetX * 1000 / pixels_per_second)
.Loop();
flow.Anchor = Anchor.TopLeft;
flow.Origin = Anchor.TopLeft;
}
else
{
flow.Anchor = NonOverflowingContentAnchor;
flow.Origin = NonOverflowingContentAnchor;
}
}
}
}