コード例 #1
0
        private void EditNoteModeTap(ScoreEditorHitTestResult hit, MouseEventArgs e)
        {
            var editor = _visualizer.Editor;

            if (hit.HitAnyNote)
            {
                var note = hit.Note;
                if (note == _lastMouseDownNote)
                {
                    // If we hit any note, its behavior is like 'select' mode, except that this one doesn't accept
                    // modifier keys.
                    if (editor.HasSelectedBars)
                    {
                        editor.ClearSelectedBars();
                    }
                    else
                    {
                        EditorToggleNoteSelection(note);
                    }
                    editor.Invalidate();
                }
            }
            else if (hit.HitBarGridIntersection)
            {
                // Add a note
                EditorAddNote(hit);
                editor.Invalidate();
            }
            else
            {
                ClearNoteAndBarSelection();
            }
        }
コード例 #2
0
        private Note EditorAddNote(ScoreEditorHitTestResult hit)
        {
            var editor = _visualizer.Editor;
            var note   = editor.AddNoteAt(hit.Bar, hit.Row, hit.Column);

            _visualizer.InformProjectModified();
            return(note);
        }
コード例 #3
0
        private void SpecialNoteAreaOnMouseUp(ScoreEditorHitTestResult hit, MouseEventArgs e)
        {
            switch (e.Button)
            {
            case MouseButtons.Left:
                ClearNoteAndBarSelection();
                break;

            case MouseButtons.Right:
                EditorPopupContextMenu(hit, e.Location.ToXna());
                break;
            }
        }
コード例 #4
0
        private void InfoAreaOnMouseUp(ScoreEditorHitTestResult hit, MouseEventArgs e)
        {
            var editor = _visualizer.Editor;

            switch (e.Button)
            {
            case MouseButtons.Left: {
                // Click info area to select measures.
                if (editor.HasSelectedNotes)
                {
                    // Clear note selection first.
                    editor.ClearSelectedNotes();
                    editor.Invalidate();
                }
                else
                {
                    // Select/unselect bar(s).
                    var bar = hit.Bar;
                    if (bar != null)
                    {
                        switch (Control.ModifierKeys)
                        {
                        case Keys.Control:
                            EditorToggleBarSelectionMultipleMode(bar);
                            break;

                        case Keys.Shift:
                        // TODO: select a series of measures.
                        //break;
                        case Keys.None:
                            EditorToggleBarSelection(bar);
                            break;
                        }
                        editor.Invalidate();
                    }
                    else
                    {
                        ClearNoteAndBarSelection();
                    }
                }
                break;
            }

            case MouseButtons.Right:
                EditorPopupContextMenu(hit, e.Location.ToXna());
                break;
            }
        }
コード例 #5
0
        private void EditorPopupContextMenu(ScoreEditorHitTestResult hit, Point location)
        {
            VisualizerContextMenu menu;

            if (hit.HitRegion == ScoreEditorHitRegion.SpecialNoteArea)
            {
                menu = hit.HitAnyNote ? VisualizerContextMenu.SpecialNoteModify : VisualizerContextMenu.SpecialNoteAdd;
            }
            else
            {
                menu = hit.HitAnyNote ? VisualizerContextMenu.Note : VisualizerContextMenu.Bar;
            }
            var ea = new ContextMenuRequestedEventArgs(menu, hit);

            _visualizer.RequestContextMenu(ea);
        }
コード例 #6
0
        private void EditNoteModeSelect(ScoreEditorHitTestResult hit, MouseEventArgs e)
        {
            var editor = _visualizer.Editor;

            if (hit.HitAnyNote)
            {
                if (editor.HasSelectedBars)
                {
                    editor.ClearSelectedBars();
                    editor.Invalidate();
                }
                else
                {
                    var note = hit.Note;
                    if (note == _lastMouseDownNote)
                    {
                        switch (Control.ModifierKeys)
                        {
                        case Keys.Control:
                            EditorToggleNoteSelectionMultipleMode(note);
                            break;

                        case Keys.Shift:
                            // TODO: select a series of notes.
                            Debug.Print("TODO: select a series of notes.");
                            EditorToggleNoteSelection(note);
                            break;

                        case Keys.None:
                            EditorToggleNoteSelection(note);
                            break;
                        }
                        editor.Invalidate();
                    }
                }
            }
            else
            {
                ClearNoteAndBarSelection();
            }
        }
