// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.ComponentModel;
using System.Linq;
using Unity.CodeEditor.Document;
using Unity.CodeEditor.Utils;
using UnityEngine;
using UnityEngine.UIElements;
namespace Unity.CodeEditor.Editing
{
///
/// Handles selection of text using the mouse.
///
internal sealed class SelectionMouseHandler //: ITextAreaInputHandler
{
#region enum SelectionMode
private enum SelectionMode
{
///
/// no selection (no mouse button down)
///
None,
///
/// left mouse button down on selection, might be normal click
/// or might be drag'n'drop
///
PossibleDragStart,
///
/// dragging text
///
Drag,
///
/// normal selection (click+drag)
///
Normal,
///
/// whole-word selection (double click+drag or ctrl+click+drag)
///
WholeWord,
///
/// whole-line selection (triple click+drag)
///
WholeLine,
///
/// rectangular selection (alt+click+drag)
///
Rectangular
}
#endregion
private SelectionMode _mode;
private AnchorSegment _startWord;
private Vector2 _possibleDragStartMousePos;
private int _consecutiveClicks;
private float _lastClickTime;
private Vector2 _lastClickPosition;
#region Constructor + Attach + Detach
internal SelectionMouseHandler(TextArea textArea)
{
TextArea = textArea ?? throw new ArgumentNullException(nameof(textArea));
}
internal TextArea TextArea { get; }
internal void Attach()
{
//TextArea.PointerPressed += TextArea_MouseLeftButtonDown;
//TextArea.PointerMoved += TextArea_MouseMove;
//TextArea.PointerReleased += TextArea_MouseLeftButtonUp;
//textArea.QueryCursor += textArea_QueryCursor;
TextArea.OptionChanged += TextArea_OptionChanged;
_enableTextDragDrop = TextArea.Options.EnableTextDragDrop;
if (_enableTextDragDrop)
{
AttachDragDrop();
}
}
internal void Detach()
{
_mode = SelectionMode.None;
//TextArea.PointerPressed -= TextArea_MouseLeftButtonDown;
//TextArea.PointerMoved -= TextArea_MouseMove;
//TextArea.PointerReleased -= TextArea_MouseLeftButtonUp;
//textArea.QueryCursor -= textArea_QueryCursor;
TextArea.OptionChanged -= TextArea_OptionChanged;
if (_enableTextDragDrop)
{
DetachDragDrop();
}
}
private void AttachDragDrop()
{
//textArea.AllowDrop = true;
//textArea.GiveFeedback += textArea_GiveFeedback;
//textArea.QueryContinueDrag += textArea_QueryContinueDrag;
//textArea.DragEnter += textArea_DragEnter;
//textArea.DragOver += textArea_DragOver;
//textArea.DragLeave += textArea_DragLeave;
//textArea.Drop += textArea_Drop;
}
private void DetachDragDrop()
{
//textArea.AllowDrop = false;
//textArea.GiveFeedback -= textArea_GiveFeedback;
//textArea.QueryContinueDrag -= textArea_QueryContinueDrag;
//textArea.DragEnter -= textArea_DragEnter;
//textArea.DragOver -= textArea_DragOver;
//textArea.DragLeave -= textArea_DragLeave;
//textArea.Drop -= textArea_Drop;
}
private bool _enableTextDragDrop;
private void TextArea_OptionChanged(object sender, PropertyChangedEventArgs e)
{
var newEnableTextDragDrop = TextArea.Options.EnableTextDragDrop;
if (newEnableTextDragDrop != _enableTextDragDrop)
{
_enableTextDragDrop = newEnableTextDragDrop;
if (newEnableTextDragDrop)
AttachDragDrop();
else
DetachDragDrop();
}
}
#endregion
#region Dropping text
//[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
//void textArea_DragEnter(object sender, DragEventArgs e)
//{
// try {
// e.Effects = GetEffect(e);
// textArea.Caret.Show();
// } catch (Exception ex) {
// OnDragException(ex);
// }
//}
//[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
//void textArea_DragOver(object sender, DragEventArgs e)
//{
// try {
// e.Effects = GetEffect(e);
// } catch (Exception ex) {
// OnDragException(ex);
// }
//}
//DragDropEffects GetEffect(DragEventArgs e)
//{
// if (e.Data.GetDataPresent(DataFormats.UnicodeText, true)) {
// e.Handled = true;
// int visualColumn;
// bool isAtEndOfLine;
// int offset = GetOffsetFromMousePosition(e.GetPosition(textArea.TextView), out visualColumn, out isAtEndOfLine);
// if (offset >= 0) {
// textArea.Caret.Position = new TextViewPosition(textArea.Document.GetLocation(offset), visualColumn) { IsAtEndOfLine = isAtEndOfLine };
// textArea.Caret.DesiredXPos = double.NaN;
// if (textArea.ReadOnlySectionProvider.CanInsert(offset)) {
// if ((e.AllowedEffects & DragDropEffects.Move) == DragDropEffects.Move
// && (e.KeyStates & DragDropKeyStates.ControlKey) != DragDropKeyStates.ControlKey)
// {
// return DragDropEffects.Move;
// } else {
// return e.AllowedEffects & DragDropEffects.Copy;
// }
// }
// }
// }
// return DragDropEffects.None;
//}
//[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
//void textArea_DragLeave(object sender, DragEventArgs e)
//{
// try {
// e.Handled = true;
// if (!textArea.IsKeyboardFocusWithin)
// textArea.Caret.Hide();
// } catch (Exception ex) {
// OnDragException(ex);
// }
//}
//[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
//void textArea_Drop(object sender, DragEventArgs e)
//{
// try {
// DragDropEffects effect = GetEffect(e);
// e.Effects = effect;
// if (effect != DragDropEffects.None) {
// int start = textArea.Caret.Offset;
// if (mode == SelectionMode.Drag && textArea.Selection.Contains(start)) {
// Debug.WriteLine("Drop: did not drop: drop target is inside selection");
// e.Effects = DragDropEffects.None;
// } else {
// Debug.WriteLine("Drop: insert at " + start);
// var pastingEventArgs = new DataObjectPastingEventArgs(e.Data, true, DataFormats.UnicodeText);
// textArea.RaiseEvent(pastingEventArgs);
// if (pastingEventArgs.CommandCancelled)
// return;
// string text = EditingCommandHandler.GetTextToPaste(pastingEventArgs, textArea);
// if (text == null)
// return;
// bool rectangular = pastingEventArgs.DataObject.GetDataPresent(RectangleSelection.RectangularSelectionDataType);
// // Mark the undo group with the currentDragDescriptor, if the drag
// // is originating from the same control. This allows combining
// // the undo groups when text is moved.
// textArea.Document.UndoStack.StartUndoGroup(this.currentDragDescriptor);
// try {
// if (rectangular && RectangleSelection.PerformRectangularPaste(textArea, textArea.Caret.Position, text, true)) {
// } else {
// textArea.Document.Insert(start, text);
// textArea.Selection = Selection.Create(textArea, start, start + text.Length);
// }
// } finally {
// textArea.Document.UndoStack.EndUndoGroup();
// }
// }
// e.Handled = true;
// }
// } catch (Exception ex) {
// OnDragException(ex);
// }
//}
//void OnDragException(Exception ex)
//{
// // swallows exceptions during drag'n'drop or reports them incorrectly, so
// // we re-throw them later to allow the application's unhandled exception handler
// // to catch them
// textArea.Dispatcher.BeginInvoke(
// DispatcherPriority.Send,
// new Action(delegate {
// throw new DragDropException("Exception during drag'n'drop", ex);
// }));
//}
//[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
//void textArea_GiveFeedback(object sender, GiveFeedbackEventArgs e)
//{
// try {
// e.UseDefaultCursors = true;
// e.Handled = true;
// } catch (Exception ex) {
// OnDragException(ex);
// }
//}
//[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
//void textArea_QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
//{
// try {
// if (e.EscapePressed) {
// e.Action = DragAction.Cancel;
// } else if ((e.KeyStates & DragDropKeyStates.LeftMouseButton) != DragDropKeyStates.LeftMouseButton) {
// e.Action = DragAction.Drop;
// } else {
// e.Action = DragAction.Continue;
// }
// e.Handled = true;
// } catch (Exception ex) {
// OnDragException(ex);
// }
//}
#endregion
#region Start Drag
//object currentDragDescriptor;
//void StartDrag()
//{
// // prevent nested StartDrag calls
// mode = SelectionMode.Drag;
// // mouse capture and Drag'n'Drop doesn't mix
// textArea.ReleaseMouseCapture();
// DataObject dataObject = textArea.Selection.CreateDataObject(textArea);
// DragDropEffects allowedEffects = DragDropEffects.All;
// var deleteOnMove = textArea.Selection.Segments.Select(s => new AnchorSegment(textArea.Document, s)).ToList();
// foreach (ISegment s in deleteOnMove) {
// ISegment[] result = textArea.GetDeletableSegments(s);
// if (result.Length != 1 || result[0].Offset != s.Offset || result[0].EndOffset != s.EndOffset) {
// allowedEffects &= ~DragDropEffects.Move;
// }
// }
// var copyingEventArgs = new DataObjectCopyingEventArgs(dataObject, true);
// textArea.RaiseEvent(copyingEventArgs);
// if (copyingEventArgs.CommandCancelled)
// return;
// object dragDescriptor = new object();
// this.currentDragDescriptor = dragDescriptor;
// DragDropEffects resultEffect;
// using (textArea.AllowCaretOutsideSelection()) {
// var oldCaretPosition = textArea.Caret.Position;
// try {
// Debug.WriteLine("DoDragDrop with allowedEffects=" + allowedEffects);
// resultEffect = DragDrop.DoDragDrop(textArea, dataObject, allowedEffects);
// Debug.WriteLine("DoDragDrop done, resultEffect=" + resultEffect);
// } catch (COMException ex) {
// // ignore COM errors - don't crash on badly implemented drop targets
// Debug.WriteLine("DoDragDrop failed: " + ex.ToString());
// return;
// }
// if (resultEffect == DragDropEffects.None) {
// // reset caret if drag was aborted
// textArea.Caret.Position = oldCaretPosition;
// }
// }
// this.currentDragDescriptor = null;
// if (deleteOnMove != null && resultEffect == DragDropEffects.Move && (allowedEffects & DragDropEffects.Move) == DragDropEffects.Move) {
// bool draggedInsideSingleDocument = (dragDescriptor == textArea.Document.UndoStack.LastGroupDescriptor);
// if (draggedInsideSingleDocument)
// textArea.Document.UndoStack.StartContinuedUndoGroup(null);
// textArea.Document.BeginUpdate();
// try {
// foreach (ISegment s in deleteOnMove) {
// textArea.Document.Remove(s.Offset, s.Length);
// }
// } finally {
// textArea.Document.EndUpdate();
// if (draggedInsideSingleDocument)
// textArea.Document.UndoStack.EndUndoGroup();
// }
// }
//}
#endregion
#region QueryCursor
// provide the IBeam Cursor for the text area
//void textArea_QueryCursor(object sender, QueryCursorEventArgs e)
//{
// if (!e.Handled) {
// if (mode != SelectionMode.None) {
// // during selection, use IBeam cursor even outside the text area
// e.Cursor = Cursors.IBeam;
// e.Handled = true;
// } else if (textArea.TextView.VisualLinesValid) {
// // Only query the cursor if the visual lines are valid.
// // If they are invalid, the cursor will get re-queried when the visual lines
// // get refreshed.
// Point p = e.GetPosition(textArea.TextView);
// if (p.X >= 0 && p.Y >= 0 && p.X <= textArea.TextView.ActualWidth && p.Y <= textArea.TextView.ActualHeight) {
// int visualColumn;
// bool isAtEndOfLine;
// int offset = GetOffsetFromMousePosition(e, out visualColumn, out isAtEndOfLine);
// if (enableTextDragDrop && textArea.Selection.Contains(offset))
// e.Cursor = Cursors.Arrow;
// else
// e.Cursor = Cursors.IBeam;
// e.Handled = true;
// }
// }
// }
//}
#endregion
#region LeftButtonDown
internal void OnPointerPressed(PointerDownEvent e)
{
Vector2 mousePoint = GetTextViewRelativePosition(e);
if (e.button != 0)
{
if (TextArea.RightClickMovesCaret == true)
{
SetCaretOffsetToMousePosition(mousePoint);
}
}
else
{
int clickCount = ComputeClickCount(e);
_mode = SelectionMode.None;
bool isShift = (e.modifiers & EventModifiers.Shift) != 0;
bool isAlt = (e.modifiers & EventModifiers.Alt) != 0;
bool isCtrl = (e.modifiers & EventModifiers.Control) != 0
|| (e.modifiers & EventModifiers.Command) != 0;
if (_enableTextDragDrop && clickCount == 1 && !isShift)
{
var offset = GetOffsetFromMousePosition(mousePoint, out _, out _);
if (TextArea.Selection.Contains(offset))
{
_mode = SelectionMode.PossibleDragStart;
_possibleDragStartMousePos = mousePoint;
return;
}
}
var oldPosition = TextArea.Caret.Position;
SetCaretOffsetToMousePosition(mousePoint);
if (!isShift)
{
TextArea.ClearSelection();
}
if (isAlt && TextArea.Options.EnableRectangularSelection)
{
_mode = SelectionMode.Rectangular;
if (isShift && TextArea.Selection is RectangleSelection)
{
TextArea.Selection = TextArea.Selection.StartSelectionOrSetEndpoint(oldPosition, TextArea.Caret.Position);
}
}
else if (isCtrl && clickCount == 1)
{
_mode = SelectionMode.WholeWord;
if (isShift && !(TextArea.Selection is RectangleSelection))
{
TextArea.Selection = TextArea.Selection.StartSelectionOrSetEndpoint(oldPosition, TextArea.Caret.Position);
}
}
else if (e.button == 0 && clickCount == 1)
{
_mode = SelectionMode.Normal;
if (isShift && !(TextArea.Selection is RectangleSelection))
{
TextArea.Selection = TextArea.Selection.StartSelectionOrSetEndpoint(oldPosition, TextArea.Caret.Position);
}
}
else
{
SimpleSegment startWord;
if (clickCount == 3)
{
_mode = SelectionMode.WholeLine;
startWord = GetLineAtMousePosition(mousePoint);
}
else
{
_mode = SelectionMode.WholeWord;
startWord = GetWordAtMousePosition(mousePoint);
}
if (startWord == SimpleSegment.Invalid)
{
_mode = SelectionMode.None;
return;
}
if (isShift && !TextArea.Selection.IsEmpty)
{
if (startWord.Offset < TextArea.Selection.SurroundingSegment.Offset)
{
TextArea.Selection = TextArea.Selection.SetEndpoint(new TextViewPosition(TextArea.Document.GetLocation(startWord.Offset)));
}
else if (startWord.EndOffset > TextArea.Selection.SurroundingSegment.EndOffset)
{
TextArea.Selection = TextArea.Selection.SetEndpoint(new TextViewPosition(TextArea.Document.GetLocation(startWord.EndOffset)));
}
_startWord = new AnchorSegment(TextArea.Document, TextArea.Selection.SurroundingSegment);
}
else
{
TextArea.Selection = Selection.Create(TextArea, startWord.Offset, startWord.EndOffset);
_startWord = new AnchorSegment(TextArea.Document, startWord.Offset, startWord.Length);
}
}
}
}
private int ComputeClickCount(PointerDownEvent e)
{
float currentTime = Time.realtimeSinceStartup;
Vector2 currentPosition = e.position;
if (currentTime - _lastClickTime < TripleClickTimeSeconds
&& Vector2.Distance(currentPosition, _lastClickPosition) < TripleClickMaxDistance)
{
_consecutiveClicks++;
}
else
{
_consecutiveClicks = 1;
}
_lastClickTime = currentTime;
_lastClickPosition = currentPosition;
return _consecutiveClicks;
}
#endregion
#region LeftButtonClick
#endregion
#region LeftButtonDoubleTap
#endregion
#region Mouse Position <-> Text coordinates
private Vector2 GetTextViewRelativePosition(IPointerEvent e)
{
return TextArea.TextView.WorldToLocal(e.position);
}
private SimpleSegment GetWordAtMousePosition(Vector2 posRelativeToTextView)
{
var textView = TextArea.TextView;
if (textView == null) return SimpleSegment.Invalid;
var pos = posRelativeToTextView;
if (pos.y < 0)
pos.y = 0;
if (pos.y > textView.Bounds.height)
pos.y = textView.Bounds.height;
pos += textView.ScrollOffset;
var line = textView.GetVisualLineFromVisualTop(pos.y);
if (line != null && line.TextLines != null)
{
var visualColumn = line.GetVisualColumn(pos, TextArea.Selection.EnableVirtualSpace);
var wordStartVc = line.GetNextCaretPosition(visualColumn + 1, LogicalDirection.Backward, CaretPositioningMode.WordStartOrSymbol, TextArea.Selection.EnableVirtualSpace);
if (wordStartVc == -1)
wordStartVc = 0;
var wordEndVc = line.GetNextCaretPosition(wordStartVc, LogicalDirection.Forward, CaretPositioningMode.WordBorderOrSymbol, TextArea.Selection.EnableVirtualSpace);
if (wordEndVc == -1)
wordEndVc = line.VisualLength;
var relOffset = line.FirstDocumentLine.Offset;
var wordStartOffset = line.GetRelativeOffset(wordStartVc) + relOffset;
var wordEndOffset = line.GetRelativeOffset(wordEndVc) + relOffset;
return new SimpleSegment(wordStartOffset, wordEndOffset - wordStartOffset);
}
else
{
return SimpleSegment.Invalid;
}
}
private SimpleSegment GetLineAtMousePosition(Vector2 posRelativeToTextView)
{
var textView = TextArea.TextView;
if (textView == null) return SimpleSegment.Invalid;
var pos = posRelativeToTextView;
if (pos.y < 0)
pos.y = 0;
if (pos.y > textView.Bounds.height)
pos.y = textView.Bounds.height;
pos += textView.ScrollOffset;
var line = textView.GetVisualLineFromVisualTop(pos.y);
return line != null && line.TextLines != null
? new SimpleSegment(line.StartOffset, line.LastDocumentLine.EndOffset - line.StartOffset)
: SimpleSegment.Invalid;
}
private int GetOffsetFromMousePosition(Vector2 mousePosition, out int visualColumn, out bool isAtEndOfLine)
{
visualColumn = 0;
var textView = TextArea.TextView;
var pos = mousePosition;
if (pos.y < 0)
pos.y = 0;
if (pos.y > textView.Bounds.height)
pos.y = textView.Bounds.height;
pos += textView.ScrollOffset;
if (pos.y >= textView.DocumentHeight)
pos.y = textView.DocumentHeight - ExtensionMethods.Epsilon;
var line = textView.GetVisualLineFromVisualTop(pos.y);
if (line != null && line.TextLines != null)
{
visualColumn = line.GetVisualColumn(pos, TextArea.Selection.EnableVirtualSpace, out isAtEndOfLine);
return line.GetRelativeOffset(visualColumn) + line.FirstDocumentLine.Offset;
}
isAtEndOfLine = false;
return -1;
}
private int GetOffsetFromMousePositionFirstTextLineOnly(Vector2 positionRelativeToTextView, out int visualColumn)
{
visualColumn = 0;
var textView = TextArea.TextView;
var pos = positionRelativeToTextView;
if (pos.y < 0)
pos.y = 0;
if (pos.y > textView.Bounds.height)
pos.y = textView.Bounds.height;
pos += textView.ScrollOffset;
if (pos.y >= textView.DocumentHeight)
pos.y = textView.DocumentHeight - ExtensionMethods.Epsilon;
var line = textView.GetVisualLineFromVisualTop(pos.y);
if (line != null && line.TextLines != null)
{
visualColumn = line.GetVisualColumn(line.TextLines.First(), pos.x, TextArea.Selection.EnableVirtualSpace);
return line.GetRelativeOffset(visualColumn) + line.FirstDocumentLine.Offset;
}
return -1;
}
#endregion
private const int MinimumHorizontalDragDistance = 2;
private const int MinimumVerticalDragDistance = 2;
private const float TripleClickTimeSeconds = 0.5f;
private const float TripleClickMaxDistance = 5f;
#region MouseMove
internal void OnPointerMoved(PointerMoveEvent e)
{
Vector2 mousePoint = GetTextViewRelativePosition(e);
if (_mode == SelectionMode.Normal || _mode == SelectionMode.WholeWord || _mode == SelectionMode.WholeLine || _mode == SelectionMode.Rectangular)
{
if (TextArea.TextView.VisualLinesValid)
{
ExtendSelectionToMouse(mousePoint);
}
}
else if (_mode == SelectionMode.PossibleDragStart)
{
Vector2 mouseMovement = mousePoint - _possibleDragStartMousePos;
if (Math.Abs(mouseMovement.x) > MinimumHorizontalDragDistance
|| Math.Abs(mouseMovement.y) > MinimumVerticalDragDistance)
{
// TODO: drag
//StartDrag();
}
}
}
#endregion
#region ExtendSelection
private void SetCaretOffsetToMousePosition(Vector2 posRelativeToTextView)
{
int visualColumn;
bool isAtEndOfLine;
int offset;
if (_mode == SelectionMode.Rectangular)
{
offset = GetOffsetFromMousePositionFirstTextLineOnly(posRelativeToTextView, out visualColumn);
isAtEndOfLine = true;
}
else
{
offset = GetOffsetFromMousePosition(posRelativeToTextView, out visualColumn, out isAtEndOfLine);
}
if (offset >= 0)
{
TextArea.Caret.Position = new TextViewPosition(TextArea.Document.GetLocation(offset), visualColumn) { IsAtEndOfLine = isAtEndOfLine };
TextArea.Caret.DesiredXPos = float.NaN;
}
}
private void ExtendSelectionToMouse(Vector2 posRelativeToTextView)
{
var oldPosition = TextArea.Caret.Position;
if (_mode == SelectionMode.Normal || _mode == SelectionMode.Rectangular)
{
SetCaretOffsetToMousePosition(posRelativeToTextView);
if (_mode == SelectionMode.Normal && TextArea.Selection is RectangleSelection)
TextArea.Selection = new SimpleSelection(TextArea, oldPosition, TextArea.Caret.Position);
else if (_mode == SelectionMode.Rectangular && !(TextArea.Selection is RectangleSelection))
TextArea.Selection = new RectangleSelection(TextArea, oldPosition, TextArea.Caret.Position);
else
TextArea.Selection = TextArea.Selection.StartSelectionOrSetEndpoint(oldPosition, TextArea.Caret.Position);
}
else if (_mode == SelectionMode.WholeWord || _mode == SelectionMode.WholeLine)
{
var newWord = (_mode == SelectionMode.WholeLine) ? GetLineAtMousePosition(posRelativeToTextView) : GetWordAtMousePosition(posRelativeToTextView);
if (newWord != SimpleSegment.Invalid && _startWord != null)
{
TextArea.Selection = Selection.Create(TextArea,
Math.Min(newWord.Offset, _startWord.Offset),
Math.Max(newWord.EndOffset, _startWord.EndOffset));
TextArea.Caret.Offset = newWord.Offset < _startWord.Offset ? newWord.Offset : Math.Max(newWord.EndOffset, _startWord.EndOffset);
}
}
TextArea.Caret.BringCaretToView(5.0f);
}
#endregion
#region MouseLeftButtonUp
internal void OnPointerReleased(PointerUpEvent e)
{
if (_mode == SelectionMode.None)
return;
Vector2 mousePoint = GetTextViewRelativePosition(e);
switch (_mode)
{
case SelectionMode.PossibleDragStart:
SetCaretOffsetToMousePosition(mousePoint);
TextArea.ClearSelection();
break;
case SelectionMode.Normal:
case SelectionMode.WholeWord:
case SelectionMode.WholeLine:
case SelectionMode.Rectangular:
if (TextArea.Options.ExtendSelectionOnMouseUp)
ExtendSelectionToMouse(mousePoint);
break;
}
_mode = SelectionMode.None;
}
#endregion
}
}