aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/SideChains/RealTimeGraphEx/ReachGraphs/RealTimeGraphExReachLineErase.cs
blob: a0049e0a6c7d70d212b3770f51f300cd1ec72cd1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;

namespace RealTimeGraphEx.ReachGraphs
{
    public class RealTimeGraphExReachLineErase : RealTimeGraphExReachLineScroll, INotifyPropertyChanged
    {
        #region Cross Thread Fields

        protected Brush _markerColor;
        protected bool _showMarker;
        protected bool _endReached;
        protected int _currentReplaceIndex;
        protected bool _enableMarkerPosition;
        protected double lastVirtualValue;
        protected Rectangle marker;

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the graph marker color.
        /// </summary>
        public Brush MarkerBrush
        {
            get { return (Brush)GetValue(MarkerBrushProperty); }
            set { SetValue(MarkerBrushProperty, value); }
        }
        public static readonly DependencyProperty MarkerBrushProperty =
            DependencyProperty.Register("MarkerBrush", typeof(Brush), typeof(RealTimeGraphExReachLineErase), new PropertyMetadata(Brushes.Red, new PropertyChangedCallback(CrossModelChanged)));

        /// <summary>
        /// Gets or sets whether to display the marker on the graph.
        /// </summary>
        public bool ShowMarker
        {
            get { return (bool)GetValue(ShowMarkerProperty); }
            set { SetValue(ShowMarkerProperty, value); }
        }
        public static readonly DependencyProperty ShowMarkerProperty =
            DependencyProperty.Register("ShowMarker", typeof(bool), typeof(RealTimeGraphExReachLineErase), new PropertyMetadata(true, new PropertyChangedCallback(CrossModelChanged)));

        /// <summary>
        /// Gets or sets a value indicating whether to enable the MarkerPosition property to be updated. (Affects performance).
        /// </summary>
        public bool EnableMarkerPosition
        {
            get { return (bool)GetValue(EnableMarkerPositionProperty); }
            set { SetValue(EnableMarkerPositionProperty, value); }
        }
        public static readonly DependencyProperty EnableMarkerPositionProperty =
            DependencyProperty.Register("EnableMarkerPosition", typeof(bool), typeof(RealTimeGraphExReachLineErase), new PropertyMetadata(false, new PropertyChangedCallback(CrossModelChanged)));

        /// <summary>
        /// Gets the current marker position on the graph.
        /// </summary>
        private Point markerPosition;
        public Point MarkerPosition
        {
            private get { return markerPosition; }
            set { markerPosition = value; RaisePropertyChanged("MarkerPosition"); }
        }

        #endregion

        #region Constructors

        public RealTimeGraphExReachLineErase()
            : base()
        {

        }

        #endregion

        #region Override Method

        protected override void OnClearGraph()
        {
            base.OnClearGraph();

            _currentReplaceIndex = 0;
            _endReached = false;

            this.Dispatcher.Invoke(() =>
            {
                marker.RenderTransform = new TranslateTransform(0, 0);
            });
        }

        protected override void Initialize()
        {
            base.Initialize();
            marker = new Rectangle() { VerticalAlignment = System.Windows.VerticalAlignment.Stretch, Width = 1, Fill = MarkerBrush, HorizontalAlignment = System.Windows.HorizontalAlignment.Left, Margin = new Thickness(-2, 0, 0, 0) };

            if (!gridLinesAndImageWrapperGrid.Children.Contains(marker))
            {
                gridLinesAndImageWrapperGrid.Children.Add(marker);
            }
        }

        protected override void OnSetCrossThreadFields()
        {
            base.OnSetCrossThreadFields();

            this.Dispatcher.Invoke(() =>
            {

                _markerColor = MarkerBrush;
                _showMarker = ShowMarker;
                _enableMarkerPosition = EnableMarkerPosition;

            }, System.Windows.Threading.DispatcherPriority.Send);
        }

