Пример #1
0
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            e.Graphics.Clear(Color.Black);

            try
            {
                var renderRequest = new RenderRequest
                {
                    Graphics    = e.Graphics,
                    CursorPoint = PointToClient(Cursor.Position),
                    IsHitTest   = false
                };

                Render(renderRequest);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
Пример #2
0
        public void Render(RenderRequest request)
        {
            var g = request.Graphics;

            // Draw the image, with stretching.
            // Might be very ugly, but the thread will improve its resolution step by step.
            var viewPortStart = Normalize(GetCurrentViewPortStart());
            var viewPortEnd   = Normalize(GetCurrentViewPortEnd());

            if (NoteRequest != null)
            {
                var viewPortInterval = new Interval(viewPortStart, viewPortEnd);

                var args = new AudioPaintEventArgs(viewPortInterval);
                NoteRequest(this, args);
                request.Notes = args.Notes;
            }

            if (request.IsRendering)
            {
                for (var i = 0; i < _work.Count; i++)
                {
                    var work = _work[i];
                    if (work.Bitmap == null)
                    {
                        continue;
                    }

                    if (work.To < viewPortStart)
                    {
                        // We've yet to get to a work that is visible.
                        continue;
                    }

                    if (work.From > viewPortEnd)
                    {
                        // We've past the last visible work, so we can abort now.
                        break;
                    }

                    var x = NormalizedByteIndexToClientX(work.From);
                    g.DrawImageUnscaled(work.Bitmap.Bitmap, (int)Math.Round(x), 0);
                }

                if (RepeatLength > 0)
                {
                    var repeatStartX = (float)ByteIndexToClientX(_repeatCurrent);
                    if (float.IsNaN(repeatStartX) == false)
                    {
                        var endByteIndex  = _repeatCurrent + Bass.ChannelSeconds2Bytes(_playChannel, _repeatLength);
                        var repeatEndX    = (float)ByteIndexToClientX(endByteIndex);
                        var repeatMiddleX =
                            (float)ByteIndexToClientX(endByteIndex -
                                                      Bass.ChannelSeconds2Bytes(_playChannel, _repeatBackwards));

                        const int repeatMarkerHeight = 20;
                        var       outlinePen         = Pens.Black;
                        var       y1 = ClientRectangle.Height - repeatMarkerHeight;
                        var       y2 = ClientRectangle.Height;

                        {
                            g.DrawLine(outlinePen, repeatStartX - 1, y1, repeatStartX - 1, y2);
                            g.DrawLine(outlinePen, repeatStartX - 1, y1 - 1, repeatStartX + 1, y1 - 1);
                            g.DrawLine(outlinePen, repeatStartX + 1, y1, repeatStartX + 1, y2);
                            g.DrawLine(Pens.LawnGreen, repeatStartX, y1, repeatStartX, y2);
                        }

                        {
                            g.DrawLine(outlinePen, repeatMiddleX - 1, y1, repeatMiddleX - 1, y2);
                            g.DrawLine(outlinePen, repeatMiddleX - 1, y1 - 1, repeatMiddleX + 1, y1 - 1);
                            g.DrawLine(outlinePen, repeatMiddleX + 1, y1, repeatMiddleX + 1, y2);
                            g.DrawLine(Pens.Orange, repeatMiddleX, y1, repeatMiddleX, y2);
                        }

                        {
                            g.DrawLine(outlinePen, repeatEndX - 1, y1, repeatEndX - 1, y2);
                            g.DrawLine(outlinePen, repeatEndX - 1, y1 - 1, repeatEndX + 1, y1 - 1);
                            g.DrawLine(outlinePen, repeatEndX + 1, y1, repeatEndX + 1, y2);
                            g.DrawLine(Pens.Red, repeatEndX, y1, repeatEndX, y2);
                        }

                        if (_repeatPauseRemaining > 0)
                        {
                            var timeString = "" + Math.Round(_repeatPauseRemaining / 1000d, 1);
                            var textSize   = g.MeasureString(timeString, SystemFonts.StatusFont);
                            g.DrawString(timeString, SystemFonts.StatusFont, Brushes.Red, Width - textSize.Width - 20,
                                         5);
                        }
                    }
                }
            }

            float paddingBottom = ClientRectangle.Bottom;

            if (IsPlayable)
            {
                var millisecondsStart =
                    (long)Math.Round(Bass.ChannelBytes2Seconds(_playChannel, viewPortStart) * 1000d);
                var millisecondsEnd = (long)Math.Round(Bass.ChannelBytes2Seconds(_playChannel, viewPortEnd) * 1000d);

                var millisecondsDistance = millisecondsEnd - millisecondsStart;

                // Resolution is one large marker every 50 pixels.
                var        preferredResolution = millisecondsDistance / (Width / 50d);
                const long startingResolution  = 100L;
                var        actualResolution    = startingResolution;

                var multipliers = new long[]
                {
                    10,    // 1 second
                    20,    // 2 seconds
                    50,    // 5 seconds
                    100,   // 10 seconds
                    150,   // 15 seconds
                    300,   // 30 seconds
                    600,   // 1 minute
                    1200,  // 2 minutes
                    3000,  // 5 minutes
                    6000,  // 10 minutes
                    9000,  // 15 minutes
                    18000, // 30 minutes
                    36000  // 1 hour
                };

                for (var i = 0; i < multipliers.Length && actualResolution < preferredResolution; i++)
                {
                    actualResolution = startingResolution * multipliers[i];
                }

                var milliseconds = millisecondsStart - millisecondsStart % actualResolution;
                while (milliseconds < millisecondsEnd)
                {
                    var offsetMilliseconds = milliseconds - millisecondsStart;
                    var x = (int)Math.Floor(offsetMilliseconds * (Width / (double)millisecondsDistance));

                    var stringTime = "" + getTimeString(milliseconds / 1000d / 60) + ":" +
                                     getTimeString(milliseconds / 1000d % 60);

                    var timeLineTop = ClientRectangle.Bottom - 10;
                    paddingBottom = Math.Min(paddingBottom, timeLineTop);

                    if (request.IsRendering)
                    {
                        g.DrawLine(Pens.White, x, timeLineTop, x, ClientRectangle.Bottom);

                        using (var f = new Font(FontFamily.GenericSansSerif, 7f))
                        {
                            var textSize = g.MeasureString(stringTime, f);
                            g.DrawString(stringTime, f, Brushes.White, x + 1, ClientRectangle.Bottom - textSize.Height);
                        }
                    }

                    milliseconds += actualResolution;
                }
            }

            if (request.Notes != null)
            {
                if (_mouseDraggingObject is Note)
                {
                    request.FocusedObject = _mouseDraggingObject;
                    request.HitTestArea   = _mouseDraggingArea;
                }

                const int hoverPadding = 10;
                foreach (var note in request.Notes)
                {
                    var x1     = (float)ByteIndexToClientX(note.Interval.Start);
                    var x2     = (float)ByteIndexToClientX(note.Interval.End);
                    var top    = paddingBottom - 45f;
                    var height = 40f;

                    var noteRectangle = new RectangleF(x1, top, x2 - x1, height);

                    if (request.FocusedObject == null)
                    {
                        var ht = request.CursorPoint;
                        if (ht.Y >= noteRectangle.Top && ht.Y <= noteRectangle.Bottom)
                        {
                            if (ht.X >= noteRectangle.Left && ht.X <= noteRectangle.Left + hoverPadding)
                            {
                                request.HitTestArea   = HitTestArea.NoteLeft;
                                request.CursorResult  = Cursors.SizeWE;
                                request.FocusedObject = note;
                            }
                            else if (ht.X >= noteRectangle.Right - hoverPadding && ht.X <= noteRectangle.Right)
                            {
                                request.HitTestArea   = HitTestArea.NoteRight;
                                request.CursorResult  = Cursors.SizeWE;
                                request.FocusedObject = note;
                            }
                            else if (noteRectangle.Contains(ht))
                            {
                                request.HitTestArea   = HitTestArea.NoteCenter;
                                request.CursorResult  = Cursors.Hand;
                                request.FocusedObject = note;
                            }
                        }
                    }

                    if (request.IsHitTest == false)
                    {
                        if (noteRectangle.Width > 1)
                        {
                            using (var b = new SolidBrush(Color.FromArgb(150, Color.GhostWhite)))
                            {
                                g.FillRectangle(b, noteRectangle);
                            }

                            if (note.Equals(request.FocusedObject))
                            {
                                using (var hatch = new HatchBrush(HatchStyle.Percent20, Color.LightGray,
                                                                  Color.Transparent))
                                {
                                    g.FillRectangle(hatch, noteRectangle.Left, noteRectangle.Top, hoverPadding,
                                                    noteRectangle.Height);
                                    g.FillRectangle(hatch, noteRectangle.Right - hoverPadding, noteRectangle.Top,
                                                    hoverPadding, noteRectangle.Height);
                                }
                            }

                            g.DrawRectangle(note.Equals(request.FocusedObject) ? Pens.LightGray : Pens.Gray,
                                            noteRectangle.Left, noteRectangle.Top, noteRectangle.Width, noteRectangle.Height);

                            var stringFormat = new StringFormat();
                            stringFormat.FormatFlags = StringFormatFlags.NoWrap;

                            using (var f = new Font(FontFamily.GenericSansSerif, 8f))
                            {
                                var measure = g.MeasureString(note.Text, f, noteRectangle.Size, stringFormat);
                                var offsetX = noteRectangle.Width / 2f - measure.Width / 2f;
                                var offsetY = noteRectangle.Height / 2f - measure.Height / 2f;

                                noteRectangle.Offset(offsetX, offsetY);

                                g.DrawString(note.Text, f, Brushes.Black, noteRectangle, stringFormat);
                            }
                        }
                    }
                }
            }

            if (request.IsRendering == false)
            {
                return;
            }

            if (_mouseDraggingZoom)
            {
                var xLow  = Math.Min(_mouseDragStartX, _mouseDragEndX);
                var xHigh = Math.Max(_mouseDragStartX, _mouseDragEndX);

                using (var b = new SolidBrush(Color.FromArgb(50, Color.LightBlue)))
                {
                    g.FillRectangle(b, new Rectangle(xLow, 0, xHigh - xLow, ClientRectangle.Height));
                }

                g.DrawLine(Pens.Gray, xLow, 0, xLow, ClientRectangle.Height);
                g.DrawLine(Pens.Gray, xHigh, 0, xHigh, ClientRectangle.Height);
            }

            const int infoPadding       = 5;
            var       overviewRectangle = new RectangleF(
                infoPadding,
                infoPadding,
                ClientRectangle.Width * 0.10f,
                10);

            using (var dimBrush = new SolidBrush(Color.FromArgb(150, Color.Gray)))
            {
                var timeSinceAnimation = DateTime.Now - _timestampLastAttributeChange;
                if (timeSinceAnimation <= _attributeChangeAnimationLength)
                {
                    var volumeWidth  = Math.Max(20, Width * 0.20f);
                    var volumeHeight = Math.Min(20, Math.Max(5, Height * 0.10f));
                    var rectVolume   = new RectangleF(
                        Width * 0.5f - volumeWidth / 2f, Height * 0.5f - volumeHeight / 2f,
                        volumeWidth, volumeHeight);
                    var volumeX = rectVolume.X + rectVolume.Width * GetVolume();

                    var c = new HsvColor((int)(360 * GetVolume()), 75, 75).ToColor();

                    g.FillRectangle(Brushes.DarkGray, rectVolume);

                    using (var intensityBrush = new SolidBrush(c))
                    {
                        g.FillRectangle(intensityBrush, rectVolume.Left, rectVolume.Top, volumeX - rectVolume.Left,
                                        rectVolume.Height);
                    }

                    g.DrawRectangle(Pens.WhiteSmoke, rectVolume.X, rectVolume.Y, rectVolume.Width, rectVolume.Height);
                    g.DrawLine(Pens.WhiteSmoke, volumeX, rectVolume.Top, volumeX, rectVolume.Bottom);

                    var percentageString = Math.Round(GetVolume() * 100) + "%";
                    var size             = g.MeasureString(percentageString, SystemFonts.StatusFont);
                    g.DrawString(percentageString, SystemFonts.StatusFont, Brushes.WhiteSmoke, rectVolume.Right + 4f,
                                 rectVolume.Top + rectVolume.Height / 2 - size.Height / 2f);
                }

                long bytePosition;
                if (IsPlayable)
                {
                    bytePosition = Normalize(Bass.ChannelGetPosition(_playChannel));

                    var timePosition      = Bass.ChannelBytes2Seconds(_playChannel, bytePosition);
                    var stringTimeCurrent =
                        "" + getTimeString(timePosition / 60) + ":" + getTimeString(timePosition % 60);
                    g.DrawString(stringTimeCurrent, SystemFonts.DefaultFont, Brushes.White, overviewRectangle.Right,
                                 overviewRectangle.Top);
                }
                else
                {
                    bytePosition = 0;
                }

                if (_bytesTotal > 0)
                {
                    g.FillRectangle(dimBrush, overviewRectangle.X, overviewRectangle.Y, overviewRectangle.Width,
                                    overviewRectangle.Height);

                    var bytesPerOverviewPixel = _bytesTotal / overviewRectangle.Width;
                    var overviewStartX        = overviewRectangle.Left + viewPortStart / bytesPerOverviewPixel;

                    using (var overviewFocusBrush = new SolidBrush(Color.FromArgb(150, Color.LightBlue)))
                    {
                        var overviewWidth = (long)Math.Max(1, overviewRectangle.Width * GetZoomRatio());
                        g.FillRectangle(overviewFocusBrush, overviewStartX, overviewRectangle.Y, overviewWidth,
                                        overviewRectangle.Height);
                    }

                    if (bytePosition >= 0)
                    {
                        using (var caretPen = new Pen(Color.FromArgb(150, Color.Red)))
                        {
                            var globalCaretX   = (float)ByteIndexToClientX(bytePosition);
                            var overviewCaretX = overviewRectangle.Left + bytePosition / bytesPerOverviewPixel;

                            g.DrawLine(caretPen, globalCaretX, 0, globalCaretX, ClientRectangle.Height);
                            g.DrawLine(caretPen, overviewCaretX, overviewRectangle.Top, overviewCaretX,
                                       overviewRectangle.Bottom);
                        }
                    }
                }
            }
        }
Пример #3
0
        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);

            var renderRequest = new RenderRequest
            {
                IsHitTest   = true,
                CursorPoint = e.Location
            };

            Render(renderRequest);

            switch (e.Button)
            {
            case MouseButtons.XButton1:
            case MouseButtons.XButton2:

                // TODO: Redo this so that the paragraph selected in the text is the selected one
                // TODO: Mouse4 changes start, mouse5 changes end
                // TODO: The note should not have to be visible; remake the NoteMoved so the note is not required


                // Middle mouse button should resize the note according to the most closely clicked location, in relevance to the location that the user is in the text
                var    clickedByteIndex = ClientXToByteIndex(e.X);
                var    clickedInterval  = new Interval(clickedByteIndex, clickedByteIndex);
                long[] closestDistances = null;
                var    closestDistance  = long.MaxValue;
                Note   closestNote      = null;
                foreach (var note in renderRequest.Notes)
                {
                    if (note.IsFocused)
                    {
                        closestNote      = note;
                        closestDistances = note.Interval.GetDistanceFromOverlap(clickedByteIndex);
                        break;
                    }
                }

                if (closestNote == null)
                {
                    foreach (var note in renderRequest.Notes)
                    {
                        var distance = note.Interval.GetDistanceFromOverlap(clickedByteIndex);
                        if (note.IsFocused || note.Interval.IsOverlapping(clickedInterval))
                        {
                            closestNote      = note;
                            closestDistances = distance;
                            break;
                        }

                        var actualDistance = Math.Min(Math.Abs(distance[0]), Math.Abs(distance[1]));
                        if (actualDistance < closestDistance)
                        {
                            closestNote      = note;
                            closestDistances = distance;
                            closestDistance  = actualDistance;
                        }
                    }
                }

                if (closestNote != null)
                {
                    var isStart = Math.Abs(closestDistances[0]) < Math.Abs(closestDistances[1]);

                    if (NoteMoved != null)
                    {
                        var args = new NoteMovedEventArgs
                        {
                            Area      = isStart ? HitTestArea.NoteLeft : HitTestArea.NoteRight,
                            ByteIndex = clickedByteIndex,
                            Note      = closestNote
                        };

                        NoteMoved(this, args);
                    }
                }

                break;

            case MouseButtons.Middle:
                break;

                #region old zoom code

                /*
                 * if (this._mouseDraggingZoom)
                 * {
                 * // Let's set the time zoom!
                 * var low = Math.Max(0, Math.Min(this._mouseDragStartX, this._mouseDragEndX));
                 * var high = Math.Min(this.ClientRectangle.Width, Math.Max(this._mouseDragStartX, this._mouseDragEndX));
                 *
                 * // Set as approximative as we can.
                 * var timeStart = this.ClientXToByteIndex(low);
                 * var timeEnd = this.ClientXToByteIndex(high);
                 *
                 * this._zoomStack.Push((timeEnd - timeStart) / (double)this._bytesTotal);
                 *
                 * // Restart the processing, since we've now zoomed in.
                 * this.ClearWork();
                 * this.QueueWork(new Work(this.GetCurrentViewPortStart(), this.GetCurrentViewPortEnd()));
                 * }
                 * else
                 * {
                 * // The user clicked Middle Mouse, but had not selected anything. Let's zoom out.
                 * // Zoom out to the previous zoom level.
                 * if (this._zoomStack.Count > 0)
                 * {
                 *  this._zoomStack.Pop();
                 *  this.ClearWork();
                 *  this.QueueWork(new Work(this.GetCurrentViewPortStart(), this.GetCurrentViewPortEnd()));
                 * }
                 * }
                 */

                #endregion

            case MouseButtons.Left:
                if (_mouseDraggingPan == false)
                {
                    var note = renderRequest.FocusedObject as Note;
                    if (note != null)
                    {
                        if (NoteClicked != null)
                        {
                            NoteClicked(this, new NoteClickedEventArgs
                            {
                                Note = note,
                                Area = renderRequest.HitTestArea
                            });
                        }
                    }
                }

                break;
            }

            if (_mouseDraggingPan)
            {
                if (_mouseDraggingObject == null && IsCaretInsideViewPort)
                {
                    var distanceIntoViewPort = GetCurrentBytePosition() - GetCurrentViewPortStart();
                    _caretOffset = distanceIntoViewPort / (double)GetCurrentViewPortDistance();
                }
                else
                {
                    // Since we stopped panning outside of the currently playing viewport, we'll set the caret offset to NaN.
                    // This means that the viewport will stay where it is, while the track is playing.
                    switch (Bass.ChannelIsActive(_playChannel))
                    {
                    case PlaybackState.Playing:
                        _caretOffset = double.NaN;
                        break;
                    }
                }

                // Let's get the new area that should be rendered, and queue the work.
                // We'll add the whole visible viewport, and it will automatically be split and merged properly.
                var work = new Work(GetCurrentViewPortStart(), GetCurrentViewPortEnd());
                QueueWork(work);
            }

            Cursor               = Cursors.Default;
            _mouseDraggingZoom   = false;
            _mouseDraggingPan    = false;
            _mouseDown           = false;
            _mouseDraggingObject = null;
            _mouseDraggingArea   = HitTestArea.None;

            Invalidate();
        }