コード例 #7
0
        /// <summary>
        /// Performs a hit test and returns the result.
        /// </summary>
        /// <param name="x">The X coordinate of the hit test point, relative to this control.</param>
        /// <param name="y">The Y coordinate of the hit test point, relative to this control.</param>
        /// <returns>The result of this hit test.</returns>
        public ScoreEditorHitTestResult HitTest(int x, int y)
        {
            var score = Project?.Project.GetScore(Difficulty);

            if (score == null || !score.HasAnyBar)
            {
                return(ScoreEditorHitTestResult.GetInvalidResult(x, y));
            }

            var barArea = ScoreEditorLayout.GetBarArea(Config, ClientSize);

            if (!barArea.Contains(x, y))
            {
                return(ScoreEditorHitTestResult.GetInvalidResult(x, y));
            }

            var config = Config;
            ScoreEditorHitRegion hitRegion;
            var relativeX = x - barArea.Left;

            if (relativeX < config.InfoAreaWidth)
            {
                hitRegion = ScoreEditorHitRegion.InfoArea;
            }
            else if (relativeX < config.InfoAreaWidth + config.GridNumberAreaWidth - config.NoteRadius)
            {
                hitRegion = ScoreEditorHitRegion.GridNumberArea;
            }
            else if (relativeX < config.InfoAreaWidth + config.GridNumberAreaWidth + config.GridAreaWidth + config.NoteRadius)
            {
                hitRegion = ScoreEditorHitRegion.GridArea;
            }
            else
            {
                hitRegion = ScoreEditorHitRegion.SpecialNoteArea;
            }

            var gridArea    = ScoreEditorLayout.GetGridArea(config, ClientSize);
            var columnWidth = gridArea.Width / (config.NumberOfColumns - 1);

            var barStartY = (float)ScrollOffsetY;

            if (y > barStartY + config.NoteRadius)
            {
                return(ScoreEditorHitTestResult.GetInvalidResult(x, y));
            }

            var unit           = Look.BarLineSpaceUnit;
            var spaceUnitRatio = ScoreEditorLayout.SpaceUnitRadiusRatio;

            foreach (var bar in score.Bars)
            {
                var numGrids  = bar.GetNumberOfGrids();
                var barHeight = numGrids * unit;

                var hitInThisBar = barStartY + config.NoteRadius >= y && y > barStartY - (barHeight - config.NoteRadius);
                if (!hitInThisBar)
                {
                    // Continue to the next bar.
                    barStartY -= barHeight;
                    continue;
                }

                // Calculate zooming compensation.
                var firstClearDrawnRatio = ScoreEditorLayout.BarZoomRatio.FirstOrDefault(i => unit * i >= config.NoteRadius * spaceUnitRatio);
                if (firstClearDrawnRatio == 0)
                {
                    firstClearDrawnRatio = numGrids;
                }
                var newUnit = unit * firstClearDrawnRatio;

                // Locate the column.
                // Remember, gridArea is already adjusted.
                var relativeGridX = x - gridArea.Left;
                var testCol       = (int)((relativeGridX + config.NoteRadius) / columnWidth);
                if (testCol < 0)
                {
                    return(new ScoreEditorHitTestResult(new Point(x, y), hitRegion, bar, null, -1, NotePosition.Default));
                }
                var testX = testCol * columnWidth;
                int col;
                if (Math.Abs(relativeGridX - testX) < config.NoteRadius)
                {
                    col = testCol;
                }
                else if (Math.Abs(relativeGridX - (testX + columnWidth)) < config.NoteRadius)
                {
                    col = testCol + 1;
                }
                else
                {
                    if (hitRegion == ScoreEditorHitRegion.SpecialNoteArea)
                    {
                        col = -1;
                    }
                    else
                    {
                        return(new ScoreEditorHitTestResult(new Point(x, y), hitRegion, bar, null, -1, NotePosition.Default));
                    }
                }

                // Y position of the hit, relative to start of this bar.
                var relativeY = -(y - barStartY);

                // List the gaming note in current column.
                var possibleNotesInColumn = bar.Notes.Where(n => (int)n.Basic.FinishPosition == col + 1).ToList();

                // Variables for row locating.
                int   testRow, row;
                float testY;

                // If no note is hit, follow the traditional algorithm to find if there is any hit on special notes.
                if (possibleNotesInColumn.Count == 0)
                {
                    // Locate the row.
                    testRow = (int)((relativeY + config.NoteRadius) / newUnit);
                    if (testRow < 0)
                    {
                        break;
                    }
                    testY = testRow * newUnit;
                    if (Math.Abs(relativeY - testY) < config.NoteRadius)
                    {
                        row = testRow;
                    }
                    else if (Math.Abs(relativeY - (testY + newUnit)) < config.NoteRadius)
                    {
                        row = testRow + 1;
                    }
                    else
                    {
                        return(new ScoreEditorHitTestResult(new Point(x, y), hitRegion, bar, null, -1, NotePosition.Default));
                    }
                    row *= firstClearDrawnRatio;

                    // Hit any gaming note?
                    var note = bar.Notes.FirstOrDefault(n => n.Basic.IndexInGrid == row && (int)n.Basic.FinishPosition == col + 1);

                    // Hit any special note?
                    if (note == null && hitRegion == ScoreEditorHitRegion.SpecialNoteArea)
                    {
                        note = bar.Notes.FirstOrDefault(n => n.Helper.IsSpecial && n.Basic.IndexInGrid == row);
                    }

                    var result = new ScoreEditorHitTestResult(new Point(x, y), hitRegion, bar, note, row, col + 1);
                    return(result);
                }

                // Otherwise, use the new algorithm to find a possible note in current column.
                possibleNotesInColumn.Sort(Note.TimingComparison);

                var noteRadius = config.NoteRadius;
                for (var i = 0; i < possibleNotesInColumn.Count; ++i)
                {
                    var currentNote = possibleNotesInColumn[i];
                    var currentY    = unit * currentNote.Basic.IndexInGrid;
                    // Is the Y coordinate inside current note's region?
                    if (currentY - noteRadius <= relativeY && relativeY <= currentY + noteRadius)
                    {
                        // We got a possible match!
                        Note  nextNote;
                        float nextY;

                        if (i < possibleNotesInColumn.Count - 1)
                        {
                            // The next note is in the same bar.
                            nextNote = possibleNotesInColumn[i + 1];
                            nextY    = unit * nextNote.Basic.IndexInGrid;
                        }
                        else
                        {
                            // The next note is in the next bar, or...
                            var nextBar = bar.GetNextBar();

                            // it is too far away (then ignore it, we found a match).
                            if (nextBar == null || nextBar.Notes.Count == 0)
                            {
                                var result = new ScoreEditorHitTestResult(new Point(x, y), hitRegion, bar, currentNote, currentNote.Basic.IndexInGrid, col + 1);
                                return(result);
                            }

                            var notesOnSameColumnInNextBar = nextBar.Notes.Where(n => (int)n.Basic.FinishPosition == col + 1).ToList();
                            notesOnSameColumnInNextBar.Sort(Note.TimingComparison);
                            nextNote = notesOnSameColumnInNextBar.FirstOrDefault();
                            if (nextNote == null)
                            {
                                // Also too far away. We've found a match.
                                var result = new ScoreEditorHitTestResult(new Point(x, y), hitRegion, bar, currentNote, currentNote.Basic.IndexInGrid, col + 1);
                                return(result);
                            }

                            nextY = barHeight + unit * nextNote.Basic.IndexInGrid;
                        }

                        // Is the Y coordinate not overlapped by the next note (because the notes are drawn from bottom to top)?
                        if (relativeY < nextY - noteRadius)
                        {
                            var result = new ScoreEditorHitTestResult(new Point(x, y), hitRegion, bar, currentNote, currentNote.Basic.IndexInGrid, col + 1);
                            return(result);
                        }
                    }
                }

                // Locate the row. Again.
                testRow = (int)((relativeY + config.NoteRadius) / newUnit);
                if (testRow < 0)
                {
                    break;
                }
                testY = testRow * newUnit;
                if (Math.Abs(relativeY - testY) < config.NoteRadius)
                {
                    row = testRow;
                }
                else if (Math.Abs(relativeY - (testY + newUnit)) < config.NoteRadius)
                {
                    row = testRow + 1;
                }
                else
                {
                    return(new ScoreEditorHitTestResult(new Point(x, y), hitRegion, bar, null, -1, NotePosition.Default));
                }
                row *= firstClearDrawnRatio;

                // Sorry, no can do. Maybe you hit the empty area.
                return(new ScoreEditorHitTestResult(new Point(x, y), hitRegion, bar, null, row, col + 1));
            }

            return(new ScoreEditorHitTestResult(new Point(x, y), hitRegion, null, null, -1, NotePosition.Default));
        }
