Esempio n. 1
0
 private Drawable[] createContent(Lyric lyric, TimeTag timeTag, TimeTagInvalid invalid) => new Drawable[]
 {
     new RightTriangle
     {
         Origin = Anchor.Centre,
         Size   = new Vector2(10),
         Colour = getInvalidColour(invalid),
         Margin = new MarginPadding {
             Left = 10
         },
     },
     new OsuSpriteText
     {
         Text   = $"#{lyric.Order}",
         Font   = OsuFont.GetFont(size: TEXT_SIZE, weight: FontWeight.Bold),
         Margin = new MarginPadding {
             Right = 10
         },
     },
     new OsuSpriteText
     {
         Text   = TextIndexUtils.PositionFormattedString(timeTag.Index),
         Font   = OsuFont.GetFont(size: TEXT_SIZE, weight: FontWeight.Bold),
         Margin = new MarginPadding {
             Right = 10
         },
     },
     new OsuSpriteText
     {
         Text             = getInvalidReason(invalid),
         Truncate         = true,
         RelativeSizeAxes = Axes.X,
         Font             = OsuFont.GetFont(size: TEXT_SIZE, weight: FontWeight.Medium)
     },
 };
Esempio n. 2
0
        protected override bool OnMouseMove(MouseMoveEvent e)
        {
            if (lyricManager == null)
            {
                return(false);
            }

            if (!isTrigger(state.Mode))
            {
                return(false);
            }

            if (state.Mode == Mode.TimeTagEditMode)
            {
                var position = ToLocalSpace(e.ScreenSpaceMousePosition).X / 2;
                var index    = drawableLyric.GetHoverIndex(position);
                state.MoveHoverCaretToTargetPosition(new TimeTagIndexCaretPosition(Lyric, index));
            }
            else
            {
                var position = ToLocalSpace(e.ScreenSpaceMousePosition).X / 2;
                var index    = drawableLyric.GetHoverIndex(position);
                state.MoveHoverCaretToTargetPosition(new TextCaretPosition(Lyric, TextIndexUtils.ToStringIndex(index)));
            }

            return(base.OnMouseMove(e));
        }
Esempio n. 3
0
        protected void UpdatePositionAndSize()
        {
            // wait until lyric update ruby position.
            ScheduleAfterChildren(() =>
            {
                var textTagRect = editorLyricPiece.GetTextTagPosition(Item);

                var startIndexPosition = editorLyricPiece.GetTextIndexPosition(TextIndexUtils.FromStringIndex(Item.StartIndex, false));
                var endIndexPosition   = editorLyricPiece.GetTextIndexPosition(TextIndexUtils.FromStringIndex(Item.EndIndex, true));

                // update select position
                updateDrawableRect(previewTextArea, textTagRect);

                // update index range position.
                var indexRangePosition = new Vector2(startIndexPosition.X, textTagRect.Y);
                var indexRangeSize     = new Vector2(endIndexPosition.X - startIndexPosition.X, textTagRect.Height);
                updateDrawableRect(indexRangeBackground, new RectangleF(indexRangePosition, indexRangeSize));
            });

            void updateDrawableRect(Drawable target, RectangleF rect)
            {
                target.X      = rect.X;
                target.Y      = rect.Y;
                target.Width  = rect.Width;
                target.Height = rect.Height;
            }
        }
Esempio n. 4
0
            protected override bool OnMouseMove(MouseMoveEvent e)
            {
                if (lyricManager == null)
                {
                    return(false);
                }

                if (!state.CaretEnabled)
                {
                    return(false);
                }

                var position = ToLocalSpace(e.ScreenSpaceMousePosition).X;

                switch (state.Mode)
                {
                case LyricEditorMode.Manage:
                    var cuttingLyricStringIndex = Math.Clamp(TextIndexUtils.ToStringIndex(lyricPiece.GetHoverIndex(position)), 0, Lyric.Text.Length - 1);
                    state.MoveHoverCaretToTargetPosition(new TextCaretPosition(Lyric, cuttingLyricStringIndex));
                    break;

                case LyricEditorMode.Typing:
                    var typingStringIndex = TextIndexUtils.ToStringIndex(lyricPiece.GetHoverIndex(position));
                    state.MoveHoverCaretToTargetPosition(new TextCaretPosition(Lyric, typingStringIndex));
                    break;

                case LyricEditorMode.EditRubyRomaji:
                    state.MoveHoverCaretToTargetPosition(new NavigateCaretPosition(Lyric));
                    break;

                case LyricEditorMode.CreateTimeTag:
                    var textIndex = lyricPiece.GetHoverIndex(position);
                    state.MoveHoverCaretToTargetPosition(new TimeTagIndexCaretPosition(Lyric, textIndex));
                    break;

                case LyricEditorMode.RecordTimeTag:
                    var timeTag = lyricPiece.GetHoverTimeTag(position);
                    state.MoveHoverCaretToTargetPosition(new TimeTagCaretPosition(Lyric, timeTag));
                    break;

                case LyricEditorMode.AdjustTimeTag:
                case LyricEditorMode.CreateNote:
                case LyricEditorMode.CreateNotePosition:
                case LyricEditorMode.AdjustNote:
                case LyricEditorMode.Layout:
                case LyricEditorMode.Singer:
                    state.MoveHoverCaretToTargetPosition(new NavigateCaretPosition(Lyric));
                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(state.Mode));
                }

                return(base.OnMouseMove(e));
            }
        [TestCase(0, TextIndex.IndexState.Start, 3, 1, null)] // test switch value.
        public void TestClamp(int index, TextIndex.IndexState state, int minIndex, int maxIndex, int?actualIndex)
        {
            var textIndex = new TextIndex(index, state);

            if (actualIndex != null)
            {
                var actualTextIndex = new TextIndex(actualIndex.Value, state);
                Assert.AreEqual(TextIndexUtils.Clamp(textIndex, minIndex, maxIndex), actualTextIndex);
            }
            else
            {
                Assert.Throws <ArgumentException>(() => TextIndexUtils.Clamp(textIndex, minIndex, maxIndex));
            }
        }