        protected internal override void OnRenderGraph()
        {
            if (_graphController.dataSeries != null && _graphController.dataSeries.Points != null && _graphController.dataSeries.Points.Count > 0  && _width > 1 && _height > 1)
            {
                var points = _graphController.dataSeries.Points.GetAndClearAllPoints();

                if (!_isPaused)
                {
                    for (int i = 0; i < points.Count; i++)
                    {
                        double value = points[i];
                        lastVirtualValue = value;

                        if (xValueCounter <= _width)
                        {
                            if (!_endReached)
                            {
                                graphPolygon.Add(value);
                                xValueCounter += _scaleFactor;
                            }
                            else
                            {
                                graphPolygon.Replace(value, _currentReplaceIndex++);
                                xValueCounter += _scaleFactor;

                                if (_currentReplaceIndex > graphPolygon.Count - 1)
                                {
                                    xValueCounter = 0;
                                    _currentReplaceIndex = 0;
                                }
                            }
                        }
                        else
                        {
                            _endReached = true;
                            xValueCounter = 0;
                            graphPolygon.Replace(value, _currentReplaceIndex++);
                            xValueCounter += _scaleFactor;
                        }
                    }
                }

                updateCounter++;

                if (updateCounter >= 1 && !_isPaused)
                {
                    updateCounter = 0;
                    if (!_disableRendering)
                    {
                        OnDrawVisuals();
                    }
                }
            }
        }

