public void MouseMove(MouseEventArgs args, Keys modifiers)
        {
            if (mode != NoteSelectionMode.None)
            {
                rect.Width  = args.X - rect.X;
                rect.Height = args.Y - rect.Y;

                if (modifiers == Keys.Shift)
                {
                    mode = NoteSelectionMode.Add;
                }
                else if (modifiers == Keys.Alt)
                {
                    mode = NoteSelectionMode.Intersect;
                }
                else if (modifiers == Keys.Control)
                {
                    mode = NoteSelectionMode.Subtract;
                }
                else if (modifiers == Keys.Space)
                {
                    mode = NoteSelectionMode.Replace;
                }

                Redraw?.Invoke();
            }
        }
        public void MouseUp(MouseEventArgs args)
        {
            if (rect.Width < 0)
            {
                rect.X     += rect.Width;
                rect.Width *= -1;
            }

            if (rect.Height < 0)
            {
                rect.Y      += rect.Height;
                rect.Height *= -1;
            }

            Selected?.Invoke(rect, mode);

            mode   = NoteSelectionMode.None;
            rect.X = float.NaN;
            rect.Y = float.NaN;
        }
        public void MouseDown(MouseEventArgs args, Keys modifiers)
        {
            rect.X = args.X;
            rect.Y = args.Y;

            if (modifiers == Keys.Shift)
            {
                mode = NoteSelectionMode.Add;
            }
            else if (modifiers == Keys.Alt)
            {
                mode = NoteSelectionMode.Intersect;
            }
            else if (modifiers == Keys.Control)
            {
                mode = NoteSelectionMode.Subtract;
            }
            else
            {
                mode = NoteSelectionMode.Replace;
            }
        }
        private void Mouseselector_Selected(RectangleF rect, NoteSelectionMode mode)
        {
            //TODO: does this work when a track has different staves throughout its duration?

            var effectedarea = default(Duration);

            if (mode == NoteSelectionMode.Replace)
            {
                foreach (var selectionkvp in editor.NoteSelections)
                {
                    var track     = selectionkvp.Key;
                    var selection = selectionkvp.Value;

                    foreach (var noteID in selection.Selected_NoteIDs)
                    {
                        effectedarea = track.Melody[noteID].Duration.Union(effectedarea);
                    }

                    selection.Selected_Start.Clear();
                    selection.Selected_End.Clear();
                    selection.Selected_Tone.Clear();
                }
            }

            for (int i = 0; i < editor.Tracks.Count; i++)
            {
                var track =
                    editor.Tracks[i] as MusicTrack;

                var selection = editor.NoteSelections[track];

                var fakeselection = new NoteSelection();

                foreach (var itemtuple in GetItemsWithRects(track))
                {
                    if (itemtuple.Item1.IntersectsWith(rect))
                    {
                        rect.Offset(-itemtuple.Item1.X, -itemtuple.Item1.Y);

                        itemtuple.Item3.Select(fakeselection, rect, itemtuple.Item2, itemtuple.Item1.Width);

                        rect.Offset(+itemtuple.Item1.X, +itemtuple.Item1.Y);
                    }
                }

                switch (mode)
                {
                case NoteSelectionMode.Replace:
                case NoteSelectionMode.Add:
                    foreach (var noteID in fakeselection.Selected_Start)
                    {
                        var note = track.Melody[noteID];
                        effectedarea = note.Duration.Union(effectedarea);

                        selection.Selected_Start.Add(noteID);
                    }
                    foreach (var noteID in fakeselection.Selected_End)
                    {
                        var note = track.Melody[noteID];
                        effectedarea = note.Duration.Union(effectedarea);

                        selection.Selected_End.Add(noteID);
                    }
                    foreach (var noteID in fakeselection.Selected_Tone)
                    {
                        var note = track.Melody[noteID];
                        effectedarea = note.Duration.Union(effectedarea);

                        selection.Selected_Tone.Add(noteID);
                    }
                    break;

                case NoteSelectionMode.Intersect:
                    foreach (var noteID in selection.Selected_Start.ToArray())
                    {
                        if (!fakeselection.Selected_Start.Contains(noteID))
                        {
                            var note = track.Melody[noteID];
                            effectedarea = note.Duration.Union(effectedarea);

                            selection.Selected_Start.Remove(noteID);
                        }
                    }
                    foreach (var noteID in selection.Selected_End.ToArray())
                    {
                        if (!fakeselection.Selected_End.Contains(noteID))
                        {
                            var note = track.Melody[noteID];
                            effectedarea = note.Duration.Union(effectedarea);

                            selection.Selected_End.Remove(noteID);
                        }
                    }
                    foreach (var noteID in selection.Selected_Tone.ToArray())
                    {
                        if (!fakeselection.Selected_Tone.Contains(noteID))
                        {
                            var note = track.Melody[noteID];
                            effectedarea = note.Duration.Union(effectedarea);

                            selection.Selected_Tone.Remove(noteID);
                        }
                    }
                    break;

                case NoteSelectionMode.Subtract:
                    foreach (var noteID in selection.Selected_Start.ToArray())
                    {
                        if (fakeselection.Selected_Start.Contains(noteID))
                        {
                            var note = track.Melody[noteID];
                            effectedarea = note.Duration.Union(effectedarea);

                            selection.Selected_Start.Remove(noteID);
                        }
                    }
                    foreach (var noteID in selection.Selected_End.ToArray())
                    {
                        if (fakeselection.Selected_End.Contains(noteID))
                        {
                            var note = track.Melody[noteID];
                            effectedarea = note.Duration.Union(effectedarea);

                            selection.Selected_End.Remove(noteID);
                        }
                    }
                    foreach (var noteID in selection.Selected_Tone.ToArray())
                    {
                        if (fakeselection.Selected_Tone.Contains(noteID))
                        {
                            var note = track.Melody[noteID];
                            effectedarea = note.Duration.Union(effectedarea);

                            selection.Selected_Tone.Remove(noteID);
                        }
                    }
                    break;

                case NoteSelectionMode.Xor:
                    foreach (var noteID in fakeselection.Selected_Start)
                    {
                        var note = track.Melody[noteID];
                        effectedarea = note.Duration.Union(effectedarea);

                        if (selection.Selected_Start.Contains(noteID))
                        {
                            selection.Selected_Start.Remove(noteID);
                        }
                        else
                        {
                            selection.Selected_Start.Add(noteID);
                        }
                    }
                    foreach (var noteID in fakeselection.Selected_End)
                    {
                        var note = track.Melody[noteID];
                        effectedarea = note.Duration.Union(effectedarea);

                        if (selection.Selected_End.Contains(noteID))
                        {
                            selection.Selected_End.Remove(noteID);
                        }
                        else
                        {
                            selection.Selected_End.Add(noteID);
                        }
                    }
                    foreach (var noteID in fakeselection.Selected_Tone)
                    {
                        var note = track.Melody[noteID];
                        effectedarea = note.Duration.Union(effectedarea);

                        if (selection.Selected_Tone.Contains(noteID))
                        {
                            selection.Selected_Tone.Remove(noteID);
                        }
                        else
                        {
                            selection.Selected_Tone.Add(noteID);
                        }
                    }
                    break;
                }
            }

            if (effectedarea != null)
            {
                editor.InvalidateTime(effectedarea);
            }

            Invalidate();
        }