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:
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user