Пример #4
0
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);

            switch (e.Button)
            {
            case MouseButtons.Right:

                // Set the caret position, so that we'll start following with the viewport
                _viewPortStart = GetCurrentViewPortStart();

                // Start playing at the location that was clicked.
                var clickedByteIndex = ClientXToByteIndex(e.Location.X);

                switch (Bass.ChannelIsActive(_playChannel))
                {
                case PlaybackState.Playing:
                    StartPlaying(clickedByteIndex);
                    break;

                default:
                    SetLocation(clickedByteIndex);
                    break;
                }

                if (double.IsNaN(_caretOffset) == false)
                {
                    _caretOffset = e.X / (double)ClientRectangle.Width;
                }
                break;

            case MouseButtons.Middle:
                _mouseDown       = true;
                _mouseDragStartX = e.Location.X;
                break;

            case MouseButtons.Left:

                var request = new RenderRequest
                {
                    IsHitTest   = true,
                    CursorPoint = e.Location
                };

                Render(request);

                _mouseDown         = true;
                _mouseDragStartX   = e.Location.X;
                _mouseDraggingArea = HitTestArea.None;

                var note = request.FocusedObject as Note;
                if (note != null)
                {
                    _mouseDraggingArea   = request.HitTestArea;
                    _mouseDraggingObject = request.FocusedObject;
                    _viewPortStart       = GetCurrentViewPortStart();

                    switch (Bass.ChannelIsActive(_playChannel))
                    {
                    case PlaybackState.Playing:
                        _caretOffset = double.NaN;
                        break;
                    }

                    switch (request.HitTestArea)
                    {
                    case HitTestArea.NoteLeft:
                        _mouseDragByteIndexStart = note.Interval.Start;
                        break;

                    case HitTestArea.NoteRight:
                        _mouseDragByteIndexStart = note.Interval.End;
                        break;

                    case HitTestArea.NoteCenter:
                        _mouseDragByteIndexStart = note.Interval.Start;
                        break;
                    }

                    Cursor = request.CursorResult ?? Cursors.Default;
                }
                else
                {
                    _mouseDragByteIndexStart = GetCurrentViewPortStart();
                    _viewPortStart           = _mouseDragByteIndexStart;
                    _caretOffset             = double.NaN;
                }

                break;
            }
        }