Esempio n. 6
0
            public override bool HandleScale(Vector2 scale, Anchor anchor)
            {
                deltaPosition += scale.X;

                // this feature only works if only select one ruby / romaji tag.
                var selectedTextTag = SelectedItems.FirstOrDefault();

                if (selectedTextTag == null)
                {
                    return(false);
                }

                // get real left-side and right-side position
                var rect = editorLyricPiece.GetTextTagPosition(selectedTextTag);

                switch (anchor)
                {
                case Anchor.CentreLeft:
                    var leftPosition = rect.Left + deltaPosition;
                    var startIndex   = TextIndexUtils.ToStringIndex(editorLyricPiece.GetHoverIndex(leftPosition));
                    if (startIndex >= selectedTextTag.EndIndex)
                    {
                        return(false);
                    }

                    selectedTextTag.StartIndex = startIndex;
                    return(true);

                case Anchor.CentreRight:
                    var rightPosition = rect.Right + deltaPosition;
                    var endIndex      = TextIndexUtils.ToStringIndex(editorLyricPiece.GetHoverIndex(rightPosition));
                    if (endIndex <= selectedTextTag.StartIndex)
                    {
                        return(false);
                    }

                    selectedTextTag.EndIndex = endIndex;
                    return(true);

                default:
                    return(false);
                }
            }
