diff --git a/osu.Game.Rulesets.Karaoke.Tests/Objects/LyricTest.cs b/osu.Game.Rulesets.Karaoke.Tests/Objects/LyricTest.cs index 0449b87db..5cb1f6e64 100644 --- a/osu.Game.Rulesets.Karaoke.Tests/Objects/LyricTest.cs +++ b/osu.Game.Rulesets.Karaoke.Tests/Objects/LyricTest.cs @@ -52,7 +52,7 @@ public void TestClone() Assert.AreNotSame(clonedLyric.TextBindable, lyric.TextBindable); Assert.AreEqual(clonedLyric.Text, lyric.Text); - Assert.AreNotSame(clonedLyric.TimeTagsVersion, lyric.TimeTagsVersion); + Assert.AreNotSame(clonedLyric.TimeTagsTimingVersion, lyric.TimeTagsTimingVersion); Assert.AreNotSame(clonedLyric.TimeTagsBindable, lyric.TimeTagsBindable); TimeTagAssert.ArePropertyEqual(clonedLyric.TimeTags, lyric.TimeTags); @@ -202,7 +202,7 @@ public void TestReferenceLyricListPropertyChanged() TextTagAssert.ArePropertyEqual(referencedLyric.RomajiTags, lyric.RomajiTags); // and because there's no change inside the tag, so there's version change. - Assert.AreEqual(0, lyric.TimeTagsVersion.Value); + Assert.AreEqual(0, lyric.TimeTagsTimingVersion.Value); Assert.AreEqual(0, lyric.RubyTagsVersion.Value); Assert.AreEqual(0, lyric.RomajiTagsVersion.Value); @@ -217,7 +217,7 @@ public void TestReferenceLyricListPropertyChanged() TextTagAssert.ArePropertyEqual(referencedLyric.RomajiTags, lyric.RomajiTags); // and note that because only one property is different, so version should change once. - Assert.AreEqual(1, lyric.TimeTagsVersion.Value); + Assert.AreEqual(1, lyric.TimeTagsTimingVersion.Value); Assert.AreEqual(1, lyric.RubyTagsVersion.Value); Assert.AreEqual(1, lyric.RomajiTagsVersion.Value); } diff --git a/osu.Game.Rulesets.Karaoke/Graphics/Sprites/DrawableKaraokeSpriteText.cs b/osu.Game.Rulesets.Karaoke/Graphics/Sprites/DrawableKaraokeSpriteText.cs index 660b0045a..f1f5aa55f 100644 --- a/osu.Game.Rulesets.Karaoke/Graphics/Sprites/DrawableKaraokeSpriteText.cs +++ b/osu.Game.Rulesets.Karaoke/Graphics/Sprites/DrawableKaraokeSpriteText.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Karaoke.Graphics.Sprites; private const int whole_chunk_index = -1; private readonly IBindable textBindable = new Bindable(); - private readonly IBindable timeTagsVersion = new Bindable(); + private readonly IBindable timeTagsTimingVersion = new Bindable(); private readonly IBindableList timeTagsBindable = new BindableList(); private readonly IBindable rubyTagsVersion = new Bindable(); private readonly IBindableList rubyTagsBindable = new BindableList(); @@ -29,7 +29,7 @@ protected DrawableKaraokeSpriteText(Lyric lyric, int chunkIndex = whole_chunk_in this.chunkIndex = chunkIndex; textBindable.BindValueChanged(_ => UpdateText(), true); - timeTagsVersion.BindValueChanged(_ => UpdateTimeTags()); + timeTagsTimingVersion.BindValueChanged(_ => UpdateTimeTags()); timeTagsBindable.BindCollectionChanged((_, _) => UpdateTimeTags()); rubyTagsVersion.BindValueChanged(_ => UpdateRubies()); rubyTagsBindable.BindCollectionChanged((_, _) => UpdateRubies()); @@ -37,7 +37,7 @@ protected DrawableKaraokeSpriteText(Lyric lyric, int chunkIndex = whole_chunk_in romajiTagsBindable.BindCollectionChanged((_, _) => UpdateRomajies()); textBindable.BindTo(lyric.TextBindable); - timeTagsVersion.BindTo(lyric.TimeTagsVersion); + timeTagsTimingVersion.BindTo(lyric.TimeTagsTimingVersion); timeTagsBindable.BindTo(lyric.TimeTagsBindable); rubyTagsVersion.BindTo(lyric.RubyTagsVersion); rubyTagsBindable.BindTo(lyric.RubyTagsBindable); diff --git a/osu.Game.Rulesets.Karaoke/Objects/Lyric.cs b/osu.Game.Rulesets.Karaoke/Objects/Lyric.cs index edd9014a7..ba9b9d141 100644 --- a/osu.Game.Rulesets.Karaoke/Objects/Lyric.cs +++ b/osu.Game.Rulesets.Karaoke/Objects/Lyric.cs @@ -45,11 +45,6 @@ public string Text set => TextBindable.Value = value; } - [JsonIgnore] - public IBindable TimeTagsVersion => timeTagsVersion; - - private readonly Bindable timeTagsVersion = new(); - [JsonIgnore] public readonly BindableList TimeTagsBindable = new(); @@ -66,11 +61,6 @@ public IList TimeTags } } - [JsonIgnore] - public IBindable RubyTagsVersion => rubyTagsVersion; - - private readonly Bindable rubyTagsVersion = new(); - [JsonIgnore] public readonly BindableList RubyTagsBindable = new(); @@ -87,11 +77,6 @@ public IList RubyTags } } - [JsonIgnore] - public IBindable RomajiTagsVersion => romajiTagsVersion; - - private readonly Bindable romajiTagsVersion = new(); - [JsonIgnore] public readonly BindableList RomajiTagsBindable = new(); @@ -188,11 +173,6 @@ public ElementId? ReferenceLyricId } } - [JsonIgnore] - public IBindable ReferenceLyricConfigVersion => referenceLyricConfigVersion; - - private readonly Bindable referenceLyricConfigVersion = new(); - [JsonIgnore] public readonly Bindable ReferenceLyricConfigBindable = new(); @@ -205,11 +185,6 @@ public IReferenceLyricPropertyConfig? ReferenceLyricConfig set => ReferenceLyricConfigBindable.Value = value; } - [JsonIgnore] - public IBindable LyricPropertyWritableVersion => lyricPropertyWritableVersion; - - private readonly Bindable lyricPropertyWritableVersion = new(); - public Lyric() { workingPropertyValidator = new LyricWorkingPropertyValidator(this); diff --git a/osu.Game.Rulesets.Karaoke/Objects/Lyric_Binding.cs b/osu.Game.Rulesets.Karaoke/Objects/Lyric_Binding.cs index e333232c2..75869c4ec 100644 --- a/osu.Game.Rulesets.Karaoke/Objects/Lyric_Binding.cs +++ b/osu.Game.Rulesets.Karaoke/Objects/Lyric_Binding.cs @@ -6,6 +6,7 @@ using System.Collections.Specialized; using System.Diagnostics; using System.Linq; +using Newtonsoft.Json; using osu.Framework.Bindables; using osu.Game.Rulesets.Karaoke.Objects.Properties; using osu.Game.Rulesets.Karaoke.Objects.Utils; @@ -18,6 +19,36 @@ namespace osu.Game.Rulesets.Karaoke.Objects; /// public partial class Lyric { + [JsonIgnore] + public IBindable TimeTagsTimingVersion => timeTagsTimingVersion; + + private readonly Bindable timeTagsTimingVersion = new(); + + [JsonIgnore] + public IBindable TimeTagsRomajiVersion => timeTagsRomajiVersion; + + private readonly Bindable timeTagsRomajiVersion = new(); + + [JsonIgnore] + public IBindable RubyTagsVersion => rubyTagsVersion; + + private readonly Bindable rubyTagsVersion = new(); + + [JsonIgnore] + public IBindable RomajiTagsVersion => romajiTagsVersion; + + private readonly Bindable romajiTagsVersion = new(); + + [JsonIgnore] + public IBindable ReferenceLyricConfigVersion => referenceLyricConfigVersion; + + private readonly Bindable referenceLyricConfigVersion = new(); + + [JsonIgnore] + public IBindable LyricPropertyWritableVersion => lyricPropertyWritableVersion; + + private readonly Bindable lyricPropertyWritableVersion = new(); + private void initInternalBindingEvent() { TimeTagsBindable.CollectionChanged += (_, args) => @@ -28,7 +59,11 @@ private void initInternalBindingEvent() Debug.Assert(args.NewItems != null); foreach (var c in args.NewItems.Cast()) - c.Changed += invalidate; + { + c.TimingChanged += timingInvalidate; + c.RomajiChanged += romajiInvalidate; + } + break; case NotifyCollectionChangedAction.Reset: @@ -36,16 +71,21 @@ private void initInternalBindingEvent() Debug.Assert(args.OldItems != null); foreach (var c in args.OldItems.Cast()) - c.Changed -= invalidate; + { + c.TimingChanged -= timingInvalidate; + c.RomajiChanged -= romajiInvalidate; + } + break; } updateLyricTime(); - void invalidate() => timeTagsVersion.Value++; + void timingInvalidate() => timeTagsTimingVersion.Value++; + void romajiInvalidate() => timeTagsRomajiVersion.Value++; }; - TimeTagsVersion.ValueChanged += _ => + TimeTagsTimingVersion.ValueChanged += _ => { updateLyricTime(); }; @@ -168,7 +208,7 @@ private void initReferenceLyricEvent() }).ToArray(); }); - bindValueChange(e, l => l.TimeTagsVersion, (_, config) => + bindValueChange(e, l => l.TimeTagsTimingVersion, (_, config) => { if (config is not SyncLyricConfig syncLyricConfig || !syncLyricConfig.SyncTimeTagProperty) return; diff --git a/osu.Game.Rulesets.Karaoke/Objects/Note_Binding.cs b/osu.Game.Rulesets.Karaoke/Objects/Note_Binding.cs index 6449f1d9c..0d0c345ed 100644 --- a/osu.Game.Rulesets.Karaoke/Objects/Note_Binding.cs +++ b/osu.Game.Rulesets.Karaoke/Objects/Note_Binding.cs @@ -25,16 +25,16 @@ private void initReferenceLyricEvent() ReferenceLyricBindable.ValueChanged += e => { if (e.OldValue != null) - e.OldValue.TimeTagsVersion.ValueChanged -= timeTagVersionChanged; + e.OldValue.TimeTagsTimingVersion.ValueChanged -= timeTagsTimingVersionChanged; if (e.NewValue != null) - e.NewValue.TimeTagsVersion.ValueChanged += timeTagVersionChanged; + e.NewValue.TimeTagsTimingVersion.ValueChanged += timeTagsTimingVersionChanged; syncStartTimeAndDurationFromTimeTag(); syncReferenceLyricSingers(); }; - void timeTagVersionChanged(ValueChangedEvent e) => syncStartTimeAndDurationFromTimeTag(); + void timeTagsTimingVersionChanged(ValueChangedEvent e) => syncStartTimeAndDurationFromTimeTag(); } private void syncStartTimeAndDurationFromTimeTag() diff --git a/osu.Game.Rulesets.Karaoke/Objects/TimeTag.cs b/osu.Game.Rulesets.Karaoke/Objects/TimeTag.cs index e092b7d3d..b194aa79c 100644 --- a/osu.Game.Rulesets.Karaoke/Objects/TimeTag.cs +++ b/osu.Game.Rulesets.Karaoke/Objects/TimeTag.cs @@ -12,16 +12,23 @@ namespace osu.Game.Rulesets.Karaoke.Objects; public class TimeTag : IDeepCloneable { /// - /// Invoked when any property of this is changed. + /// Invoked when of this is changed. /// - public event Action? Changed; + public event Action? TimingChanged; + + /// + /// Invoked when or of this is changed. + /// + public event Action? RomajiChanged; public TimeTag(TextIndex index, double? time = null) { Index = index; Time = time; - TimeBindable.ValueChanged += _ => Changed?.Invoke(); + TimeBindable.ValueChanged += _ => TimingChanged?.Invoke(); + InitialRomajiBindable.ValueChanged += _ => RomajiChanged?.Invoke(); + RomajiTextBindable.ValueChanged += _ => RomajiChanged?.Invoke(); } /// @@ -42,6 +49,40 @@ public double? Time set => TimeBindable.Value = value; } + [JsonIgnore] + public readonly Bindable InitialRomajiBindable = new(); + + /// + /// Mark if this romaji is the first letter of the romaji word. + /// + /// + /// There's the Japanese lyric: + /// 枯れた世界に輝く + /// There's the Romaji: + /// kareta sekai ni kagayaku. + /// And it will be separated as: + /// ka|re|ta se|kai ni ka|ga|ya|ku. + /// If this is the first or(4th) time-tag, then this value should be true. + /// If this ts the 2th or 3th time-tag, then this value should be false. + /// + public bool InitialRomaji + { + get => InitialRomajiBindable.Value; + set => InitialRomajiBindable.Value = value; + } + + [JsonIgnore] + public readonly Bindable RomajiTextBindable = new(); + + /// + /// Romaji + /// + public string? RomajiText + { + get => RomajiTextBindable.Value; + set => RomajiTextBindable.Value = value; + } + public TimeTag DeepClone() { return new TimeTag(Index, Time); diff --git a/osu.Game.Rulesets.Karaoke/Screens/Edit/Beatmaps/Lyrics/Compose/BottomEditor/TimeTagScrollContainer.cs b/osu.Game.Rulesets.Karaoke/Screens/Edit/Beatmaps/Lyrics/Compose/BottomEditor/TimeTagScrollContainer.cs index 81c77dd72..1c962d05e 100644 --- a/osu.Game.Rulesets.Karaoke/Screens/Edit/Beatmaps/Lyrics/Compose/BottomEditor/TimeTagScrollContainer.cs +++ b/osu.Game.Rulesets.Karaoke/Screens/Edit/Beatmaps/Lyrics/Compose/BottomEditor/TimeTagScrollContainer.cs @@ -23,7 +23,7 @@ public abstract partial class TimeTagScrollContainer : BindableScrollContainer { private readonly IBindable bindableFocusedLyric = new Bindable(); - private readonly IBindable timeTagsVersion = new Bindable(); + private readonly IBindable timeTagsTimingVersion = new Bindable(); [Cached] private readonly BindableList timeTagsBindable = new(); @@ -42,19 +42,19 @@ protected TimeTagScrollContainer() { RelativeSizeAxes = Axes.X; - timeTagsVersion.BindValueChanged(_ => updateTimeRange()); + timeTagsTimingVersion.BindValueChanged(_ => updateTimeRange()); timeTagsBindable.BindCollectionChanged((_, _) => updateTimeRange()); bindableFocusedLyric.BindValueChanged(e => { - timeTagsVersion.UnbindBindings(); + timeTagsTimingVersion.UnbindBindings(); timeTagsBindable.UnbindBindings(); var lyric = e.NewValue; if (lyric == null) return; - timeTagsVersion.BindTo(lyric.TimeTagsVersion); + timeTagsTimingVersion.BindTo(lyric.TimeTagsTimingVersion); timeTagsBindable.BindTo(lyric.TimeTagsBindable); Schedule(() => diff --git a/osu.Game.Rulesets.Karaoke/Screens/Edit/Beatmaps/Lyrics/LyricList/Rows/Info/Badge/TimeTagInfo.cs b/osu.Game.Rulesets.Karaoke/Screens/Edit/Beatmaps/Lyrics/LyricList/Rows/Info/Badge/TimeTagInfo.cs index 7c10bd631..9e3fcf328 100644 --- a/osu.Game.Rulesets.Karaoke/Screens/Edit/Beatmaps/Lyrics/LyricList/Rows/Info/Badge/TimeTagInfo.cs +++ b/osu.Game.Rulesets.Karaoke/Screens/Edit/Beatmaps/Lyrics/LyricList/Rows/Info/Badge/TimeTagInfo.cs @@ -11,13 +11,13 @@ namespace osu.Game.Rulesets.Karaoke.Screens.Edit.Beatmaps.Lyrics.LyricList.Rows. public partial class TimeTagInfo : SubInfo { - private readonly IBindable bindableTimeTagsVersion; + private readonly IBindable bindableTimeTagsTimingVersion; private readonly IBindableList bindableTimeTags; public TimeTagInfo(Lyric lyric) : base(lyric) { - bindableTimeTagsVersion = lyric.TimeTagsVersion.GetBoundCopy(); + bindableTimeTagsTimingVersion = lyric.TimeTagsTimingVersion.GetBoundCopy(); bindableTimeTags = lyric.TimeTagsBindable.GetBoundCopy(); } @@ -26,7 +26,7 @@ private void load(OsuColour colours) { BadgeColour = colours.Green; - bindableTimeTagsVersion.BindValueChanged(_ => updateBadgeText()); + bindableTimeTagsTimingVersion.BindValueChanged(_ => updateBadgeText()); bindableTimeTags.BindCollectionChanged((_, _) => updateBadgeText()); updateBadgeText();