コード例 #8
0
        private void EditNoteModeHoldFlick(ScoreEditorHitTestResult hit, MouseEventArgs e)
        {
            var editor = _visualizer.Editor;

            Note lastNote = null;

            if (editor.HasOneSelectedNote)
            {
                lastNote = editor.GetSelectedNote();
            }
            else if (hit.HitAnyNote && editor.HasSelectedNotes)
            {
                Debug.Print("You can only select one note to create a hold pair.");
                return;
            }

            Note thisNote    = null;
            var  isNoteAdded = false;

            if (hit.HitAnyNote)
            {
                // The clicked note is always selected.
                thisNote = hit.Note == _lastMouseDownNote ? hit.Note : null;
            }
            else if (hit.HitBarGridIntersection)
            {
                // If not selected, add a note and select it.
                thisNote    = EditorAddNote(hit);
                isNoteAdded = true;
            }

            // If the user clicked on nothing, then clear all selections.
            if (thisNote == null)
            {
                ClearNoteAndBarSelection();
                editor.Invalidate();
                return;
            }

            // If the user clicked on the same note, just perform the standard note selection.
            if (lastNote == null || lastNote == thisNote)
            {
                thisNote.EditorToggleSelected();
                editor.Invalidate();
                return;
            }

            var relationCreated = false;

            if (thisNote.Basic.FinishPosition == lastNote.Basic.FinishPosition)
            {
                do
                {
                    // If the selected note is already a hold note (start/end) and there is a hold relation between the
                    // two notes, then switch selection.
                    if (NoteHelper.AreNotesInHoldChain(thisNote, lastNote))
                    {
                        // Yep just switch selection. Do nothing in this branch.
                    }
                    else
                    {
                        var errStr = EnsureHoldValid(thisNote, lastNote);
                        if (errStr != null)
                        {
                            if (isNoteAdded)
                            {
                                thisNote.Basic.Bar.RemoveNote(thisNote);
                            }
                            Debug.Print(errStr);
                            break;
                        }

                        // Make hold.
                        var(first, second) = NoteHelper.Split(thisNote, lastNote);
                        NoteHelper.MakeHold(first, second);
                        _visualizer.InformProjectModified();
                        relationCreated = true;
                    }
                } while (false);
            }
            else
            {
                do
                {
                    // If the selected note is already a flick note and there is a flick relation between the
                    // two notes, then switch selection.
                    if (NoteHelper.AreNotesInFlickChain(thisNote, lastNote))
                    {
                        // Yep just switch selection. Do nothing in this branch.
                    }
                    else
                    {
                        var errStr = EnsureFlickValid(thisNote, lastNote);
                        if (errStr != null)
                        {
                            if (isNoteAdded)
                            {
                                thisNote.Basic.Bar.RemoveNote(thisNote);
                            }
                            Debug.Print(errStr);
                            break;
                        }

                        // Make flick.
                        var(first, second) = NoteHelper.Split(thisNote, lastNote);
                        NoteHelper.MakeFlick(first, second);
                        _visualizer.InformProjectModified();
                        relationCreated = true;
                    }
                } while (false);
            }

            // Now handle a special case: link flick after a slide.
            if (!relationCreated)
            {
                var(first, second) = NoteHelper.Split(thisNote, lastNote);
                if (first.Basic.FinishPosition != second.Basic.FinishPosition)
                {
                    if (first.Helper.IsSlideEnd && second.Helper.IsFlickStart)
                    {
                        NoteHelper.MakeSlideToFlick(first, second);
                        _visualizer.InformProjectModified();
                        relationCreated = true;
                    }
                }
            }

            if (relationCreated)
            {
                thisNote.EditorUnselect();
                lastNote.EditorUnselect();
            }
            else
            {
                lastNote.EditorUnselect();
                thisNote.EditorSelect();
            }

            // Did we created a hold pair?
            // If so, ensure the pair's start position being the same.
            if (relationCreated)
            {
                if (thisNote.Helper.IsHoldStart)
                {
                    thisNote.Editor.HoldPair.Basic.StartPosition = thisNote.Basic.StartPosition;
                }
                else if (thisNote.Helper.IsHoldEnd)
                {
                    thisNote.Basic.StartPosition = thisNote.Editor.HoldPair.Basic.StartPosition;
                }
            }

            editor.Invalidate();
        }