Esempio n. 7
0
        public Note[] CreateNotes(Lyric lyric)
        {
            var timeTags = TimeTagsUtils.ToDictionary(lyric.TimeTags);
            var notes    = new List <Note>();

            foreach (var timeTag in timeTags)
            {
                var(key, endTime) = timeTags.GetNext(timeTag);

                if (key.Index <= 0)
                {
                    continue;
                }

                var startTime = timeTag.Value;

                int startIndex = timeTag.Key.Index;
                int endIndex   = TextIndexUtils.ToStringIndex(key);

                var text = lyric.Text[startIndex..endIndex];
Esempio n. 8
0
        protected override bool ApplySnapResult(SelectionBlueprint <ITextTag>[] blueprints, SnapResult result)
        {
            if (!base.ApplySnapResult(blueprints, result))
            {
                return(false);
            }

            // handle lots of ruby / romaji drag position changed.
            var items = blueprints.Select(x => x.Item).ToArray();

            if (!items.Any())
            {
                return(false);
            }

            var leftPosition = ToLocalSpace(result.ScreenSpacePosition).X;
            var startIndex   = TextIndexUtils.ToStringIndex(editorLyricPiece.GetHoverIndex(leftPosition));
            var diff         = startIndex - items.First().StartIndex;

            if (diff == 0)
            {
                return(false);
            }

            foreach (var item in items)
            {
                var newStartIndex = item.StartIndex + diff;
                var newEndIndex   = item.EndIndex + diff;
                if (!LyricUtils.AbleToInsertTextTagAtIndex(Lyric, newStartIndex) || !LyricUtils.AbleToInsertTextTagAtIndex(Lyric, newEndIndex))
                {
                    continue;
                }

                item.StartIndex = newStartIndex;
                item.EndIndex   = newEndIndex;
            }

            return(true);
        }
Esempio n. 9
0
        public override bool SetContent(object content)
        {
            if (!(content is Issue[] issues))
            {
                return(false);
            }

            // clear exist warning.
            invalidMessage.Clear();

            foreach (var issue in issues)
            {
                switch (issue)
                {
                // Print time invalid message
                case LyricTimeIssue lyricTimeIssue:
                    lyricTimeIssue.InvalidLyricTime?.ForEach(createTimeInvalidMessage);
                    break;

                // Print time-tag invalid message
                case TimeTagIssue timeTagIssue:
                    if (timeTagIssue.MissingStartTimeTag)
                    {
                        invalidMessage.AddAlertParagraph("Missing start time tag at the start of lyric.");
                    }

                    if (timeTagIssue.MissingEndTimeTag)
                    {
                        invalidMessage.AddAlertParagraph("Missing end time tag at the end of lyric.");
                    }

                    timeTagIssue.InvalidTimeTags?.ForEach(x => createTimeTagInvalidMessage(x.Key, x.Value));
                    break;

                // Print ruby invalid message
                case RubyTagIssue rubyTagIssue:
                    rubyTagIssue.InvalidRubyTags?.ForEach(x => createRubyInvalidMessage(x.Key, x.Value));
                    break;

                // Print romaji invalid message
                case RomajiTagIssue romajiTagIssue:
                    romajiTagIssue.InvalidRomajiTags?.ForEach(x => createRomajiInvalidMessage(x.Key, x.Value));
                    break;

                // print normal message
                case Issue _:
                    invalidMessage.AddAlertParagraph(issue.Template.GetMessage());
                    break;

                // Should throw exception because every issue message should be printed.
                default:
                    throw new ArgumentOutOfRangeException(nameof(issue));
                }
            }

            // show no problem message
            if (issues.Length == 0)
            {
                invalidMessage.AddSuccessParagraph("Seems no issue in this lyric.");
            }

            return(true);

            void createTimeInvalidMessage(TimeInvalid timeInvalid)
            {
                switch (timeInvalid)
                {
                case TimeInvalid.Overlapping:
                    invalidMessage.AddAlertParagraph("Start time larger then end time in lyric.");
                    break;

                case TimeInvalid.StartTimeInvalid:
                    invalidMessage.AddAlertParagraph("Start time is larger than minimum time tag's time.");
                    break;

                case TimeInvalid.EndTimeInvalid:
                    invalidMessage.AddAlertParagraph("End time is smaller than maximum time tag's time.");
                    break;
                }
            }

            void createTimeTagInvalidMessage(TimeTagInvalid invalid, TimeTag[] timeTags)
            {
                switch (invalid)
                {
                case TimeTagInvalid.OutOfRange:
                    invalidMessage.AddAlertParagraph("Time tag(s) is out of lyric text size at position ");
                    break;

                case TimeTagInvalid.Overlapping:
                    invalidMessage.AddAlertParagraph("Time tag(s) is invalid at position ");
                    break;

                case TimeTagInvalid.EmptyTime:
                    invalidMessage.AddAlertParagraph("Time tag(s) is missing time at position ");
                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(invalid));
                }

                displayInvalidTag(timeTags, tag => invalidMessage.AddHighlightText(TextIndexUtils.PositionFormattedString(tag.Index)));
            }

            void createRubyInvalidMessage(RubyTagInvalid invalid, RubyTag[] rubyTags)
            {
                switch (invalid)
                {
                case RubyTagInvalid.OutOfRange:
                    invalidMessage.AddAlertParagraph("Ruby tag(s) is out of lyric text size at position ");
                    break;

                case RubyTagInvalid.Overlapping:
                    invalidMessage.AddAlertParagraph("Ruby tag(s) is overlapping to others at position ");
                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(invalid));
                }

                displayInvalidTag(rubyTags, tag => invalidMessage.AddHighlightText(TextTagUtils.PositionFormattedString(tag)));
            }

            void createRomajiInvalidMessage(RomajiTagInvalid invalid, RomajiTag[] romajiTags)
            {
                switch (invalid)
                {
                case RomajiTagInvalid.OutOfRange:
                    invalidMessage.AddAlertParagraph("Romaji tag(s) is out of lyric text size at position ");
                    break;

                case RomajiTagInvalid.Overlapping:
                    invalidMessage.AddAlertParagraph("Romaji tag(s) is overlapping to others at position ");
                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(invalid));
                }

                displayInvalidTag(romajiTags, tag => invalidMessage.AddHighlightText(TextTagUtils.PositionFormattedString(tag)));
            }

            void displayInvalidTag <T>(T[] tags, Action <T> action)
            {
                if (tags == null)
                {
                    throw new ArgumentNullException(nameof(tags));
                }

                // e.g: ka(-2~-1), ra(4~6), and ke(6~7)
                for (int i = 0; i < tags.Length; i++)
                {
                    action?.Invoke(tags[i]);

                    if (i == tags.Length - 2 && tags.Length > 1)
                    {
                        invalidMessage.AddText(" and ");
                    }
                    else if (i >= 0 && tags.Length > 1)
                    {
                        invalidMessage.AddText(", ");
                    }
                    else
                    {
                        invalidMessage.AddText(".");
                    }
                }
            }
        }