        protected override void OnDrawVisuals()
        {
            base.OnDrawVisuals();

            double scale = GetPolygonScaleFactor();

            this.Dispatcher.Invoke(() =>
            {
                double x = ((_currentReplaceIndex * scale));
                marker.RenderTransform = new TranslateTransform((x) - 2, 0);
            });
        }

        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        public void RaisePropertyChanged(String propName)
        {
            this.Dispatcher.Invoke(() =>
            {

                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propName));

            });
        }

        #endregion
    }
}
"p">} } [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; int offset = GetOffsetFromMousePosition(e.GetPosition(textArea.TextView), out visualColumn); if (offset >= 0) { textArea.Caret.Position = new TextViewPosition(textArea.Document.GetLocation(offset), visualColumn); 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) { string text = e.Data.GetData(DataFormats.UnicodeText, true) as string; if (text != null) { 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); bool rectangular = e.Data.GetDataPresent(RectangleSelection.RectangularSelectionDataType); string newLine = TextUtilities.GetNewLineFromDocument(textArea.Document, textArea.Caret.Line); text = TextUtilities.NormalizeNewLines(text, newLine); // 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) { // WPF 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.Normal, 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; } } 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 || !enableTextDragDrop) { 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; int offset = GetOffsetFromMousePosition(e, out visualColumn); if (textArea.Selection.Contains(offset)) e.Cursor = Cursors.Arrow; else e.Cursor = Cursors.IBeam; e.Handled = true; } } } } #endregion #region LeftButtonDown void textArea_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { mode = SelectionMode.None; if (!e.Handled && e.ChangedButton == MouseButton.Left) { ModifierKeys modifiers = Keyboard.Modifiers; bool shift = (modifiers & ModifierKeys.Shift) == ModifierKeys.Shift; if (enableTextDragDrop && e.ClickCount == 1 && !shift) { int visualColumn; int offset = GetOffsetFromMousePosition(e, out visualColumn); if (textArea.Selection.Contains(offset)) { if (textArea.CaptureMouse()) { mode = SelectionMode.PossibleDragStart; possibleDragStartMousePos = e.GetPosition(textArea); } e.Handled = true; return; } } var oldPosition = textArea.Caret.Position; SetCaretOffsetToMousePosition(e); if (!shift) { textArea.ClearSelection(); } if (textArea.CaptureMouse()) { if ((modifiers & ModifierKeys.Alt) == ModifierKeys.Alt && textArea.Options.EnableRectangularSelection) { mode = SelectionMode.Rectangular; if (shift && textArea.Selection is RectangleSelection) { textArea.Selection = textArea.Selection.StartSelectionOrSetEndpoint(oldPosition, textArea.Caret.Position); } } else if (e.ClickCount == 1 && ((modifiers & ModifierKeys.Control) == 0)) { mode = SelectionMode.Normal; if (shift && !(textArea.Selection is RectangleSelection)) { textArea.Selection = textArea.Selection.StartSelectionOrSetEndpoint(oldPosition, textArea.Caret.Position); } } else { SimpleSegment startWord; if (e.ClickCount == 3) { mode = SelectionMode.WholeLine; startWord = GetLineAtMousePosition(e); } else { mode = SelectionMode.WholeWord; startWord = GetWordAtMousePosition(e); } if (startWord == SimpleSegment.Invalid) { mode = SelectionMode.None; textArea.ReleaseMouseCapture(); return; } if (shift && !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))); } this.startWord = new AnchorSegment(textArea.Document, textArea.Selection.SurroundingSegment); } else { textArea.Selection = Selection.Create(textArea, startWord.Offset, startWord.EndOffset); this.startWord = new AnchorSegment(textArea.Document, startWord.Offset, startWord.Length); } } } } e.Handled = true; } #endregion #region Mouse Position <-> Text coordinates SimpleSegment GetWordAtMousePosition(MouseEventArgs e) { TextView textView = textArea.TextView; if (textView == null) return SimpleSegment.Invalid; Point pos = e.GetPosition(textView); if (pos.Y < 0) pos.Y = 0; if (pos.Y > textView.ActualHeight) pos.Y = textView.ActualHeight; pos += textView.ScrollOffset; VisualLine line = textView.GetVisualLineFromVisualTop(pos.Y); if (line != null) { int visualColumn = line.GetVisualColumn(pos, textArea.Selection.EnableVirtualSpace); int wordStartVC = line.GetNextCaretPosition(visualColumn + 1, LogicalDirection.Backward, CaretPositioningMode.WordStartOrSymbol, textArea.Selection.EnableVirtualSpace); if (wordStartVC == -1) wordStartVC = 0; int wordEndVC = line.GetNextCaretPosition(wordStartVC, LogicalDirection.Forward, CaretPositioningMode.WordBorderOrSymbol, textArea.Selection.EnableVirtualSpace); if (wordEndVC == -1) wordEndVC = line.VisualLength; int relOffset = line.FirstDocumentLine.Offset; int wordStartOffset = line.GetRelativeOffset(wordStartVC) + relOffset; int wordEndOffset = line.GetRelativeOffset(wordEndVC) + relOffset; return new SimpleSegment(wordStartOffset, wordEndOffset - wordStartOffset); } else { return SimpleSegment.Invalid; } } SimpleSegment GetLineAtMousePosition(MouseEventArgs e) { TextView textView = textArea.TextView; if (textView == null) return SimpleSegment.Invalid; Point pos = e.GetPosition(textView); if (pos.Y < 0) pos.Y = 0; if (pos.Y > textView.ActualHeight) pos.Y = textView.ActualHeight; pos += textView.ScrollOffset; VisualLine line = textView.GetVisualLineFromVisualTop(pos.Y); if (line != null) { return new SimpleSegment(line.StartOffset, line.LastDocumentLine.EndOffset - line.StartOffset); } else { return SimpleSegment.Invalid; } } int GetOffsetFromMousePosition(MouseEventArgs e, out int visualColumn) { return GetOffsetFromMousePosition(e.GetPosition(textArea.TextView), out visualColumn); } int GetOffsetFromMousePosition(Point positionRelativeToTextView, out int visualColumn) { visualColumn = 0; TextView textView = textArea.TextView; Point pos = positionRelativeToTextView; if (pos.Y < 0) pos.Y = 0; if (pos.Y > textView.ActualHeight) pos.Y = textView.ActualHeight; pos += textView.ScrollOffset; if (pos.Y > textView.DocumentHeight) pos.Y = textView.DocumentHeight - ExtensionMethods.Epsilon; VisualLine line = textView.GetVisualLineFromVisualTop(pos.Y); if (line != null) { visualColumn = line.GetVisualColumn(pos, textArea.Selection.EnableVirtualSpace); return line.GetRelativeOffset(visualColumn) + line.FirstDocumentLine.Offset; } return -1; } int GetOffsetFromMousePositionFirstTextLineOnly(Point positionRelativeToTextView, out int visualColumn) { visualColumn = 0; TextView textView = textArea.TextView; Point pos = positionRelativeToTextView; if (pos.Y < 0) pos.Y = 0; if (pos.Y > textView.ActualHeight) pos.Y = textView.ActualHeight; pos += textView.ScrollOffset; if (pos.Y > textView.DocumentHeight) pos.Y = textView.DocumentHeight - ExtensionMethods.Epsilon; VisualLine line = textView.GetVisualLineFromVisualTop(pos.Y); if (line != null) { visualColumn = line.GetVisualColumn(line.TextLines.First(), pos.X, textArea.Selection.EnableVirtualSpace); return line.GetRelativeOffset(visualColumn) + line.FirstDocumentLine.Offset; } return -1; } #endregion #region MouseMove void textArea_MouseMove(object sender, MouseEventArgs e) { if (e.Handled) return; if (mode == SelectionMode.Normal || mode == SelectionMode.WholeWord || mode == SelectionMode.WholeLine || mode == SelectionMode.Rectangular) { e.Handled = true; if (textArea.TextView.VisualLinesValid) { // If the visual lines are not valid, don't extend the selection. // Extending the selection forces a VisualLine refresh, and it is sufficient // to do that on MouseUp, we don't have to do it every MouseMove. ExtendSelectionToMouse(e); } } else if (mode == SelectionMode.PossibleDragStart) { e.Handled = true; Vector mouseMovement = e.GetPosition(textArea) - possibleDragStartMousePos; if (Math.Abs(mouseMovement.X) > SystemParameters.MinimumHorizontalDragDistance || Math.Abs(mouseMovement.Y) > SystemParameters.MinimumVerticalDragDistance) { StartDrag(); } } } #endregion #region ExtendSelection void SetCaretOffsetToMousePosition(MouseEventArgs e) { SetCaretOffsetToMousePosition(e, null); } void SetCaretOffsetToMousePosition(MouseEventArgs e, ISegment allowedSegment) { int visualColumn; int offset; if (mode == SelectionMode.Rectangular) offset = GetOffsetFromMousePositionFirstTextLineOnly(e.GetPosition(textArea.TextView), out visualColumn); else offset = GetOffsetFromMousePosition(e, out visualColumn); if (allowedSegment != null) { offset = offset.CoerceValue(allowedSegment.Offset, allowedSegment.EndOffset); } if (offset >= 0) { textArea.Caret.Position = new TextViewPosition(textArea.Document.GetLocation(offset), visualColumn); textArea.Caret.DesiredXPos = double.NaN; } } void ExtendSelectionToMouse(MouseEventArgs e) { TextViewPosition oldPosition = textArea.Caret.Position; if (mode == SelectionMode.Normal || mode == SelectionMode.Rectangular) { SetCaretOffsetToMousePosition(e); 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(e) : GetWordAtMousePosition(e); if (newWord != SimpleSegment.Invalid) { textArea.Selection = Selection.Create(textArea, Math.Min(newWord.Offset, startWord.Offset), Math.Max(newWord.EndOffset, startWord.EndOffset)); // Set caret offset, but limit the caret to stay inside the selection. // in whole-word selection, it's otherwise possible that we get the caret outside the // selection - but the TextArea doesn't like that and will reset the selection, causing // flickering. SetCaretOffsetToMousePosition(e, textArea.Selection.SurroundingSegment); } } textArea.Caret.BringCaretToView(5.0); } #endregion #region MouseLeftButtonUp void textArea_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { if (mode == SelectionMode.None || e.Handled) return; e.Handled = true; if (mode == SelectionMode.PossibleDragStart) { // -> this was not a drag start (mouse didn't move after mousedown) SetCaretOffsetToMousePosition(e); textArea.ClearSelection(); } else if (mode == SelectionMode.Normal || mode == SelectionMode.WholeWord || mode == SelectionMode.WholeLine || mode == SelectionMode.Rectangular) { ExtendSelectionToMouse(e); } mode = SelectionMode.None; textArea.ReleaseMouseCapture(); } #endregion } }