private void ScrollHorizontallyToPoint(MouseTextPosition position) { if (position.Horizontal == HorizontalBounds.Inside) { return; } // If outside to the left then reset the viewport all the way to the start first if (position.Horizontal == HorizontalBounds.Left) { this.textView.ViewportLeft = 0; } // Ensure the position is visible, either if we were off the right or if // we were off to the left and went too far by resetting the viewport left to 0 this.textView.ViewScroller.EnsureSpanVisible( this.textView.GetTextElementSpan(position.Point)); }
private MouseTextPosition GetMouseTextPosition(MouseEventArgs args) { var mousePoint = args?.GetPosition(this.textView.VisualElement) ?? Mouse.GetPosition(this.textView.VisualElement); var result = new MouseTextPosition { Horizontal = HorizontalBounds.Inside }; // Find the line we are interested in based on mouse position ITextViewLine line; if (mousePoint.Y <= 0) { line = this.textView.TextViewLines.FirstVisibleLine; result.Vertical = VerticalBounds.Above; } else if (mousePoint.Y >= this.textView.ViewportBottom - this.textView.ViewportTop) { line = this.textView.TextViewLines.LastVisibleLine; result.Vertical = VerticalBounds.Below; } else { // If GetTextViewLineContainingYCoordinate returns null in this situation // then since we are within the viewport we know we must have scrolled all // the way to the end of the document and the mosue must be over the viewport // space showing after the end of the document hence in that case we select the // last line. line = this.textView.TextViewLines.GetTextViewLineContainingYCoordinate( mousePoint.Y + this.textView.ViewportTop) ?? this.textView.TextViewLines.LastVisibleLine; result.Vertical = VerticalBounds.Inside; } var x = mousePoint.X + this.textView.ViewportLeft; // If the mouse is outside the viewport to right or left then // select the first or last point on the line if (x < this.textView.ViewportLeft) { result.Point = line.Start; if (line.TextLeft < this.textView.ViewportLeft) { result.Horizontal = HorizontalBounds.Left; } else if (line.TextLeft > this.textView.ViewportRight) { result.Horizontal = HorizontalBounds.Right; } return(result); } if (x > this.textView.ViewportRight) { result.Point = line.End; if (line.TextRight > this.textView.ViewportRight) { result.Horizontal = HorizontalBounds.Right; } else if (line.TextRight < this.textView.ViewportLeft) { result.Horizontal = HorizontalBounds.Left; } return(result); } // Find and adjust the desired point based on x position var point = line.GetBufferPositionFromXCoordinate(x); if (point.HasValue) { // The point will always be for the charecter that the mouse is over // however it feels far more natural (and VS selection does this) to // select a charecter based on the closest start point to the mouse. // Here we select the next charecter if its start position is closer. var bounds = line.GetCharacterBounds(point.Value); if (x > (bounds.Left + (bounds.Width / 2))) { result.Point = line.GetBufferPositionFromXCoordinate(x + bounds.Width) ?? point.Value; return(result); } result.Point = point.Value; return(result); } // If we get here the line does not go all the way to the viewport right // side and we are past the end of the line but inside the viewport result.Point = line.End; if (line.TextRight < this.textView.ViewportLeft) { result.Horizontal = HorizontalBounds.Left; } return(result); }