diff --git a/osu.Framework.Font/Graphics/Sprites/KaraokeSpriteText.cs b/osu.Framework.Font/Graphics/Sprites/KaraokeSpriteText.cs index 991a398..4dd8107 100644 --- a/osu.Framework.Font/Graphics/Sprites/KaraokeSpriteText.cs +++ b/osu.Framework.Font/Graphics/Sprites/KaraokeSpriteText.cs @@ -20,11 +20,11 @@ public class KaraokeSpriteText : KaraokeSpriteText public partial class KaraokeSpriteText : CompositeDrawable, ISingleShaderBufferedDrawable, IHasRuby, IHasRomaji where T : LyricSpriteText, new() { - private readonly MaskingContainer frontLyricTextContainer; - private readonly T frontLyricText; + private readonly MaskingContainer leftLyricTextContainer; + private readonly T leftLyricText; - private readonly MaskingContainer backLyricTextContainer; - private readonly T backLyricText; + private readonly MaskingContainer rightLyricTextContainer; + private readonly T rightLyricText; // todo: should have a better way to let user able to customize formats? private readonly BufferedDrawNodeSharedData sharedData = new BufferedDrawNodeSharedData(2); @@ -37,23 +37,23 @@ public KaraokeSpriteText() AutoSizeAxes = Axes.Both; InternalChildren = new Drawable[] { - backLyricTextContainer = new MaskingContainer + rightLyricTextContainer = new MaskingContainer { AutoSizeAxes = Axes.Y, Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, MaskingEdges = Edges.Left, - Child = backLyricText = new T + Child = rightLyricText = new T { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, } }, - frontLyricTextContainer = new MaskingContainer + leftLyricTextContainer = new MaskingContainer { AutoSizeAxes = Axes.Y, MaskingEdges = Edges.Right, - Child = frontLyricText = new T(), + Child = leftLyricText = new T(), } }; } @@ -144,10 +144,10 @@ public IReadOnlyList Shaders public IReadOnlyList LeftLyricTextShaders { - get => frontLyricText.Shaders; + get => leftLyricText.Shaders; set { - frontLyricText.Shaders = value; + leftLyricText.Shaders = value; Invalidate(Invalidation.DrawNode); } @@ -155,10 +155,10 @@ public IReadOnlyList LeftLyricTextShaders public IReadOnlyList RightLyricTextShaders { - get => backLyricText.Shaders; + get => rightLyricText.Shaders; set { - backLyricText.Shaders = value; + rightLyricText.Shaders = value; Invalidate(Invalidation.DrawNode); } @@ -170,11 +170,11 @@ public IReadOnlyList RightLyricTextShaders public string Text { - get => frontLyricText.Text; + get => leftLyricText.Text; set { - frontLyricText.Text = value; - backLyricText.Text = value; + leftLyricText.Text = value; + rightLyricText.Text = value; Invalidate(Invalidation.DrawNode); } @@ -182,11 +182,11 @@ public string Text public IReadOnlyList Rubies { - get => frontLyricText.Rubies; + get => leftLyricText.Rubies; set { - frontLyricText.Rubies = value; - backLyricText.Rubies = value; + leftLyricText.Rubies = value; + rightLyricText.Rubies = value; Invalidate(Invalidation.DrawNode); } @@ -194,11 +194,11 @@ public IReadOnlyList Rubies public IReadOnlyList Romajies { - get => frontLyricText.Romajies; + get => leftLyricText.Romajies; set { - frontLyricText.Romajies = value; - backLyricText.Romajies = value; + leftLyricText.Romajies = value; + rightLyricText.Romajies = value; Invalidate(Invalidation.DrawNode); } @@ -210,11 +210,11 @@ public IReadOnlyList Romajies public FontUsage Font { - get => frontLyricText.Font; + get => leftLyricText.Font; set { - frontLyricText.Font = value; - backLyricText.Font = value; + leftLyricText.Font = value; + rightLyricText.Font = value; Invalidate(Invalidation.DrawNode); } @@ -222,11 +222,11 @@ public FontUsage Font public FontUsage RubyFont { - get => frontLyricText.RubyFont; + get => leftLyricText.RubyFont; set { - frontLyricText.RubyFont = value; - backLyricText.RubyFont = value; + leftLyricText.RubyFont = value; + rightLyricText.RubyFont = value; Invalidate(Invalidation.DrawNode); } @@ -234,11 +234,11 @@ public FontUsage RubyFont public FontUsage RomajiFont { - get => frontLyricText.RomajiFont; + get => leftLyricText.RomajiFont; set { - frontLyricText.RomajiFont = value; - backLyricText.RomajiFont = value; + leftLyricText.RomajiFont = value; + rightLyricText.RomajiFont = value; Invalidate(Invalidation.DrawNode); } @@ -250,10 +250,10 @@ public FontUsage RomajiFont public ColourInfo LeftTextColour { - get => frontLyricText.Colour; + get => leftLyricText.Colour; set { - frontLyricText.Colour = value; + leftLyricText.Colour = value; Invalidate(Invalidation.DrawNode); } @@ -261,10 +261,10 @@ public ColourInfo LeftTextColour public ColourInfo RightTextColour { - get => backLyricText.Colour; + get => rightLyricText.Colour; set { - backLyricText.Colour = value; + rightLyricText.Colour = value; Invalidate(Invalidation.DrawNode); } @@ -272,11 +272,11 @@ public ColourInfo RightTextColour public LyricTextAlignment RubyAlignment { - get => frontLyricText.RubyAlignment; + get => leftLyricText.RubyAlignment; set { - frontLyricText.RubyAlignment = value; - backLyricText.RubyAlignment = value; + leftLyricText.RubyAlignment = value; + rightLyricText.RubyAlignment = value; Invalidate(Invalidation.DrawNode); } @@ -284,11 +284,11 @@ public LyricTextAlignment RubyAlignment public LyricTextAlignment RomajiAlignment { - get => frontLyricText.RomajiAlignment; + get => leftLyricText.RomajiAlignment; set { - frontLyricText.RomajiAlignment = value; - backLyricText.RomajiAlignment = value; + leftLyricText.RomajiAlignment = value; + rightLyricText.RomajiAlignment = value; Invalidate(Invalidation.DrawNode); } @@ -300,11 +300,11 @@ public LyricTextAlignment RomajiAlignment public Vector2 Spacing { - get => frontLyricText.Spacing; + get => leftLyricText.Spacing; set { - frontLyricText.Spacing = value; - backLyricText.Spacing = value; + leftLyricText.Spacing = value; + rightLyricText.Spacing = value; Invalidate(Invalidation.DrawNode); } @@ -312,11 +312,11 @@ public Vector2 Spacing public Vector2 RubySpacing { - get => frontLyricText.RubySpacing; + get => leftLyricText.RubySpacing; set { - frontLyricText.RubySpacing = value; - backLyricText.RubySpacing = value; + leftLyricText.RubySpacing = value; + rightLyricText.RubySpacing = value; Invalidate(Invalidation.DrawNode); } @@ -324,11 +324,11 @@ public Vector2 RubySpacing public Vector2 RomajiSpacing { - get => frontLyricText.RomajiSpacing; + get => leftLyricText.RomajiSpacing; set { - frontLyricText.RomajiSpacing = value; - backLyricText.RomajiSpacing = value; + leftLyricText.RomajiSpacing = value; + rightLyricText.RomajiSpacing = value; Invalidate(Invalidation.DrawNode); } @@ -340,11 +340,11 @@ public Vector2 RomajiSpacing public int RubyMargin { - get => frontLyricText.RubyMargin; + get => leftLyricText.RubyMargin; set { - frontLyricText.RubyMargin = value; - backLyricText.RubyMargin = value; + leftLyricText.RubyMargin = value; + rightLyricText.RubyMargin = value; Invalidate(Invalidation.DrawNode); } @@ -352,11 +352,11 @@ public int RubyMargin public int RomajiMargin { - get => frontLyricText.RomajiMargin; + get => leftLyricText.RomajiMargin; set { - frontLyricText.RomajiMargin = value; - backLyricText.RomajiMargin = value; + leftLyricText.RomajiMargin = value; + rightLyricText.RomajiMargin = value; Invalidate(Invalidation.DrawNode); } @@ -391,8 +391,8 @@ public override double LifetimeStart set { base.LifetimeStart = value; - frontLyricText.LifetimeStart = value; - backLyricText.LifetimeStart = value; + leftLyricText.LifetimeStart = value; + rightLyricText.LifetimeStart = value; } } @@ -402,8 +402,8 @@ public override double LifetimeEnd set { base.LifetimeEnd = value; - frontLyricText.LifetimeEnd = value; - backLyricText.LifetimeEnd = value; + leftLyricText.LifetimeEnd = value; + rightLyricText.LifetimeEnd = value; } } @@ -415,7 +415,7 @@ public override double LifetimeEnd public override Vector2 Size { - get => frontLyricText.Size; + get => leftLyricText.Size; set => throw new InvalidOperationException(); } @@ -423,9 +423,7 @@ protected override bool OnInvalidate(Invalidation invalidation, InvalidationSour { var result = base.OnInvalidate(invalidation, source); - var hasTimeTag = TimeTags != null; - var hasText = !string.IsNullOrEmpty(Text); - if (!invalidation.HasFlag(Invalidation.Presence) || !hasTimeTag || !hasText) + if (!invalidation.HasFlag(Invalidation.Presence)) return result; Schedule(RefreshStateTransforms); @@ -435,48 +433,60 @@ protected override bool OnInvalidate(Invalidation invalidation, InvalidationSour public virtual void RefreshStateTransforms() { - // todo: IApplicableToCharacterSize should affect padding in the masking container also. - - // set initial width. - // we should get width from child object because draw width haven't updated. - var width = frontLyricText.Width; - frontLyricTextContainer.Width = 0; - backLyricTextContainer.Width = width; - // reset masking transform. - frontLyricTextContainer.ClearTransforms(); - backLyricTextContainer.ClearTransforms(); + leftLyricTextContainer.ClearTransforms(); + rightLyricTextContainer.ClearTransforms(); // filter valid time-tag with order. var validTimeTag = TimeTags .Where(x => x.Key.Index >= 0 && x.Key.Index < Text.Length) .OrderBy(x => x.Value).ToArray(); + // not initialize if no time-tag or text. + var hasTimeTag = validTimeTag.Any(); + var hasText = !string.IsNullOrEmpty(Text); + if (!hasTimeTag || !hasText) + return; + + // set initial width. + // we should get width from child object because draw width haven't updated. + var width = leftLyricText.Width; + var startPosition = getTextIndexPosition(new TextIndex()); + var endPosition = width - startPosition; + leftLyricTextContainer.Width = startPosition; + rightLyricTextContainer.Width = endPosition; + // get first time-tag relative start time. var currentTime = Time.Current; var relativeTime = validTimeTag.FirstOrDefault().Value; // get transform sequence and set initial delay time. var delay = relativeTime - currentTime; - var frontTransformSequence = frontLyricTextContainer.Delay(delay).ResizeWidthTo(0).Then(); - var backTransformSequence = backLyricTextContainer.Delay(delay).ResizeWidthTo(width).Then(); + var leftTransformSequence = leftLyricTextContainer.Delay(delay).ResizeWidthTo(startPosition).Then(); + var rightTransformSequence = rightLyricTextContainer.Delay(delay).ResizeWidthTo(endPosition).Then(); foreach ((var textIndex, double time) in validTimeTag) { // calculate position and duration relative to precious time-tag time. - var position = getCharacterPosition(textIndex); + var position = getTextIndexPosition(textIndex); var duration = Math.Max(time - relativeTime, 0); // apply the position with delay time. - frontTransformSequence.ResizeWidthTo(position, duration).Then(); - backTransformSequence.ResizeWidthTo(width - position, duration).Then(); + leftTransformSequence.ResizeWidthTo(position, duration).Then(); + rightTransformSequence.ResizeWidthTo(width - position, duration).Then(); // save current time-tag time for letting next time-tag able to calculate duration. relativeTime = time; } } - private float getCharacterPosition(TextIndex index) - => index.State == TextIndex.IndexState.Start ? frontLyricText.GetTextIndexPosition(index) : backLyricText.GetTextIndexPosition(index); + private float getTextIndexPosition(TextIndex index) + { + var leftTextIndexPosition = leftLyricText.GetTextIndexPosition(index); + var rightTextIndexPosition = rightLyricText.GetTextIndexPosition(index); + return index.State == TextIndex.IndexState.Start + ? Math.Min(leftTextIndexPosition, rightTextIndexPosition) + : Math.Max(leftTextIndexPosition, rightTextIndexPosition); + } } }