コード例 #9
0
 private void SpecialNoteAreaOnMouseDown(ScoreEditorHitTestResult hit, MouseEventArgs e)
 {
 }
コード例 #10
0
        private void GridAreaOnMouseUp(ScoreEditorHitTestResult hit, MouseEventArgs e)
        {
            var editor = _visualizer.Editor;

            switch (e.Button)
            {
            case MouseButtons.Left:
                if (!_selectionRectangle.IsEmpty)
                {
                    // We are handling selection here.
                    break;
                }

                // Whatever note you hit, change its start up position.
                // If no note is hit and we are hitting a grid crossing, the EditorAddNote method is invoked
                // and the newly added note's StartPosition is automatically set there.
                if (hit.HitAnyNote && editor.NoteStartPosition != NotePosition.Default)
                {
                    var note = hit.Note;
                    note.Basic.StartPosition = editor.NoteStartPosition;
                    if (note.Helper.IsHoldStart)
                    {
                        note.Editor.HoldPair.Basic.StartPosition = note.Basic.StartPosition;
                    }
                    else if (note.Helper.IsHoldEnd)
                    {
                        note.Basic.StartPosition = note.Editor.HoldPair.Basic.StartPosition;
                    }
                    _visualizer.InformProjectModified();
                }

                if (hit.HitAnyNote)
                {
                    var modifiers = Control.ModifierKeys;
                    if (modifiers == Keys.Alt)
                    {
                        if (hit.Note.Helper.IsHoldEnd || hit.Note.Helper.IsSlideEnd)
                        {
                            // Alt+Click on end hold or end slide to change its flick type.
                            var flickType = hit.Note.Basic.FlickType;
                            switch (flickType)
                            {
                            case NoteFlickType.None:
                                flickType = NoteFlickType.Left;
                                break;

                            case NoteFlickType.Left:
                                flickType = NoteFlickType.Right;
                                break;

                            case NoteFlickType.Right:
                                flickType = NoteFlickType.None;
                                break;

                            default:
                                throw new ArgumentOutOfRangeException(nameof(flickType), flickType, null);
                            }
                            hit.Note.Basic.FlickType = flickType;
                            _visualizer.InformProjectModified();
                        }
                        else if (hit.Note.Helper.IsFlickEnd)
                        {
                            // Alt+Click on end flick to change its flick type. Left / right only.
                            // This can be used to make reversed flick. (Star!!, Master+)
                            var flickType = hit.Note.Basic.FlickType;
                            switch (flickType)
                            {
                            case NoteFlickType.Left:
                                flickType = NoteFlickType.Right;
                                break;

                            case NoteFlickType.Right:
                                flickType = NoteFlickType.Left;
                                break;

                            default:
                                throw new ArgumentOutOfRangeException(nameof(flickType), flickType, null);
                            }
                            hit.Note.Basic.FlickType = flickType;
                            _visualizer.InformProjectModified();
                        }
                    }
                }

                // Then handle the mode-specific actions.
                switch (editor.EditMode)
                {
                case ScoreEditMode.Select:
                    EditNoteModeSelect(hit, e);
                    break;

                case ScoreEditMode.Tap:
                    EditNoteModeTap(hit, e);
                    break;

                case ScoreEditMode.HoldFlick:
                    EditNoteModeHoldFlick(hit, e);
                    break;

                case ScoreEditMode.Slide:
                    EditNoteModeSlide(hit, e);
                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(editor.EditMode), editor.EditMode, null);
                }
                break;

            case MouseButtons.Right:
                EditorPopupContextMenu(hit, e.Location.ToXna());
                break;
            }
        }
コード例 #11
0
 private void GridAreaOnMouseDown(ScoreEditorHitTestResult hit, MouseEventArgs e)
 {
 }
コード例 #12
0
 private void GridNumberAreaOnMouseUp(ScoreEditorHitTestResult hit, MouseEventArgs e)
 {
     ClearNoteAndBarSelection();
 }