private void OnScrollViewerMouseMove(object sender, MouseEventArgs e) { // When "scrollViewer.CaptureMouse()" is called, mouse-move event will be // sent before "CaptureMouse" returns. So if this event is sent due to the // mouse being captured, then we won't process it at all. // if (false != ignoreMouseMoveEvent) { return; } IScriptObject activeScript = Solution.Current.ActiveScript; if (activeScript == null) { return; // There's no active script just yet. } if (IsMouseInClickableRegion(sender, e) == false) { return; } // Retreive the coordinates of the mouse move event. Note that we always // want the mouse coordinates relative to the top-left corner of the canvas // instead of the scroll viewer (whose top coordinates are off if scroll // offset is not at the top of the view). // CharPosition cursor = activeScript.CreateCharPosition(); System.Windows.Point screenPoint = GetRelativeCanvasPosition(e); cursor.SetScreenPosition(screenPoint.X, screenPoint.Y); mouseCharacterPosition = cursor.GetCharacterPosition(); if (-1 == clickedLineIndex) { if (textCore.InternalDragSourceExists == false) { // There is nothing being dragged right now. textCore.SetMouseMovePosition(mouseCharacterPosition.X, mouseCharacterPosition.Y, e); } else { // Stop caret blinking while dragging. textCanvas.PauseCaretTimer(true); DragDrop.AddDragOverHandler(scrollViewer, OnDragOver); DragDrop.AddDropHandler(scrollViewer, OnDrop); try { string textToMove = textCore.SelectionText; textToMove = textToMove.Replace("\n", "\r\n"); // Beginning the modal loop of "DoDragDrop" will immediately trigger // a mouse-mvoe event before it returns (e.g. drop has been made or // cancelled). So here we set the "ignoreMouseMoveEvent" to true and // ignore the immediate mouse event from being processed (which will // result in yet another "DoDragDrop" being called, causing two drop // operations). // ignoreMouseMoveEvent = true; DragDrop.DoDragDrop(textCanvas, textToMove, DragDropEffects.All); ignoreMouseMoveEvent = false; } finally { DragDrop.RemoveDragOverHandler(scrollViewer, OnDragOver); DragDrop.RemoveDropHandler(scrollViewer, OnDrop); textCore.ClearDragDropState(); textCanvas.PauseCaretTimer(false); // Resume caret blinking... } } // We turn the cursor to an arrow if it is within the breakpoint or line // column, and I-beam otherwise. Clicking on the breakpoint column triggers // a breakpoint and clicking on the line column selects the entire line. // scrollViewer.Cursor = Cursors.Arrow; if (!IsPointWithinLineColumn(screenPoint)) { if (!IsPointWithinBreakColumn(GetRelativeCanvasPosition(e))) { if (!textCore.IsPointInSelection(mouseCharacterPosition.X, mouseCharacterPosition.Y)) { scrollViewer.Cursor = Cursors.IBeam; } } } if (textCore.ReadOnlyState && (false != TextCanvasHasKeyboardFocus)) { if (inspectionToolTipTimer == null) { inspectionToolTipTimer = new DispatcherTimer(); inspectionToolTipTimer.Tick += new EventHandler(OnInspectionToolTipTimerTick); // One has to hover over a word for 3/4ths of a second to be considered // a valid 'Mouse Hover'. Yes, this is decided spontaneously. inspectionToolTipTimer.Interval = new TimeSpan(0, 0, 0, 0, 200); } // Restart timer as cursor moves. inspectionToolTipTimer.Stop(); inspectionToolTipTimer.Start(); } } else { scrollViewer.Cursor = Cursors.Arrow; int currentLine = mouseCharacterPosition.Y; textCore.SelectLines(clickedLineIndex, currentLine - clickedLineIndex); } if ((e.LeftButton & MouseButtonState.Pressed) != 0) { // If this message is sent by dragging a thumb on a scrollbar, then the // user wishes to scroll the text canvas, in which case we should not force // to bring the caret into view (which is what 'UpdateCaretPosition' does). // if ((e.OriginalSource as Thumb) == null) { UpdateCaretPosition(); } } }