diff --git a/osu.Game/Overlays/MarqueeContainer.cs b/osu.Game/Overlays/MarqueeContainer.cs index 1b0b59abe0..2d651abb00 100644 --- a/osu.Game/Overlays/MarqueeContainer.cs +++ b/osu.Game/Overlays/MarqueeContainer.cs @@ -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? 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); + } } } } diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index 6217a9bc9e..5cbde6ba57 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -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); diff --git a/osu.Game/Overlays/NowPlayingOverlay.cs b/osu.Game/Overlays/NowPlayingOverlay.cs index 11819cb485..a58aa27e24 100644 --- a/osu.Game/Overlays/NowPlayingOverlay.cs +++ b/osu.Game/Overlays/NowPlayingOverlay.cs @@ -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 { diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.cs b/osu.Game/Screens/SelectV2/BeatmapTitleWedge.cs index 530b1348dd..a74872eaa7 100644 --- a/osu.Game/Screens/SelectV2/BeatmapTitleWedge.cs +++ b/osu.Game/Screens/SelectV2/BeatmapTitleWedge.cs @@ -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();