Пример #5
0
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            var renderRequest = new RenderRequest
            {
                IsHitTest   = true,
                CursorPoint = e.Location
            };

            Render(renderRequest);

            if (_mouseDown)
            {
                _mouseDragEndX = e.Location.X;
                var distance = Math.Max(_mouseDragStartX, _mouseDragEndX) - Math.Min(_mouseDragStartX, _mouseDragEndX);

                // If we've dragged more than a few pixels, so we'll count it as a drag/zoom action
                var isDragging = distance > 3;
                switch (e.Button)
                {
                case MouseButtons.Middle:
                    _mouseDraggingZoom = isDragging;
                    break;

                case MouseButtons.Left:
                    var previous = _mouseDraggingPan;
                    _mouseDraggingPan = isDragging;
                    if (previous != _mouseDraggingPan && _mouseDraggingObject == null)
                    {
                        Cursor = _mouseDraggingPan ? Cursors.Hand : Cursors.Default;
                    }
                    break;
                }
            }

            if (_mouseDraggingPan)
            {
                var startByteIndex   = ClientXToByteIndex(_mouseDragStartX);
                var currentByteIndex = ClientXToByteIndex(e.Location.X);
                var byteDistance     = startByteIndex - currentByteIndex;

                if (_mouseDraggingObject is Note)
                {
                    var note = (Note)_mouseDraggingObject;

                    var capStart = 0L;
                    var capEnd   = _bytesTotal;
                    if (renderRequest.Notes != null)
                    {
                        var foundIndex = -1;
                        for (var i = 0; i < renderRequest.Notes.Count; i++)
                        {
                            var otherNote = renderRequest.Notes[i];
                            if (otherNote.Equals(note) == false)
                            {
                                continue;
                            }

                            switch (_mouseDraggingArea)
                            {
                            case HitTestArea.NoteLeft:
                                capEnd = otherNote.Interval.End -
                                         (long)Math.Round(GetBytesPerPixel() * GetZoomRatio() * 2);
                                break;

                            case HitTestArea.NoteRight:
                                capStart = otherNote.Interval.Start +
                                           (long)Math.Round(GetBytesPerPixel() * GetZoomRatio() * 2);
                                break;
                            }

                            foundIndex = i;
                            break;
                        }

                        if (foundIndex != -1)
                        {
                            long previousEnd;
                            long nextStart;
                            if (renderRequest.HitTestArea == HitTestArea.NoteCenter)
                            {
                                previousEnd = foundIndex > 0
                                    ? renderRequest.Notes[foundIndex - 1].Interval.End
                                    : capStart;
                                nextStart = foundIndex < renderRequest.Notes.Count - 1
                                    ? renderRequest.Notes[foundIndex + 1].Interval.Start -
                                            renderRequest.Notes[foundIndex + 1].Interval.Length
                                    : capEnd;
                            }
                            else
                            {
                                previousEnd = foundIndex > 0
                                    ? renderRequest.Notes[foundIndex - 1].Interval.End
                                    : capStart;
                                nextStart = foundIndex < renderRequest.Notes.Count - 1
                                    ? renderRequest.Notes[foundIndex + 1].Interval.Start
                                    : capEnd;
                            }

                            capStart = Math.Max(capStart, previousEnd);
                            capEnd   = Math.Min(capEnd, nextStart);
                        }
                    }

                    var args = new NoteMovedEventArgs
                    {
                        Note      = note,
                        Area      = _mouseDraggingArea,
                        ByteIndex = Math.Max(capStart, Math.Min(capEnd, _mouseDragByteIndexStart - byteDistance))
                    };

                    NoteMoved(this, args);
                }
                else
                {
                    _viewPortStart = Math.Max(0, _mouseDragByteIndexStart + byteDistance);
                }
            }
            else
            {
                if (_mouseDown == false)
                {
                    Cursor = renderRequest.CursorResult ?? Cursors.Default;
                }
            }

            Invalidate();
        }