1 //
2 //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
3 //  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
4 //  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
5 //  PURPOSE.
6 //
7 //  License: GNU Lesser General Public License (LGPLv3)
8 //
9 //  Email: pavel_torgashov@ukr.net.
10 //
11 //  Copyright (C) Pavel Torgashov, 2011-2015.
12 
13 // #define debug
14 
15 
16 // -------------------------------------------------------------------------------
17 // By default the FastColoredTextbox supports no more 16 styles at the same time.
18 // This restriction saves memory.
19 // However, you can to compile FCTB with 32 styles supporting.
20 // Uncomment following definition if you need 32 styles instead of 16:
21 //
22 // #define Styles32
23 
24 using System;
25 using System.Collections.Generic;
26 using System.ComponentModel;
27 using System.Diagnostics;
28 using System.Drawing;
29 using System.Drawing.Design;
30 using System.Drawing.Drawing2D;
31 using System.IO;
32 using System.Reflection;
33 using System.Runtime.InteropServices;
34 using System.Text;
35 using System.Text.RegularExpressions;
36 using System.Threading;
37 using System.Windows.Forms;
38 using System.Windows.Forms.Design;
39 using Microsoft.Win32;
40 using Timer = System.Windows.Forms.Timer;
41 
42 namespace FastColoredTextBoxNS
43 {
44     /// <summary>
45     /// Fast colored textbox
46     /// </summary>
47     public partial class FastColoredTextBox : UserControl, ISupportInitialize
48     {
49         internal const int minLeftIndent = 8;
50         private const int maxBracketSearchIterations = 1000;
51         private const int maxLinesForFolding = 3000;
52         private const int minLinesForAccuracy = 100000;
53         private const int WM_IME_SETCONTEXT = 0x0281;
54         private const int WM_HSCROLL = 0x114;
55         private const int WM_VSCROLL = 0x115;
56         private const int SB_ENDSCROLL = 0x8;
57 
58         public readonly List<LineInfo> LineInfos = new List<LineInfo>();
59         private readonly Range selection;
60         private readonly Timer timer = new Timer();
61         private readonly Timer timer2 = new Timer();
62         private readonly Timer timer3 = new Timer();
63         private readonly List<VisualMarker> visibleMarkers = new List<VisualMarker>();
64         public int TextHeight;
65         public bool AllowInsertRemoveLines = true;
66         private Brush backBrush;
67         private BaseBookmarks bookmarks;
68         private bool caretVisible;
69         private Color changedLineColor;
70         private int charHeight;
71         private Color currentLineColor;
72         private Cursor defaultCursor;
73         private Range delayedTextChangedRange;
74         private SyntaxDescriptor syntaxDescriptor;
75         private int endFoldingLine = -1;
76         private Color foldingIndicatorColor;
77         protected Dictionary<int, int> foldingPairs = new Dictionary<int, int>();
78         private bool handledChar;
79         private bool highlightFoldingIndicator;
80         private Hints hints;
81         private Color indentBackColor;
82         private bool isChanged;
83         private bool isLineSelect;
84         private bool isReplaceMode;
85         private Language language;
86         private Keys lastModifiers;
87         private Point lastMouseCoord;
88         private DateTime lastNavigatedDateTime;
89         private Range leftBracketPosition;
90         private Range leftBracketPosition2;
91         private int leftPadding;
92         private int lineInterval;
93         private Color lineNumberColor;
94         private uint lineNumberStartValue;
95         private int lineSelectFrom;
96         private TextSource lines;
97         private IntPtr m_hImc;
98         private int maxLineLength;
99         private bool mouseIsDrag;
100         private bool mouseIsDragDrop;
101         private bool multiline;
102         protected bool needRecalc;
103         protected bool needRecalcWordWrap;
104         private Point needRecalcWordWrapInterval;
105         private bool needRecalcFoldingLines;
106         private bool needRiseSelectionChangedDelayed;
107         private bool needRiseTextChangedDelayed;
108         private bool needRiseVisibleRangeChangedDelayed;
109         private Color paddingBackColor;
110         private int preferredLineWidth;
111         private Range rightBracketPosition;
112         private Range rightBracketPosition2;
113         private bool scrollBars;
114         private Color selectionColor;
115         private Color serviceLinesColor;
116         private bool showFoldingLines;
117         private bool showLineNumbers;
118         private FastColoredTextBox sourceTextBox;
119         private int startFoldingLine = -1;
120         private int updating;
121         private Range updatingRange;
122         private Range visibleRange;
123         private bool wordWrap;
124         private WordWrapMode wordWrapMode = WordWrapMode.WordWrapControlWidth;
125         private int reservedCountOfLineNumberChars = 1;
126         private int zoom = 100;
127         private Size localAutoScrollMinSize;
128 
129         /// <summary>
130         /// Constructor
131         /// </summary>
FastColoredTextBox()132         public FastColoredTextBox()
133         {
134             if(MonoUtility.IsLinux)
135             {
136                 ImeMode |= System.Windows.Forms.ImeMode.Disable;
137             }
138             else
139             {
140                 //register type provider
141                 TypeDescriptionProvider prov = TypeDescriptor.GetProvider(GetType());
142                 object theProvider =
143                     prov.GetType().GetField("Provider", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(prov);
144                 if (theProvider.GetType() != typeof (FCTBDescriptionProvider))
145                     TypeDescriptor.AddProvider(new FCTBDescriptionProvider(GetType()), GetType());
146             }
147             //drawing optimization
148             SetStyle(ControlStyles.AllPaintingInWmPaint, true);
149             SetStyle(ControlStyles.UserPaint, true);
150             SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
151             SetStyle(ControlStyles.ResizeRedraw, true);
152             //create one line
153             InitTextSource(CreateTextSource());
154             if (lines.Count == 0)
155                 lines.InsertLine(0, lines.CreateLine());
156             //append monospace font
157             //Font = new Font("Consolas", 9.75f, FontStyle.Regular, GraphicsUnit.Point);
158             Font = new Font(FontFamily.GenericMonospace, 9.75f);
159             selection = new Range(this) {Start = new Place(0, 0)};
160             //default settings
161             Cursor = Cursors.IBeam;
162             BackColor = Color.White;
163             LineNumberColor = Color.Teal;
164             IndentBackColor = Color.WhiteSmoke;
165             ServiceLinesColor = Color.Silver;
166             FoldingIndicatorColor = Color.Green;
167             CurrentLineColor = Color.Transparent;
168             ChangedLineColor = Color.Transparent;
169             HighlightFoldingIndicator = true;
170             ShowLineNumbers = true;
171             TabLength = 4;
172             FoldedBlockStyle = new FoldedBlockStyle(Brushes.Gray, null, FontStyle.Regular);
173             SelectionColor = Color.Blue;
174             BracketsStyle = new MarkerStyle(new SolidBrush(Color.FromArgb(80, Color.Lime)));
175             BracketsStyle2 = new MarkerStyle(new SolidBrush(Color.FromArgb(60, Color.Red)));
176             DelayedEventsInterval = 100;
177             DelayedTextChangedInterval = 100;
178             AllowSeveralTextStyleDrawing = false;
179             LeftBracket = '\x0';
180             RightBracket = '\x0';
181             LeftBracket2 = '\x0';
182             RightBracket2 = '\x0';
183             SyntaxHighlighter = new SyntaxHighlighter();
184             language = Language.Custom;
185             PreferredLineWidth = 0;
186             needRecalc = true;
187             lastNavigatedDateTime = DateTime.Now;
188             AutoIndent = true;
189             AutoIndentExistingLines = true;
190             CommentPrefix = "//";
191             lineNumberStartValue = 1;
192             multiline = true;
193             scrollBars = true;
194             AcceptsTab = true;
195             AcceptsReturn = true;
196             caretVisible = true;
197             CaretColor = Color.Black;
198             WideCaret = false;
199             Paddings = new Padding(0, 0, 0, 0);
200             PaddingBackColor = Color.Transparent;
201             DisabledColor = Color.FromArgb(100, 180, 180, 180);
202             needRecalcFoldingLines = true;
203             AllowDrop = true;
204             FindEndOfFoldingBlockStrategy = FindEndOfFoldingBlockStrategy.Strategy1;
205             VirtualSpace = false;
206             bookmarks = new Bookmarks(this);
207             BookmarkColor = Color.PowderBlue;
208             ToolTip = new ToolTip();
209             timer3.Interval = 500;
210             hints = new Hints(this);
211             SelectionHighlightingForLineBreaksEnabled = true;
212             textAreaBorder = TextAreaBorderType.None;
213             textAreaBorderColor = Color.Black;
214             macrosManager = new MacrosManager(this);
215             HotkeysMapping = new HotkeysMapping();
216             HotkeysMapping.InitDefault();
217             WordWrapAutoIndent = true;
218             FoldedBlocks = new Dictionary<int, int>();
219             AutoCompleteBrackets = false;
220             AutoIndentCharsPatterns = @"^\s*[\w\.]+\s*(?<range>=)\s*(?<range>[^;]+);";
221             AutoIndentChars = true;
222             CaretBlinking = true;
223             ServiceColors = new ServiceColors();
224             //
225             base.AutoScroll = true;
226             timer.Tick += timer_Tick;
227             timer2.Tick += timer2_Tick;
228             timer3.Tick += timer3_Tick;
229             middleClickScrollingTimer.Tick += middleClickScrollingTimer_Tick;
230         }
231 
232         private char[] autoCompleteBracketsList = { '(', ')', '{', '}', '[', ']', '"', '"', '\'', '\'' };
233 
234         public char[] AutoCompleteBracketsList
235         {
236             get { return autoCompleteBracketsList; }
237             set { autoCompleteBracketsList = value; }
238         }
239 
240         /// <summary>
241         /// AutoComplete brackets
242         /// </summary>
243         [DefaultValue(false)]
244         [Description("AutoComplete brackets.")]
245         public bool AutoCompleteBrackets { get; set; }
246 
247         /// <summary>
248         /// Colors of some service visual markers
249         /// </summary>
250 		  [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
251         public ServiceColors ServiceColors { get; set; }
252 
253         /// <summary>
254         /// Contains UniqueId of start lines of folded blocks
255         /// </summary>
256         /// <remarks>This dictionary remembers folding state of blocks.
257         /// It is needed to restore child folding after user collapsed/expanded top-level folding block.</remarks>
258         [Browsable(false)]
259         public Dictionary<int, int> FoldedBlocks { get; private set; }
260 
261         /// <summary>
262         /// Strategy of search of brackets to highlighting
263         /// </summary>
264         [DefaultValue(typeof(BracketsHighlightStrategy), "Strategy1")]
265         [Description("Strategy of search of brackets to highlighting.")]
266         public BracketsHighlightStrategy BracketsHighlightStrategy { get; set; }
267 
268         /// <summary>
269         /// Automatically shifts secondary wordwrap lines on the shift amount of the first line
270         /// </summary>
271         [DefaultValue(true)]
272         [Description("Automatically shifts secondary wordwrap lines on the shift amount of the first line.")]
273         public bool WordWrapAutoIndent { get; set; }
274 
275         /// <summary>
276         /// Indent of secondary wordwrap lines (in chars)
277         /// </summary>
278         [DefaultValue(0)]
279         [Description("Indent of secondary wordwrap lines (in chars).")]
280         public int WordWrapIndent { get; set; }
281 
282         MacrosManager macrosManager;
283         /// <summary>
284         /// MacrosManager records, stores and executes the macroses
285         /// </summary>
286         [Browsable(false)]
287         public MacrosManager MacrosManager { get { return macrosManager; } }
288 
289         /// <summary>
290         /// Allows drag and drop
291         /// </summary>
292         [DefaultValue(true)]
293         [Description("Allows drag and drop")]
294         public override bool AllowDrop
295         {
296             get { return base.AllowDrop; }
297             set { base.AllowDrop = value; }
298         }
299 
300         /// <summary>
301         /// Collection of Hints.
302         /// This is temporary buffer for currently displayed hints.
303         /// </summary>
304         /// <remarks>You can asynchronously add, remove and clear hints. Appropriate hints will be shown or hidden from the screen.</remarks>
305         [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
306          EditorBrowsable(EditorBrowsableState.Never)]
307         public Hints Hints
308         {
309             get { return hints; }
310             set { hints = value; }
311         }
312 
313         /// <summary>
314         /// Delay (ms) of ToolTip
315         /// </summary>
316         [Browsable(true)]
317         [DefaultValue(500)]
318         [Description("Delay(ms) of ToolTip.")]
319         public int ToolTipDelay
320         {
321             get { return timer3.Interval; }
322             set { timer3.Interval = value; }
323         }
324 
325         /// <summary>
326         /// ToolTip component
327         /// </summary>
328         [Browsable(true)]
329         [Description("ToolTip component.")]
330         public ToolTip ToolTip { get; set; }
331 
332         /// <summary>
333         /// Color of bookmarks
334         /// </summary>
335         [Browsable(true)]
336         [DefaultValue(typeof (Color), "PowderBlue")]
337         [Description("Color of bookmarks.")]
338         public Color BookmarkColor { get; set; }
339 
340         /// <summary>
341         /// Bookmarks
342         /// </summary>
343         [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
344          EditorBrowsable(EditorBrowsableState.Never)]
345         public BaseBookmarks Bookmarks
346         {
347             get { return bookmarks; }
348             set { bookmarks = value; }
349         }
350 
351         /// <summary>
352         /// Enables virtual spaces
353         /// </summary>
354         [DefaultValue(false)]
355         [Description("Enables virtual spaces.")]
356         public bool VirtualSpace { get; set; }
357 
358         /// <summary>
359         /// Strategy of search of end of folding block
360         /// </summary>
361         [DefaultValue(FindEndOfFoldingBlockStrategy.Strategy1)]
362         [Description("Strategy of search of end of folding block.")]
363         public FindEndOfFoldingBlockStrategy FindEndOfFoldingBlockStrategy { get; set; }
364 
365         /// <summary>
366         /// Indicates if tab characters are accepted as input
367         /// </summary>
368         [DefaultValue(true)]
369         [Description("Indicates if tab characters are accepted as input.")]
370         public bool AcceptsTab { get; set; }
371 
372         /// <summary>
373         /// Indicates if return characters are accepted as input
374         /// </summary>
375         [DefaultValue(true)]
376         [Description("Indicates if return characters are accepted as input.")]
377         public bool AcceptsReturn { get; set; }
378 
379         /// <summary>
380         /// Shows or hides the caret
381         /// </summary>
382         [DefaultValue(true)]
383         [Description("Shows or hides the caret")]
384         public bool CaretVisible
385         {
386             get { return caretVisible; }
387             set
388             {
389                 caretVisible = value;
390                 Invalidate();
391             }
392         }
393 
394         /// <summary>
395         /// Enables caret blinking
396         /// </summary>
397         [DefaultValue(true)]
398         [Description("Enables caret blinking")]
399         public bool CaretBlinking { get; set; }
400 
401 
402         Color textAreaBorderColor;
403 
404         /// <summary>
405         /// Color of border of text area
406         /// </summary>
407         [DefaultValue(typeof(Color), "Black")]
408         [Description("Color of border of text area")]
409         public Color TextAreaBorderColor
410         {
411             get { return textAreaBorderColor; }
412             set
413             {
414                 textAreaBorderColor = value;
415                 Invalidate();
416             }
417         }
418 
419         TextAreaBorderType textAreaBorder;
420         /// <summary>
421         /// Type of border of text area
422         /// </summary>
423         [DefaultValue(typeof(TextAreaBorderType), "None")]
424         [Description("Type of border of text area")]
425         public TextAreaBorderType TextAreaBorder
426         {
427             get { return textAreaBorder; }
428             set
429             {
430                 textAreaBorder = value;
431                 Invalidate();
432             }
433         }
434 
435         /// <summary>
436         /// Background color for current line
437         /// </summary>
438         [DefaultValue(typeof (Color), "Transparent")]
439         [Description("Background color for current line. Set to Color.Transparent to hide current line highlighting")]
440         public Color CurrentLineColor
441         {
442             get { return currentLineColor; }
443             set
444             {
445                 currentLineColor = value;
446                 Invalidate();
447             }
448         }
449 
450         /// <summary>
451         /// Background color for highlighting of changed lines
452         /// </summary>
453         [DefaultValue(typeof (Color), "Transparent")]
454         [Description("Background color for highlighting of changed lines. Set to Color.Transparent to hide changed line highlighting")]
455         public Color ChangedLineColor
456         {
457             get { return changedLineColor; }
458             set
459             {
460                 changedLineColor = value;
461                 Invalidate();
462             }
463         }
464 
465         /// <summary>
466         /// Fore color (default style color)
467         /// </summary>
468         public override Color ForeColor
469         {
470             get { return base.ForeColor; }
471             set
472             {
473                 base.ForeColor = value;
474                 lines.InitDefaultStyle();
475                 Invalidate();
476             }
477         }
478 
479         /// <summary>
480         /// Height of char in pixels (includes LineInterval)
481         /// </summary>
482         [Browsable(false)]
483         public int CharHeight
484         {
485             get { return charHeight; }
486             set
487             {
488                 charHeight = value;
489                 NeedRecalc();
490                 OnCharSizeChanged();
491             }
492         }
493 
494         /// <summary>
495         /// Interval between lines (in pixels)
496         /// </summary>
497         [Description("Interval between lines in pixels")]
498         [DefaultValue(0)]
499         public int LineInterval
500         {
501             get { return lineInterval; }
502             set
503             {
504                 lineInterval = value;
505                 SetFont(Font);
506                 Invalidate();
507             }
508         }
509 
510         /// <summary>
511         /// Width of char in pixels
512         /// </summary>
513         [Browsable(false)]
514         public int CharWidth { get; set; }
515 
516         /// <summary>
517         /// Spaces count for tab
518         /// </summary>
519         [DefaultValue(4)]
520         [Description("Spaces count for tab")]
521         public int TabLength { get; set; }
522 
523         /// <summary>
524         /// Text was changed
525         /// </summary>
526         [Browsable(false)]
527         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
528         public bool IsChanged
529         {
530             get { return isChanged; }
531             set
532             {
533                 if (!value)
534                     //clear line's IsChanged property
535                     lines.ClearIsChanged();
536 
537                 isChanged = value;
538             }
539         }
540 
541         /// <summary>
542         /// Text version
543         /// </summary>
544         /// <remarks>This counter is incremented each time changes the text</remarks>
545         [Browsable(false)]
546         public int TextVersion { get; private set; }
547 
548         /// <summary>
549         /// Read only
550         /// </summary>
551         [DefaultValue(false)]
552         public bool ReadOnly { get; set; }
553 
554         /// <summary>
555         /// Shows line numbers.
556         /// </summary>
557         [DefaultValue(true)]
558         [Description("Shows line numbers.")]
559         public bool ShowLineNumbers
560         {
561             get { return showLineNumbers; }
562             set
563             {
564                 showLineNumbers = value;
565                 NeedRecalc();
566                 Invalidate();
567             }
568         }
569 
570         /// <summary>
571         /// Shows vertical lines between folding start line and folding end line.
572         /// </summary>
573         [DefaultValue(false)]
574         [Description("Shows vertical lines between folding start line and folding end line.")]
575         public bool ShowFoldingLines
576         {
577             get { return showFoldingLines; }
578             set
579             {
580                 showFoldingLines = value;
581                 Invalidate();
582             }
583         }
584 
585         /// <summary>
586         /// Rectangle where located text
587         /// </summary>
588         [Browsable(false)]
589         public Rectangle TextAreaRect
590         {
591             get
592             {
593                 int rightPaddingStartX = LeftIndent + maxLineLength * CharWidth + Paddings.Left + 1;
594                 rightPaddingStartX = Math.Max(ClientSize.Width - Paddings.Right, rightPaddingStartX);
595                 int bottomPaddingStartY = TextHeight + Paddings.Top;
596                 bottomPaddingStartY = Math.Max(ClientSize.Height - Paddings.Bottom, bottomPaddingStartY);
597                 var top = Math.Max(0, Paddings.Top - 1) - VerticalScroll.Value;
598                 var left = LeftIndent - HorizontalScroll.Value - 2 + Math.Max(0, Paddings.Left - 1);
599                 var rect = Rectangle.FromLTRB(left, top, rightPaddingStartX - HorizontalScroll.Value, bottomPaddingStartY - VerticalScroll.Value);
600                 return rect;
601             }
602         }
603 
604         /// <summary>
605         /// Color of line numbers.
606         /// </summary>
607         [DefaultValue(typeof (Color), "Teal")]
608         [Description("Color of line numbers.")]
609         public Color LineNumberColor
610         {
611             get { return lineNumberColor; }
612             set
613             {
614                 lineNumberColor = value;
615                 Invalidate();
616             }
617         }
618 
619         /// <summary>
620         /// Start value of first line number.
621         /// </summary>
622         [DefaultValue(typeof (uint), "1")]
623         [Description("Start value of first line number.")]
624         public uint LineNumberStartValue
625         {
626             get { return lineNumberStartValue; }
627             set
628             {
629                 lineNumberStartValue = value;
630                 needRecalc = true;
631                 Invalidate();
632             }
633         }
634 
635         /// <summary>
636         /// Background color of indent area
637         /// </summary>
638         [DefaultValue(typeof(Color), "WhiteSmoke")]
639         [Description("Background color of indent area")]
640         public Color IndentBackColor
641         {
642             get { return indentBackColor; }
643             set
644             {
645                 indentBackColor = value;
646                 Invalidate();
647             }
648         }
649 
650         /// <summary>
651         /// Background color of padding area
652         /// </summary>
653         [DefaultValue(typeof (Color), "Transparent")]
654         [Description("Background color of padding area")]
655         public Color PaddingBackColor
656         {
657             get { return paddingBackColor; }
658             set
659             {
660                 paddingBackColor = value;
661                 Invalidate();
662             }
663         }
664 
665         /// <summary>
666         /// Color of disabled component
667         /// </summary>
668         [DefaultValue(typeof (Color), "100;180;180;180")]
669         [Description("Color of disabled component")]
670         public Color DisabledColor { get; set; }
671 
672         /// <summary>
673         /// Color of caret
674         /// </summary>
675         [DefaultValue(typeof (Color), "Black")]
676         [Description("Color of caret.")]
677         public Color CaretColor { get; set; }
678 
679         /// <summary>
680         /// Wide caret
681         /// </summary>
682         [DefaultValue(false)]
683         [Description("Wide caret.")]
684         public bool WideCaret { get; set; }
685 
686         /// <summary>
687         /// Color of service lines (folding lines, borders of blocks etc.)
688         /// </summary>
689         [DefaultValue(typeof (Color), "Silver")]
690         [Description("Color of service lines (folding lines, borders of blocks etc.)")]
691         public Color ServiceLinesColor
692         {
693             get { return serviceLinesColor; }
694             set
695             {
696                 serviceLinesColor = value;
697                 Invalidate();
698             }
699         }
700 
701         /// <summary>
702         /// Padings of text area
703         /// </summary>
704         [Browsable(true)]
705         [Description("Paddings of text area.")]
706         public Padding Paddings { get; set; }
707 
708         /// <summary>
709         /// --Do not use this property--
710         /// </summary>
711         [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
712          EditorBrowsable(EditorBrowsableState.Never)]
713         public new Padding Padding
714         {
715             get { throw new NotImplementedException(); }
716             set { throw new NotImplementedException(); }
717         }
718 
719         //hide RTL
720         [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
721          EditorBrowsable(EditorBrowsableState.Never)]
722         public new bool RightToLeft
723         {
724             get { throw new NotImplementedException(); }
725             set { throw new NotImplementedException(); }
726         }
727 
728         /// <summary>
729         /// Color of folding area indicator
730         /// </summary>
731         [DefaultValue(typeof (Color), "Green")]
732         [Description("Color of folding area indicator.")]
733         public Color FoldingIndicatorColor
734         {
735             get { return foldingIndicatorColor; }
736             set
737             {
738                 foldingIndicatorColor = value;
739                 Invalidate();
740             }
741         }
742 
743         /// <summary>
744         /// Enables folding indicator (left vertical line between folding bounds)
745         /// </summary>
746         [DefaultValue(true)]
747         [Description("Enables folding indicator (left vertical line between folding bounds)")]
748         public bool HighlightFoldingIndicator
749         {
750             get { return highlightFoldingIndicator; }
751             set
752             {
753                 highlightFoldingIndicator = value;
754                 Invalidate();
755             }
756         }
757 
758         /// <summary>
759         /// Left distance to text beginning
760         /// </summary>
761         [Browsable(false)]
762         [Description("Left distance to text beginning.")]
763         public int LeftIndent { get; private set; }
764 
765         /// <summary>
766         /// Left padding in pixels
767         /// </summary>
768         [DefaultValue(0)]
769         [Description("Width of left service area (in pixels)")]
770         public int LeftPadding
771         {
772             get { return leftPadding; }
773             set
774             {
775                 leftPadding = value;
776                 Invalidate();
777             }
778         }
779 
780         /// <summary>
781         /// This property draws vertical line after defined char position.
782         /// Set to 0 for disable drawing of vertical line.
783         /// </summary>
784         [DefaultValue(0)]
785         [Description("This property draws vertical line after defined char position. Set to 0 for disable drawing of vertical line.")]
786         public int PreferredLineWidth
787         {
788             get { return preferredLineWidth; }
789             set
790             {
791                 preferredLineWidth = value;
792                 Invalidate();
793             }
794         }
795 
796         /// <summary>
797         /// Styles
798         /// </summary>
799         [Browsable(false)]
800         public Style[] Styles
801         {
802             get { return lines.Styles; }
803         }
804 
805 		/// <summary>
806 		/// Hotkeys. Do not use this property in your code, use HotkeysMapping property.
807 		/// </summary>
808 		[Browsable(false)]
809 		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
810 		public string Hotkeys {
811             get { return HotkeysMapping.ToString(); }
812             set { HotkeysMapping = HotkeysMapping.Parse(value); }
813         }
814 
815         /// <summary>
816         /// Hotkeys mapping
817         /// </summary>
818         [Browsable(false)]
819         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
820         public HotkeysMapping HotkeysMapping{ get; set;}
821 
822         /// <summary>
823         /// Default text style
824         /// This style is using when no one other TextStyle is not defined in Char.style
825         /// </summary>
826         [Browsable(false)]
827         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
828         public TextStyle DefaultStyle
829         {
830             get { return lines.DefaultStyle; }
831             set { lines.DefaultStyle = value; }
832         }
833 
834         /// <summary>
835         /// Style for rendering Selection area
836         /// </summary>
837         [Browsable(false)]
838         public SelectionStyle SelectionStyle { get; set; }
839 
840         /// <summary>
841         /// Style for folded block rendering
842         /// </summary>
843         [Browsable(false)]
844         public TextStyle FoldedBlockStyle { get; set; }
845 
846         /// <summary>
847         /// Style for brackets highlighting
848         /// </summary>
849         [Browsable(false)]
850         public MarkerStyle BracketsStyle { get; set; }
851 
852         /// <summary>
853         /// Style for alternative brackets highlighting
854         /// </summary>
855         [Browsable(false)]
856         public MarkerStyle BracketsStyle2 { get; set; }
857 
858         /// <summary>
859         /// Opening bracket for brackets highlighting.
860         /// Set to '\x0' for disable brackets highlighting.
861         /// </summary>
862         [DefaultValue('\x0')]
863         [Description("Opening bracket for brackets highlighting. Set to '\\x0' for disable brackets highlighting.")]
864         public char LeftBracket { get; set; }
865 
866         /// <summary>
867         /// Closing bracket for brackets highlighting.
868         /// Set to '\x0' for disable brackets highlighting.
869         /// </summary>
870         [DefaultValue('\x0')]
871         [Description("Closing bracket for brackets highlighting. Set to '\\x0' for disable brackets highlighting.")]
872         public char RightBracket { get; set; }
873 
874         /// <summary>
875         /// Alternative opening bracket for brackets highlighting.
876         /// Set to '\x0' for disable brackets highlighting.
877         /// </summary>
878         [DefaultValue('\x0')]
879         [Description("Alternative opening bracket for brackets highlighting. Set to '\\x0' for disable brackets highlighting.")]
880         public char LeftBracket2 { get; set; }
881 
882         /// <summary>
883         /// Alternative closing bracket for brackets highlighting.
884         /// Set to '\x0' for disable brackets highlighting.
885         /// </summary>
886         [DefaultValue('\x0')]
887         [Description("Alternative closing bracket for brackets highlighting. Set to '\\x0' for disable brackets highlighting.")]
888         public char RightBracket2 { get; set; }
889 
890         /// <summary>
891         /// Comment line prefix.
892         /// </summary>
893         [DefaultValue("//")]
894         [Description("Comment line prefix.")]
895         public string CommentPrefix { get; set; }
896 
897         /// <summary>
898         /// This property specifies which part of the text will be highlighted as you type (by built-in highlighter).
899         /// </summary>
900         /// <remarks>When a user enters text, a component refreshes highlighting (because the text was changed).
901         /// This property specifies exactly which section of the text will be re-highlighted.
902         /// This can be useful to highlight multi-line comments, for example.</remarks>
903         [DefaultValue(typeof (HighlightingRangeType), "ChangedRange")]
904         [Description("This property specifies which part of the text will be highlighted as you type.")]
905         public HighlightingRangeType HighlightingRangeType { get; set; }
906 
907         /// <summary>
908         /// Is keyboard in replace mode (wide caret) ?
909         /// </summary>
910         [Browsable(false)]
911         public bool IsReplaceMode
912         {
913             get
914             {
915                 return isReplaceMode &&
916                        Selection.IsEmpty &&
917                        (!Selection.ColumnSelectionMode) &&
918                        Selection.Start.iChar < lines[Selection.Start.iLine].Count;
919             }
920             set { isReplaceMode = value; }
921         }
922 
923         /// <summary>
924         /// Allows text rendering several styles same time.
925         /// </summary>
926         [Browsable(true)]
927         [DefaultValue(false)]
928         [Description("Allows text rendering several styles same time.")]
929         public bool AllowSeveralTextStyleDrawing { get; set; }
930 
931         /// <summary>
932         /// Allows to record macros.
933         /// </summary>
934         [Browsable(true)]
935         [DefaultValue(true)]
936         [Description("Allows to record macros.")]
937         public bool AllowMacroRecording
938         {
939             get { return macrosManager.AllowMacroRecordingByUser; }
940             set { macrosManager.AllowMacroRecordingByUser = value; }
941         }
942 
943         /// <summary>
944         /// Allows AutoIndent. Inserts spaces before new line.
945         /// </summary>
946         [DefaultValue(true)]
947         [Description("Allows auto indent. Inserts spaces before line chars.")]
948         public bool AutoIndent { get; set; }
949 
950         /// <summary>
951         /// Does autoindenting in existing lines. It works only if AutoIndent is True.
952         /// </summary>
953         [DefaultValue(true)]
954         [Description("Does autoindenting in existing lines. It works only if AutoIndent is True.")]
955         public bool AutoIndentExistingLines { get; set; }
956 
957         /// <summary>
958         /// Minimal delay(ms) for delayed events (except TextChangedDelayed).
959         /// </summary>
960         [Browsable(true)]
961         [DefaultValue(100)]
962         [Description("Minimal delay(ms) for delayed events (except TextChangedDelayed).")]
963         public int DelayedEventsInterval
964         {
965             get { return timer.Interval; }
966             set { timer.Interval = value; }
967         }
968 
969         /// <summary>
970         /// Minimal delay(ms) for TextChangedDelayed event.
971         /// </summary>
972         [Browsable(true)]
973         [DefaultValue(100)]
974         [Description("Minimal delay(ms) for TextChangedDelayed event.")]
975         public int DelayedTextChangedInterval
976         {
977             get { return timer2.Interval; }
978             set { timer2.Interval = value; }
979         }
980 
981         /// <summary>
982         /// Language for highlighting by built-in highlighter.
983         /// </summary>
984         [Browsable(true)]
985         [DefaultValue(typeof (Language), "Custom")]
986         [Description("Language for highlighting by built-in highlighter.")]
987         public Language Language
988         {
989             get { return language; }
990             set
991             {
992                 language = value;
993                 if (SyntaxHighlighter != null)
994                     SyntaxHighlighter.InitStyleSchema(language);
995                 Invalidate();
996             }
997         }
998 
999         /// <summary>
1000         /// Syntax Highlighter
1001         /// </summary>
1002         [Browsable(false)]
1003         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
1004         public SyntaxHighlighter SyntaxHighlighter { get; set; }
1005 
1006         /// <summary>
1007         /// XML file with description of syntax highlighting.
1008         /// This property works only with Language == Language.Custom.
1009         /// </summary>
1010         [Browsable(true)]
1011         [DefaultValue(null)]
1012         //[Editor(typeof (FileNameEditor), typeof (UITypeEditor))]
1013         [Description(
1014             "XML file with description of syntax highlighting. This property works only with Language == Language.Custom."
1015             )]
1016         public SyntaxDescriptor SyntaxDescriptor
1017         {
1018             get { return syntaxDescriptor; }
1019             set
1020             {
1021                 syntaxDescriptor = value;
1022                 Invalidate();
1023             }
1024         }
1025 
1026         /// <summary>
1027         /// Position of left highlighted bracket.
1028         /// </summary>
1029         [Browsable(false)]
1030         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
1031         public Range LeftBracketPosition
1032         {
1033             get { return leftBracketPosition; }
1034         }
1035 
1036         /// <summary>
1037         /// Position of right highlighted bracket.
1038         /// </summary>
1039         [Browsable(false)]
1040         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
1041         public Range RightBracketPosition
1042         {
1043             get { return rightBracketPosition; }
1044         }
1045 
1046         /// <summary>
1047         /// Position of left highlighted alternative bracket.
1048         /// </summary>
1049         [Browsable(false)]
1050         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
1051         public Range LeftBracketPosition2
1052         {
1053             get { return leftBracketPosition2; }
1054         }
1055 
1056         /// <summary>
1057         /// Position of right highlighted alternative bracket.
1058         /// </summary>
1059         [Browsable(false)]
1060         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
1061         public Range RightBracketPosition2
1062         {
1063             get { return rightBracketPosition2; }
1064         }
1065 
1066         /// <summary>
1067         /// Start line index of current highlighted folding area. Return -1 if start of area is not found.
1068         /// </summary>
1069         [Browsable(false)]
1070         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
1071         public int StartFoldingLine
1072         {
1073             get { return startFoldingLine; }
1074         }
1075 
1076         /// <summary>
1077         /// End line index of current highlighted folding area. Return -1 if end of area is not found.
1078         /// </summary>
1079         [Browsable(false)]
1080         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
1081         public int EndFoldingLine
1082         {
1083             get { return endFoldingLine; }
1084         }
1085 
1086         /// <summary>
1087         /// TextSource
1088         /// </summary>
1089         [Browsable(false)]
1090         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
1091         public TextSource TextSource
1092         {
1093             get { return lines; }
1094             set { InitTextSource(value); }
1095         }
1096 
1097         [Browsable(false)]
1098         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
1099         public bool HasSourceTextBox
1100         {
1101             get { return SourceTextBox != null; }
1102         }
1103 
1104         /// <summary>
1105         /// The source of the text.
1106         /// Allows to get text from other FastColoredTextBox.
1107         /// </summary>
1108         [Browsable(true)]
1109         [DefaultValue(null)]
1110         [Description("Allows to get text from other FastColoredTextBox.")]
1111         //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
1112         public FastColoredTextBox SourceTextBox
1113         {
1114             get { return sourceTextBox; }
1115             set
1116             {
1117                 if (value == sourceTextBox)
1118                     return;
1119 
1120                 sourceTextBox = value;
1121 
1122                 if (sourceTextBox == null)
1123                 {
1124                     InitTextSource(CreateTextSource());
1125                     lines.InsertLine(0, TextSource.CreateLine());
1126                     IsChanged = false;
1127                 }
1128                 else
1129                 {
1130                     InitTextSource(SourceTextBox.TextSource);
1131                     isChanged = false;
1132                 }
1133                 Invalidate();
1134             }
1135         }
1136 
1137         /// <summary>
1138         /// Returns current visible range of text
1139         /// </summary>
1140         [Browsable(false)]
1141         public Range VisibleRange
1142         {
1143             get
1144             {
1145                 if (visibleRange != null)
1146                     return visibleRange;
1147                 return GetRange(
1148                     PointToPlace(new Point(LeftIndent, 0)),
1149                     PointToPlace(new Point(ClientSize.Width, ClientSize.Height))
1150                     );
1151             }
1152         }
1153 
1154         /// <summary>
1155         /// Current selection range
1156         /// </summary>
1157         [Browsable(false)]
1158         public Range Selection
1159         {
1160             get { return selection; }
1161             set
1162             {
1163                 if (value == selection)
1164                     return;
1165 
1166                 selection.BeginUpdate();
1167                 selection.Start = value.Start;
1168                 selection.End = value.End;
1169                 selection.EndUpdate();
1170                 Invalidate();
1171             }
1172         }
1173 
1174         /// <summary>
1175         /// Background color.
1176         /// It is used if BackBrush is null.
1177         /// </summary>
1178         [DefaultValue(typeof (Color), "White")]
1179         [Description("Background color.")]
1180         public override Color BackColor
1181         {
1182             get { return base.BackColor; }
1183             set { base.BackColor = value; }
1184         }
1185 
1186         /// <summary>
1187         /// Background brush.
1188         /// If Null then BackColor is used.
1189         /// </summary>
1190         [Browsable(false)]
1191         public Brush BackBrush
1192         {
1193             get { return backBrush; }
1194             set
1195             {
1196                 backBrush = value;
1197                 Invalidate();
1198             }
1199         }
1200 
1201         [Browsable(true)]
1202         [DefaultValue(true)]
1203         [Description("Scollbars visibility.")]
1204         public bool ShowScrollBars
1205         {
1206             get { return scrollBars; }
1207             set
1208             {
1209                 if (value == scrollBars) return;
1210                 scrollBars = value;
1211                 needRecalc = true;
1212                 Invalidate();
1213             }
1214         }
1215 
1216         /// <summary>
1217         /// Multiline
1218         /// </summary>
1219         [Browsable(true)]
1220         [DefaultValue(true)]
1221         [Description("Multiline mode.")]
1222         public bool Multiline
1223         {
1224             get { return multiline; }
1225             set
1226             {
1227                 if (multiline == value) return;
1228                 multiline = value;
1229                 needRecalc = true;
1230                 if (multiline)
1231                 {
1232                     base.AutoScroll = true;
1233                     ShowScrollBars = true;
1234                 }
1235                 else
1236                 {
1237                     base.AutoScroll = false;
1238                     ShowScrollBars = false;
1239                     if (lines.Count > 1)
1240                         lines.RemoveLine(1, lines.Count - 1);
1241                     lines.Manager.ClearHistory();
1242                 }
1243                 Invalidate();
1244             }
1245         }
1246 
1247         /// <summary>
1248         /// WordWrap.
1249         /// </summary>
1250         [Browsable(true)]
1251         [DefaultValue(false)]
1252         [Description("WordWrap.")]
1253         public bool WordWrap
1254         {
1255             get { return wordWrap; }
1256             set
1257             {
1258                 if (wordWrap == value) return;
1259                 wordWrap = value;
1260                 if (wordWrap)
1261                     Selection.ColumnSelectionMode = false;
1262                 NeedRecalc(false, true);
1263                 //RecalcWordWrap(0, LinesCount - 1);
1264                 Invalidate();
1265             }
1266         }
1267 
1268         /// <summary>
1269         /// WordWrap mode.
1270         /// </summary>
1271         [Browsable(true)]
1272         [DefaultValue(typeof (WordWrapMode), "WordWrapControlWidth")]
1273         [Description("WordWrap mode.")]
1274         public WordWrapMode WordWrapMode
1275         {
1276             get { return wordWrapMode; }
1277             set
1278             {
1279                 if (wordWrapMode == value) return;
1280                 wordWrapMode = value;
1281                 NeedRecalc(false, true);
1282                 //RecalcWordWrap(0, LinesCount - 1);
1283                 Invalidate();
1284             }
1285         }
1286 
1287         private bool selectionHighlightingForLineBreaksEnabled;
1288         /// <summary>
1289         /// If <c>true</c> then line breaks included into the selection will be selected too.
1290         /// Then line breaks will be shown as selected blank character.
1291         /// </summary>
1292         [DefaultValue(true)]
1293         [Description("If enabled then line ends included into the selection will be selected too. " +
1294             "Then line ends will be shown as selected blank character.")]
1295         public bool SelectionHighlightingForLineBreaksEnabled
1296         {
1297             get { return selectionHighlightingForLineBreaksEnabled; }
1298             set
1299             {
1300                 selectionHighlightingForLineBreaksEnabled = value;
1301                 Invalidate();
1302             }
1303         }
1304 
1305 
1306         [Browsable(false)]
1307         public FindForm findForm { get; private set; }
1308 
1309         [Browsable(false)]
1310         public ReplaceForm replaceForm { get; private set; }
1311 
1312         /// <summary>
1313         /// Do not change this property
1314         /// </summary>
1315         [Browsable(false)]
1316         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
1317         public override bool AutoScroll
1318         {
1319             get { return base.AutoScroll; }
1320             set { ; }
1321         }
1322 
1323         /// <summary>
1324         /// Count of lines
1325         /// </summary>
1326         [Browsable(false)]
1327         public int LinesCount
1328         {
1329             get { return lines.Count; }
1330         }
1331 
1332         /// <summary>
1333         /// Gets or sets char and styleId for given place
1334         /// This property does not fire OnTextChanged event
1335         /// </summary>
1336         public Char this[Place place]
1337         {
1338             get { return lines[place.iLine][place.iChar]; }
1339             set { lines[place.iLine][place.iChar] = value; }
1340         }
1341 
1342         /// <summary>
1343         /// Gets Line
1344         /// </summary>
1345         public Line this[int iLine]
1346         {
1347             get { return lines[iLine]; }
1348         }
1349 
1350         /// <summary>
1351         /// Text of control
1352         /// </summary>
1353         [Browsable(true)]
1354         [Localizable(true)]
1355         [Editor(
1356             "System.ComponentModel.Design.MultilineStringEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
1357             , typeof (UITypeEditor))]
1358         [SettingsBindable(true)]
1359         [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
1360         [Description("Text of the control.")]
1361         [Bindable(true)]
1362         public override string Text
1363         {
1364             get
1365             {
1366                 if (LinesCount == 0)
1367                     return "";
1368                 var sel = new Range(this);
1369                 sel.SelectAll();
1370                 return sel.Text;
1371             }
1372 
1373             set
1374             {
1375                 if (value == Text && value != "")
1376                     return;
1377 
1378                 SetAsCurrentTB();
1379 
1380                 Selection.ColumnSelectionMode = false;
1381 
1382                 Selection.BeginUpdate();
1383                 try
1384                 {
1385                     Selection.SelectAll();
1386                     InsertText(value);
1387                     GoHome();
1388                 }
1389                 finally
1390                 {
1391                     Selection.EndUpdate();
1392                 }
1393             }
1394         }
1395 
1396         /// <summary>
1397         /// Text lines
1398         /// </summary>
1399         [Browsable(false)]
1400         public IList<string> Lines
1401         {
1402             get { return lines.GetLines(); }
1403         }
1404 
1405         /// <summary>
1406         /// Gets colored text as HTML
1407         /// </summary>
1408         /// <remarks>For more flexibility you can use ExportToHTML class also</remarks>
1409         [Browsable(false)]
1410         public string Html
1411         {
1412             get
1413             {
1414                 var exporter = new ExportToHTML();
1415                 exporter.UseNbsp = false;
1416                 exporter.UseStyleTag = false;
1417                 exporter.UseBr = false;
1418                 return "<pre>" + exporter.GetHtml(this) + "</pre>";
1419             }
1420         }
1421 
1422         /// <summary>
1423         /// Gets colored text as RTF
1424         /// </summary>
1425         /// <remarks>For more flexibility you can use ExportToRTF class also</remarks>
1426         [Browsable(false)]
1427         public string Rtf
1428         {
1429             get
1430             {
1431                 var exporter = new ExportToRTF();
1432                 return exporter.GetRtf(this);
1433             }
1434         }
1435 
1436         /// <summary>
1437         /// Text of current selection
1438         /// </summary>
1439         [Browsable(false)]
1440         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
1441         public string SelectedText
1442         {
1443             get { return Selection.Text; }
1444             set { InsertText(value); }
1445         }
1446 
1447         /// <summary>
1448         /// Start position of selection
1449         /// </summary>
1450         [Browsable(false)]
1451         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
1452         public int SelectionStart
1453         {
1454             get { return Math.Min(PlaceToPosition(Selection.Start), PlaceToPosition(Selection.End)); }
1455             set { Selection.Start = PositionToPlace(value); }
1456         }
1457 
1458         /// <summary>
1459         /// Length of selected text
1460         /// </summary>
1461         [Browsable(false)]
1462         [DefaultValue(0)]
1463         public int SelectionLength
1464         {
1465             get { return Math.Abs(PlaceToPosition(Selection.Start) - PlaceToPosition(Selection.End)); }
1466             set
1467             {
1468                 Selection.End = PositionToPlace(SelectionStart + value);
1469             }
1470         }
1471 
1472         /// <summary>
1473         /// Font
1474         /// </summary>
1475         /// <remarks>Use only monospaced font</remarks>
1476         [DefaultValue(typeof (Font), "Courier New, 9.75")]
1477         public override Font Font
1478         {
1479             get { return BaseFont; }
1480             set {
1481                 originalFont = (Font)value.Clone();
1482                 SetFont(value);
1483             }
1484         }
1485 
1486 
1487         Font baseFont;
1488         /// <summary>
1489         /// Font
1490         /// </summary>
1491         /// <remarks>Use only monospaced font</remarks>
1492         [DefaultValue(typeof(Font), "Courier New, 9.75")]
1493         private Font BaseFont
1494         {
1495             get { return baseFont; }
1496             set
1497             {
1498                 baseFont = value;
1499             }
1500         }
1501 
SetFont(Font newFont)1502         private void SetFont(Font newFont)
1503         {
1504             BaseFont = newFont;
1505             //check monospace font
1506             /*SizeF sizeM = GetCharSize(BaseFont, 'M');
1507             SizeF sizeDot = GetCharSize(BaseFont, '.');
1508             if (sizeM != sizeDot)
1509                 BaseFont = new Font("Courier New", BaseFont.SizeInPoints, FontStyle.Regular, GraphicsUnit.Point);*/
1510             //clac size
1511             SizeF size = GetCharSize(BaseFont, 'M');
1512             CharWidth = (int) Math.Round(size.Width*1f /*0.85*/) - 1 /*0*/;
1513             CharHeight = lineInterval + (int) Math.Round(size.Height*1f /*0.9*/) - 1 /*0*/;
1514             //
1515             //if (wordWrap)
1516             //    RecalcWordWrap(0, Lines.Count - 1);
1517             NeedRecalc(false, wordWrap);
1518             //
1519             Invalidate();
1520         }
1521 
1522         public new Size AutoScrollMinSize
1523         {
1524             set
1525             {
1526                 if (scrollBars)
1527                 {
1528                     if (!base.AutoScroll)
1529                         base.AutoScroll = true;
1530                     Size newSize = value;
1531                     if (WordWrap && WordWrapMode != FastColoredTextBoxNS.WordWrapMode.Custom)
1532                     {
1533                         int maxWidth = GetMaxLineWordWrapedWidth();
1534                         newSize = new Size(Math.Min(newSize.Width, maxWidth), newSize.Height);
1535                     }
1536                     base.AutoScrollMinSize = newSize;
1537                 }
1538                 else
1539                 {
1540                     if (base.AutoScroll)
1541                         base.AutoScroll = false;
1542                     base.AutoScrollMinSize = new Size(0, 0);
1543                     VerticalScroll.Visible = false;
1544                     HorizontalScroll.Visible = false;
1545                     VerticalScroll.Maximum = Math.Max(0, value.Height - ClientSize.Height);
1546                     HorizontalScroll.Maximum = Math.Max(0, value.Width - ClientSize.Width);
1547                     localAutoScrollMinSize = value;
1548                 }
1549             }
1550 
1551             get
1552             {
1553                 if (scrollBars)
1554                     return base.AutoScrollMinSize;
1555                 else
1556                     //return new Size(HorizontalScroll.Maximum, VerticalScroll.Maximum);
1557                     return localAutoScrollMinSize;
1558             }
1559         }
1560 
1561         /// <summary>
1562         /// Indicates that IME is allowed (for CJK language entering)
1563         /// </summary>
1564         [Browsable(false)]
1565         public bool ImeAllowed
1566         {
1567             get
1568             {
1569                 return ImeMode != ImeMode.Disable &&
1570                        ImeMode != ImeMode.Off &&
1571                        ImeMode != ImeMode.NoControl;
1572             }
1573         }
1574 
1575         /// <summary>
1576         /// Is undo enabled?
1577         /// </summary>
1578         [Browsable(false)]
1579         public bool UndoEnabled
1580         {
1581             get { return lines.Manager.UndoEnabled; }
1582         }
1583 
1584         /// <summary>
1585         /// Is redo enabled?
1586         /// </summary>
1587         [Browsable(false)]
1588         public bool RedoEnabled
1589         {
1590             get { return lines.Manager.RedoEnabled; }
1591         }
1592 
1593         private int LeftIndentLine
1594         {
1595             get { return LeftIndent - minLeftIndent/2 - 3; }
1596         }
1597 
1598         /// <summary>
1599         /// Range of all text
1600         /// </summary>
1601         [Browsable(false)]
1602         public Range Range
1603         {
1604             get { return new Range(this, new Place(0, 0), new Place(lines[lines.Count - 1].Count, lines.Count - 1)); }
1605         }
1606 
1607         /// <summary>
1608         /// Color of selected area
1609         /// </summary>
1610         [DefaultValue(typeof (Color), "Blue")]
1611         [Description("Color of selected area.")]
1612         public virtual Color SelectionColor
1613         {
1614             get { return selectionColor; }
1615             set
1616             {
1617                 selectionColor = value;
1618                 if (selectionColor.A == 255)
1619                     selectionColor = Color.FromArgb(60, selectionColor);
1620                 SelectionStyle = new SelectionStyle(new SolidBrush(selectionColor));
1621                 Invalidate();
1622             }
1623         }
1624 
1625         public override Cursor Cursor
1626         {
1627             get { return base.Cursor; }
1628             set
1629             {
1630                 defaultCursor = value;
1631                 base.Cursor = value;
1632             }
1633         }
1634 
1635         /// <summary>
1636         /// Reserved space for line number characters.
1637         /// If smaller than needed (e. g. line count >= 10 and this value set to 1) this value will have no impact.
1638         /// If you want to reserve space, e. g. for line numbers >= 10 or >= 100 than you can set this value to 2 or 3 or higher.
1639         /// </summary>
1640         [DefaultValue(1)]
1641         [Description(
1642             "Reserved space for line number characters. If smaller than needed (e. g. line count >= 10 and " +
1643             "this value set to 1) this value will have no impact. If you want to reserve space, e. g. for line " +
1644             "numbers >= 10 or >= 100, than you can set this value to 2 or 3 or higher.")]
1645         public int ReservedCountOfLineNumberChars
1646         {
1647             get { return reservedCountOfLineNumberChars; }
1648             set
1649             {
1650                 reservedCountOfLineNumberChars = value;
1651                 NeedRecalc();
1652                 Invalidate();
1653             }
1654         }
1655 
1656         /// <summary>
1657         /// Occurs when mouse is moving over text and tooltip is needed
1658         /// </summary>
1659         [Browsable(true)]
1660         [Description("Occurs when mouse is moving over text and tooltip is needed.")]
1661         public event EventHandler<ToolTipNeededEventArgs> ToolTipNeeded;
1662 
1663         /// <summary>
1664         /// Removes all hints
1665         /// </summary>
ClearHints()1666         public void ClearHints()
1667         {
1668             if (Hints != null)
1669                 Hints.Clear();
1670         }
1671 
1672         /// <summary>
1673         /// Add and shows the hint
1674         /// </summary>
1675         /// <param name="range">Linked range</param>
1676         /// <param name="innerControl">Inner control</param>
1677         /// <param name="scrollToHint">Scrolls textbox to the hint</param>
1678         /// <param name="inline">Inlining. If True then hint will moves apart text</param>
1679         /// <param name="dock">Docking. If True then hint will fill whole line</param>
AddHint(Range range, Control innerControl, bool scrollToHint, bool inline, bool dock)1680         public virtual Hint AddHint(Range range, Control innerControl, bool scrollToHint, bool inline,
1681                                     bool dock)
1682         {
1683             var hint = new Hint(range, innerControl, inline, dock);
1684             Hints.Add(hint);
1685             if (scrollToHint)
1686                 hint.DoVisible();
1687 
1688             return hint;
1689         }
1690 
1691         /// <summary>
1692         /// Add and shows the hint
1693         /// </summary>
1694         /// <param name="range">Linked range</param>
1695         /// <param name="innerControl">Inner control</param>
AddHint(Range range, Control innerControl)1696         public Hint AddHint(Range range, Control innerControl)
1697         {
1698             return AddHint(range, innerControl, true, true, true);
1699         }
1700 
1701         /// <summary>
1702         /// Add and shows simple text hint
1703         /// </summary>
1704         /// <param name="range">Linked range</param>
1705         /// <param name="text">Text of simple hint</param>
1706         /// <param name="scrollToHint">Scrolls textbox to the hint</param>
1707         /// <param name="inline">Inlining. If True then hint will moves apart text</param>
1708         /// <param name="dock">Docking. If True then hint will fill whole line</param>
AddHint(Range range, string text, bool scrollToHint, bool inline, bool dock)1709         public virtual Hint AddHint(Range range, string text, bool scrollToHint, bool inline, bool dock)
1710         {
1711             var hint = new Hint(range, text, inline, dock);
1712             Hints.Add(hint);
1713             if (scrollToHint)
1714                 hint.DoVisible();
1715 
1716             return hint;
1717         }
1718 
1719         /// <summary>
1720         /// Add and shows simple text hint
1721         /// </summary>
1722         /// <param name="range">Linked range</param>
1723         /// <param name="text">Text of simple hint</param>
AddHint(Range range, string text)1724         public Hint AddHint(Range range, string text)
1725         {
1726             return AddHint(range, text, true, true, true);
1727         }
1728 
1729         /// <summary>
1730         /// Occurs when user click on the hint
1731         /// </summary>
1732         /// <param name="hint"></param>
OnHintClick(Hint hint)1733         public virtual void OnHintClick(Hint hint)
1734         {
1735             if (HintClick != null)
1736                 HintClick(this, new HintClickEventArgs(hint));
1737         }
1738 
timer3_Tick(object sender, EventArgs e)1739         private void timer3_Tick(object sender, EventArgs e)
1740         {
1741             timer3.Stop();
1742             OnToolTip();
1743         }
1744 
OnToolTip()1745         protected virtual void OnToolTip()
1746         {
1747             if (ToolTip == null)
1748                 return;
1749             if (ToolTipNeeded == null)
1750                 return;
1751 
1752             //get place under mouse
1753             Place place = PointToPlace(lastMouseCoord);
1754 
1755             //check distance
1756             Point p = PlaceToPoint(place);
1757             if (Math.Abs(p.X - lastMouseCoord.X) > CharWidth*2 ||
1758                 Math.Abs(p.Y - lastMouseCoord.Y) > CharHeight*2)
1759                 return;
1760             //get word under mouse
1761             var r = new Range(this, place, place);
1762             string hoveredWord = r.GetFragment("[a-zA-Z]").Text;
1763             //event handler
1764             var ea = new ToolTipNeededEventArgs(place, hoveredWord);
1765             ToolTipNeeded(this, ea);
1766 
1767             if (ea.ToolTipText != null)
1768             {
1769                 //show tooltip
1770                 ToolTip.ToolTipTitle = ea.ToolTipTitle;
1771                 ToolTip.ToolTipIcon = ea.ToolTipIcon;
1772                 //ToolTip.SetToolTip(this, ea.ToolTipText);
1773                 ToolTip.Show(ea.ToolTipText, this, new Point(lastMouseCoord.X, lastMouseCoord.Y + CharHeight));
1774             }
1775         }
1776 
1777         /// <summary>
1778         /// Occurs when VisibleRange is changed
1779         /// </summary>
OnVisibleRangeChanged()1780         public virtual void OnVisibleRangeChanged()
1781         {
1782             needRecalcFoldingLines = true;
1783 
1784             needRiseVisibleRangeChangedDelayed = true;
1785             ResetTimer(timer);
1786             if (VisibleRangeChanged != null)
1787                 VisibleRangeChanged(this, new EventArgs());
1788         }
1789 
1790         /// <summary>
1791         /// Invalidates the entire surface of the control and causes the control to be redrawn.
1792         /// This method is thread safe and does not require Invoke.
1793         /// </summary>
Invalidate()1794         public new void Invalidate()
1795         {
1796             if (InvokeRequired)
1797                 BeginInvoke(new MethodInvoker(Invalidate));
1798             else
1799                 base.Invalidate();
1800         }
1801 
OnCharSizeChanged()1802         protected virtual void OnCharSizeChanged()
1803         {
1804             VerticalScroll.SmallChange = charHeight;
1805             VerticalScroll.LargeChange = 10*charHeight;
1806             HorizontalScroll.SmallChange = CharWidth;
1807         }
1808 
1809         /// <summary>
1810         /// HintClick event.
1811         /// It occurs if user click on the hint.
1812         /// </summary>
1813         [Browsable(true)]
1814         [Description("It occurs if user click on the hint.")]
1815         public event EventHandler<HintClickEventArgs> HintClick;
1816 
1817         /// <summary>
1818         /// TextChanged event.
1819         /// It occurs after insert, delete, clear, undo and redo operations.
1820         /// </summary>
1821         [Browsable(true)]
1822         [Description("It occurs after insert, delete, clear, undo and redo operations.")]
1823         public new event EventHandler<TextChangedEventArgs> TextChanged;
1824 
1825         /// <summary>
1826         /// Fake event for correct data binding
1827         /// </summary>
1828         [Browsable(false)]
1829         internal event EventHandler BindingTextChanged;
1830 
1831         /// <summary>
1832         /// Occurs when user paste text from clipboard
1833         /// </summary>
1834         [Description("Occurs when user paste text from clipboard")]
1835         public event EventHandler<TextChangingEventArgs> Pasting;
1836 
1837         /// <summary>
1838         /// TextChanging event.
1839         /// It occurs before insert, delete, clear, undo and redo operations.
1840         /// </summary>
1841         [Browsable(true)]
1842         [Description("It occurs before insert, delete, clear, undo and redo operations.")]
1843         public event EventHandler<TextChangingEventArgs> TextChanging;
1844 
1845         /// <summary>
1846         /// SelectionChanged event.
1847         /// It occurs after changing of selection.
1848         /// </summary>
1849         [Browsable(true)]
1850         [Description("It occurs after changing of selection.")]
1851         public event EventHandler SelectionChanged;
1852 
1853         /// <summary>
1854         /// VisibleRangeChanged event.
1855         /// It occurs after changing of visible range.
1856         /// </summary>
1857         [Browsable(true)]
1858         [Description("It occurs after changing of visible range.")]
1859         public event EventHandler VisibleRangeChanged;
1860 
1861         /// <summary>
1862         /// TextChangedDelayed event.
1863         /// It occurs after insert, delete, clear, undo and redo operations.
1864         /// This event occurs with a delay relative to TextChanged, and fires only once.
1865         /// </summary>
1866         [Browsable(true)]
1867         [Description(
1868             "It occurs after insert, delete, clear, undo and redo operations. This event occurs with a delay relative to TextChanged, and fires only once."
1869             )]
1870         public event EventHandler<TextChangedEventArgs> TextChangedDelayed;
1871 
1872         /// <summary>
1873         /// SelectionChangedDelayed event.
1874         /// It occurs after changing of selection.
1875         /// This event occurs with a delay relative to SelectionChanged, and fires only once.
1876         /// </summary>
1877         [Browsable(true)]
1878         [Description(
1879             "It occurs after changing of selection. This event occurs with a delay relative to SelectionChanged, and fires only once."
1880             )]
1881         public event EventHandler SelectionChangedDelayed;
1882 
1883         /// <summary>
1884         /// VisibleRangeChangedDelayed event.
1885         /// It occurs after changing of visible range.
1886         /// This event occurs with a delay relative to VisibleRangeChanged, and fires only once.
1887         /// </summary>
1888         [Browsable(true)]
1889         [Description(
1890             "It occurs after changing of visible range. This event occurs with a delay relative to VisibleRangeChanged, and fires only once."
1891             )]
1892         public event EventHandler VisibleRangeChangedDelayed;
1893 
1894         /// <summary>
1895         /// It occurs when user click on VisualMarker.
1896         /// </summary>
1897         [Browsable(true)]
1898         [Description("It occurs when user click on VisualMarker.")]
1899         public event EventHandler<VisualMarkerEventArgs> VisualMarkerClick;
1900 
1901         /// <summary>
1902         /// It occurs when visible char is enetering (alphabetic, digit, punctuation, DEL, BACKSPACE)
1903         /// </summary>
1904         /// <remarks>Set Handle to True for cancel key</remarks>
1905         [Browsable(true)]
1906         [Description("It occurs when visible char is enetering (alphabetic, digit, punctuation, DEL, BACKSPACE).")]
1907         public event KeyPressEventHandler KeyPressing;
1908 
1909         /// <summary>
1910         /// It occurs when visible char is enetered (alphabetic, digit, punctuation, DEL, BACKSPACE)
1911         /// </summary>
1912         [Browsable(true)]
1913         [Description("It occurs when visible char is enetered (alphabetic, digit, punctuation, DEL, BACKSPACE).")]
1914         public event KeyPressEventHandler KeyPressed;
1915 
1916         /// <summary>
1917         /// It occurs when calculates AutoIndent for new line
1918         /// </summary>
1919         [Browsable(true)]
1920         [Description("It occurs when calculates AutoIndent for new line.")]
1921         public event EventHandler<AutoIndentEventArgs> AutoIndentNeeded;
1922 
1923         /// <summary>
1924         /// It occurs when line background is painting
1925         /// </summary>
1926         [Browsable(true)]
1927         [Description("It occurs when line background is painting.")]
1928         public event EventHandler<PaintLineEventArgs> PaintLine;
1929 
1930         /// <summary>
1931         /// Occurs when line was inserted/added
1932         /// </summary>
1933         [Browsable(true)]
1934         [Description("Occurs when line was inserted/added.")]
1935         public event EventHandler<LineInsertedEventArgs> LineInserted;
1936 
1937         /// <summary>
1938         /// Occurs when line was removed
1939         /// </summary>
1940         [Browsable(true)]
1941         [Description("Occurs when line was removed.")]
1942         public event EventHandler<LineRemovedEventArgs> LineRemoved;
1943 
1944         /// <summary>
1945         /// Occurs when current highlighted folding area is changed.
1946         /// Current folding area see in StartFoldingLine and EndFoldingLine.
1947         /// </summary>
1948         /// <remarks></remarks>
1949         [Browsable(true)]
1950         [Description("Occurs when current highlighted folding area is changed.")]
1951         public event EventHandler<EventArgs> FoldingHighlightChanged;
1952 
1953         /// <summary>
1954         /// Occurs when undo/redo stack is changed
1955         /// </summary>
1956         /// <remarks></remarks>
1957         [Browsable(true)]
1958         [Description("Occurs when undo/redo stack is changed.")]
1959         public event EventHandler<EventArgs> UndoRedoStateChanged;
1960 
1961         /// <summary>
1962         /// Occurs when component was zoomed
1963         /// </summary>
1964         [Browsable(true)]
1965         [Description("Occurs when component was zoomed.")]
1966         public event EventHandler ZoomChanged;
1967 
1968 
1969         /// <summary>
1970         /// Occurs when user pressed key, that specified as CustomAction
1971         /// </summary>
1972         [Browsable(true)]
1973         [Description("Occurs when user pressed key, that specified as CustomAction.")]
1974         public event EventHandler<CustomActionEventArgs> CustomAction;
1975 
1976         /// <summary>
1977         /// Occurs when scroolbars are updated
1978         /// </summary>
1979         [Browsable(true)]
1980         [Description("Occurs when scroolbars are updated.")]
1981         public event EventHandler ScrollbarsUpdated;
1982 
1983         /// <summary>
1984         /// Occurs when custom wordwrap is needed
1985         /// </summary>
1986         [Browsable(true)]
1987         [Description("Occurs when custom wordwrap is needed.")]
1988         public event EventHandler<WordWrapNeededEventArgs> WordWrapNeeded;
1989 
1990 
1991         /// <summary>
1992         /// Returns list of styles of given place
1993         /// </summary>
GetStylesOfChar(Place place)1994         public List<Style> GetStylesOfChar(Place place)
1995         {
1996             var result = new List<Style>();
1997             if (place.iLine < LinesCount && place.iChar < this[place.iLine].Count)
1998             {
1999 #if Styles32
2000                 var s = (uint) this[place].style;
2001                 for (int i = 0; i < 32; i++)
2002                     if ((s & ((uint) 1) << i) != 0)
2003                         result.Add(Styles[i]);
2004 #else
2005                 var s = (ushort)this[place].style;
2006                 for (int i = 0; i < 16; i++)
2007                     if ((s & ((ushort) 1) << i) != 0)
2008                         result.Add(Styles[i]);
2009 #endif
2010             }
2011 
2012             return result;
2013         }
2014 
CreateTextSource()2015         protected virtual TextSource CreateTextSource()
2016         {
2017             return new TextSource(this);
2018         }
2019 
SetAsCurrentTB()2020         private void SetAsCurrentTB()
2021         {
2022             TextSource.CurrentTB = this;
2023         }
2024 
InitTextSource(TextSource ts)2025         protected void InitTextSource(TextSource ts)
2026         {
2027             if (lines != null)
2028             {
2029                 lines.LineInserted -= ts_LineInserted;
2030                 lines.LineRemoved -= ts_LineRemoved;
2031                 lines.TextChanged -= ts_TextChanged;
2032                 lines.RecalcNeeded -= ts_RecalcNeeded;
2033                 lines.RecalcWordWrap -= ts_RecalcWordWrap;
2034                 lines.TextChanging -= ts_TextChanging;
2035 
2036                 lines.Dispose();
2037             }
2038 
2039             LineInfos.Clear();
2040             ClearHints();
2041             if (Bookmarks != null)
2042                 Bookmarks.Clear();
2043 
2044             lines = ts;
2045 
2046             if (ts != null)
2047             {
2048                 ts.LineInserted += ts_LineInserted;
2049                 ts.LineRemoved += ts_LineRemoved;
2050                 ts.TextChanged += ts_TextChanged;
2051                 ts.RecalcNeeded += ts_RecalcNeeded;
2052                 ts.RecalcWordWrap += ts_RecalcWordWrap;
2053                 ts.TextChanging += ts_TextChanging;
2054 
2055                 while (LineInfos.Count < ts.Count)
2056                     LineInfos.Add(new LineInfo(-1));
2057             }
2058 
2059             isChanged = false;
2060             needRecalc = true;
2061         }
2062 
ts_RecalcWordWrap(object sender, TextSource.TextChangedEventArgs e)2063         private void ts_RecalcWordWrap(object sender, TextSource.TextChangedEventArgs e)
2064         {
2065             RecalcWordWrap(e.iFromLine, e.iToLine);
2066         }
2067 
ts_TextChanging(object sender, TextChangingEventArgs e)2068         private void ts_TextChanging(object sender, TextChangingEventArgs e)
2069         {
2070             if (TextSource.CurrentTB == this)
2071             {
2072                 string text = e.InsertingText;
2073                 OnTextChanging(ref text);
2074                 e.InsertingText = text;
2075             }
2076         }
2077 
ts_RecalcNeeded(object sender, TextSource.TextChangedEventArgs e)2078         private void ts_RecalcNeeded(object sender, TextSource.TextChangedEventArgs e)
2079         {
2080             if (e.iFromLine == e.iToLine && !WordWrap && lines.Count > minLinesForAccuracy)
2081                 RecalcScrollByOneLine(e.iFromLine);
2082             else
2083                 needRecalc = true;
2084         }
2085 
2086         /// <summary>
2087         /// Call this method if the recalc of the position of lines is needed.
2088         /// </summary>
NeedRecalc()2089         public void NeedRecalc()
2090         {
2091             NeedRecalc(false);
2092         }
2093 
2094         /// <summary>
2095         /// Call this method if the recalc of the position of lines is needed.
2096         /// </summary>
NeedRecalc(bool forced)2097         public void NeedRecalc(bool forced)
2098         {
2099             NeedRecalc(forced, false);
2100         }
2101 
2102         /// <summary>
2103         /// Call this method if the recalc of the position of lines is needed.
2104         /// </summary>
NeedRecalc(bool forced, bool wordWrapRecalc)2105         public void NeedRecalc(bool forced, bool wordWrapRecalc)
2106         {
2107             needRecalc = true;
2108 
2109             if(wordWrapRecalc)
2110             {
2111                 needRecalcWordWrapInterval = new Point(0, LinesCount - 1);
2112                 needRecalcWordWrap = true;
2113             }
2114 
2115             if (forced)
2116                 Recalc();
2117         }
2118 
ts_TextChanged(object sender, TextSource.TextChangedEventArgs e)2119         private void ts_TextChanged(object sender, TextSource.TextChangedEventArgs e)
2120         {
2121             if (e.iFromLine == e.iToLine && !WordWrap)
2122                 RecalcScrollByOneLine(e.iFromLine);
2123             else
2124                 needRecalc = true;
2125 
2126             Invalidate();
2127             if (TextSource.CurrentTB == this)
2128                 OnTextChanged(e.iFromLine, e.iToLine);
2129         }
2130 
ts_LineRemoved(object sender, LineRemovedEventArgs e)2131         private void ts_LineRemoved(object sender, LineRemovedEventArgs e)
2132         {
2133             LineInfos.RemoveRange(e.Index, e.Count);
2134             OnLineRemoved(e.Index, e.Count, e.RemovedLineUniqueIds);
2135         }
2136 
ts_LineInserted(object sender, LineInsertedEventArgs e)2137         private void ts_LineInserted(object sender, LineInsertedEventArgs e)
2138         {
2139             VisibleState newState = VisibleState.Visible;
2140             if (e.Index >= 0 && e.Index < LineInfos.Count && LineInfos[e.Index].VisibleState == VisibleState.Hidden)
2141                 newState = VisibleState.Hidden;
2142 
2143             if (e.Count > 100000)
2144                 LineInfos.Capacity = LineInfos.Count + e.Count + 1000;
2145 
2146             var temp = new LineInfo[e.Count];
2147             for (int i = 0; i < e.Count; i++)
2148             {
2149                 temp[i].startY = -1;
2150                 temp[i].VisibleState = newState;
2151             }
2152             LineInfos.InsertRange(e.Index, temp);
2153 
2154             /*
2155             for (int i = 0; i < e.Count; i++)
2156             {
2157                 LineInfos.Add(new LineInfo(-1) { VisibleState = newState });//<---- needed Insert
2158                 if(i % 1000000 == 0 && i > 0)
2159                     GC.Collect();
2160             }*/
2161 
2162             if (e.Count > 1000000)
2163                 GC.Collect();
2164 
2165             OnLineInserted(e.Index, e.Count);
2166         }
2167 
2168         /// <summary>
2169         /// Navigates forward (by Line.LastVisit property)
2170         /// </summary>
NavigateForward()2171         public bool NavigateForward()
2172         {
2173             DateTime min = DateTime.Now;
2174             int iLine = -1;
2175             for (int i = 0; i < LinesCount; i++)
2176                 if (lines.IsLineLoaded(i))
2177                     if (lines[i].LastVisit > lastNavigatedDateTime && lines[i].LastVisit < min)
2178                     {
2179                         min = lines[i].LastVisit;
2180                         iLine = i;
2181                     }
2182             if (iLine >= 0)
2183             {
2184                 Navigate(iLine);
2185                 return true;
2186             }
2187             else
2188                 return false;
2189         }
2190 
2191         /// <summary>
2192         /// Navigates backward (by Line.LastVisit property)
2193         /// </summary>
NavigateBackward()2194         public bool NavigateBackward()
2195         {
2196             var max = new DateTime();
2197             int iLine = -1;
2198             for (int i = 0; i < LinesCount; i++)
2199                 if (lines.IsLineLoaded(i))
2200                     if (lines[i].LastVisit < lastNavigatedDateTime && lines[i].LastVisit > max)
2201                     {
2202                         max = lines[i].LastVisit;
2203                         iLine = i;
2204                     }
2205             if (iLine >= 0)
2206             {
2207                 Navigate(iLine);
2208                 return true;
2209             }
2210             else
2211                 return false;
2212         }
2213 
2214         /// <summary>
2215         /// Navigates to defined line, without Line.LastVisit reseting
2216         /// </summary>
Navigate(int iLine)2217         public void Navigate(int iLine)
2218         {
2219             if (iLine >= LinesCount) return;
2220             lastNavigatedDateTime = lines[iLine].LastVisit;
2221             Selection.Start = new Place(0, iLine);
2222             DoSelectionVisible();
2223         }
2224 
OnLoad(EventArgs e)2225         protected override void OnLoad(EventArgs e)
2226         {
2227             base.OnLoad(e);
2228             m_hImc = NativeMethodsWrapper.ImmGetContext(Handle);
2229         }
2230 
timer2_Tick(object sender, EventArgs e)2231         private void timer2_Tick(object sender, EventArgs e)
2232         {
2233             timer2.Enabled = false;
2234             if (needRiseTextChangedDelayed)
2235             {
2236                 needRiseTextChangedDelayed = false;
2237                 if (delayedTextChangedRange == null)
2238                     return;
2239                 delayedTextChangedRange = Range.GetIntersectionWith(delayedTextChangedRange);
2240                 delayedTextChangedRange.Expand();
2241                 OnTextChangedDelayed(delayedTextChangedRange);
2242                 delayedTextChangedRange = null;
2243             }
2244         }
2245 
AddVisualMarker(VisualMarker marker)2246         public void AddVisualMarker(VisualMarker marker)
2247         {
2248             visibleMarkers.Add(marker);
2249         }
2250 
timer_Tick(object sender, EventArgs e)2251         private void timer_Tick(object sender, EventArgs e)
2252         {
2253             timer.Enabled = false;
2254             if (needRiseSelectionChangedDelayed)
2255             {
2256                 needRiseSelectionChangedDelayed = false;
2257                 OnSelectionChangedDelayed();
2258             }
2259             if (needRiseVisibleRangeChangedDelayed)
2260             {
2261                 needRiseVisibleRangeChangedDelayed = false;
2262                 OnVisibleRangeChangedDelayed();
2263             }
2264         }
2265 
OnTextChangedDelayed(Range changedRange)2266         public virtual void OnTextChangedDelayed(Range changedRange)
2267         {
2268             if (TextChangedDelayed != null)
2269                 TextChangedDelayed(this, new TextChangedEventArgs(changedRange));
2270         }
2271 
OnSelectionChangedDelayed()2272         public virtual void OnSelectionChangedDelayed()
2273         {
2274             RecalcScrollByOneLine(Selection.Start.iLine);
2275             //highlight brackets
2276             ClearBracketsPositions();
2277             if (LeftBracket != '\x0' && RightBracket != '\x0')
2278                 HighlightBrackets(LeftBracket, RightBracket, ref leftBracketPosition, ref rightBracketPosition);
2279             if (LeftBracket2 != '\x0' && RightBracket2 != '\x0')
2280                 HighlightBrackets(LeftBracket2, RightBracket2, ref leftBracketPosition2, ref rightBracketPosition2);
2281             //remember last visit time
2282             if (Selection.IsEmpty && Selection.Start.iLine < LinesCount)
2283             {
2284                 if (lastNavigatedDateTime != lines[Selection.Start.iLine].LastVisit)
2285                 {
2286                     lines[Selection.Start.iLine].LastVisit = DateTime.Now;
2287                     lastNavigatedDateTime = lines[Selection.Start.iLine].LastVisit;
2288                 }
2289             }
2290 
2291             if (SelectionChangedDelayed != null)
2292                 SelectionChangedDelayed(this, new EventArgs());
2293         }
2294 
OnVisibleRangeChangedDelayed()2295         public virtual void OnVisibleRangeChangedDelayed()
2296         {
2297             if (VisibleRangeChangedDelayed != null)
2298                 VisibleRangeChangedDelayed(this, new EventArgs());
2299         }
2300 
2301         Dictionary<Timer, Timer> timersToReset = new Dictionary<Timer, Timer>();
2302 
ResetTimer(Timer timer)2303         private void ResetTimer(Timer timer)
2304         {
2305             if(InvokeRequired)
2306             {
2307                 BeginInvoke(new MethodInvoker(()=>ResetTimer(timer)));
2308                 return;
2309             }
2310             timer.Stop();
2311             if (IsHandleCreated)
2312                 timer.Start();
2313             else
2314                 timersToReset[timer] = timer;
2315         }
2316 
OnHandleCreated(EventArgs e)2317         protected override void OnHandleCreated(EventArgs e)
2318         {
2319             base.OnHandleCreated(e);
2320             foreach (var timer in new List<Timer>(timersToReset.Keys))
2321                 ResetTimer(timer);
2322             timersToReset.Clear();
2323 
2324             OnScrollbarsUpdated();
2325         }
2326 
2327         /// <summary>
2328         /// Add new style
2329         /// </summary>
2330         /// <returns>Layer index of this style</returns>
AddStyle(Style style)2331         public int AddStyle(Style style)
2332         {
2333             if (style == null) return -1;
2334 
2335             int i = GetStyleIndex(style);
2336             if (i >= 0)
2337                 return i;
2338 
2339             for (i = Styles.Length - 1; i >= 0; i--)
2340                 if (Styles[i] != null)
2341                     break;
2342 
2343             i++;
2344             if (i >= Styles.Length)
2345                 throw new Exception("Maximum count of Styles is exceeded.");
2346 
2347             Styles[i] = style;
2348             return i;
2349         }
2350 
2351         /// <summary>
2352         /// Shows find dialog
2353         /// </summary>
ShowFindDialog()2354         public void ShowFindDialog()
2355         {
2356             ShowFindDialog(null);
2357         }
2358 
2359         /// <summary>
2360         /// Shows find dialog
2361         /// </summary>
ShowFindDialog(string findText)2362         public void ShowFindDialog(string findText)
2363         {
2364             if (findForm == null)
2365                 findForm = new FindForm(this);
2366 
2367             if (findText != null)
2368                 findForm.tbFind.Text = findText;
2369             else if (!Selection.IsEmpty && Selection.Start.iLine == Selection.End.iLine)
2370                 findForm.tbFind.Text = Selection.Text;
2371 
2372             findForm.tbFind.SelectAll();
2373             findForm.StartPosition = FormStartPosition.Manual;
2374             findForm.Top = this.FindForm().Top + (this.FindForm().Height - findForm.Height) / 2;
2375             findForm.Left = this.FindForm().Left + (this.FindForm().Width - findForm.Width) / 2;
2376             findForm.Show(this);
2377             findForm.Focus();
2378         }
2379 
2380         /// <summary>
2381         /// Shows replace dialog
2382         /// </summary>
ShowReplaceDialog()2383         public void ShowReplaceDialog()
2384         {
2385             ShowReplaceDialog(null);
2386         }
2387 
2388         /// <summary>
2389         /// Shows replace dialog
2390         /// </summary>
ShowReplaceDialog(string findText)2391         public virtual void ShowReplaceDialog(string findText)
2392         {
2393             if (ReadOnly)
2394                 return;
2395             if (replaceForm == null)
2396                 replaceForm = new ReplaceForm(this);
2397 
2398             if (findText != null)
2399                 replaceForm.tbFind.Text = findText;
2400             else if (!Selection.IsEmpty && Selection.Start.iLine == Selection.End.iLine)
2401                 replaceForm.tbFind.Text = Selection.Text;
2402 
2403             replaceForm.tbFind.SelectAll();
2404             replaceForm.Show();
2405             replaceForm.Focus();
2406         }
2407 
2408         /// <summary>
2409         /// Gets length of given line
2410         /// </summary>
2411         /// <param name="iLine">Line index</param>
2412         /// <returns>Length of line</returns>
GetLineLength(int iLine)2413         public int GetLineLength(int iLine)
2414         {
2415             if (iLine < 0 || iLine >= lines.Count)
2416                 throw new ArgumentOutOfRangeException("Line index out of range");
2417 
2418             return lines[iLine].Count;
2419         }
2420 
2421         /// <summary>
2422         /// Get range of line
2423         /// </summary>
2424         /// <param name="iLine">Line index</param>
GetLine(int iLine)2425         public Range GetLine(int iLine)
2426         {
2427             if (iLine < 0 || iLine >= lines.Count)
2428                 throw new ArgumentOutOfRangeException("Line index out of range");
2429 
2430             var sel = new Range(this);
2431             sel.Start = new Place(0, iLine);
2432             sel.End = new Place(lines[iLine].Count, iLine);
2433             return sel;
2434         }
2435 
2436         /// <summary>
2437         /// Copy selected text into Clipboard
2438         /// </summary>
Copy()2439         public virtual void Copy()
2440         {
2441             if (Selection.IsEmpty)
2442                 Selection.Expand();
2443             if (!Selection.IsEmpty)
2444             {
2445                 var data = new DataObject();
2446                 OnCreateClipboardData(data);
2447                 //
2448                 var thread = new Thread(() => SetClipboard(data));
2449                 thread.SetApartmentState(ApartmentState.STA);
2450                 thread.Start();
2451                 thread.Join();
2452             }
2453         }
2454 
OnCreateClipboardData(DataObject data)2455         protected virtual void OnCreateClipboardData(DataObject data)
2456         {
2457             var exp = new ExportToHTML();
2458             exp.UseBr = false;
2459             exp.UseNbsp = false;
2460             exp.UseStyleTag = true;
2461             string html = "<pre>" + exp.GetHtml(Selection.Clone()) + "</pre>";
2462 
2463             data.SetData(DataFormats.UnicodeText, true, Selection.Text);
2464             data.SetData(DataFormats.Html, PrepareHtmlForClipboard(html));
2465             data.SetData(DataFormats.Rtf, new ExportToRTF().GetRtf(Selection.Clone()));
2466         }
2467 
SetClipboard(DataObject data)2468         protected void SetClipboard(DataObject data)
2469         {
2470                 try
2471                 {
2472                     /*
2473                     while (GetOpenClipboardWindow() != IntPtr.Zero)
2474                         Thread.Sleep(0);*/
2475                     NativeMethodsWrapper.CloseClipboard();
2476                     Clipboard.SetDataObject(data, true, 5, 100);
2477                 }
2478                 catch(ExternalException)
2479                 {
2480                     //occurs if some other process holds open clipboard
2481                 }
2482         }
2483 
PrepareHtmlForClipboard(string html)2484         public static MemoryStream PrepareHtmlForClipboard(string html)
2485         {
2486             Encoding enc = Encoding.UTF8;
2487 
2488             string begin = "Version:0.9\r\nStartHTML:{0:000000}\r\nEndHTML:{1:000000}"
2489                            + "\r\nStartFragment:{2:000000}\r\nEndFragment:{3:000000}\r\n";
2490 
2491             string html_begin = "<html>\r\n<head>\r\n"
2492                                 + "<meta http-equiv=\"Content-Type\""
2493                                 + " content=\"text/html; charset=" + enc.WebName + "\">\r\n"
2494                                 + "<title>HTML clipboard</title>\r\n</head>\r\n<body>\r\n"
2495                                 + "<!--StartFragment-->";
2496 
2497             string html_end = "<!--EndFragment-->\r\n</body>\r\n</html>\r\n";
2498 
2499             string begin_sample = String.Format(begin, 0, 0, 0, 0);
2500 
2501             int count_begin = enc.GetByteCount(begin_sample);
2502             int count_html_begin = enc.GetByteCount(html_begin);
2503             int count_html = enc.GetByteCount(html);
2504             int count_html_end = enc.GetByteCount(html_end);
2505 
2506             string html_total = String.Format(
2507                 begin
2508                 , count_begin
2509                 , count_begin + count_html_begin + count_html + count_html_end
2510                 , count_begin + count_html_begin
2511                 , count_begin + count_html_begin + count_html
2512                                     ) + html_begin + html + html_end;
2513 
2514             return new MemoryStream(enc.GetBytes(html_total));
2515         }
2516 
2517 
2518         /// <summary>
2519         /// Cut selected text into Clipboard
2520         /// </summary>
Cut()2521         public virtual void Cut()
2522         {
2523             if (!Selection.IsEmpty)
2524             {
2525                 Copy();
2526                 ClearSelected();
2527             }
2528             else
2529             if (LinesCount == 1)
2530             {
2531                 Selection.SelectAll();
2532                 Copy();
2533                 ClearSelected();
2534             }
2535             else
2536             {
2537                 Copy();
2538                 //remove current line
2539                 if (Selection.Start.iLine >= 0 && Selection.Start.iLine < LinesCount)
2540                 {
2541                     int iLine = Selection.Start.iLine;
2542                     RemoveLines(new List<int> {iLine});
2543                     Selection.Start = new Place(0, Math.Max(0, Math.Min(iLine, LinesCount - 1)));
2544                 }
2545             }
2546         }
2547 
2548         /// <summary>
2549         /// Paste text from clipboard into selected position
2550         /// </summary>
Paste()2551         public virtual void Paste()
2552         {
2553             string text = null;
2554             var thread = new Thread(() =>
2555                                         {
2556                                             if (Clipboard.ContainsText())
2557                                                 text = Clipboard.GetText();
2558                                         });
2559             thread.SetApartmentState(ApartmentState.STA);
2560             thread.Start();
2561             thread.Join();
2562 
2563             if (Pasting != null)
2564             {
2565                 var args = new TextChangingEventArgs
2566                                {
2567                                    Cancel = false,
2568                                    InsertingText = text
2569                                };
2570 
2571                 Pasting(this, args);
2572 
2573                 if (args.Cancel)
2574                     text = string.Empty;
2575                 else
2576                     text = args.InsertingText;
2577             }
2578 
2579             if (!string.IsNullOrEmpty(text))
2580                 InsertText(text);
2581         }
2582 
2583         /// <summary>
2584         /// Select all chars of text
2585         /// </summary>
SelectAll()2586         public void SelectAll()
2587         {
2588             Selection.SelectAll();
2589         }
2590 
2591         /// <summary>
2592         /// Move caret to end of text
2593         /// </summary>
GoEnd()2594         public void GoEnd()
2595         {
2596             if (lines.Count > 0)
2597                 Selection.Start = new Place(lines[lines.Count - 1].Count, lines.Count - 1);
2598             else
2599                 Selection.Start = new Place(0, 0);
2600 
2601             DoCaretVisible();
2602         }
2603 
2604         /// <summary>
2605         /// Move caret to first position
2606         /// </summary>
GoHome()2607         public void GoHome()
2608         {
2609             Selection.Start = new Place(0, 0);
2610 
2611             DoCaretVisible();
2612             //VerticalScroll.Value = 0;
2613             //HorizontalScroll.Value = 0;
2614         }
2615 
2616         /// <summary>
2617         /// Clear text, styles, history, caches
2618         /// </summary>
Clear()2619         public virtual void Clear()
2620         {
2621             Selection.BeginUpdate();
2622             try
2623             {
2624                 Selection.SelectAll();
2625                 ClearSelected();
2626                 lines.Manager.ClearHistory();
2627                 Invalidate();
2628             }
2629             finally
2630             {
2631                 Selection.EndUpdate();
2632             }
2633         }
2634 
2635         /// <summary>
2636         /// Clear buffer of styles
2637         /// </summary>
ClearStylesBuffer()2638         public void ClearStylesBuffer()
2639         {
2640             for (int i = 0; i < Styles.Length; i++)
2641                 Styles[i] = null;
2642         }
2643 
2644         /// <summary>
2645         /// Clear style of all text
2646         /// </summary>
ClearStyle(StyleIndex styleIndex)2647         public void ClearStyle(StyleIndex styleIndex)
2648         {
2649             foreach (Line line in lines)
2650                 line.ClearStyle(styleIndex);
2651 
2652             for (int i = 0; i < LineInfos.Count; i++)
2653                 SetVisibleState(i, VisibleState.Visible);
2654 
2655             Invalidate();
2656         }
2657 
2658 
2659         /// <summary>
2660         /// Clears undo and redo stacks
2661         /// </summary>
ClearUndo()2662         public void ClearUndo()
2663         {
2664             lines.Manager.ClearHistory();
2665         }
2666 
2667         /// <summary>
2668         /// Insert text into current selected position
2669         /// </summary>
InsertText(string text)2670         public virtual void InsertText(string text)
2671         {
2672             InsertText(text, true);
2673         }
2674 
2675         /// <summary>
2676         /// Insert text into current selected position
2677         /// </summary>
2678         /// <param name="text"></param>
InsertText(string text, bool jumpToCaret)2679         public virtual void InsertText(string text, bool jumpToCaret)
2680         {
2681             if (text == null)
2682                 return;
2683             if (text == "\r")
2684                 text = "\n";
2685 
2686             lines.Manager.BeginAutoUndoCommands();
2687             try
2688             {
2689                 if (!Selection.IsEmpty)
2690                     lines.Manager.ExecuteCommand(new ClearSelectedCommand(TextSource));
2691 
2692                 //insert virtual spaces
2693                 if(this.TextSource.Count > 0)
2694                 if (Selection.IsEmpty && Selection.Start.iChar > GetLineLength(Selection.Start.iLine) && VirtualSpace)
2695                     InsertVirtualSpaces();
2696 
2697                 lines.Manager.ExecuteCommand(new InsertTextCommand(TextSource, text));
2698                 if (updating <= 0 && jumpToCaret)
2699                     DoCaretVisible();
2700             }
2701             finally
2702             {
2703                 lines.Manager.EndAutoUndoCommands();
2704             }
2705             //
2706             Invalidate();
2707         }
2708 
2709         /// <summary>
2710         /// Insert text into current selection position (with predefined style)
2711         /// </summary>
2712         /// <param name="text"></param>
InsertText(string text, Style style)2713         public virtual Range InsertText(string text, Style style)
2714         {
2715             return InsertText(text, style, true);
2716         }
2717 
2718         /// <summary>
2719         /// Insert text into current selection position (with predefined style)
2720         /// </summary>
InsertText(string text, Style style, bool jumpToCaret)2721         public virtual Range InsertText(string text, Style style, bool jumpToCaret)
2722         {
2723             if (text == null)
2724                 return null;
2725 
2726             //remember last caret position
2727             Place last = Selection.Start > Selection.End ? Selection.End : Selection.Start;
2728             //insert text
2729             InsertText(text, jumpToCaret);
2730             //get range
2731             var range = new Range(this, last, Selection.Start){ColumnSelectionMode = Selection.ColumnSelectionMode};
2732             range = range.GetIntersectionWith(Range);
2733             //set style for range
2734             range.SetStyle(style);
2735 
2736             return range;
2737         }
2738 
2739         /// <summary>
2740         /// Append string to end of the Text
2741         /// </summary>
AppendText(string text)2742         public virtual void AppendText(string text)
2743         {
2744             AppendText(text, null);
2745         }
2746 
2747         /// <summary>
2748         /// Append string to end of the Text
2749         /// </summary>
AppendText(string text, Style style)2750         public virtual void AppendText(string text, Style style)
2751         {
2752             if (text == null)
2753                 return;
2754 
2755             Selection.ColumnSelectionMode = false;
2756 
2757             Place oldStart = Selection.Start;
2758             Place oldEnd = Selection.End;
2759 
2760             Selection.BeginUpdate();
2761             lines.Manager.BeginAutoUndoCommands();
2762             try
2763             {
2764                 if (lines.Count > 0)
2765                     Selection.Start = new Place(lines[lines.Count - 1].Count, lines.Count - 1);
2766                 else
2767                     Selection.Start = new Place(0, 0);
2768 
2769                 //remember last caret position
2770                 Place last = Selection.Start;
2771 
2772                 lines.Manager.ExecuteCommand(new InsertTextCommand(TextSource, text));
2773 
2774                 if (style != null)
2775                     new Range(this, last, Selection.Start).SetStyle(style);
2776             }
2777             finally
2778             {
2779                 lines.Manager.EndAutoUndoCommands();
2780                 Selection.Start = oldStart;
2781                 Selection.End = oldEnd;
2782                 Selection.EndUpdate();
2783             }
2784             //
2785             Invalidate();
2786         }
2787 
2788         /// <summary>
2789         /// Returns index of the style in Styles
2790         /// -1 otherwise
2791         /// </summary>
2792         /// <param name="style"></param>
2793         /// <returns>Index of the style in Styles</returns>
GetStyleIndex(Style style)2794         public int GetStyleIndex(Style style)
2795         {
2796             return Array.IndexOf(Styles, style);
2797         }
2798 
2799         /// <summary>
2800         /// Returns StyleIndex mask of given styles
2801         /// </summary>
2802         /// <param name="styles"></param>
2803         /// <returns>StyleIndex mask of given styles</returns>
GetStyleIndexMask(Style[] styles)2804         public StyleIndex GetStyleIndexMask(Style[] styles)
2805         {
2806             StyleIndex mask = StyleIndex.None;
2807             foreach (Style style in styles)
2808             {
2809                 int i = GetStyleIndex(style);
2810                 if (i >= 0)
2811                     mask |= Range.ToStyleIndex(i);
2812             }
2813 
2814             return mask;
2815         }
2816 
GetOrSetStyleLayerIndex(Style style)2817         internal int GetOrSetStyleLayerIndex(Style style)
2818         {
2819             int i = GetStyleIndex(style);
2820             if (i < 0)
2821                 i = AddStyle(style);
2822             return i;
2823         }
2824 
GetCharSize(Font font, char c)2825         public static SizeF GetCharSize(Font font, char c)
2826         {
2827             Size sz2 = TextRenderer.MeasureText("<" + c.ToString() + ">", font);
2828             Size sz3 = TextRenderer.MeasureText("<>", font);
2829 
2830             return new SizeF(sz2.Width - sz3.Width + 1, /*sz2.Height*/font.Height);
2831         }
2832 
WndProc(ref Message m)2833         protected override void WndProc(ref Message m)
2834         {
2835             if (m.Msg == WM_HSCROLL || m.Msg == WM_VSCROLL)
2836                 if (m.WParam.ToInt32() != SB_ENDSCROLL)
2837                     Invalidate();
2838 
2839             base.WndProc(ref m);
2840 
2841             if (ImeAllowed)
2842                 if (m.Msg == WM_IME_SETCONTEXT && m.WParam.ToInt32() == 1)
2843                 {
2844                     NativeMethodsWrapper.ImmAssociateContext(Handle, m_hImc);
2845                 }
2846         }
2847 
OnScroll(ScrollEventArgs se, bool alignByLines)2848         public void OnScroll(ScrollEventArgs se, bool alignByLines)
2849         {
2850             if (se.ScrollOrientation == ScrollOrientation.VerticalScroll)
2851             {
2852                 //align by line height
2853                 int newValue = se.NewValue;
2854                 if (alignByLines)
2855                     newValue = (int)(Math.Ceiling(1d * newValue / CharHeight) * CharHeight);
2856                 //
2857                 VerticalScroll.Value = Math.Max(VerticalScroll.Minimum, Math.Min(VerticalScroll.Maximum, newValue));
2858             }
2859             if (se.ScrollOrientation == ScrollOrientation.HorizontalScroll)
2860                 HorizontalScroll.Value = Math.Max(HorizontalScroll.Minimum, Math.Min(HorizontalScroll.Maximum, se.NewValue));
2861 
2862             UpdateScrollbars();
2863 
2864             Invalidate();
2865             //
2866             base.OnScroll(se);
2867             OnVisibleRangeChanged();
2868         }
2869 
OnScroll(ScrollEventArgs se)2870         protected override void OnScroll(ScrollEventArgs se)
2871         {
2872             OnScroll(se, true);
2873         }
2874 
InsertChar(char c)2875         protected virtual void InsertChar(char c)
2876         {
2877             lines.Manager.BeginAutoUndoCommands();
2878             try
2879             {
2880                 if (!Selection.IsEmpty)
2881                     lines.Manager.ExecuteCommand(new ClearSelectedCommand(TextSource));
2882 
2883                 //insert virtual spaces
2884                 if (Selection.IsEmpty && Selection.Start.iChar > GetLineLength(Selection.Start.iLine) && VirtualSpace)
2885                     InsertVirtualSpaces();
2886 
2887                 //insert char
2888                 lines.Manager.ExecuteCommand(new InsertCharCommand(TextSource, c));
2889             }
2890             finally
2891             {
2892                 lines.Manager.EndAutoUndoCommands();
2893             }
2894 
2895             Invalidate();
2896         }
2897 
InsertVirtualSpaces()2898         private void InsertVirtualSpaces()
2899         {
2900             int lineLength = GetLineLength(Selection.Start.iLine);
2901             int count = Selection.Start.iChar - lineLength;
2902             Selection.BeginUpdate();
2903             try
2904             {
2905                 Selection.Start = new Place(lineLength, Selection.Start.iLine);
2906                 lines.Manager.ExecuteCommand(new InsertTextCommand(TextSource, new string(' ', count)));
2907             }
2908             finally
2909             {
2910                 Selection.EndUpdate();
2911             }
2912         }
2913 
2914         /// <summary>
2915         /// Deletes selected chars
2916         /// </summary>
ClearSelected()2917         public virtual void ClearSelected()
2918         {
2919             if (!Selection.IsEmpty)
2920             {
2921                 lines.Manager.ExecuteCommand(new ClearSelectedCommand(TextSource));
2922                 Invalidate();
2923             }
2924         }
2925 
2926         /// <summary>
2927         /// Deletes current line(s)
2928         /// </summary>
ClearCurrentLine()2929         public void ClearCurrentLine()
2930         {
2931             Selection.Expand();
2932 
2933             lines.Manager.ExecuteCommand(new ClearSelectedCommand(TextSource));
2934             if (Selection.Start.iLine == 0)
2935                 if (!Selection.GoRightThroughFolded()) return;
2936             if (Selection.Start.iLine > 0)
2937                 lines.Manager.ExecuteCommand(new InsertCharCommand(TextSource, '\b')); //backspace
2938             Invalidate();
2939         }
2940 
Recalc()2941         private void Recalc()
2942         {
2943             if (!needRecalc)
2944                 return;
2945 
2946 #if debug
2947             var sw = Stopwatch.StartNew();
2948 #endif
2949 
2950             needRecalc = false;
2951             //calc min left indent
2952             LeftIndent = LeftPadding;
2953             long maxLineNumber = LinesCount + lineNumberStartValue - 1;
2954             int charsForLineNumber = 2 + (maxLineNumber > 0 ? (int) Math.Log10(maxLineNumber) : 0);
2955 
2956             // If there are reserved character for line numbers: correct this
2957             if (this.ReservedCountOfLineNumberChars + 1 > charsForLineNumber)
2958                 charsForLineNumber = this.ReservedCountOfLineNumberChars + 1;
2959 
2960             if (Created)
2961             {
2962                 if (ShowLineNumbers)
2963                     LeftIndent += charsForLineNumber*CharWidth + minLeftIndent + 1;
2964 
2965                 //calc wordwrapping
2966                 if (needRecalcWordWrap)
2967                 {
2968                     RecalcWordWrap(needRecalcWordWrapInterval.X, needRecalcWordWrapInterval.Y);
2969                     needRecalcWordWrap = false;
2970                 }
2971             }
2972             else
2973                 needRecalc = true;
2974 
2975             //calc max line length and count of wordWrapLines
2976             TextHeight = 0;
2977 
2978             maxLineLength = RecalcMaxLineLength();
2979 
2980             //adjust AutoScrollMinSize
2981             int minWidth;
2982             CalcMinAutosizeWidth(out minWidth, ref maxLineLength);
2983 
2984             AutoScrollMinSize = new Size(minWidth, TextHeight + Paddings.Top + Paddings.Bottom);
2985             UpdateScrollbars();
2986 #if debug
2987             sw.Stop();
2988             Console.WriteLine("Recalc: " + sw.ElapsedMilliseconds);
2989 #endif
2990         }
2991 
CalcMinAutosizeWidth(out int minWidth, ref int maxLineLength)2992         private void CalcMinAutosizeWidth(out int minWidth, ref int maxLineLength)
2993         {
2994             //adjust AutoScrollMinSize
2995             minWidth = LeftIndent + (maxLineLength)*CharWidth + 2 + Paddings.Left + Paddings.Right;
2996             if (wordWrap)
2997                 switch (WordWrapMode)
2998                 {
2999                     case WordWrapMode.WordWrapControlWidth:
3000                     case WordWrapMode.CharWrapControlWidth:
3001                         maxLineLength = Math.Min(maxLineLength,
3002                                                  (ClientSize.Width - LeftIndent - Paddings.Left - Paddings.Right)/
3003                                                  CharWidth);
3004                         minWidth = 0;
3005                         break;
3006                     case WordWrapMode.WordWrapPreferredWidth:
3007                     case WordWrapMode.CharWrapPreferredWidth:
3008                         maxLineLength = Math.Min(maxLineLength, PreferredLineWidth);
3009                         minWidth = LeftIndent + PreferredLineWidth*CharWidth + 2 + Paddings.Left + Paddings.Right;
3010                         break;
3011                 }
3012         }
3013 
RecalcScrollByOneLine(int iLine)3014         private void RecalcScrollByOneLine(int iLine)
3015         {
3016             if (iLine >= lines.Count)
3017                 return;
3018 
3019             int maxLineLength = lines[iLine].Count;
3020             if (this.maxLineLength < maxLineLength && !WordWrap)
3021                 this.maxLineLength = maxLineLength;
3022 
3023             int minWidth;
3024             CalcMinAutosizeWidth(out minWidth, ref maxLineLength);
3025 
3026             if (AutoScrollMinSize.Width < minWidth)
3027                 AutoScrollMinSize = new Size(minWidth, AutoScrollMinSize.Height);
3028         }
3029 
RecalcMaxLineLength()3030         private int RecalcMaxLineLength()
3031         {
3032             int maxLineLength = 0;
3033             TextSource lines = this.lines;
3034             int count = lines.Count;
3035             int charHeight = CharHeight;
3036             int topIndent = Paddings.Top;
3037             TextHeight = topIndent;
3038 
3039             for (int i = 0; i < count; i++)
3040             {
3041                 int lineLength = lines.GetLineLength(i);
3042                 LineInfo lineInfo = LineInfos[i];
3043                 if (lineLength > maxLineLength && lineInfo.VisibleState == VisibleState.Visible)
3044                     maxLineLength = lineLength;
3045                 lineInfo.startY = TextHeight;
3046                 TextHeight += lineInfo.WordWrapStringsCount*charHeight + lineInfo.bottomPadding;
3047                 LineInfos[i] = lineInfo;
3048             }
3049 
3050             TextHeight -= topIndent;
3051 
3052             return maxLineLength;
3053         }
3054 
GetMaxLineWordWrapedWidth()3055         private int GetMaxLineWordWrapedWidth()
3056         {
3057             if (wordWrap)
3058                 switch (wordWrapMode)
3059                 {
3060                     case WordWrapMode.WordWrapControlWidth:
3061                     case WordWrapMode.CharWrapControlWidth:
3062                         return ClientSize.Width;
3063                     case WordWrapMode.WordWrapPreferredWidth:
3064                     case WordWrapMode.CharWrapPreferredWidth:
3065                         return LeftIndent + PreferredLineWidth*CharWidth + 2 + Paddings.Left + Paddings.Right;
3066                 }
3067 
3068             return int.MaxValue;
3069         }
3070 
RecalcWordWrap(int fromLine, int toLine)3071         private void RecalcWordWrap(int fromLine, int toLine)
3072         {
3073             int maxCharsPerLine = 0;
3074             bool charWrap = false;
3075 
3076             toLine = Math.Min(LinesCount - 1, toLine);
3077 
3078             switch (WordWrapMode)
3079             {
3080                 case WordWrapMode.WordWrapControlWidth:
3081                     maxCharsPerLine = (ClientSize.Width - LeftIndent - Paddings.Left - Paddings.Right)/CharWidth;
3082                     break;
3083                 case WordWrapMode.CharWrapControlWidth:
3084                     maxCharsPerLine = (ClientSize.Width - LeftIndent - Paddings.Left - Paddings.Right)/CharWidth;
3085                     charWrap = true;
3086                     break;
3087                 case WordWrapMode.WordWrapPreferredWidth:
3088                     maxCharsPerLine = PreferredLineWidth;
3089                     break;
3090                 case WordWrapMode.CharWrapPreferredWidth:
3091                     maxCharsPerLine = PreferredLineWidth;
3092                     charWrap = true;
3093                     break;
3094             }
3095 
3096             for (int iLine = fromLine; iLine <= toLine; iLine++)
3097                 if (lines.IsLineLoaded(iLine))
3098                 {
3099                     if (!wordWrap)
3100                         LineInfos[iLine].CutOffPositions.Clear();
3101                     else
3102                     {
3103                         LineInfo li = LineInfos[iLine];
3104 
3105                         li.wordWrapIndent = WordWrapAutoIndent ? lines[iLine].StartSpacesCount + WordWrapIndent : WordWrapIndent;
3106 
3107                         if (WordWrapMode == WordWrapMode.Custom)
3108                         {
3109                             if (WordWrapNeeded != null)
3110                                 WordWrapNeeded(this, new WordWrapNeededEventArgs(li.CutOffPositions, ImeAllowed, lines[iLine]));
3111                         }
3112                         else
3113                             CalcCutOffs(li.CutOffPositions, maxCharsPerLine, maxCharsPerLine - li.wordWrapIndent, ImeAllowed, charWrap, lines[iLine]);
3114 
3115                         LineInfos[iLine] = li;
3116                     }
3117                 }
3118             needRecalc = true;
3119         }
3120 
3121         /// <summary>
3122         /// Calculates wordwrap cutoffs
3123         /// </summary>
CalcCutOffs(List<int> cutOffPositions, int maxCharsPerLine, int maxCharsPerSecondaryLine, bool allowIME, bool charWrap, Line line)3124         public static void CalcCutOffs(List<int> cutOffPositions, int maxCharsPerLine, int maxCharsPerSecondaryLine, bool allowIME, bool charWrap, Line line)
3125         {
3126             if (maxCharsPerSecondaryLine < 1) maxCharsPerSecondaryLine = 1;
3127             if (maxCharsPerLine < 1) maxCharsPerLine = 1;
3128 
3129             int segmentLength = 0;
3130             int cutOff = 0;
3131             cutOffPositions.Clear();
3132 
3133             for (int i = 0; i < line.Count - 1; i++)
3134             {
3135                 char c = line[i].c;
3136                 if (charWrap)
3137                 {
3138                     //char wrapping
3139                     cutOff = i + 1;
3140                 }
3141                 else
3142                 {
3143                     //word wrapping
3144                     if (allowIME && IsCJKLetter(c))//in CJK languages cutoff can be in any letter
3145                     {
3146                         cutOff = i;
3147                     }
3148                     else
3149                         if (!char.IsLetterOrDigit(c) && c != '_' && c != '\'' && c != '\xa0')
3150                             cutOff = Math.Min(i + 1, line.Count - 1);
3151                 }
3152 
3153                 segmentLength++;
3154 
3155                 if (segmentLength == maxCharsPerLine)
3156                 {
3157                     if (cutOff == 0 || (cutOffPositions.Count > 0 && cutOff == cutOffPositions[cutOffPositions.Count - 1]))
3158                         cutOff = i + 1;
3159                     cutOffPositions.Add(cutOff);
3160                     segmentLength = 1 + i - cutOff;
3161                     maxCharsPerLine = maxCharsPerSecondaryLine;
3162                 }
3163             }
3164         }
3165 
IsCJKLetter(char c)3166         public static bool IsCJKLetter(char c)
3167         {
3168             int code = Convert.ToInt32(c);
3169             return
3170             (code >= 0x3300 && code <= 0x33FF) ||
3171             (code >= 0xFE30 && code <= 0xFE4F) ||
3172             (code >= 0xF900 && code <= 0xFAFF) ||
3173             (code >= 0x2E80 && code <= 0x2EFF) ||
3174             (code >= 0x31C0 && code <= 0x31EF) ||
3175             (code >= 0x4E00 && code <= 0x9FFF) ||
3176             (code >= 0x3400 && code <= 0x4DBF) ||
3177             (code >= 0x3200 && code <= 0x32FF) ||
3178             (code >= 0x2460 && code <= 0x24FF) ||
3179             (code >= 0x3040 && code <= 0x309F) ||
3180             (code >= 0x2F00 && code <= 0x2FDF) ||
3181             (code >= 0x31A0 && code <= 0x31BF) ||
3182             (code >= 0x4DC0 && code <= 0x4DFF) ||
3183             (code >= 0x3100 && code <= 0x312F) ||
3184             (code >= 0x30A0 && code <= 0x30FF) ||
3185             (code >= 0x31F0 && code <= 0x31FF) ||
3186             (code >= 0x2FF0 && code <= 0x2FFF) ||
3187             (code >= 0x1100 && code <= 0x11FF) ||
3188             (code >= 0xA960 && code <= 0xA97F) ||
3189             (code >= 0xD7B0 && code <= 0xD7FF) ||
3190             (code >= 0x3130 && code <= 0x318F) ||
3191             (code >= 0xAC00 && code <= 0xD7AF);
3192 
3193         }
3194 
OnClientSizeChanged(EventArgs e)3195         protected override void OnClientSizeChanged(EventArgs e)
3196         {
3197             base.OnClientSizeChanged(e);
3198             if (WordWrap)
3199             {
3200                 //RecalcWordWrap(0, lines.Count - 1);
3201                 NeedRecalc(false, true);
3202                 Invalidate();
3203             }
3204             OnVisibleRangeChanged();
3205             UpdateScrollbars();
3206         }
3207 
3208         /// <summary>
3209         /// Scroll control for display defined rectangle
3210         /// </summary>
3211         /// <param name="rect"></param>
DoVisibleRectangle(Rectangle rect)3212         private void DoVisibleRectangle(Rectangle rect)
3213         {
3214             int oldV = VerticalScroll.Value;
3215             int v = VerticalScroll.Value;
3216             int h = HorizontalScroll.Value;
3217 
3218             if (rect.Bottom > ClientRectangle.Height)
3219                 v += rect.Bottom - ClientRectangle.Height;
3220             else if (rect.Top < 0)
3221                 v += rect.Top;
3222 
3223             if (rect.Right > ClientRectangle.Width)
3224                 h += rect.Right - ClientRectangle.Width;
3225             else if (rect.Left < LeftIndent)
3226                 h += rect.Left - LeftIndent;
3227             //
3228             if (!Multiline)
3229                 v = 0;
3230             //
3231             v = Math.Max(VerticalScroll.Minimum, v); // was 0
3232             h = Math.Max(HorizontalScroll.Minimum, h); // was 0
3233             //
3234             try
3235             {
3236                 if (VerticalScroll.Visible || !ShowScrollBars)
3237                     VerticalScroll.Value = Math.Min(v, VerticalScroll.Maximum);
3238                 if (HorizontalScroll.Visible || !ShowScrollBars)
3239                     HorizontalScroll.Value = Math.Min(h, HorizontalScroll.Maximum);
3240             }
3241             catch (ArgumentOutOfRangeException)
3242             {
3243                 ;
3244             }
3245 
3246             UpdateScrollbars();
3247             //
3248             if (oldV != VerticalScroll.Value)
3249                 OnVisibleRangeChanged();
3250         }
3251 
3252         /// <summary>
3253         /// Updates scrollbar position after Value changed
3254         /// </summary>
UpdateScrollbars()3255         public void UpdateScrollbars()
3256         {
3257             if (ShowScrollBars)
3258             {
3259                 //some magic for update scrolls
3260                 base.AutoScrollMinSize -= new Size(1, 0);
3261                 base.AutoScrollMinSize += new Size(1, 0);
3262 
3263             }
3264             else
3265                 AutoScrollMinSize = AutoScrollMinSize;
3266 
3267             if(IsHandleCreated)
3268                 BeginInvoke((MethodInvoker)OnScrollbarsUpdated);
3269         }
3270 
OnScrollbarsUpdated()3271         protected virtual void OnScrollbarsUpdated()
3272         {
3273             if (ScrollbarsUpdated != null)
3274                 ScrollbarsUpdated(this, EventArgs.Empty);
3275         }
3276 
3277         /// <summary>
3278         /// Scroll control for display caret
3279         /// </summary>
DoCaretVisible()3280         public void DoCaretVisible()
3281         {
3282             Invalidate();
3283             Recalc();
3284             Point car = PlaceToPoint(Selection.Start);
3285             car.Offset(-CharWidth, 0);
3286             DoVisibleRectangle(new Rectangle(car, new Size(2*CharWidth, 2*CharHeight)));
3287         }
3288 
3289         /// <summary>
3290         /// Scroll control left
3291         /// </summary>
ScrollLeft()3292         public void ScrollLeft()
3293         {
3294             Invalidate();
3295             HorizontalScroll.Value = 0;
3296             AutoScrollMinSize -= new Size(1, 0);
3297             AutoScrollMinSize += new Size(1, 0);
3298         }
3299 
3300         /// <summary>
3301         /// Scroll control for display selection area
3302         /// </summary>
DoSelectionVisible()3303         public void DoSelectionVisible()
3304         {
3305             if (LineInfos[Selection.End.iLine].VisibleState != VisibleState.Visible)
3306                 ExpandBlock(Selection.End.iLine);
3307 
3308             if (LineInfos[Selection.Start.iLine].VisibleState != VisibleState.Visible)
3309                 ExpandBlock(Selection.Start.iLine);
3310 
3311             Recalc();
3312             DoVisibleRectangle(new Rectangle(PlaceToPoint(new Place(0, Selection.End.iLine)),
3313                                              new Size(2*CharWidth, 2*CharHeight)));
3314 
3315             Point car = PlaceToPoint(Selection.Start);
3316             Point car2 = PlaceToPoint(Selection.End);
3317             car.Offset(-CharWidth, -ClientSize.Height/2);
3318             DoVisibleRectangle(new Rectangle(car, new Size(Math.Abs(car2.X - car.X), ClientSize.Height)));
3319             //Math.Abs(car2.Y-car.Y) + 2 * CharHeight
3320 
3321             Invalidate();
3322         }
3323 
3324         /// <summary>
3325         /// Scroll control for display given range
3326         /// </summary>
DoRangeVisible(Range range)3327         public void DoRangeVisible(Range range)
3328         {
3329             DoRangeVisible(range, false);
3330         }
3331 
3332         /// <summary>
3333         /// Scroll control for display given range
3334         /// </summary>
DoRangeVisible(Range range, bool tryToCentre)3335         public void DoRangeVisible(Range range, bool tryToCentre)
3336         {
3337             range = range.Clone();
3338             range.Normalize();
3339             range.End = new Place(range.End.iChar,
3340                                   Math.Min(range.End.iLine, range.Start.iLine + ClientSize.Height/CharHeight));
3341 
3342             if (LineInfos[range.End.iLine].VisibleState != VisibleState.Visible)
3343                 ExpandBlock(range.End.iLine);
3344 
3345             if (LineInfos[range.Start.iLine].VisibleState != VisibleState.Visible)
3346                 ExpandBlock(range.Start.iLine);
3347 
3348             Recalc();
3349             int h = (1 + range.End.iLine - range.Start.iLine)*CharHeight;
3350             Point p = PlaceToPoint(new Place(0, range.Start.iLine));
3351             if (tryToCentre)
3352             {
3353                 p.Offset(0, -ClientSize.Height/2);
3354                 h = ClientSize.Height;
3355             }
3356             DoVisibleRectangle(new Rectangle(p, new Size(2*CharWidth, h)));
3357 
3358             Invalidate();
3359         }
3360 
3361 
OnKeyUp(KeyEventArgs e)3362         protected override void OnKeyUp(KeyEventArgs e)
3363         {
3364             base.OnKeyUp(e);
3365 
3366             if (e.KeyCode == Keys.ShiftKey)
3367                 lastModifiers &= ~Keys.Shift;
3368             if (e.KeyCode == Keys.Alt)
3369                 lastModifiers &= ~Keys.Alt;
3370             if (e.KeyCode == Keys.ControlKey)
3371                 lastModifiers &= ~Keys.Control;
3372         }
3373 
3374 
3375         bool findCharMode;
3376 
OnKeyDown(KeyEventArgs e)3377         protected override void OnKeyDown(KeyEventArgs e)
3378         {
3379             if (middleClickScrollingActivated)
3380                 return;
3381 
3382             base.OnKeyDown(e);
3383 
3384             if (Focused)//???
3385                 lastModifiers = e.Modifiers;
3386 
3387             handledChar = false;
3388 
3389             if (e.Handled)
3390             {
3391                 handledChar = true;
3392                 return;
3393             }
3394 
3395             if (ProcessKey(e.KeyData))
3396                 return;
3397 
3398             e.Handled = true;
3399 
3400             DoCaretVisible();
3401             Invalidate();
3402         }
3403 
ProcessDialogKey(Keys keyData)3404         protected override bool ProcessDialogKey(Keys keyData)
3405         {
3406             if ((keyData & Keys.Alt) > 0)
3407             {
3408                 if (HotkeysMapping.ContainsKey(keyData))
3409                 {
3410                     ProcessKey(keyData);
3411                     return true;
3412                 }
3413             }
3414 
3415             return base.ProcessDialogKey(keyData);
3416         }
3417 
3418         static Dictionary<FCTBAction, bool> scrollActions = new Dictionary<FCTBAction, bool>() { { FCTBAction.ScrollDown, true }, { FCTBAction.ScrollUp, true }, { FCTBAction.ZoomOut, true }, { FCTBAction.ZoomIn, true }, { FCTBAction.ZoomNormal, true } };
3419 
3420         /// <summary>
3421         /// Process control keys
3422         /// </summary>
ProcessKey(Keys keyData)3423         public virtual bool ProcessKey(Keys keyData)
3424         {
3425             KeyEventArgs a = new KeyEventArgs(keyData);
3426 
3427             if(a.KeyCode == Keys.Tab && !AcceptsTab)
3428                  return false;
3429 
3430 
3431             if (macrosManager != null)
3432             if (!HotkeysMapping.ContainsKey(keyData) || (HotkeysMapping[keyData] != FCTBAction.MacroExecute && HotkeysMapping[keyData] != FCTBAction.MacroRecord))
3433                 macrosManager.ProcessKey(keyData);
3434 
3435 
3436             if (HotkeysMapping.ContainsKey(keyData))
3437             {
3438                 var act = HotkeysMapping[keyData];
3439                 DoAction(act);
3440                 if (scrollActions.ContainsKey(act))
3441                     return true;
3442                 if (keyData == Keys.Tab || keyData == (Keys.Tab | Keys.Shift))
3443                 {
3444                     handledChar = true;
3445                     return true;
3446                 }
3447             }
3448             else
3449             {
3450                 //
3451                 if (a.KeyCode == Keys.Alt)
3452                     return true;
3453 
3454                 if ((a.Modifiers & Keys.Control) != 0)
3455                     return true;
3456 
3457                 if ((a.Modifiers & Keys.Alt) != 0)
3458                 {
3459                     if ((MouseButtons & MouseButtons.Left) != 0)
3460                         CheckAndChangeSelectionType();
3461                     return true;
3462                 }
3463 
3464                 if (a.KeyCode == Keys.ShiftKey)
3465                     return true;
3466             }
3467 
3468             return false;
3469         }
3470 
DoAction(FCTBAction action)3471         private void DoAction(FCTBAction action)
3472         {
3473             switch (action)
3474             {
3475                 case FCTBAction.ZoomIn:
3476                     ChangeFontSize(2);
3477                     break;
3478                 case FCTBAction.ZoomOut:
3479                     ChangeFontSize(-2);
3480                     break;
3481                 case FCTBAction.ZoomNormal:
3482                     RestoreFontSize();
3483                     break;
3484                 case FCTBAction.ScrollDown:
3485                     DoScrollVertical(1, -1);
3486                     break;
3487 
3488                 case FCTBAction.ScrollUp:
3489                     DoScrollVertical(1, 1);
3490                     break;
3491 
3492                 case FCTBAction.GoToDialog:
3493                     ShowGoToDialog();
3494                     break;
3495 
3496                 case FCTBAction.FindDialog:
3497                     ShowFindDialog();
3498                     break;
3499 
3500                 case FCTBAction.FindChar:
3501                     findCharMode = true;
3502                     break;
3503 
3504                 case FCTBAction.FindNext:
3505                     if (findForm == null || findForm.tbFind.Text == "")
3506                         ShowFindDialog();
3507                     else
3508                         findForm.FindNext(findForm.tbFind.Text);
3509                     break;
3510 
3511                 case FCTBAction.ReplaceDialog:
3512                     ShowReplaceDialog();
3513                     break;
3514 
3515                 case FCTBAction.Copy:
3516                     Copy();
3517                     break;
3518 
3519                 case FCTBAction.CommentSelected:
3520                     CommentSelected();
3521                     break;
3522 
3523                 case FCTBAction.Cut:
3524                     if (!Selection.ReadOnly)
3525                         Cut();
3526                     break;
3527 
3528                 case FCTBAction.Paste:
3529                     if (!Selection.ReadOnly)
3530                         Paste();
3531                     break;
3532 
3533                 case FCTBAction.SelectAll:
3534                     Selection.SelectAll();
3535                     break;
3536 
3537                 case FCTBAction.Undo:
3538                     if (!ReadOnly)
3539                         Undo();
3540                     break;
3541 
3542                 case FCTBAction.Redo:
3543                     if (!ReadOnly)
3544                         Redo();
3545                     break;
3546 
3547                 case FCTBAction.LowerCase:
3548                     if (!Selection.ReadOnly)
3549                         LowerCase();
3550                     break;
3551 
3552                 case FCTBAction.UpperCase:
3553                     if (!Selection.ReadOnly)
3554                         UpperCase();
3555                     break;
3556 
3557                 case FCTBAction.IndentDecrease:
3558                     if (!Selection.ReadOnly)
3559                     {
3560                         var sel = Selection.Clone();
3561                         if(sel.Start.iLine == sel.End.iLine)
3562                         {
3563                             var line = this[sel.Start.iLine];
3564                             if (sel.Start.iChar == 0 && sel.End.iChar == line.Count)
3565                                 Selection = new Range(this, line.StartSpacesCount, sel.Start.iLine, line.Count, sel.Start.iLine);
3566                             else
3567                             if (sel.Start.iChar == line.Count && sel.End.iChar == 0)
3568                                 Selection = new Range(this, line.Count, sel.Start.iLine, line.StartSpacesCount, sel.Start.iLine);
3569                         }
3570 
3571 
3572                         DecreaseIndent();
3573                     }
3574                     break;
3575 
3576                 case FCTBAction.IndentIncrease:
3577                     if (!Selection.ReadOnly)
3578                     {
3579                         var sel = Selection.Clone();
3580                         var inverted = sel.Start > sel.End;
3581                         sel.Normalize();
3582                         var spaces = this[sel.Start.iLine].StartSpacesCount;
3583                         if (sel.Start.iLine != sel.End.iLine || //selected several lines
3584                            (sel.Start.iChar <= spaces && sel.End.iChar == this[sel.Start.iLine].Count) || //selected whole line
3585                            sel.End.iChar <= spaces)//selected space prefix
3586                         {
3587                             IncreaseIndent();
3588                             if (sel.Start.iLine == sel.End.iLine && !sel.IsEmpty)
3589                             {
3590                                 Selection = new Range(this, this[sel.Start.iLine].StartSpacesCount, sel.End.iLine, this[sel.Start.iLine].Count, sel.End.iLine); //select whole line
3591                                 if (inverted)
3592                                     Selection.Inverse();
3593                             }
3594                         }
3595                         else
3596                             ProcessKey('\t', Keys.None);
3597                     }
3598                     break;
3599 
3600                 case FCTBAction.AutoIndentChars:
3601                     if (!Selection.ReadOnly)
3602                         DoAutoIndentChars(Selection.Start.iLine);
3603                     break;
3604 
3605                 case FCTBAction.NavigateBackward:
3606                     NavigateBackward();
3607                     break;
3608 
3609                 case FCTBAction.NavigateForward:
3610                     NavigateForward();
3611                     break;
3612 
3613                 case FCTBAction.UnbookmarkLine:
3614                     UnbookmarkLine(Selection.Start.iLine);
3615                     break;
3616 
3617                 case FCTBAction.BookmarkLine:
3618                     BookmarkLine(Selection.Start.iLine);
3619                     break;
3620 
3621                 case FCTBAction.GoNextBookmark:
3622                     GotoNextBookmark(Selection.Start.iLine);
3623                     break;
3624 
3625                 case FCTBAction.GoPrevBookmark:
3626                     GotoPrevBookmark(Selection.Start.iLine);
3627                     break;
3628 
3629                 case FCTBAction.ClearWordLeft:
3630                     if (OnKeyPressing('\b')) //KeyPress event processed key
3631                         break;
3632                     if (!Selection.ReadOnly)
3633                     {
3634                         if (!Selection.IsEmpty)
3635                             ClearSelected();
3636                         Selection.GoWordLeft(true);
3637                         if (!Selection.ReadOnly)
3638                             ClearSelected();
3639                     }
3640                     OnKeyPressed('\b');
3641                     break;
3642 
3643                 case FCTBAction.ReplaceMode:
3644                     if (!ReadOnly)
3645                         isReplaceMode = !isReplaceMode;
3646                     break;
3647 
3648                 case FCTBAction.DeleteCharRight:
3649                     if (!Selection.ReadOnly)
3650                     {
3651                         if (OnKeyPressing((char) 0xff)) //KeyPress event processed key
3652                             break;
3653                         if (!Selection.IsEmpty)
3654                             ClearSelected();
3655                         else
3656                         {
3657                             //if line contains only spaces then delete line
3658                             if (this[Selection.Start.iLine].StartSpacesCount == this[Selection.Start.iLine].Count)
3659                                 RemoveSpacesAfterCaret();
3660 
3661                             if (!Selection.IsReadOnlyRightChar())
3662                                 if (Selection.GoRightThroughFolded())
3663                                 {
3664                                     int iLine = Selection.Start.iLine;
3665 
3666                                     InsertChar('\b');
3667 
3668                                     //if removed \n then trim spaces
3669                                     if (iLine != Selection.Start.iLine && AutoIndent)
3670                                         if (Selection.Start.iChar > 0)
3671                                             RemoveSpacesAfterCaret();
3672                                 }
3673                         }
3674 
3675                         if (AutoIndentChars)
3676                             DoAutoIndentChars(Selection.Start.iLine);
3677 
3678                         OnKeyPressed((char) 0xff);
3679                     }
3680                     break;
3681 
3682                 case FCTBAction.ClearWordRight:
3683                     if (OnKeyPressing((char) 0xff)) //KeyPress event processed key
3684                         break;
3685                     if (!Selection.ReadOnly)
3686                     {
3687                         if (!Selection.IsEmpty)
3688                             ClearSelected();
3689                         Selection.GoWordRight(true);
3690                         if (!Selection.ReadOnly)
3691                             ClearSelected();
3692                     }
3693                     OnKeyPressed((char) 0xff);
3694                     break;
3695 
3696                 case FCTBAction.GoWordLeft:
3697                     Selection.GoWordLeft(false);
3698                     break;
3699 
3700                 case FCTBAction.GoWordLeftWithSelection:
3701                     Selection.GoWordLeft(true);
3702                     break;
3703 
3704                 case FCTBAction.GoLeft:
3705                     Selection.GoLeft(false);
3706                     break;
3707 
3708                 case FCTBAction.GoLeftWithSelection:
3709                     Selection.GoLeft(true);
3710                     break;
3711 
3712                 case FCTBAction.GoLeft_ColumnSelectionMode:
3713                     CheckAndChangeSelectionType();
3714                     if (Selection.ColumnSelectionMode)
3715                         Selection.GoLeft_ColumnSelectionMode();
3716                     Invalidate();
3717                     break;
3718 
3719                 case FCTBAction.GoWordRight:
3720                     Selection.GoWordRight(false, true);
3721                     break;
3722 
3723                 case FCTBAction.GoWordRightWithSelection:
3724                     Selection.GoWordRight(true, true);
3725                     break;
3726 
3727                 case FCTBAction.GoRight:
3728                     Selection.GoRight(false);
3729                     break;
3730 
3731                 case FCTBAction.GoRightWithSelection:
3732                     Selection.GoRight(true);
3733                     break;
3734 
3735                 case FCTBAction.GoRight_ColumnSelectionMode:
3736                     CheckAndChangeSelectionType();
3737                     if (Selection.ColumnSelectionMode)
3738                         Selection.GoRight_ColumnSelectionMode();
3739                     Invalidate();
3740                     break;
3741 
3742                 case FCTBAction.GoUp:
3743                     Selection.GoUp(false);
3744                     ScrollLeft();
3745                     break;
3746 
3747                 case FCTBAction.GoUpWithSelection:
3748                     Selection.GoUp(true);
3749                     ScrollLeft();
3750                     break;
3751 
3752                 case FCTBAction.GoUp_ColumnSelectionMode:
3753                     CheckAndChangeSelectionType();
3754                     if (Selection.ColumnSelectionMode)
3755                         Selection.GoUp_ColumnSelectionMode();
3756                     Invalidate();
3757                     break;
3758 
3759                 case FCTBAction.MoveSelectedLinesUp:
3760                     if (!Selection.ColumnSelectionMode)
3761                         MoveSelectedLinesUp();
3762                     break;
3763 
3764                 case FCTBAction.GoDown:
3765                     Selection.GoDown(false);
3766                     ScrollLeft();
3767                     break;
3768 
3769                 case FCTBAction.GoDownWithSelection:
3770                     Selection.GoDown(true);
3771                     ScrollLeft();
3772                     break;
3773 
3774                 case FCTBAction.GoDown_ColumnSelectionMode:
3775                     CheckAndChangeSelectionType();
3776                     if (Selection.ColumnSelectionMode)
3777                         Selection.GoDown_ColumnSelectionMode();
3778                     Invalidate();
3779                     break;
3780 
3781                 case FCTBAction.MoveSelectedLinesDown:
3782                     if (!Selection.ColumnSelectionMode)
3783                         MoveSelectedLinesDown();
3784                     break;
3785                 case FCTBAction.GoPageUp:
3786                     Selection.GoPageUp(false);
3787                     ScrollLeft();
3788                     break;
3789 
3790                 case FCTBAction.GoPageUpWithSelection:
3791                     Selection.GoPageUp(true);
3792                     ScrollLeft();
3793                     break;
3794 
3795                 case FCTBAction.GoPageDown:
3796                     Selection.GoPageDown(false);
3797                     ScrollLeft();
3798                     break;
3799 
3800                 case FCTBAction.GoPageDownWithSelection:
3801                     Selection.GoPageDown(true);
3802                     ScrollLeft();
3803                     break;
3804 
3805                 case FCTBAction.GoFirstLine:
3806                     Selection.GoFirst(false);
3807                     break;
3808 
3809                 case FCTBAction.GoFirstLineWithSelection:
3810                     Selection.GoFirst(true);
3811                     break;
3812 
3813                 case FCTBAction.GoHome:
3814                     GoHome(false);
3815                     ScrollLeft();
3816                     break;
3817 
3818                 case FCTBAction.GoHomeWithSelection:
3819                     GoHome(true);
3820                     ScrollLeft();
3821                     break;
3822 
3823                 case FCTBAction.GoLastLine:
3824                     Selection.GoLast(false);
3825                     break;
3826 
3827                 case FCTBAction.GoLastLineWithSelection:
3828                     Selection.GoLast(true);
3829                     break;
3830 
3831                 case FCTBAction.GoEnd:
3832                     Selection.GoEnd(false);
3833                     break;
3834 
3835                 case FCTBAction.GoEndWithSelection:
3836                     Selection.GoEnd(true);
3837                     break;
3838 
3839                 case FCTBAction.ClearHints:
3840                     ClearHints();
3841                     if(MacrosManager != null)
3842                         MacrosManager.IsRecording = false;
3843                     break;
3844 
3845                 case FCTBAction.MacroRecord:
3846                     if(MacrosManager != null)
3847                     {
3848                         if (MacrosManager.AllowMacroRecordingByUser)
3849                             MacrosManager.IsRecording = !MacrosManager.IsRecording;
3850                         if (MacrosManager.IsRecording)
3851                             MacrosManager.ClearMacros();
3852                     }
3853                     break;
3854 
3855                 case FCTBAction.MacroExecute:
3856                     if (MacrosManager != null)
3857                     {
3858                         MacrosManager.IsRecording = false;
3859                         MacrosManager.ExecuteMacros();
3860                     }
3861                     break;
3862                 case FCTBAction.CustomAction1 :
3863                 case FCTBAction.CustomAction2 :
3864                 case FCTBAction.CustomAction3 :
3865                 case FCTBAction.CustomAction4 :
3866                 case FCTBAction.CustomAction5 :
3867                 case FCTBAction.CustomAction6 :
3868                 case FCTBAction.CustomAction7 :
3869                 case FCTBAction.CustomAction8 :
3870                 case FCTBAction.CustomAction9 :
3871                 case FCTBAction.CustomAction10:
3872                 case FCTBAction.CustomAction11:
3873                 case FCTBAction.CustomAction12:
3874                 case FCTBAction.CustomAction13:
3875                 case FCTBAction.CustomAction14:
3876                 case FCTBAction.CustomAction15:
3877                 case FCTBAction.CustomAction16:
3878                 case FCTBAction.CustomAction17:
3879                 case FCTBAction.CustomAction18:
3880                 case FCTBAction.CustomAction19:
3881                 case FCTBAction.CustomAction20:
3882                     OnCustomAction(new CustomActionEventArgs(action));
3883                     break;
3884             }
3885         }
3886 
OnCustomAction(CustomActionEventArgs e)3887         protected virtual void OnCustomAction(CustomActionEventArgs e)
3888         {
3889             if (CustomAction != null)
3890                 CustomAction(this, e);
3891         }
3892 
3893         Font originalFont;
3894         public Font OriginalFont { get { return originalFont; } }
3895 
RestoreFontSize()3896         public void RestoreFontSize()
3897         {
3898             Zoom = 100;
3899         }
3900 
3901         /// <summary>
3902         /// Scrolls to nearest bookmark or to first bookmark
3903         /// </summary>
3904         /// <param name="iLine">Current bookmark line index</param>
GotoNextBookmark(int iLine)3905         public bool GotoNextBookmark(int iLine)
3906         {
3907             Bookmark nearestBookmark = null;
3908             int minNextLineIndex = int.MaxValue;
3909             Bookmark minBookmark = null;
3910             int minLineIndex = int.MaxValue;
3911             foreach (Bookmark bookmark in bookmarks)
3912             {
3913                 if (bookmark.LineIndex < minLineIndex)
3914                 {
3915                     minLineIndex = bookmark.LineIndex;
3916                     minBookmark = bookmark;
3917                 }
3918 
3919                 if (bookmark.LineIndex > iLine && bookmark.LineIndex < minNextLineIndex)
3920                 {
3921                     minNextLineIndex = bookmark.LineIndex;
3922                     nearestBookmark = bookmark;
3923                 }
3924             }
3925 
3926             if (nearestBookmark != null)
3927             {
3928                 nearestBookmark.DoVisible();
3929                 return true;
3930             }
3931             else if (minBookmark != null)
3932             {
3933                 minBookmark.DoVisible();
3934                 return true;
3935             }
3936 
3937             return false;
3938         }
3939 
3940         /// <summary>
3941         /// Scrolls to nearest previous bookmark or to last bookmark
3942         /// </summary>
3943         /// <param name="iLine">Current bookmark line index</param>
GotoPrevBookmark(int iLine)3944         public bool GotoPrevBookmark(int iLine)
3945         {
3946             Bookmark nearestBookmark = null;
3947             int maxPrevLineIndex = -1;
3948             Bookmark maxBookmark = null;
3949             int maxLineIndex = -1;
3950             foreach (Bookmark bookmark in bookmarks)
3951             {
3952                 if (bookmark.LineIndex > maxLineIndex)
3953                 {
3954                     maxLineIndex = bookmark.LineIndex;
3955                     maxBookmark = bookmark;
3956                 }
3957 
3958                 if (bookmark.LineIndex < iLine && bookmark.LineIndex > maxPrevLineIndex)
3959                 {
3960                     maxPrevLineIndex = bookmark.LineIndex;
3961                     nearestBookmark = bookmark;
3962                 }
3963             }
3964 
3965             if (nearestBookmark != null)
3966             {
3967                 nearestBookmark.DoVisible();
3968                 return true;
3969             }
3970             else if (maxBookmark != null)
3971             {
3972                 maxBookmark.DoVisible();
3973                 return true;
3974             }
3975 
3976             return false;
3977         }
3978 
3979         /// <summary>
3980         /// Bookmarks line
3981         /// </summary>
BookmarkLine(int iLine)3982         public virtual void BookmarkLine(int iLine)
3983         {
3984             if (!bookmarks.Contains(iLine))
3985                 bookmarks.Add(iLine);
3986         }
3987 
3988         /// <summary>
3989         /// Unbookmarks current line
3990         /// </summary>
UnbookmarkLine(int iLine)3991         public virtual void UnbookmarkLine(int iLine)
3992         {
3993             bookmarks.Remove(iLine);
3994         }
3995 
3996         /// <summary>
3997         /// Moves selected lines down
3998         /// </summary>
MoveSelectedLinesDown()3999         public virtual void MoveSelectedLinesDown()
4000         {
4001             Range prevSelection = Selection.Clone();
4002             Selection.Expand();
4003             if (!Selection.ReadOnly)
4004             {
4005                 int iLine = Selection.Start.iLine;
4006                 if (Selection.End.iLine >= LinesCount - 1)
4007                 {
4008                     Selection = prevSelection;
4009                     return;
4010                 }
4011                 string text = SelectedText;
4012                 var temp = new List<int>();
4013                 for (int i = Selection.Start.iLine; i <= Selection.End.iLine; i++)
4014                     temp.Add(i);
4015                 RemoveLines(temp);
4016                 Selection.Start = new Place(GetLineLength(iLine), iLine);
4017                 SelectedText = "\n" + text;
4018                 Selection.Start = new Place(prevSelection.Start.iChar, prevSelection.Start.iLine + 1);
4019                 Selection.End = new Place(prevSelection.End.iChar, prevSelection.End.iLine + 1);
4020             }else
4021                 Selection = prevSelection;
4022         }
4023 
4024         /// <summary>
4025         /// Moves selected lines up
4026         /// </summary>
MoveSelectedLinesUp()4027         public virtual void MoveSelectedLinesUp()
4028         {
4029             Range prevSelection = Selection.Clone();
4030             Selection.Expand();
4031             if (!Selection.ReadOnly)
4032             {
4033                 int iLine = Selection.Start.iLine;
4034                 if (iLine == 0)
4035                 {
4036                     Selection = prevSelection;
4037                     return;
4038                 }
4039                 string text = SelectedText;
4040                 var temp = new List<int>();
4041                 for (int i = Selection.Start.iLine; i <= Selection.End.iLine; i++)
4042                     temp.Add(i);
4043                 RemoveLines(temp);
4044                 Selection.Start = new Place(0, iLine - 1);
4045                 SelectedText = text + "\n";
4046                 Selection.Start = new Place(prevSelection.Start.iChar, prevSelection.Start.iLine - 1);
4047                 Selection.End = new Place(prevSelection.End.iChar, prevSelection.End.iLine - 1);
4048             }else
4049                 Selection = prevSelection;
4050         }
4051 
GoHome(bool shift)4052         private void GoHome(bool shift)
4053         {
4054             Selection.BeginUpdate();
4055             try
4056             {
4057                 int iLine = Selection.Start.iLine;
4058                 int spaces = this[iLine].StartSpacesCount;
4059                 if (Selection.Start.iChar <= spaces)
4060                     Selection.GoHome(shift);
4061                 else
4062                 {
4063                     Selection.GoHome(shift);
4064                     for (int i = 0; i < spaces; i++)
4065                         Selection.GoRight(shift);
4066                 }
4067             }
4068             finally
4069             {
4070                 Selection.EndUpdate();
4071             }
4072         }
4073 
4074         /// <summary>
4075         /// Convert selected text to upper case
4076         /// </summary>
UpperCase()4077         public virtual void UpperCase()
4078         {
4079             Range old = Selection.Clone();
4080             SelectedText = SelectedText.ToUpper();
4081             Selection.Start = old.Start;
4082             Selection.End = old.End;
4083         }
4084 
4085         /// <summary>
4086         /// Convert selected text to lower case
4087         /// </summary>
LowerCase()4088         public virtual void LowerCase()
4089         {
4090             Range old = Selection.Clone();
4091             SelectedText = SelectedText.ToLower();
4092             Selection.Start = old.Start;
4093             Selection.End = old.End;
4094         }
4095 
4096         /// <summary>
4097         /// Convert selected text to title case
4098         /// </summary>
TitleCase()4099         public virtual void TitleCase()
4100         {
4101             Range old = Selection.Clone();
4102             SelectedText = Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(SelectedText.ToLower());
4103             Selection.Start = old.Start;
4104             Selection.End = old.End;
4105         }
4106 
4107         /// <summary>
4108         /// Insert/remove comment prefix into selected lines
4109         /// </summary>
CommentSelected()4110         public void CommentSelected()
4111         {
4112             CommentSelected(CommentPrefix);
4113         }
4114 
4115         /// <summary>
4116         /// Insert/remove comment prefix into selected lines
4117         /// </summary>
CommentSelected(string commentPrefix)4118         public virtual void CommentSelected(string commentPrefix)
4119         {
4120             if (string.IsNullOrEmpty(commentPrefix))
4121                 return;
4122             Selection.Normalize();
4123             bool isCommented = lines[Selection.Start.iLine].Text.TrimStart().StartsWith(commentPrefix);
4124             if (isCommented)
4125                 RemoveLinePrefix(commentPrefix);
4126             else
4127                 InsertLinePrefix(commentPrefix);
4128         }
4129 
OnKeyPressing(KeyPressEventArgs args)4130         public void OnKeyPressing(KeyPressEventArgs args)
4131         {
4132             if (KeyPressing != null)
4133                 KeyPressing(this, args);
4134         }
4135 
OnKeyPressing(char c)4136         private bool OnKeyPressing(char c)
4137         {
4138             if (findCharMode)
4139             {
4140                 findCharMode = false;
4141                 FindChar(c);
4142                 return true;
4143             }
4144             var args = new KeyPressEventArgs(c);
4145             OnKeyPressing(args);
4146             return args.Handled;
4147         }
4148 
OnKeyPressed(char c)4149         public void OnKeyPressed(char c)
4150         {
4151             var args = new KeyPressEventArgs(c);
4152             if (KeyPressed != null)
4153                 KeyPressed(this, args);
4154         }
4155 
ProcessMnemonic(char charCode)4156         protected override bool ProcessMnemonic(char charCode)
4157         {
4158             if (middleClickScrollingActivated)
4159                 return false;
4160 
4161             if (Focused)
4162                 return ProcessKey(charCode, lastModifiers) || base.ProcessMnemonic(charCode);
4163             else
4164                 return false;
4165         }
4166 
4167         const int WM_CHAR = 0x102;
4168 
ProcessKeyMessage(ref Message m)4169         protected override bool ProcessKeyMessage(ref Message m)
4170         {
4171             if (m.Msg == WM_CHAR)
4172                 ProcessMnemonic(Convert.ToChar(m.WParam.ToInt32()));
4173 
4174             return base.ProcessKeyMessage(ref m);
4175         }
4176 
4177         /// <summary>
4178         /// Process "real" keys (no control)
4179         /// </summary>
ProcessKey(char c, Keys modifiers)4180         public virtual bool ProcessKey(char c, Keys modifiers)
4181         {
4182             if (handledChar)
4183                 return true;
4184 
4185             if (macrosManager != null)
4186                 macrosManager.ProcessKey(c, modifiers);
4187             /*  !!!!
4188             if (c == ' ')
4189                 return true;*/
4190 
4191             //backspace
4192             if (c == '\b' && (modifiers == Keys.None || modifiers == Keys.Shift || (modifiers & Keys.Alt) != 0))
4193             {
4194                 if (ReadOnly || !Enabled)
4195                     return false;
4196 
4197                 if (OnKeyPressing(c))
4198                     return true;
4199 
4200                 if (Selection.ReadOnly)
4201                     return false;
4202 
4203                 if (!Selection.IsEmpty)
4204                     ClearSelected();
4205                 else
4206                     if (!Selection.IsReadOnlyLeftChar()) //is not left char readonly?
4207                         InsertChar('\b');
4208 
4209                 if (AutoIndentChars)
4210                     DoAutoIndentChars(Selection.Start.iLine);
4211 
4212                 OnKeyPressed('\b');
4213                 return true;
4214             }
4215 
4216             /* !!!!
4217             if (c == '\b' && (modifiers & Keys.Alt) != 0)
4218                 return true;*/
4219 
4220             if (char.IsControl(c) && c != '\r' && c != '\t')
4221                 return false;
4222 
4223             if (ReadOnly || !Enabled)
4224                 return false;
4225 
4226 
4227             if (modifiers != Keys.None &&
4228                 modifiers != Keys.Shift &&
4229                 modifiers != (Keys.Control | Keys.Alt) && //ALT+CTRL is special chars (AltGr)
4230                 modifiers != (Keys.Shift | Keys.Control | Keys.Alt) && //SHIFT + ALT + CTRL is special chars (AltGr)
4231                 (modifiers != (Keys.Alt) || char.IsLetterOrDigit(c)) //may be ALT+LetterOrDigit is mnemonic code
4232                 )
4233                 return false; //do not process Ctrl+? and Alt+? keys
4234 
4235             char sourceC = c;
4236             if (OnKeyPressing(sourceC)) //KeyPress event processed key
4237                 return true;
4238 
4239             //
4240             if (Selection.ReadOnly)
4241                 return false;
4242             //
4243             if (c == '\r' && !AcceptsReturn)
4244                 return false;
4245 
4246             //replace \r on \n
4247             if (c == '\r')
4248                 c = '\n';
4249             //replace mode? select forward char
4250             if (IsReplaceMode)
4251             {
4252                 Selection.GoRight(true);
4253                 Selection.Inverse();
4254             }
4255             //insert char
4256             if (!Selection.ReadOnly)
4257             {
4258                 if (!DoAutocompleteBrackets(c))
4259                     InsertChar(c);
4260             }
4261 
4262             //do autoindent
4263             if (c == '\n' || AutoIndentExistingLines)
4264                 DoAutoIndentIfNeed();
4265 
4266             if (AutoIndentChars)
4267                 DoAutoIndentChars(Selection.Start.iLine);
4268 
4269             DoCaretVisible();
4270             Invalidate();
4271 
4272             OnKeyPressed(sourceC);
4273 
4274             return true;
4275         }
4276 
4277         #region AutoIndentChars
4278 
4279         /// <summary>
4280         /// Enables AutoIndentChars mode
4281         /// </summary>
4282         [Description("Enables AutoIndentChars mode")]
4283         [DefaultValue(true)]
4284         public bool AutoIndentChars { get; set; }
4285 
4286         /// <summary>
4287         /// Regex patterns for AutoIndentChars (one regex per line)
4288         /// </summary>
4289         [Description("Regex patterns for AutoIndentChars (one regex per line)")]
4290         [Editor( "System.ComponentModel.Design.MultilineStringEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" , typeof(UITypeEditor))]
4291         [DefaultValue(@"^\s*[\w\.]+\s*(?<range>=)\s*(?<range>[^;]+);")]
4292         public string AutoIndentCharsPatterns { get; set; }
4293 
4294         /// <summary>
4295         /// Do AutoIndentChars
4296         /// </summary>
DoAutoIndentChars(int iLine)4297         public void DoAutoIndentChars(int iLine)
4298         {
4299             var patterns = AutoIndentCharsPatterns.Split(new char[] {'\r', '\n'}, StringSplitOptions.RemoveEmptyEntries);
4300 
4301             foreach (var pattern in patterns)
4302             {
4303                 var m = Regex.Match(this[iLine].Text, pattern);
4304                 if (m.Success)
4305                 {
4306                     DoAutoIndentChars(iLine, new Regex(pattern));
4307                     break;
4308                 }
4309             }
4310         }
4311 
DoAutoIndentChars(int iLine, Regex regex)4312         protected void DoAutoIndentChars(int iLine, Regex regex)
4313         {
4314             var oldSel = Selection.Clone();
4315 
4316             var captures = new SortedDictionary<int, CaptureCollection>();
4317             var texts = new SortedDictionary<int, string>();
4318             var maxCapturesCount = 0;
4319 
4320             var spaces = this[iLine].StartSpacesCount;
4321 
4322             for(var i = iLine; i >= 0; i--)
4323             {
4324                 if (spaces != this[i].StartSpacesCount)
4325                     break;
4326 
4327                 var text = this[i].Text;
4328                 var m = regex.Match(text);
4329                 if (m.Success)
4330                 {
4331                     captures[i] = m.Groups["range"].Captures;
4332                     texts[i] = text;
4333 
4334                     if (captures[i].Count > maxCapturesCount)
4335                         maxCapturesCount = captures[i].Count;
4336                 }
4337                 else
4338                     break;
4339             }
4340 
4341             for (var i = iLine + 1; i < LinesCount; i++)
4342             {
4343                 if (spaces != this[i].StartSpacesCount)
4344                     break;
4345 
4346                 var text = this[i].Text;
4347                 var m = regex.Match(text);
4348                 if (m.Success)
4349                 {
4350                     captures[i] = m.Groups["range"].Captures;
4351                     texts[i] = text;
4352 
4353                     if (captures[i].Count > maxCapturesCount)
4354                         maxCapturesCount = captures[i].Count;
4355 
4356                 }
4357                 else
4358                     break;
4359             }
4360 
4361             var changed = new Dictionary<int, bool>();
4362             var was = false;
4363 
4364             for (int iCapture = maxCapturesCount - 1; iCapture >= 0; iCapture--)
4365             {
4366                 //find max dist
4367                 var maxDist = 0;
4368                 foreach(var i in captures.Keys)
4369                 {
4370                     var caps = captures[i];
4371                     if (caps.Count <= iCapture)
4372                         continue;
4373                     var dist = 0;
4374                     var cap = caps[iCapture];
4375 
4376                     var index = cap.Index;
4377 
4378                     var text = texts[i];
4379                     while (index > 0 && text[index - 1] == ' ') index--;
4380 
4381                     if (iCapture == 0)
4382                         dist = index;
4383                     else
4384                         dist = index - caps[iCapture - 1].Index - 1;
4385 
4386                     if (dist > maxDist)
4387                         maxDist = dist;
4388                 }
4389 
4390                 //insert whitespaces
4391                 foreach(var i in new List<int>(texts.Keys))
4392                 {
4393                     if (captures[i].Count <= iCapture)
4394                         continue;
4395 
4396                     var dist = 0;
4397                     var cap = captures[i][iCapture];
4398 
4399                     if (iCapture == 0)
4400                         dist = cap.Index;
4401                     else
4402                         dist = cap.Index - captures[i][iCapture - 1].Index - 1;
4403 
4404                     var addSpaces = maxDist - dist + 1;//+1 because min space count is 1
4405 
4406                     if (addSpaces == 0)
4407                         continue;
4408 
4409                     if (oldSel.Start.iLine == i && oldSel.Start.iChar > cap.Index)
4410                         oldSel.Start = new Place(oldSel.Start.iChar + addSpaces, i);
4411 
4412                     if (addSpaces > 0)
4413                         texts[i] = texts[i].Insert(cap.Index, new string(' ', addSpaces));
4414                     else
4415                         texts[i] = texts[i].Remove(cap.Index + addSpaces, -addSpaces);
4416 
4417                     changed[i] = true;
4418                     was = true;
4419                 }
4420             }
4421 
4422             //insert text
4423             if (was)
4424             {
4425                 Selection.BeginUpdate();
4426                 BeginAutoUndo();
4427                 BeginUpdate();
4428 
4429                 TextSource.Manager.ExecuteCommand(new SelectCommand(TextSource));
4430 
4431                 foreach (var i in texts.Keys)
4432                 if (changed.ContainsKey(i))
4433                 {
4434                     Selection = new Range(this, 0, i, this[i].Count, i);
4435                     if(!Selection.ReadOnly)
4436                         InsertText(texts[i]);
4437                 }
4438 
4439                 Selection = oldSel;
4440 
4441                 EndUpdate();
4442                 EndAutoUndo();
4443                 Selection.EndUpdate();
4444             }
4445         }
4446 
4447         #endregion
4448 
DoAutocompleteBrackets(char c)4449         private bool DoAutocompleteBrackets(char c)
4450         {
4451             if (AutoCompleteBrackets)
4452             {
4453                 if (!Selection.ColumnSelectionMode)
4454                     for (int i = 1; i < autoCompleteBracketsList.Length; i += 2)
4455                         if (c == autoCompleteBracketsList[i] && c == Selection.CharAfterStart)
4456                         {
4457                             Selection.GoRight();
4458                             return true;
4459                         }
4460 
4461                 for (int i = 0; i < autoCompleteBracketsList.Length; i += 2)
4462                     if (c == autoCompleteBracketsList[i])
4463                     {
4464                         InsertBrackets(autoCompleteBracketsList[i], autoCompleteBracketsList[i + 1]);
4465                         return true;
4466                     }
4467             }
4468             return false;
4469         }
4470 
InsertBrackets(char left, char right)4471         private bool InsertBrackets(char left, char right)
4472         {
4473             if (Selection.ColumnSelectionMode)
4474             {
4475                 var range = Selection.Clone();
4476                 range.Normalize();
4477                 Selection.BeginUpdate();
4478                 BeginAutoUndo();
4479                 Selection = new Range(this, range.Start.iChar, range.Start.iLine, range.Start.iChar, range.End.iLine) { ColumnSelectionMode = true };
4480                 InsertChar(left);
4481                 Selection = new Range(this, range.End.iChar + 1, range.Start.iLine, range.End.iChar + 1, range.End.iLine) { ColumnSelectionMode = true };
4482                 InsertChar(right);
4483                 if (range.IsEmpty)
4484                     Selection = new Range(this, range.End.iChar + 1, range.Start.iLine, range.End.iChar + 1, range.End.iLine) { ColumnSelectionMode = true };
4485                 EndAutoUndo();
4486                 Selection.EndUpdate();
4487             }
4488             else
4489                 if (Selection.IsEmpty)
4490                 {
4491                     InsertText(left + "" + right);
4492                     Selection.GoLeft();
4493                 }
4494                 else
4495                     InsertText(left + SelectedText + right);
4496 
4497             return true;
4498         }
4499 
4500         /// <summary>
4501         /// Finds given char after current caret position, moves the caret to found pos.
4502         /// </summary>
4503         /// <param name="c"></param>
FindChar(char c)4504         protected virtual void FindChar(char c)
4505         {
4506             if (c == '\r')
4507                 c = '\n';
4508 
4509             var r = Selection.Clone();
4510             while (r.GoRight())
4511             {
4512                 if (r.CharBeforeStart == c)
4513                 {
4514                     Selection = r;
4515                     DoCaretVisible();
4516                     return;
4517                 }
4518             }
4519         }
4520 
DoAutoIndentIfNeed()4521         public virtual void DoAutoIndentIfNeed()
4522         {
4523             if (Selection.ColumnSelectionMode)
4524                 return;
4525             if (AutoIndent)
4526             {
4527                 DoCaretVisible();
4528                 int needSpaces = CalcAutoIndent(Selection.Start.iLine);
4529                 if (this[Selection.Start.iLine].AutoIndentSpacesNeededCount != needSpaces)
4530                 {
4531                     DoAutoIndent(Selection.Start.iLine);
4532                     this[Selection.Start.iLine].AutoIndentSpacesNeededCount = needSpaces;
4533                 }
4534             }
4535         }
4536 
RemoveSpacesAfterCaret()4537         private void RemoveSpacesAfterCaret()
4538         {
4539             if (!Selection.IsEmpty)
4540                 return;
4541             Place end = Selection.Start;
4542             while (Selection.CharAfterStart == ' ')
4543                 Selection.GoRight(true);
4544             ClearSelected();
4545         }
4546 
4547         /// <summary>
4548         /// Inserts autoindent's spaces in the line
4549         /// </summary>
DoAutoIndent(int iLine)4550         public virtual void DoAutoIndent(int iLine)
4551         {
4552             if (Selection.ColumnSelectionMode)
4553                 return;
4554             Place oldStart = Selection.Start;
4555             //
4556             int needSpaces = CalcAutoIndent(iLine);
4557             //
4558             int spaces = lines[iLine].StartSpacesCount;
4559             int needToInsert = needSpaces - spaces;
4560             if (needToInsert < 0)
4561                 needToInsert = -Math.Min(-needToInsert, spaces);
4562             //insert start spaces
4563             if (needToInsert == 0)
4564                 return;
4565             Selection.Start = new Place(0, iLine);
4566             if (needToInsert > 0)
4567                 InsertText(new String(' ', needToInsert));
4568             else
4569             {
4570                 Selection.Start = new Place(0, iLine);
4571                 Selection.End = new Place(-needToInsert, iLine);
4572                 ClearSelected();
4573             }
4574 
4575             Selection.Start = new Place(Math.Min(lines[iLine].Count, Math.Max(0, oldStart.iChar + needToInsert)), iLine);
4576         }
4577 
4578         /// <summary>
4579         /// Returns needed start space count for the line
4580         /// </summary>
CalcAutoIndent(int iLine)4581         public virtual int CalcAutoIndent(int iLine)
4582         {
4583             if (iLine < 0 || iLine >= LinesCount) return 0;
4584 
4585 
4586             EventHandler<AutoIndentEventArgs> calculator = AutoIndentNeeded;
4587             if (calculator == null)
4588                 if (Language != Language.Custom && SyntaxHighlighter != null)
4589                     calculator = SyntaxHighlighter.AutoIndentNeeded;
4590                 else
4591                     calculator = CalcAutoIndentShiftByCodeFolding;
4592 
4593             int needSpaces = 0;
4594 
4595             var stack = new Stack<AutoIndentEventArgs>();
4596             //calc indent for previous lines, find stable line
4597             int i;
4598             for (i = iLine - 1; i >= 0; i--)
4599             {
4600                 var args = new AutoIndentEventArgs(i, lines[i].Text, i > 0 ? lines[i - 1].Text : "", TabLength, 0);
4601                 calculator(this, args);
4602                 stack.Push(args);
4603                 if (args.Shift == 0 && args.AbsoluteIndentation == 0 && args.LineText.Trim() != "")
4604                     break;
4605             }
4606             int indent = lines[i >= 0 ? i : 0].StartSpacesCount;
4607             while (stack.Count != 0)
4608             {
4609                 var arg = stack.Pop();
4610                 if (arg.AbsoluteIndentation != 0)
4611                     indent = arg.AbsoluteIndentation + arg.ShiftNextLines;
4612                 else
4613                     indent += arg.ShiftNextLines;
4614             }
4615             //clalc shift for current line
4616             var a = new AutoIndentEventArgs(iLine, lines[iLine].Text, iLine > 0 ? lines[iLine - 1].Text : "", TabLength, indent);
4617             calculator(this, a);
4618             needSpaces = a.AbsoluteIndentation + a.Shift;
4619 
4620             return needSpaces;
4621         }
4622 
CalcAutoIndentShiftByCodeFolding(object sender, AutoIndentEventArgs args)4623         internal virtual void CalcAutoIndentShiftByCodeFolding(object sender, AutoIndentEventArgs args)
4624         {
4625             //inset TAB after start folding marker
4626             if (string.IsNullOrEmpty(lines[args.iLine].FoldingEndMarker) &&
4627                 !string.IsNullOrEmpty(lines[args.iLine].FoldingStartMarker))
4628             {
4629                 args.ShiftNextLines = TabLength;
4630                 return;
4631             }
4632             //remove TAB before end folding marker
4633             if (!string.IsNullOrEmpty(lines[args.iLine].FoldingEndMarker) &&
4634                 string.IsNullOrEmpty(lines[args.iLine].FoldingStartMarker))
4635             {
4636                 args.Shift = -TabLength;
4637                 args.ShiftNextLines = -TabLength;
4638                 return;
4639             }
4640         }
4641 
4642 
GetMinStartSpacesCount(int fromLine, int toLine)4643         protected int GetMinStartSpacesCount(int fromLine, int toLine)
4644         {
4645             if (fromLine > toLine)
4646                 return 0;
4647 
4648             int result = int.MaxValue;
4649             for (int i = fromLine; i <= toLine; i++)
4650             {
4651                 int count = lines[i].StartSpacesCount;
4652                 if (count < result)
4653                     result = count;
4654             }
4655 
4656             return result;
4657         }
4658 
GetMaxStartSpacesCount(int fromLine, int toLine)4659         protected int GetMaxStartSpacesCount(int fromLine, int toLine)
4660         {
4661             if (fromLine > toLine)
4662                 return 0;
4663 
4664             int result = 0;
4665             for (int i = fromLine; i <= toLine; i++)
4666             {
4667                 int count = lines[i].StartSpacesCount;
4668                 if (count > result)
4669                     result = count;
4670             }
4671 
4672             return result;
4673         }
4674 
4675         /// <summary>
4676         /// Undo last operation
4677         /// </summary>
Undo()4678         public virtual void Undo()
4679         {
4680             lines.Manager.Undo();
4681             DoCaretVisible();
4682             Invalidate();
4683         }
4684 
4685         /// <summary>
4686         /// Redo
4687         /// </summary>
Redo()4688         public virtual void Redo()
4689         {
4690             lines.Manager.Redo();
4691             DoCaretVisible();
4692             Invalidate();
4693         }
4694 
IsInputKey(Keys keyData)4695         protected override bool IsInputKey(Keys keyData)
4696         {
4697             if (keyData == Keys.Tab && !AcceptsTab)
4698                 return false;
4699             if (keyData == Keys.Enter && !AcceptsReturn)
4700                 return false;
4701 
4702             if ((keyData & Keys.Alt) == Keys.None)
4703             {
4704                 Keys keys = keyData & Keys.KeyCode;
4705                 if (keys == Keys.Return)
4706                     return true;
4707             }
4708 
4709             if ((keyData & Keys.Alt) != Keys.Alt)
4710             {
4711                 switch ((keyData & Keys.KeyCode))
4712                 {
4713                     case Keys.Prior:
4714                     case Keys.Next:
4715                     case Keys.End:
4716                     case Keys.Home:
4717                     case Keys.Left:
4718                     case Keys.Right:
4719                     case Keys.Up:
4720                     case Keys.Down:
4721                         return true;
4722 
4723                     case Keys.Escape:
4724                         return false;
4725 
4726                     case Keys.Tab:
4727                         return (keyData & Keys.Control) == Keys.None;
4728                 }
4729             }
4730 
4731             return base.IsInputKey(keyData);
4732         }
4733 
OnPaintBackground(PaintEventArgs e)4734         protected override void OnPaintBackground(PaintEventArgs e)
4735         {
4736             if (BackBrush == null)
4737                 base.OnPaintBackground(e);
4738             else
4739                 e.Graphics.FillRectangle(BackBrush, ClientRectangle);
4740         }
4741 
4742         /// <summary>
4743         /// Draws text to given Graphics
4744         /// </summary>
4745         /// <param name="gr"></param>
4746         /// <param name="start">Start place of drawing text</param>
4747         /// <param name="size">Size of drawing</param>
DrawText(Graphics gr, Place start, Size size)4748         public void DrawText(Graphics gr, Place start, Size size)
4749         {
4750             if (needRecalc)
4751                 Recalc();
4752 
4753             if (needRecalcFoldingLines)
4754                 RecalcFoldingLines();
4755 
4756             var startPoint = PlaceToPoint(start);
4757             var startY = startPoint.Y + VerticalScroll.Value;
4758             var startX = startPoint.X + HorizontalScroll.Value - LeftIndent - Paddings.Left;
4759             int firstChar = start.iChar;
4760             int lastChar = (startX + size.Width) / CharWidth;
4761 
4762             var startLine = start.iLine;
4763             //draw text
4764             for (int iLine = startLine; iLine < lines.Count; iLine++)
4765             {
4766                 Line line = lines[iLine];
4767                 LineInfo lineInfo = LineInfos[iLine];
4768                 //
4769                 if (lineInfo.startY > startY + size.Height)
4770                     break;
4771                 if (lineInfo.startY + lineInfo.WordWrapStringsCount * CharHeight < startY)
4772                     continue;
4773                 if (lineInfo.VisibleState == VisibleState.Hidden)
4774                     continue;
4775 
4776                 int y = lineInfo.startY - startY;
4777                 //
4778                 gr.SmoothingMode = SmoothingMode.None;
4779                 //draw line background
4780                 if (lineInfo.VisibleState == VisibleState.Visible)
4781                     if (line.BackgroundBrush != null)
4782                         gr.FillRectangle(line.BackgroundBrush, new Rectangle(0, y, size.Width, CharHeight * lineInfo.WordWrapStringsCount));
4783                 //
4784                 gr.SmoothingMode = SmoothingMode.AntiAlias;
4785 
4786                 //draw wordwrap strings of line
4787                 for (int iWordWrapLine = 0; iWordWrapLine < lineInfo.WordWrapStringsCount; iWordWrapLine++)
4788                 {
4789                     y = lineInfo.startY + iWordWrapLine * CharHeight - startY;
4790                     //indent
4791                     var indent = iWordWrapLine == 0 ? 0 : lineInfo.wordWrapIndent * CharWidth;
4792                     //draw chars
4793                     DrawLineChars(gr, firstChar, lastChar, iLine, iWordWrapLine, -startX + indent, y);
4794                 }
4795             }
4796         }
4797 
4798         /// <summary>
4799         /// Draw control
4800         /// </summary>
OnPaint(PaintEventArgs e)4801         protected override void OnPaint(PaintEventArgs e)
4802         {
4803             if (needRecalc)
4804                 Recalc();
4805 
4806             if (needRecalcFoldingLines)
4807                 RecalcFoldingLines();
4808 #if debug
4809             var sw = Stopwatch.StartNew();
4810 #endif
4811             visibleMarkers.Clear();
4812             e.Graphics.SmoothingMode = SmoothingMode.None;
4813             //
4814             var servicePen = new Pen(ServiceLinesColor);
4815             Brush changedLineBrush = new SolidBrush(ChangedLineColor);
4816             Brush indentBrush = new SolidBrush(IndentBackColor);
4817             Brush paddingBrush = new SolidBrush(PaddingBackColor);
4818             Brush currentLineBrush =
4819                 new SolidBrush(Color.FromArgb(CurrentLineColor.A == 255 ? 50 : CurrentLineColor.A, CurrentLineColor));
4820             //draw padding area
4821             var textAreaRect = TextAreaRect;
4822             //top
4823             e.Graphics.FillRectangle(paddingBrush, 0, -VerticalScroll.Value, ClientSize.Width, Math.Max(0, Paddings.Top - 1));
4824             //bottom
4825             e.Graphics.FillRectangle(paddingBrush, 0, textAreaRect.Bottom, ClientSize.Width,ClientSize.Height);
4826             //right
4827             e.Graphics.FillRectangle(paddingBrush, textAreaRect.Right, 0, ClientSize.Width, ClientSize.Height);
4828             //left
4829             e.Graphics.FillRectangle(paddingBrush, LeftIndentLine, 0, LeftIndent - LeftIndentLine - 1, ClientSize.Height);
4830             if (HorizontalScroll.Value <= Paddings.Left)
4831                 e.Graphics.FillRectangle(paddingBrush, LeftIndent - HorizontalScroll.Value - 2, 0,
4832                                          Math.Max(0, Paddings.Left - 1), ClientSize.Height);
4833             //
4834             int textWidth = textAreaRect.Width;
4835             //draw indent area
4836             e.Graphics.FillRectangle(indentBrush, 0, 0, LeftIndentLine, ClientSize.Height);
4837             if (LeftIndent > minLeftIndent)
4838                 e.Graphics.DrawLine(servicePen, LeftIndentLine, 0, LeftIndentLine, ClientSize.Height);
4839             //draw preferred line width
4840             if (PreferredLineWidth > 0)
4841                 e.Graphics.DrawLine(servicePen,
4842                                     new Point(
4843                                         LeftIndent + Paddings.Left + PreferredLineWidth*CharWidth -
4844                                         HorizontalScroll.Value + 1, textAreaRect.Top + 1),
4845                                     new Point(
4846                                         LeftIndent + Paddings.Left + PreferredLineWidth*CharWidth -
4847                                         HorizontalScroll.Value + 1, textAreaRect.Bottom - 1));
4848 
4849             //draw text area border
4850             DrawTextAreaBorder(e.Graphics);
4851             //
4852             int firstChar = (Math.Max(0, HorizontalScroll.Value - Paddings.Left))/CharWidth;
4853             int lastChar = (HorizontalScroll.Value + ClientSize.Width)/CharWidth;
4854             //
4855             var x = LeftIndent + Paddings.Left - HorizontalScroll.Value;
4856             if (x < LeftIndent)
4857                 firstChar++;
4858             //create dictionary of bookmarks
4859             var bookmarksByLineIndex = new Dictionary<int, Bookmark>();
4860             foreach (Bookmark item in bookmarks)
4861                 bookmarksByLineIndex[item.LineIndex] = item;
4862             //
4863             int startLine = YtoLineIndex(VerticalScroll.Value);
4864             int iLine;
4865 
4866             e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
4867 
4868             //draw text
4869             for (iLine = startLine; iLine < lines.Count; iLine++)
4870             {
4871                 Line line = lines[iLine];
4872                 LineInfo lineInfo = LineInfos[iLine];
4873                 //
4874                 if (lineInfo.startY > VerticalScroll.Value + ClientSize.Height)
4875                     break;
4876                 if (lineInfo.startY + lineInfo.WordWrapStringsCount*CharHeight < VerticalScroll.Value)
4877                     continue;
4878                 if (lineInfo.VisibleState == VisibleState.Hidden)
4879                     continue;
4880 
4881                 int y = lineInfo.startY - VerticalScroll.Value;
4882                 //
4883                 e.Graphics.SmoothingMode = SmoothingMode.None;
4884                 //draw line background
4885                 if (lineInfo.VisibleState == VisibleState.Visible)
4886                     if (line.BackgroundBrush != null)
4887                         e.Graphics.FillRectangle(line.BackgroundBrush,
4888                                                  new Rectangle(textAreaRect.Left, y, textAreaRect.Width,
4889                                                                CharHeight*lineInfo.WordWrapStringsCount));
4890                 //draw current line background
4891                 if (CurrentLineColor != Color.Transparent && iLine == Selection.Start.iLine)
4892                     if (Selection.IsEmpty)
4893                         e.Graphics.FillRectangle(currentLineBrush,
4894                                                  new Rectangle(textAreaRect.Left, y, textAreaRect.Width, CharHeight));
4895                 //draw changed line marker
4896                 if (ChangedLineColor != Color.Transparent && line.IsChanged)
4897                     e.Graphics.FillRectangle(changedLineBrush,
4898                                              new RectangleF(-10, y, LeftIndent - minLeftIndent - 2 + 10, CharHeight + 1));
4899                 //
4900                 e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
4901                 //
4902                 //draw bookmark
4903                 if (bookmarksByLineIndex.ContainsKey(iLine))
4904                     bookmarksByLineIndex[iLine].Paint(e.Graphics,
4905                                                       new Rectangle(LeftIndent, y, Width,
4906                                                                     CharHeight*lineInfo.WordWrapStringsCount));
4907                 //OnPaintLine event
4908                 if (lineInfo.VisibleState == VisibleState.Visible)
4909                     OnPaintLine(new PaintLineEventArgs(iLine,
4910                                                        new Rectangle(LeftIndent, y, Width,
4911                                                                      CharHeight*lineInfo.WordWrapStringsCount),
4912                                                        e.Graphics, e.ClipRectangle));
4913                 //draw line number
4914                 if (ShowLineNumbers)
4915                     using (var lineNumberBrush = new SolidBrush(LineNumberColor))
4916                         e.Graphics.DrawString((iLine + lineNumberStartValue).ToString(), Font, lineNumberBrush,
4917                                               new RectangleF(-10, y, LeftIndent - minLeftIndent - 2 + 10, CharHeight),
4918                                               new StringFormat(StringFormatFlags.DirectionRightToLeft));
4919                 //create markers
4920                 if (lineInfo.VisibleState == VisibleState.StartOfHiddenBlock)
4921                     visibleMarkers.Add(new ExpandFoldingMarker(iLine, new Rectangle(LeftIndentLine - 4, y + CharHeight/2 - 3, 8, 8)));
4922 
4923                 if (!string.IsNullOrEmpty(line.FoldingStartMarker) && lineInfo.VisibleState == VisibleState.Visible &&
4924                     string.IsNullOrEmpty(line.FoldingEndMarker))
4925                         visibleMarkers.Add(new CollapseFoldingMarker(iLine, new Rectangle(LeftIndentLine - 4, y + CharHeight/2 - 3, 8, 8)));
4926 
4927                 if (lineInfo.VisibleState == VisibleState.Visible && !string.IsNullOrEmpty(line.FoldingEndMarker) &&
4928                     string.IsNullOrEmpty(line.FoldingStartMarker))
4929                     e.Graphics.DrawLine(servicePen, LeftIndentLine, y + CharHeight*lineInfo.WordWrapStringsCount - 1,
4930                                         LeftIndentLine + 4, y + CharHeight*lineInfo.WordWrapStringsCount - 1);
4931                 //draw wordwrap strings of line
4932                 for (int iWordWrapLine = 0; iWordWrapLine < lineInfo.WordWrapStringsCount; iWordWrapLine++)
4933                 {
4934                     y = lineInfo.startY + iWordWrapLine*CharHeight - VerticalScroll.Value;
4935                     //indent
4936                     var indent = iWordWrapLine == 0 ? 0 : lineInfo.wordWrapIndent * CharWidth;
4937                     //draw chars
4938                     DrawLineChars(e.Graphics, firstChar, lastChar, iLine, iWordWrapLine, x + indent, y);
4939                 }
4940             }
4941 
4942             int endLine = iLine - 1;
4943 
4944             //draw folding lines
4945             if (ShowFoldingLines)
4946                 DrawFoldingLines(e, startLine, endLine);
4947 
4948             //draw column selection
4949             if (Selection.ColumnSelectionMode)
4950                 if (SelectionStyle.BackgroundBrush is SolidBrush)
4951                 {
4952                     Color color = ((SolidBrush) SelectionStyle.BackgroundBrush).Color;
4953                     Point p1 = PlaceToPoint(Selection.Start);
4954                     Point p2 = PlaceToPoint(Selection.End);
4955                     using (var pen = new Pen(color))
4956                         e.Graphics.DrawRectangle(pen,
4957                                                  Rectangle.FromLTRB(Math.Min(p1.X, p2.X) - 1, Math.Min(p1.Y, p2.Y),
4958                                                                     Math.Max(p1.X, p2.X),
4959                                                                     Math.Max(p1.Y, p2.Y) + CharHeight));
4960                 }
4961             //draw brackets highlighting
4962             if (BracketsStyle != null && leftBracketPosition != null && rightBracketPosition != null)
4963             {
4964                 BracketsStyle.Draw(e.Graphics, PlaceToPoint(leftBracketPosition.Start), leftBracketPosition);
4965                 BracketsStyle.Draw(e.Graphics, PlaceToPoint(rightBracketPosition.Start), rightBracketPosition);
4966             }
4967             if (BracketsStyle2 != null && leftBracketPosition2 != null && rightBracketPosition2 != null)
4968             {
4969                 BracketsStyle2.Draw(e.Graphics, PlaceToPoint(leftBracketPosition2.Start), leftBracketPosition2);
4970                 BracketsStyle2.Draw(e.Graphics, PlaceToPoint(rightBracketPosition2.Start), rightBracketPosition2);
4971             }
4972             //
4973             e.Graphics.SmoothingMode = SmoothingMode.None;
4974             //draw folding indicator
4975             if ((startFoldingLine >= 0 || endFoldingLine >= 0) && Selection.Start == Selection.End)
4976                 if (endFoldingLine < LineInfos.Count)
4977                 {
4978                     //folding indicator
4979                     int startFoldingY = (startFoldingLine >= 0 ? LineInfos[startFoldingLine].startY : 0) -
4980                                         VerticalScroll.Value + CharHeight/2;
4981                     int endFoldingY = (endFoldingLine >= 0
4982                                            ? LineInfos[endFoldingLine].startY +
4983                                              (LineInfos[endFoldingLine].WordWrapStringsCount - 1)*CharHeight
4984                                            : TextHeight + CharHeight) - VerticalScroll.Value + CharHeight;
4985 
4986                     using (var indicatorPen = new Pen(Color.FromArgb(100, FoldingIndicatorColor), 4))
4987                         e.Graphics.DrawLine(indicatorPen, LeftIndent - 5, startFoldingY, LeftIndent - 5, endFoldingY);
4988                 }
4989             //draw hint's brackets
4990             PaintHintBrackets(e.Graphics);
4991             //draw markers
4992             DrawMarkers(e, servicePen);
4993             //draw caret
4994             Point car = PlaceToPoint(Selection.Start);
4995             var caretHeight = CharHeight - lineInterval;
4996             car.Offset(0, lineInterval / 2);
4997 
4998             if ((Focused || IsDragDrop) && car.X >= LeftIndent && CaretVisible)
4999             {
5000                 int carWidth = (IsReplaceMode || WideCaret) ? CharWidth : 1;
5001                 if (WideCaret)
5002                 {
5003                     using (var brush = new SolidBrush(CaretColor))
5004                         e.Graphics.FillRectangle(brush, car.X, car.Y, carWidth, caretHeight + 1);
5005                 }
5006                 else
5007                     using (var pen = new Pen(CaretColor))
5008                         e.Graphics.DrawLine(pen, car.X, car.Y, car.X, car.Y + caretHeight);
5009 
5010                 var caretRect = new Rectangle(HorizontalScroll.Value + car.X, VerticalScroll.Value + car.Y, carWidth, caretHeight + 1);
5011 
5012                 if (CaretBlinking)
5013                 if (prevCaretRect != caretRect || !ShowScrollBars)
5014                 {
5015                     NativeMethodsWrapper.CreateCaret(Handle, 0, carWidth, caretHeight + 1);
5016                     NativeMethodsWrapper.SetCaretPos(car.X, car.Y);
5017                     NativeMethodsWrapper.ShowCaret(Handle);
5018                 }
5019 
5020                 prevCaretRect = caretRect;
5021             }
5022             else
5023             {
5024                 NativeMethodsWrapper.HideCaret(Handle);
5025                 prevCaretRect = Rectangle.Empty;
5026             }
5027 
5028             //draw disabled mask
5029             if (!Enabled)
5030                 using (var brush = new SolidBrush(DisabledColor))
5031                     e.Graphics.FillRectangle(brush, ClientRectangle);
5032 
5033             if (MacrosManager.IsRecording)
5034                 DrawRecordingHint(e.Graphics);
5035 
5036             if (middleClickScrollingActivated)
5037                 DrawMiddleClickScrolling(e.Graphics);
5038 
5039             //dispose resources
5040             servicePen.Dispose();
5041             changedLineBrush.Dispose();
5042             indentBrush.Dispose();
5043             currentLineBrush.Dispose();
5044             paddingBrush.Dispose();
5045             //
5046 #if debug
5047             sw.Stop();
5048             Console.WriteLine("OnPaint: "+ sw.ElapsedMilliseconds);
5049 #endif
5050             //
5051             base.OnPaint(e);
5052         }
5053 
DrawMarkers(PaintEventArgs e, Pen servicePen)5054         private void DrawMarkers(PaintEventArgs e, Pen servicePen)
5055         {
5056             foreach (VisualMarker m in visibleMarkers)
5057             {
5058                 if(m is CollapseFoldingMarker)
5059                     using(var bk = new SolidBrush(ServiceColors.CollapseMarkerBackColor))
5060                     using(var fore = new Pen(ServiceColors.CollapseMarkerForeColor))
5061                     using(var border = new Pen(ServiceColors.CollapseMarkerBorderColor))
5062                         (m as CollapseFoldingMarker).Draw(e.Graphics, border, bk, fore);
5063                 else
5064                 if (m is ExpandFoldingMarker)
5065                     using (var bk = new SolidBrush(ServiceColors.ExpandMarkerBackColor))
5066                     using (var fore = new Pen(ServiceColors.ExpandMarkerForeColor))
5067                     using (var border = new Pen(ServiceColors.ExpandMarkerBorderColor))
5068                         (m as ExpandFoldingMarker).Draw(e.Graphics, border, bk, fore);
5069                 else
5070                     m.Draw(e.Graphics, servicePen);
5071             }
5072         }
5073 
5074         private Rectangle prevCaretRect;
5075 
DrawRecordingHint(Graphics graphics)5076         private void DrawRecordingHint(Graphics graphics)
5077         {
5078             const int w = 75;
5079             const int h = 13;
5080             var rect = new Rectangle(ClientRectangle.Right - w, ClientRectangle.Bottom - h, w, h);
5081             var iconRect = new Rectangle(-h/2 + 3, -h/2 + 3, h - 7, h - 7);
5082             var state = graphics.Save();
5083             graphics.SmoothingMode = SmoothingMode.HighQuality;
5084             graphics.TranslateTransform(rect.Left + h/2, rect.Top + h/2);
5085             graphics.RotateTransform(180 * (DateTime.Now.Millisecond/1000f));
5086             using (var pen = new Pen(Color.Red, 2))
5087             {
5088                 graphics.DrawArc(pen, iconRect, 0, 90);
5089                 graphics.DrawArc(pen, iconRect, 180, 90);
5090             }
5091             graphics.DrawEllipse(Pens.Red, iconRect);
5092             graphics.Restore(state);
5093             using (var font = new Font(FontFamily.GenericSansSerif, 8f))
5094                 graphics.DrawString("Recording...", font, Brushes.Red, new PointF(rect.Left + h, rect.Top));
5095             System.Threading.Timer tm = null;
5096             tm = new System.Threading.Timer(
5097                 (o) => {
5098                     Invalidate(rect);
5099                     tm.Dispose();
5100                 }, null, 200, System.Threading.Timeout.Infinite);
5101         }
5102 
DrawTextAreaBorder(Graphics graphics)5103         private void DrawTextAreaBorder(Graphics graphics)
5104         {
5105             if (TextAreaBorder == TextAreaBorderType.None)
5106                 return;
5107 
5108             var rect = TextAreaRect;
5109 
5110             if (TextAreaBorder == TextAreaBorderType.Shadow)
5111             {
5112                 const int shadowSize = 4;
5113                 var rBottom = new Rectangle(rect.Left + shadowSize, rect.Bottom, rect.Width - shadowSize, shadowSize);
5114                 var rCorner = new Rectangle(rect.Right, rect.Bottom, shadowSize, shadowSize);
5115                 var rRight = new Rectangle(rect.Right, rect.Top + shadowSize, shadowSize, rect.Height - shadowSize);
5116 
5117                 using (var brush = new SolidBrush(Color.FromArgb(80, TextAreaBorderColor)))
5118                 {
5119                     graphics.FillRectangle(brush, rBottom);
5120                     graphics.FillRectangle(brush, rRight);
5121                     graphics.FillRectangle(brush, rCorner);
5122                 }
5123             }
5124 
5125             using(Pen pen = new Pen(TextAreaBorderColor))
5126                 graphics.DrawRectangle(pen, rect);
5127         }
5128 
PaintHintBrackets(Graphics gr)5129         private void PaintHintBrackets(Graphics gr)
5130         {
5131             foreach (Hint hint in hints)
5132             {
5133                 Range r = hint.Range.Clone();
5134                 r.Normalize();
5135                 Point p1 = PlaceToPoint(r.Start);
5136                 Point p2 = PlaceToPoint(r.End);
5137                 if (GetVisibleState(r.Start.iLine) != VisibleState.Visible ||
5138                     GetVisibleState(r.End.iLine) != VisibleState.Visible)
5139                     continue;
5140 
5141                 using (var pen = new Pen(hint.BorderColor))
5142                 {
5143                     pen.DashStyle = DashStyle.Dash;
5144                     if (r.IsEmpty)
5145                     {
5146                         p1.Offset(1, -1);
5147                         gr.DrawLines(pen, new[] {p1, new Point(p1.X, p1.Y + charHeight + 2)});
5148                     }
5149                     else
5150                     {
5151                         p1.Offset(-1, -1);
5152                         p2.Offset(1, -1);
5153                         gr.DrawLines(pen,
5154                                      new[]
5155                                          {
5156                                              new Point(p1.X + CharWidth/2, p1.Y), p1,
5157                                              new Point(p1.X, p1.Y + charHeight + 2),
5158                                              new Point(p1.X + CharWidth/2, p1.Y + charHeight + 2)
5159                                          });
5160                         gr.DrawLines(pen,
5161                                      new[]
5162                                          {
5163                                              new Point(p2.X - CharWidth/2, p2.Y), p2,
5164                                              new Point(p2.X, p2.Y + charHeight + 2),
5165                                              new Point(p2.X - CharWidth/2, p2.Y + charHeight + 2)
5166                                          });
5167                     }
5168                 }
5169             }
5170         }
5171 
DrawFoldingLines(PaintEventArgs e, int startLine, int endLine)5172         protected virtual void DrawFoldingLines(PaintEventArgs e, int startLine, int endLine)
5173         {
5174             e.Graphics.SmoothingMode = SmoothingMode.None;
5175             using (var pen = new Pen(Color.FromArgb(200, ServiceLinesColor)) {DashStyle = DashStyle.Dot})
5176                 foreach (var iLine in foldingPairs)
5177                     if (iLine.Key < endLine && iLine.Value > startLine)
5178                     {
5179                         Line line = lines[iLine.Key];
5180                         int y = LineInfos[iLine.Key].startY - VerticalScroll.Value + CharHeight;
5181                         y += y%2;
5182 
5183                         int y2;
5184 
5185                         if (iLine.Value >= LinesCount)
5186                             y2 = LineInfos[LinesCount - 1].startY + CharHeight - VerticalScroll.Value;
5187                         else if (LineInfos[iLine.Value].VisibleState == VisibleState.Visible)
5188                         {
5189                             int d = 0;
5190                             int spaceCount = line.StartSpacesCount;
5191                             if (lines[iLine.Value].Count <= spaceCount || lines[iLine.Value][spaceCount].c == ' ')
5192                                 d = CharHeight;
5193                             y2 = LineInfos[iLine.Value].startY - VerticalScroll.Value + d;
5194                         }
5195                         else
5196                             continue;
5197 
5198                         int x = LeftIndent + Paddings.Left + line.StartSpacesCount*CharWidth - HorizontalScroll.Value;
5199                         if (x >= LeftIndent + Paddings.Left)
5200                             e.Graphics.DrawLine(pen, x, y >= 0 ? y : 0, x,
5201                                                 y2 < ClientSize.Height ? y2 : ClientSize.Height);
5202                     }
5203         }
5204 
DrawLineChars(Graphics gr, int firstChar, int lastChar, int iLine, int iWordWrapLine, int startX, int y)5205         private void DrawLineChars(Graphics gr, int firstChar, int lastChar, int iLine, int iWordWrapLine, int startX,
5206                                    int y)
5207         {
5208             Line line = lines[iLine];
5209             LineInfo lineInfo = LineInfos[iLine];
5210             int from = lineInfo.GetWordWrapStringStartPosition(iWordWrapLine);
5211             int to = lineInfo.GetWordWrapStringFinishPosition(iWordWrapLine, line);
5212 
5213             lastChar = Math.Min(to - from, lastChar);
5214 
5215             gr.SmoothingMode = SmoothingMode.AntiAlias;
5216 
5217             //folded block ?
5218             if (lineInfo.VisibleState == VisibleState.StartOfHiddenBlock)
5219             {
5220                 //rendering by FoldedBlockStyle
5221                 FoldedBlockStyle.Draw(gr, new Point(startX + firstChar*CharWidth, y),
5222                                       new Range(this, from + firstChar, iLine, from + lastChar + 1, iLine));
5223             }
5224             else
5225             {
5226                 //render by custom styles
5227                 StyleIndex currentStyleIndex = StyleIndex.None;
5228                 int iLastFlushedChar = firstChar - 1;
5229 
5230                 for (int iChar = firstChar; iChar <= lastChar; iChar++)
5231                 {
5232                     StyleIndex style = line[from + iChar].style;
5233                     if (currentStyleIndex != style)
5234                     {
5235                         FlushRendering(gr, currentStyleIndex,
5236                                        new Point(startX + (iLastFlushedChar + 1)*CharWidth, y),
5237                                        new Range(this, from + iLastFlushedChar + 1, iLine, from + iChar, iLine));
5238                         iLastFlushedChar = iChar - 1;
5239                         currentStyleIndex = style;
5240                     }
5241                 }
5242                 FlushRendering(gr, currentStyleIndex, new Point(startX + (iLastFlushedChar + 1)*CharWidth, y),
5243                                new Range(this, from + iLastFlushedChar + 1, iLine, from + lastChar + 1, iLine));
5244             }
5245 
5246             //draw selection
5247             if (SelectionHighlightingForLineBreaksEnabled  && iWordWrapLine == lineInfo.WordWrapStringsCount - 1) lastChar++;//draw selection for CR
5248             if (!Selection.IsEmpty && lastChar >= firstChar)
5249             {
5250                 gr.SmoothingMode = SmoothingMode.None;
5251                 var textRange = new Range(this, from + firstChar, iLine, from + lastChar + 1, iLine);
5252                 textRange = Selection.GetIntersectionWith(textRange);
5253                 if (textRange != null && SelectionStyle != null)
5254                 {
5255                     SelectionStyle.Draw(gr, new Point(startX + (textRange.Start.iChar - from)*CharWidth, 1 + y),
5256                                         textRange);
5257                 }
5258             }
5259         }
5260 
FlushRendering(Graphics gr, StyleIndex styleIndex, Point pos, Range range)5261         private void FlushRendering(Graphics gr, StyleIndex styleIndex, Point pos, Range range)
5262         {
5263             if (range.End > range.Start)
5264             {
5265                 int mask = 1;
5266                 bool hasTextStyle = false;
5267                 for (int i = 0; i < Styles.Length; i++)
5268                 {
5269                     if (Styles[i] != null && ((int) styleIndex & mask) != 0)
5270                     {
5271                         Style style = Styles[i];
5272                         bool isTextStyle = style is TextStyle;
5273                         if (!hasTextStyle || !isTextStyle || AllowSeveralTextStyleDrawing)
5274                             //cancelling secondary rendering by TextStyle
5275                             style.Draw(gr, pos, range); //rendering
5276                         hasTextStyle |= isTextStyle;
5277                     }
5278                     mask = mask << 1;
5279                 }
5280                 //draw by default renderer
5281                 if (!hasTextStyle)
5282                     DefaultStyle.Draw(gr, pos, range);
5283             }
5284         }
5285 
OnEnter(EventArgs e)5286         protected override void OnEnter(EventArgs e)
5287         {
5288             base.OnEnter(e);
5289             mouseIsDrag = false;
5290             mouseIsDragDrop = false;
5291             draggedRange = null;
5292         }
5293 
OnMouseUp(MouseEventArgs e)5294         protected override void OnMouseUp(MouseEventArgs e)
5295         {
5296             base.OnMouseUp(e);
5297             isLineSelect = false;
5298 
5299             if (e.Button == System.Windows.Forms.MouseButtons.Left)
5300             {
5301                 if (mouseIsDragDrop)
5302                     OnMouseClickText(e);
5303             }
5304         }
5305 
OnMouseDown(MouseEventArgs e)5306         protected override void OnMouseDown(MouseEventArgs e)
5307         {
5308             base.OnMouseDown(e);
5309 
5310             if (middleClickScrollingActivated)
5311             {
5312                 DeactivateMiddleClickScrollingMode();
5313                 mouseIsDrag = false;
5314                 if(e.Button == System.Windows.Forms.MouseButtons.Middle)
5315                     RestoreScrollsAfterMiddleClickScrollingMode();
5316                 return;
5317             }
5318 
5319             MacrosManager.IsRecording = false;
5320 
5321             Select();
5322             ActiveControl = null;
5323 
5324             if (e.Button == MouseButtons.Left)
5325             {
5326                 VisualMarker marker = FindVisualMarkerForPoint(e.Location);
5327                 //click on marker
5328                 if (marker != null)
5329                 {
5330                     mouseIsDrag = false;
5331                     mouseIsDragDrop = false;
5332                     draggedRange = null;
5333                     OnMarkerClick(e, marker);
5334                     return;
5335                 }
5336 
5337                 mouseIsDrag = true;
5338                 mouseIsDragDrop = false;
5339                 draggedRange = null;
5340                 isLineSelect = (e.Location.X < LeftIndentLine);
5341 
5342                 if (!isLineSelect)
5343                 {
5344                     var p = PointToPlace(e.Location);
5345 
5346                     if (e.Clicks == 2)
5347                     {
5348                         mouseIsDrag = false;
5349                         mouseIsDragDrop = false;
5350                         draggedRange = null;
5351 
5352                         SelectWord(p);
5353                         return;
5354                     }
5355 
5356                     if (Selection.IsEmpty || !Selection.Contains(p) || this[p.iLine].Count <= p.iChar || ReadOnly)
5357                         OnMouseClickText(e);
5358                     else
5359                     {
5360                         mouseIsDragDrop = true;
5361                         mouseIsDrag = false;
5362                     }
5363                 }
5364                 else
5365                 {
5366                     CheckAndChangeSelectionType();
5367 
5368                     Selection.BeginUpdate();
5369                     //select whole line
5370                     int iLine = PointToPlaceSimple(e.Location).iLine;
5371                     lineSelectFrom = iLine;
5372                     Selection.Start = new Place(0, iLine);
5373                     Selection.End = new Place(GetLineLength(iLine), iLine);
5374                     Selection.EndUpdate();
5375                     Invalidate();
5376                 }
5377             }
5378             else
5379             if (e.Button == MouseButtons.Middle)
5380             {
5381                 ActivateMiddleClickScrollingMode(e);
5382             }
5383         }
5384 
OnMouseClickText(MouseEventArgs e)5385         private void OnMouseClickText(MouseEventArgs e)
5386         {
5387             //click on text
5388             Place oldEnd = Selection.End;
5389             Selection.BeginUpdate();
5390 
5391             if (Selection.ColumnSelectionMode)
5392             {
5393                 Selection.Start = PointToPlaceSimple(e.Location);
5394                 Selection.ColumnSelectionMode = true;
5395             }
5396             else
5397             {
5398                 if (VirtualSpace)
5399                     Selection.Start = PointToPlaceSimple(e.Location);
5400                 else
5401                     Selection.Start = PointToPlace(e.Location);
5402             }
5403 
5404             if ((lastModifiers & Keys.Shift) != 0)
5405                 Selection.End = oldEnd;
5406 
5407             CheckAndChangeSelectionType();
5408 
5409             Selection.EndUpdate();
5410             Invalidate();
5411             return;
5412         }
5413 
CheckAndChangeSelectionType()5414         protected virtual void CheckAndChangeSelectionType()
5415         {
5416             //change selection type to ColumnSelectionMode
5417             if ((ModifierKeys & Keys.Alt) != 0 && !WordWrap)
5418             {
5419                 Selection.ColumnSelectionMode = true;
5420             }
5421             else
5422             //change selection type to Range
5423             {
5424                 Selection.ColumnSelectionMode = false;
5425             }
5426         }
5427 
OnMouseWheel(MouseEventArgs e)5428         protected override void OnMouseWheel(MouseEventArgs e)
5429         {
5430             Invalidate();
5431 
5432             if (lastModifiers == Keys.Control)
5433             {
5434                 ChangeFontSize(2 * Math.Sign(e.Delta));
5435                 if (!MonoUtility.IsLinux)
5436                 {
5437                     ((HandledMouseEventArgs)e).Handled = true;
5438                 }
5439             }
5440             else
5441             if (VerticalScroll.Visible || !ShowScrollBars)
5442             {
5443                 //base.OnMouseWheel(e);
5444 
5445                 // Determine scoll offset
5446                 int mouseWheelScrollLinesSetting = GetControlPanelWheelScrollLinesValue();
5447 
5448                 DoScrollVertical(mouseWheelScrollLinesSetting, e.Delta);
5449 
5450                 if (!MonoUtility.IsLinux)
5451                 {
5452                     ((HandledMouseEventArgs)e).Handled = true;
5453                 }
5454             }
5455 
5456             DeactivateMiddleClickScrollingMode();
5457         }
5458 
DoScrollVertical(int countLines, int direction)5459         private void DoScrollVertical(int countLines, int direction)
5460         {
5461             if (VerticalScroll.Visible || !ShowScrollBars)
5462             {
5463                 int numberOfVisibleLines = ClientSize.Height/CharHeight;
5464 
5465                 int offset;
5466                 if ((countLines == -1) || (countLines > numberOfVisibleLines))
5467                     offset = CharHeight*numberOfVisibleLines;
5468                 else
5469                     offset = CharHeight*countLines;
5470 
5471                 var newScrollPos = VerticalScroll.Value - Math.Sign(direction)*offset;
5472 
5473                 var ea =
5474                     new ScrollEventArgs(direction > 0 ? ScrollEventType.SmallDecrement : ScrollEventType.SmallIncrement,
5475                                         VerticalScroll.Value,
5476                                         newScrollPos,
5477                                         ScrollOrientation.VerticalScroll);
5478 
5479                 OnScroll(ea);
5480             }
5481         }
5482 
5483         /// <summary>
5484         /// Gets the value for the system control panel mouse wheel scroll settings.
5485         /// The value returns the number of lines that shall be scolled if the user turns the mouse wheet one step.
5486         /// </summary>
5487         /// <remarks>
5488         /// This methods gets the "WheelScrollLines" value our from the registry key "HKEY_CURRENT_USER\Control Panel\Desktop".
5489         /// If the value of this option is 0, the screen will not scroll when the mouse wheel is turned.
5490         /// If the value of this option is -1 or is greater than the number of lines visible in the window,
5491         /// the screen will scroll up or down by one page.
5492         /// </remarks>
5493         /// <returns>
5494         /// Number of lines to scrol l when the mouse wheel is turned
5495         /// </returns>
GetControlPanelWheelScrollLinesValue()5496         private static int GetControlPanelWheelScrollLinesValue()
5497         {
5498             try
5499             {
5500                 using (RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Control Panel\Desktop", false))
5501                 {
5502                     return Convert.ToInt32(key.GetValue("WheelScrollLines"));
5503                 }
5504             }
5505             catch
5506             {
5507                 // Use default value
5508                 return 1;
5509             }
5510         }
5511 
5512 
ChangeFontSize(int step)5513         public void ChangeFontSize(int step)
5514         {
5515             var points = Font.SizeInPoints;
5516             using (var gr = Graphics.FromHwnd(Handle))
5517             {
5518                 var dpi = gr.DpiY;
5519                 var newPoints = points + step * 72f / dpi;
5520                 if(newPoints < 1f) return;
5521                 var k = newPoints / originalFont.SizeInPoints;
5522                  Zoom = (int)(100 * k);
5523             }
5524         }
5525 
5526         /// <summary>
5527         /// Zooming (in percentages)
5528         /// </summary>
5529         [Browsable(false)]
5530         public int Zoom
5531         {
5532             get { return zoom; }
5533             set {
5534                 if(value >= 30 && value <= 500) {
5535                    zoom = value;
5536                    DoZoom(zoom / 100f);
5537                    OnZoomChanged();
5538                 }
5539             }
5540         }
5541 
OnZoomChanged()5542         protected virtual void OnZoomChanged()
5543         {
5544             if (ZoomChanged != null)
5545                 ZoomChanged(this, EventArgs.Empty);
5546         }
5547 
DoZoom(float koeff)5548         private void DoZoom(float koeff)
5549         {
5550             //remmber first displayed line
5551             var iLine = YtoLineIndex(VerticalScroll.Value);
5552             //
5553             var points = originalFont.SizeInPoints;
5554             points *= koeff;
5555 
5556             if (points < 1f || points > 300f) return;
5557 
5558             var oldFont = Font;
5559             SetFont(new Font(Font.FontFamily, points, Font.Style, GraphicsUnit.Point));
5560             oldFont.Dispose();
5561 
5562             NeedRecalc(true);
5563 
5564             //restore first displayed line
5565             if (iLine < LinesCount)
5566                 VerticalScroll.Value = Math.Min(VerticalScroll.Maximum, LineInfos[iLine].startY - Paddings.Top);
5567             UpdateScrollbars();
5568             //
5569             Invalidate();
5570             OnVisibleRangeChanged();
5571         }
5572 
OnMouseLeave(EventArgs e)5573         protected override void OnMouseLeave(EventArgs e)
5574         {
5575             base.OnMouseLeave(e);
5576 
5577             CancelToolTip();
5578         }
5579 
5580         protected Range draggedRange;
5581 
OnMouseMove(MouseEventArgs e)5582         protected override void OnMouseMove(MouseEventArgs e)
5583         {
5584             base.OnMouseMove(e);
5585 
5586             if (middleClickScrollingActivated)
5587                 return;
5588 
5589             if (lastMouseCoord != e.Location)
5590             {
5591                 //restart tooltip timer
5592                 CancelToolTip();
5593                 timer3.Start();
5594             }
5595             lastMouseCoord = e.Location;
5596 
5597             if (e.Button == MouseButtons.Left && mouseIsDragDrop)
5598             {
5599                 draggedRange = Selection.Clone();
5600                 DoDragDrop(SelectedText, DragDropEffects.Copy);
5601                 draggedRange = null;
5602                 return;
5603             }
5604 
5605             if (e.Button == MouseButtons.Left && mouseIsDrag)
5606             {
5607                 Place place;
5608                 if (Selection.ColumnSelectionMode || VirtualSpace)
5609                     place = PointToPlaceSimple(e.Location);
5610                 else
5611                     place = PointToPlace(e.Location);
5612 
5613                 if (isLineSelect)
5614                 {
5615                     Selection.BeginUpdate();
5616 
5617                     int iLine = place.iLine;
5618                     if (iLine < lineSelectFrom)
5619                     {
5620                         Selection.Start = new Place(0, iLine);
5621                         Selection.End = new Place(GetLineLength(lineSelectFrom), lineSelectFrom);
5622                     }
5623                     else
5624                     {
5625                         Selection.Start = new Place(GetLineLength(iLine), iLine);
5626                         Selection.End = new Place(0, lineSelectFrom);
5627                     }
5628 
5629                     Selection.EndUpdate();
5630                     DoCaretVisible();
5631                     HorizontalScroll.Value = 0;
5632                     UpdateScrollbars();
5633                     Invalidate();
5634                 }
5635                 else if (place != Selection.Start)
5636                 {
5637                     Place oldEnd = Selection.End;
5638                     Selection.BeginUpdate();
5639                     if (Selection.ColumnSelectionMode)
5640                     {
5641                         Selection.Start = place;
5642                         Selection.ColumnSelectionMode = true;
5643                     }
5644                     else
5645                         Selection.Start = place;
5646                     Selection.End = oldEnd;
5647                     Selection.EndUpdate();
5648                     DoCaretVisible();
5649                     Invalidate();
5650                     return;
5651                 }
5652             }
5653 
5654             VisualMarker marker = FindVisualMarkerForPoint(e.Location);
5655             if (marker != null)
5656                 base.Cursor = marker.Cursor;
5657             else
5658             {
5659                 if (e.Location.X < LeftIndentLine || isLineSelect)
5660                     base.Cursor = Cursors.Arrow;
5661                 else
5662                     base.Cursor = defaultCursor;
5663             }
5664         }
5665 
CancelToolTip()5666         private void CancelToolTip()
5667         {
5668             timer3.Stop();
5669             if (ToolTip != null && !string.IsNullOrEmpty(ToolTip.GetToolTip(this)))
5670             {
5671                 ToolTip.Hide(this);
5672                 ToolTip.SetToolTip(this, null);
5673             }
5674         }
5675 
OnMouseDoubleClick(MouseEventArgs e)5676         protected override void OnMouseDoubleClick(MouseEventArgs e)
5677         {
5678             base.OnMouseDoubleClick(e);
5679 
5680             var m = FindVisualMarkerForPoint(e.Location);
5681             if (m != null)
5682                 OnMarkerDoubleClick(m);
5683         }
5684 
SelectWord(Place p)5685         private void SelectWord(Place p)
5686         {
5687             int fromX = p.iChar;
5688             int toX = p.iChar;
5689 
5690             for (int i = p.iChar; i < lines[p.iLine].Count; i++)
5691             {
5692                 char c = lines[p.iLine][i].c;
5693                 if (char.IsLetterOrDigit(c) || c == '_')
5694                     toX = i + 1;
5695                 else
5696                     break;
5697             }
5698 
5699             for (int i = p.iChar - 1; i >= 0; i--)
5700             {
5701                 char c = lines[p.iLine][i].c;
5702                 if (char.IsLetterOrDigit(c) || c == '_')
5703                     fromX = i;
5704                 else
5705                     break;
5706             }
5707 
5708             Selection = new Range(this, toX, p.iLine, fromX, p.iLine);
5709         }
5710 
YtoLineIndex(int y)5711         private int YtoLineIndex(int y)
5712         {
5713             int i = LineInfos.BinarySearch(new LineInfo(-10), new LineYComparer(y));
5714             i = i < 0 ? -i - 2 : i;
5715             if (i < 0) return 0;
5716             if (i > lines.Count - 1) return lines.Count - 1;
5717             return i;
5718         }
5719 
5720         /// <summary>
5721         /// Gets nearest line and char position from coordinates
5722         /// </summary>
5723         /// <param name="point">Point</param>
5724         /// <returns>Line and char position</returns>
PointToPlace(Point point)5725         public Place PointToPlace(Point point)
5726         {
5727             #if debug
5728             var sw = Stopwatch.StartNew();
5729             #endif
5730             point.Offset(HorizontalScroll.Value, VerticalScroll.Value);
5731             point.Offset(-LeftIndent - Paddings.Left, 0);
5732             int iLine = YtoLineIndex(point.Y);
5733             if (iLine < 0)
5734                 return Place.Empty;
5735 
5736             int y = 0;
5737 
5738             for (; iLine < lines.Count; iLine++)
5739             {
5740                 y = LineInfos[iLine].startY + LineInfos[iLine].WordWrapStringsCount*CharHeight;
5741                 if (y > point.Y && LineInfos[iLine].VisibleState == VisibleState.Visible)
5742                     break;
5743             }
5744             if (iLine >= lines.Count)
5745                 iLine = lines.Count - 1;
5746             if (LineInfos[iLine].VisibleState != VisibleState.Visible)
5747                 iLine = FindPrevVisibleLine(iLine);
5748             //
5749             int iWordWrapLine = LineInfos[iLine].WordWrapStringsCount;
5750             do
5751             {
5752                 iWordWrapLine--;
5753                 y -= CharHeight;
5754             } while (y > point.Y);
5755             if (iWordWrapLine < 0) iWordWrapLine = 0;
5756             //
5757             int start = LineInfos[iLine].GetWordWrapStringStartPosition(iWordWrapLine);
5758             int finish = LineInfos[iLine].GetWordWrapStringFinishPosition(iWordWrapLine, lines[iLine]);
5759             var x = (int) Math.Round((float) point.X/CharWidth);
5760             if (iWordWrapLine > 0)
5761                 x -= LineInfos[iLine].wordWrapIndent;
5762 
5763             x = x < 0 ? start : start + x;
5764             if (x > finish)
5765                 x = finish + 1;
5766             if (x > lines[iLine].Count)
5767                 x = lines[iLine].Count;
5768 
5769 #if debug
5770             Console.WriteLine("PointToPlace: " + sw.ElapsedMilliseconds);
5771 #endif
5772 
5773             return new Place(x, iLine);
5774         }
5775 
PointToPlaceSimple(Point point)5776         private Place PointToPlaceSimple(Point point)
5777         {
5778             point.Offset(HorizontalScroll.Value, VerticalScroll.Value);
5779             point.Offset(-LeftIndent - Paddings.Left, 0);
5780             int iLine = YtoLineIndex(point.Y);
5781             var x = (int) Math.Round((float) point.X/CharWidth);
5782             if (x < 0) x = 0;
5783             return new Place(x, iLine);
5784         }
5785 
5786         /// <summary>
5787         /// Gets nearest absolute text position for given point
5788         /// </summary>
5789         /// <param name="point">Point</param>
5790         /// <returns>Position</returns>
PointToPosition(Point point)5791         public int PointToPosition(Point point)
5792         {
5793             return PlaceToPosition(PointToPlace(point));
5794         }
5795 
5796         /// <summary>
5797         /// Fires TextChanging event
5798         /// </summary>
OnTextChanging(ref string text)5799         public virtual void OnTextChanging(ref string text)
5800         {
5801             ClearBracketsPositions();
5802 
5803             if (TextChanging != null)
5804             {
5805                 var args = new TextChangingEventArgs {InsertingText = text};
5806                 TextChanging(this, args);
5807                 text = args.InsertingText;
5808                 if (args.Cancel)
5809                     text = string.Empty;
5810             }
5811         }
5812 
OnTextChanging()5813         public virtual void OnTextChanging()
5814         {
5815             string temp = null;
5816             OnTextChanging(ref temp);
5817         }
5818 
5819         /// <summary>
5820         /// Fires TextChanged event
5821         /// </summary>
OnTextChanged()5822         public virtual void OnTextChanged()
5823         {
5824             var r = new Range(this);
5825             r.SelectAll();
5826             OnTextChanged(new TextChangedEventArgs(r));
5827         }
5828 
5829         /// <summary>
5830         /// Fires TextChanged event
5831         /// </summary>
OnTextChanged(int fromLine, int toLine)5832         public virtual void OnTextChanged(int fromLine, int toLine)
5833         {
5834             var r = new Range(this);
5835             r.Start = new Place(0, Math.Min(fromLine, toLine));
5836             r.End = new Place(lines[Math.Max(fromLine, toLine)].Count, Math.Max(fromLine, toLine));
5837             OnTextChanged(new TextChangedEventArgs(r));
5838         }
5839 
5840         /// <summary>
5841         /// Fires TextChanged event
5842         /// </summary>
OnTextChanged(Range r)5843         public virtual void OnTextChanged(Range r)
5844         {
5845             OnTextChanged(new TextChangedEventArgs(r));
5846         }
5847 
5848         /// <summary>
5849         /// Call this method before multiple text changing
5850         /// </summary>
BeginUpdate()5851         public void BeginUpdate()
5852         {
5853             if (updating == 0)
5854                 updatingRange = null;
5855             updating++;
5856         }
5857 
5858         /// <summary>
5859         /// Call this method after multiple text changing
5860         /// </summary>
EndUpdate()5861         public void EndUpdate()
5862         {
5863             updating--;
5864 
5865             if (updating == 0 && updatingRange != null)
5866             {
5867                 updatingRange.Expand();
5868                 OnTextChanged(updatingRange);
5869             }
5870         }
5871 
5872 
5873         /// <summary>
5874         /// Fires TextChanged event
5875         /// </summary>
OnTextChanged(TextChangedEventArgs args)5876         protected virtual void OnTextChanged(TextChangedEventArgs args)
5877         {
5878             //
5879             args.ChangedRange.Normalize();
5880             //
5881             if (updating > 0)
5882             {
5883                 if (updatingRange == null)
5884                     updatingRange = args.ChangedRange.Clone();
5885                 else
5886                 {
5887                     if (updatingRange.Start.iLine > args.ChangedRange.Start.iLine)
5888                         updatingRange.Start = new Place(0, args.ChangedRange.Start.iLine);
5889                     if (updatingRange.End.iLine < args.ChangedRange.End.iLine)
5890                         updatingRange.End = new Place(lines[args.ChangedRange.End.iLine].Count,
5891                                                       args.ChangedRange.End.iLine);
5892                     updatingRange = updatingRange.GetIntersectionWith(Range);
5893                 }
5894                 return;
5895             }
5896             //
5897 #if debug
5898             var sw = Stopwatch.StartNew();
5899             #endif
5900             CancelToolTip();
5901             ClearHints();
5902             IsChanged = true;
5903             TextVersion++;
5904             MarkLinesAsChanged(args.ChangedRange);
5905             ClearFoldingState(args.ChangedRange);
5906             //
5907             if (wordWrap)
5908                 RecalcWordWrap(args.ChangedRange.Start.iLine, args.ChangedRange.End.iLine);
5909             //
5910             base.OnTextChanged(args);
5911 
5912             //dalayed event stuffs
5913             if (delayedTextChangedRange == null)
5914                 delayedTextChangedRange = args.ChangedRange.Clone();
5915             else
5916                 delayedTextChangedRange = delayedTextChangedRange.GetUnionWith(args.ChangedRange);
5917 
5918             needRiseTextChangedDelayed = true;
5919             ResetTimer(timer2);
5920             //
5921             OnSyntaxHighlight(args);
5922             //
5923             if (TextChanged != null)
5924                 TextChanged(this, args);
5925             //
5926             if (BindingTextChanged != null)
5927                 BindingTextChanged(this, EventArgs.Empty);
5928             //
5929             base.OnTextChanged(EventArgs.Empty);
5930             //
5931 #if debug
5932             Console.WriteLine("OnTextChanged: " + sw.ElapsedMilliseconds);
5933 #endif
5934 
5935             OnVisibleRangeChanged();
5936         }
5937 
5938         /// <summary>
5939         /// Clears folding state for range of text
5940         /// </summary>
ClearFoldingState(Range range)5941         private void ClearFoldingState(Range range)
5942         {
5943             for (int iLine = range.Start.iLine; iLine <= range.End.iLine; iLine++)
5944                 if (iLine >= 0 && iLine < lines.Count)
5945                     FoldedBlocks.Remove(this[iLine].UniqueId);
5946         }
5947 
5948 
MarkLinesAsChanged(Range range)5949         private void MarkLinesAsChanged(Range range)
5950         {
5951             for (int iLine = range.Start.iLine; iLine <= range.End.iLine; iLine++)
5952                 if (iLine >= 0 && iLine < lines.Count)
5953                     lines[iLine].IsChanged = true;
5954         }
5955 
5956         /// <summary>
5957         /// Fires SelectionChanged event
5958         /// </summary>
OnSelectionChanged()5959         public virtual void OnSelectionChanged()
5960         {
5961 #if debug
5962             var sw = Stopwatch.StartNew();
5963             #endif
5964             //find folding markers for highlighting
5965             if (HighlightFoldingIndicator)
5966                 HighlightFoldings();
5967             //
5968             needRiseSelectionChangedDelayed = true;
5969             ResetTimer(timer);
5970 
5971             if (SelectionChanged != null)
5972                 SelectionChanged(this, new EventArgs());
5973 
5974 #if debug
5975             Console.WriteLine("OnSelectionChanged: "+ sw.ElapsedMilliseconds);
5976 #endif
5977         }
5978 
5979         //find folding markers for highlighting
HighlightFoldings()5980         private void HighlightFoldings()
5981         {
5982             if (LinesCount == 0)
5983                 return;
5984             //
5985             int prevStartFoldingLine = startFoldingLine;
5986             int prevEndFoldingLine = endFoldingLine;
5987             //
5988             startFoldingLine = -1;
5989             endFoldingLine = -1;
5990             int counter = 0;
5991             for (int i = Selection.Start.iLine; i >= Math.Max(Selection.Start.iLine - maxLinesForFolding, 0); i--)
5992             {
5993                 bool hasStartMarker = lines.LineHasFoldingStartMarker(i);
5994                 bool hasEndMarker = lines.LineHasFoldingEndMarker(i);
5995 
5996                 if (hasEndMarker && hasStartMarker)
5997                     continue;
5998 
5999                 if (hasStartMarker)
6000                 {
6001                     counter--;
6002                     if (counter == -1) //found start folding
6003                     {
6004                         startFoldingLine = i;
6005                         break;
6006                     }
6007                 }
6008                 if (hasEndMarker && i != Selection.Start.iLine)
6009                     counter++;
6010             }
6011             if (startFoldingLine >= 0)
6012             {
6013                 //find end of block
6014                 endFoldingLine = FindEndOfFoldingBlock(startFoldingLine, maxLinesForFolding);
6015                 if (endFoldingLine == startFoldingLine)
6016                     endFoldingLine = -1;
6017             }
6018 
6019             if (startFoldingLine != prevStartFoldingLine || endFoldingLine != prevEndFoldingLine)
6020                 OnFoldingHighlightChanged();
6021         }
6022 
OnFoldingHighlightChanged()6023         protected virtual void OnFoldingHighlightChanged()
6024         {
6025             if (FoldingHighlightChanged != null)
6026                 FoldingHighlightChanged(this, EventArgs.Empty);
6027         }
6028 
OnGotFocus(EventArgs e)6029         protected override void OnGotFocus(EventArgs e)
6030         {
6031             SetAsCurrentTB();
6032             base.OnGotFocus(e);
6033             Invalidate();
6034         }
6035 
OnLostFocus(EventArgs e)6036         protected override void OnLostFocus(EventArgs e)
6037         {
6038             lastModifiers = Keys.None;
6039             DeactivateMiddleClickScrollingMode();
6040             base.OnLostFocus(e);
6041             Invalidate();
6042         }
6043 
6044         /// <summary>
6045         /// Gets absolute text position from line and char position
6046         /// </summary>
6047         /// <param name="point">Line and char position</param>
6048         /// <returns>Point of char</returns>
PlaceToPosition(Place point)6049         public int PlaceToPosition(Place point)
6050         {
6051             if (point.iLine < 0 || point.iLine >= lines.Count ||
6052                 point.iChar >= lines[point.iLine].Count + Environment.NewLine.Length)
6053                 return -1;
6054 
6055             int result = 0;
6056             for (int i = 0; i < point.iLine; i++)
6057                 result += lines[i].Count + Environment.NewLine.Length;
6058             result += point.iChar;
6059 
6060             return result;
6061         }
6062 
6063         /// <summary>
6064         /// Gets line and char position from absolute text position
6065         /// </summary>
PositionToPlace(int pos)6066         public Place PositionToPlace(int pos)
6067         {
6068             if (pos < 0)
6069                 return new Place(0, 0);
6070 
6071             for (int i = 0; i < lines.Count; i++)
6072             {
6073                 int lineLength = lines[i].Count + Environment.NewLine.Length;
6074                 if (pos < lines[i].Count)
6075                     return new Place(pos, i);
6076                 if (pos < lineLength)
6077                     return new Place(lines[i].Count, i);
6078 
6079                 pos -= lineLength;
6080             }
6081 
6082             if (lines.Count > 0)
6083                 return new Place(lines[lines.Count - 1].Count, lines.Count - 1);
6084             else
6085                 return new Place(0, 0);
6086             //throw new ArgumentOutOfRangeException("Position out of range");
6087         }
6088 
6089         /// <summary>
6090         /// Gets absolute char position from char position
6091         /// </summary>
PositionToPoint(int pos)6092         public Point PositionToPoint(int pos)
6093         {
6094             return PlaceToPoint(PositionToPlace(pos));
6095         }
6096 
6097         /// <summary>
6098         /// Gets point for given line and char position
6099         /// </summary>
6100         /// <param name="place">Line and char position</param>
6101         /// <returns>Coordiantes</returns>
PlaceToPoint(Place place)6102         public Point PlaceToPoint(Place place)
6103         {
6104             if (place.iLine >= LineInfos.Count)
6105                 return new Point();
6106             int y = LineInfos[place.iLine].startY;
6107             //
6108             int iWordWrapIndex = LineInfos[place.iLine].GetWordWrapStringIndex(place.iChar);
6109             y += iWordWrapIndex*CharHeight;
6110             int x = (place.iChar - LineInfos[place.iLine].GetWordWrapStringStartPosition(iWordWrapIndex))*CharWidth;
6111             if(iWordWrapIndex > 0 )
6112                 x += LineInfos[place.iLine].wordWrapIndent * CharWidth;
6113             //
6114             y = y - VerticalScroll.Value;
6115             x = LeftIndent + Paddings.Left + x - HorizontalScroll.Value;
6116 
6117             return new Point(x, y);
6118         }
6119 
6120         /// <summary>
6121         /// Get range of text
6122         /// </summary>
6123         /// <param name="fromPos">Absolute start position</param>
6124         /// <param name="toPos">Absolute finish position</param>
6125         /// <returns>Range</returns>
GetRange(int fromPos, int toPos)6126         public Range GetRange(int fromPos, int toPos)
6127         {
6128             var sel = new Range(this);
6129             sel.Start = PositionToPlace(fromPos);
6130             sel.End = PositionToPlace(toPos);
6131             return sel;
6132         }
6133 
6134         /// <summary>
6135         /// Get range of text
6136         /// </summary>
6137         /// <param name="fromPlace">Line and char position</param>
6138         /// <param name="toPlace">Line and char position</param>
6139         /// <returns>Range</returns>
GetRange(Place fromPlace, Place toPlace)6140         public Range GetRange(Place fromPlace, Place toPlace)
6141         {
6142             return new Range(this, fromPlace, toPlace);
6143         }
6144 
6145         /// <summary>
6146         /// Finds ranges for given regex pattern
6147         /// </summary>
6148         /// <param name="regexPattern">Regex pattern</param>
6149         /// <returns>Enumeration of ranges</returns>
GetRanges(string regexPattern)6150         public IEnumerable<Range> GetRanges(string regexPattern)
6151         {
6152             var range = new Range(this);
6153             range.SelectAll();
6154             //
6155             foreach (Range r in range.GetRanges(regexPattern, RegexOptions.None))
6156                 yield return r;
6157         }
6158 
6159         /// <summary>
6160         /// Finds ranges for given regex pattern
6161         /// </summary>
6162         /// <param name="regexPattern">Regex pattern</param>
6163         /// <returns>Enumeration of ranges</returns>
GetRanges(string regexPattern, RegexOptions options)6164         public IEnumerable<Range> GetRanges(string regexPattern, RegexOptions options)
6165         {
6166             var range = new Range(this);
6167             range.SelectAll();
6168             //
6169             foreach (Range r in range.GetRanges(regexPattern, options))
6170                 yield return r;
6171         }
6172 
6173         /// <summary>
6174         /// Get text of given line
6175         /// </summary>
6176         /// <param name="iLine">Line index</param>
6177         /// <returns>Text</returns>
GetLineText(int iLine)6178         public string GetLineText(int iLine)
6179         {
6180             if (iLine < 0 || iLine >= lines.Count)
6181                 throw new ArgumentOutOfRangeException("Line index out of range");
6182             var sb = new StringBuilder(lines[iLine].Count);
6183             foreach (Char c in lines[iLine])
6184                 sb.Append(c.c);
6185             return sb.ToString();
6186         }
6187 
6188         /// <summary>
6189         /// Exapnds folded block
6190         /// </summary>
6191         /// <param name="iLine">Start line</param>
ExpandFoldedBlock(int iLine)6192         public virtual void ExpandFoldedBlock(int iLine)
6193         {
6194             if (iLine < 0 || iLine >= lines.Count)
6195                 throw new ArgumentOutOfRangeException("Line index out of range");
6196             //find all hidden lines afetr iLine
6197             int end = iLine;
6198             for (; end < LinesCount - 1; end++)
6199             {
6200                 if (LineInfos[end + 1].VisibleState != VisibleState.Hidden)
6201                     break;
6202             }
6203 
6204             ExpandBlock(iLine, end);
6205 
6206             FoldedBlocks.Remove(this[iLine].UniqueId);//remove folded state for this line
6207             AdjustFolding();
6208         }
6209 
6210         /// <summary>
6211         /// Collapse folding blocks using FoldedBlocks dictionary.
6212         /// </summary>
AdjustFolding()6213         public virtual void AdjustFolding()
6214         {
6215             //collapse folded blocks
6216             for (int iLine = 0; iLine < LinesCount; iLine++)
6217                 if (LineInfos[iLine].VisibleState == VisibleState.Visible)
6218                     if (FoldedBlocks.ContainsKey(this[iLine].UniqueId))
6219                         CollapseFoldingBlock(iLine);
6220         }
6221 
6222 
6223         /// <summary>
6224         /// Expand collapsed block
6225         /// </summary>
ExpandBlock(int fromLine, int toLine)6226         public virtual void ExpandBlock(int fromLine, int toLine)
6227         {
6228             int from = Math.Min(fromLine, toLine);
6229             int to = Math.Max(fromLine, toLine);
6230             for (int i = from; i <= to; i++)
6231                 SetVisibleState(i, VisibleState.Visible);
6232             needRecalc = true;
6233 
6234             Invalidate();
6235             OnVisibleRangeChanged();
6236         }
6237 
6238         /// <summary>
6239         /// Expand collapsed block
6240         /// </summary>
6241         /// <param name="iLine">Any line inside collapsed block</param>
ExpandBlock(int iLine)6242         public void ExpandBlock(int iLine)
6243         {
6244             if (LineInfos[iLine].VisibleState == VisibleState.Visible)
6245                 return;
6246 
6247             for (int i = iLine; i < LinesCount; i++)
6248                 if (LineInfos[i].VisibleState == VisibleState.Visible)
6249                     break;
6250                 else
6251                 {
6252                     SetVisibleState(i, VisibleState.Visible);
6253                     needRecalc = true;
6254                 }
6255 
6256             for (int i = iLine - 1; i >= 0; i--)
6257                 if (LineInfos[i].VisibleState == VisibleState.Visible)
6258                     break;
6259                 else
6260                 {
6261                     SetVisibleState(i, VisibleState.Visible);
6262                     needRecalc = true;
6263                 }
6264 
6265             Invalidate();
6266             OnVisibleRangeChanged();
6267         }
6268 
6269         /// <summary>
6270         /// Collapses all folding blocks
6271         /// </summary>
CollapseAllFoldingBlocks()6272         public virtual void CollapseAllFoldingBlocks()
6273         {
6274             for (int i = 0; i < LinesCount; i++)
6275                 if (lines.LineHasFoldingStartMarker(i))
6276                 {
6277                     int iFinish = FindEndOfFoldingBlock(i);
6278                     if (iFinish >= 0)
6279                     {
6280                         CollapseBlock(i, iFinish);
6281                         i = iFinish;
6282                     }
6283                 }
6284 
6285             OnVisibleRangeChanged();
6286             UpdateScrollbars();
6287         }
6288 
6289         /// <summary>
6290         /// Exapnds all folded blocks
6291         /// </summary>
6292         /// <param name="iLine"></param>
ExpandAllFoldingBlocks()6293         public virtual void ExpandAllFoldingBlocks()
6294         {
6295             for (int i = 0; i < LinesCount; i++)
6296                 SetVisibleState(i, VisibleState.Visible);
6297 
6298             FoldedBlocks.Clear();
6299 
6300             OnVisibleRangeChanged();
6301             Invalidate();
6302             UpdateScrollbars();
6303         }
6304 
6305         /// <summary>
6306         /// Collapses folding block
6307         /// </summary>
6308         /// <param name="iLine">Start folding line</param>
CollapseFoldingBlock(int iLine)6309         public virtual void CollapseFoldingBlock(int iLine)
6310         {
6311             if (iLine < 0 || iLine >= lines.Count)
6312                 throw new ArgumentOutOfRangeException("Line index out of range");
6313             if (string.IsNullOrEmpty(lines[iLine].FoldingStartMarker))
6314                 throw new ArgumentOutOfRangeException("This line is not folding start line");
6315             //find end of block
6316             int i = FindEndOfFoldingBlock(iLine);
6317             //collapse
6318             if (i >= 0)
6319             {
6320                 CollapseBlock(iLine, i);
6321                 var id = this[iLine].UniqueId;
6322                 FoldedBlocks[id] = id; //add folded state for line
6323             }
6324         }
6325 
FindEndOfFoldingBlock(int iStartLine)6326         private int FindEndOfFoldingBlock(int iStartLine)
6327         {
6328             return FindEndOfFoldingBlock(iStartLine, int.MaxValue);
6329         }
6330 
FindEndOfFoldingBlock(int iStartLine, int maxLines)6331         protected virtual int FindEndOfFoldingBlock(int iStartLine, int maxLines)
6332         {
6333             //find end of block
6334             int i;
6335             string marker = lines[iStartLine].FoldingStartMarker;
6336             var stack = new Stack<string>();
6337 
6338             switch (FindEndOfFoldingBlockStrategy)
6339             {
6340                 case FindEndOfFoldingBlockStrategy.Strategy1:
6341                     for (i = iStartLine /*+1*/; i < LinesCount; i++)
6342                     {
6343                         if (lines.LineHasFoldingStartMarker(i))
6344                             stack.Push(lines[i].FoldingStartMarker);
6345 
6346                         if (lines.LineHasFoldingEndMarker(i))
6347                         {
6348                             string m = lines[i].FoldingEndMarker;
6349                             while (stack.Count > 0 && stack.Pop() != m) ;
6350                             if (stack.Count == 0)
6351                                 return i;
6352                         }
6353 
6354                         maxLines--;
6355                         if (maxLines < 0)
6356                             return i;
6357                     }
6358                     break;
6359 
6360                 case FindEndOfFoldingBlockStrategy.Strategy2:
6361                     for (i = iStartLine /*+1*/; i < LinesCount; i++)
6362                     {
6363                         if (lines.LineHasFoldingEndMarker(i))
6364                         {
6365                             string m = lines[i].FoldingEndMarker;
6366                             while (stack.Count > 0 && stack.Pop() != m) ;
6367                             if (stack.Count == 0)
6368                                 return i;
6369                         }
6370 
6371                         if (lines.LineHasFoldingStartMarker(i))
6372                             stack.Push(lines[i].FoldingStartMarker);
6373 
6374                         maxLines--;
6375                         if (maxLines < 0)
6376                             return i;
6377                     }
6378                     break;
6379             }
6380 
6381             //return -1;
6382             return LinesCount - 1;
6383         }
6384 
6385         /// <summary>
6386         /// Start foilding marker for the line
6387         /// </summary>
GetLineFoldingStartMarker(int iLine)6388         public string GetLineFoldingStartMarker(int iLine)
6389         {
6390             if (lines.LineHasFoldingStartMarker(iLine))
6391                 return lines[iLine].FoldingStartMarker;
6392             return null;
6393         }
6394 
6395         /// <summary>
6396         /// End foilding marker for the line
6397         /// </summary>
GetLineFoldingEndMarker(int iLine)6398         public string GetLineFoldingEndMarker(int iLine)
6399         {
6400             if (lines.LineHasFoldingEndMarker(iLine))
6401                 return lines[iLine].FoldingEndMarker;
6402             return null;
6403         }
6404 
RecalcFoldingLines()6405         protected virtual void RecalcFoldingLines()
6406         {
6407             if (!needRecalcFoldingLines)
6408                 return;
6409             needRecalcFoldingLines = false;
6410             if (!ShowFoldingLines)
6411                 return;
6412 
6413             foldingPairs.Clear();
6414             //
6415             Range range = VisibleRange;
6416             int startLine = Math.Max(range.Start.iLine - maxLinesForFolding, 0);
6417             int endLine = Math.Min(range.End.iLine + maxLinesForFolding, Math.Max(range.End.iLine, LinesCount - 1));
6418             var stack = new Stack<int>();
6419             for (int i = startLine; i <= endLine; i++)
6420             {
6421                 bool hasStartMarker = lines.LineHasFoldingStartMarker(i);
6422                 bool hasEndMarker = lines.LineHasFoldingEndMarker(i);
6423 
6424                 if (hasEndMarker && hasStartMarker)
6425                     continue;
6426 
6427                 if (hasStartMarker)
6428                 {
6429                     stack.Push(i);
6430                 }
6431                 if (hasEndMarker)
6432                 {
6433                     string m = lines[i].FoldingEndMarker;
6434                     while (stack.Count > 0)
6435                     {
6436                         int iStartLine = stack.Pop();
6437                         foldingPairs[iStartLine] = i;
6438                         if (m == lines[iStartLine].FoldingStartMarker)
6439                             break;
6440                     }
6441                 }
6442             }
6443 
6444             while (stack.Count > 0)
6445                 foldingPairs[stack.Pop()] = endLine + 1;
6446         }
6447 
6448         /// <summary>
6449         /// Collapse text block
6450         /// </summary>
CollapseBlock(int fromLine, int toLine)6451         public virtual void CollapseBlock(int fromLine, int toLine)
6452         {
6453             int from = Math.Min(fromLine, toLine);
6454             int to = Math.Max(fromLine, toLine);
6455             if (from == to)
6456                 return;
6457 
6458             //find first non empty line
6459             for (; from <= to; from++)
6460             {
6461                 if (GetLineText(from).Trim().Length > 0)
6462                 {
6463                     //hide lines
6464                     for (int i = from + 1; i <= to; i++)
6465                         SetVisibleState(i, VisibleState.Hidden);
6466                     SetVisibleState(from, VisibleState.StartOfHiddenBlock);
6467                     Invalidate();
6468                     break;
6469                 }
6470             }
6471             //Move caret outside
6472             from = Math.Min(fromLine, toLine);
6473             to = Math.Max(fromLine, toLine);
6474             int newLine = FindNextVisibleLine(to);
6475             if (newLine == to)
6476                 newLine = FindPrevVisibleLine(from);
6477             Selection.Start = new Place(0, newLine);
6478             //
6479             needRecalc = true;
6480             Invalidate();
6481             OnVisibleRangeChanged();
6482         }
6483 
6484 
FindNextVisibleLine(int iLine)6485         internal int FindNextVisibleLine(int iLine)
6486         {
6487             if (iLine >= lines.Count - 1) return iLine;
6488             int old = iLine;
6489             do
6490                 iLine++; while (iLine < lines.Count - 1 && LineInfos[iLine].VisibleState != VisibleState.Visible);
6491 
6492             if (LineInfos[iLine].VisibleState != VisibleState.Visible)
6493                 return old;
6494             else
6495                 return iLine;
6496         }
6497 
6498 
FindPrevVisibleLine(int iLine)6499         internal int FindPrevVisibleLine(int iLine)
6500         {
6501             if (iLine <= 0) return iLine;
6502             int old = iLine;
6503             do
6504                 iLine--; while (iLine > 0 && LineInfos[iLine].VisibleState != VisibleState.Visible);
6505 
6506             if (LineInfos[iLine].VisibleState != VisibleState.Visible)
6507                 return old;
6508             else
6509                 return iLine;
6510         }
6511 
FindVisualMarkerForPoint(Point p)6512         private VisualMarker FindVisualMarkerForPoint(Point p)
6513         {
6514             foreach (VisualMarker m in visibleMarkers)
6515                 if (m.rectangle.Contains(p))
6516                     return m;
6517             return null;
6518         }
6519 
6520         /// <summary>
6521         /// Insert TAB into front of seletcted lines.
6522         /// </summary>
IncreaseIndent()6523         public virtual void IncreaseIndent()
6524         {
6525             if (Selection.Start == Selection.End)
6526             {
6527                 if (!Selection.ReadOnly)
6528                 {
6529                     Selection.Start = new Place(this[Selection.Start.iLine].StartSpacesCount, Selection.Start.iLine);
6530                     //insert tab as spaces
6531                     int spaces = TabLength - (Selection.Start.iChar % TabLength);
6532                     //replace mode? select forward chars
6533                     if (IsReplaceMode)
6534                     {
6535                         for (int i = 0; i < spaces; i++)
6536                             Selection.GoRight(true);
6537                         Selection.Inverse();
6538                     }
6539 
6540                     InsertText(new String(' ', spaces));
6541                 }
6542                 return;
6543             }
6544 
6545             bool carretAtEnd = (Selection.Start > Selection.End) && !Selection.ColumnSelectionMode;
6546 
6547             int startChar = 0; // Only move selection when in 'ColumnSelectionMode'
6548             if (Selection.ColumnSelectionMode)
6549                 startChar = Math.Min(Selection.End.iChar, Selection.Start.iChar);
6550 
6551             BeginUpdate();
6552             Selection.BeginUpdate();
6553             lines.Manager.BeginAutoUndoCommands();
6554 
6555             var old = Selection.Clone();
6556             lines.Manager.ExecuteCommand(new SelectCommand(TextSource));//remember selection
6557 
6558             //
6559             Selection.Normalize();
6560             Range currentSelection = this.Selection.Clone();
6561             int from = Selection.Start.iLine;
6562             int to = Selection.End.iLine;
6563 
6564             if (!Selection.ColumnSelectionMode)
6565                 if (Selection.End.iChar == 0) to--;
6566 
6567             for (int i = from; i <= to; i++)
6568             {
6569                 if (lines[i].Count == 0) continue;
6570                 Selection.Start = new Place(startChar, i);
6571                 lines.Manager.ExecuteCommand(new InsertTextCommand(TextSource, new String(' ', TabLength)));
6572             }
6573 
6574             // Restore selection
6575             if (Selection.ColumnSelectionMode == false)
6576             {
6577                 int newSelectionStartCharacterIndex = currentSelection.Start.iChar + this.TabLength;
6578                 int newSelectionEndCharacterIndex = currentSelection.End.iChar + (currentSelection.End.iLine == to?this.TabLength : 0);
6579                 this.Selection.Start = new Place(newSelectionStartCharacterIndex, currentSelection.Start.iLine);
6580                 this.Selection.End = new Place(newSelectionEndCharacterIndex, currentSelection.End.iLine);
6581             }
6582             else
6583             {
6584                 Selection = old;
6585             }
6586             lines.Manager.EndAutoUndoCommands();
6587 
6588             if (carretAtEnd)
6589                 Selection.Inverse();
6590 
6591             needRecalc = true;
6592             Selection.EndUpdate();
6593             EndUpdate();
6594             Invalidate();
6595         }
6596 
6597         /// <summary>
6598         /// Remove TAB from front of seletcted lines.
6599         /// </summary>
DecreaseIndent()6600         public virtual void DecreaseIndent()
6601         {
6602             if (Selection.Start.iLine == Selection.End.iLine)
6603             {
6604                 DecreaseIndentOfSingleLine();
6605                 return;
6606             }
6607 
6608             int startCharIndex = 0;
6609             if (Selection.ColumnSelectionMode)
6610                 startCharIndex = Math.Min(Selection.End.iChar, Selection.Start.iChar);
6611 
6612             BeginUpdate();
6613             Selection.BeginUpdate();
6614             lines.Manager.BeginAutoUndoCommands();
6615             var old = Selection.Clone();
6616             lines.Manager.ExecuteCommand(new SelectCommand(TextSource));//remember selection
6617 
6618             // Remember current selection infos
6619             Range currentSelection = this.Selection.Clone();
6620             Selection.Normalize();
6621             int from = Selection.Start.iLine;
6622             int to = Selection.End.iLine;
6623 
6624             if (!Selection.ColumnSelectionMode)
6625                 if (Selection.End.iChar == 0) to--;
6626 
6627             int numberOfDeletedWhitespacesOfFirstLine = 0;
6628             int numberOfDeletetWhitespacesOfLastLine = 0;
6629 
6630             for (int i = from; i <= to; i++)
6631             {
6632                 if (startCharIndex > lines[i].Count)
6633                     continue;
6634                 // Select first characters from the line
6635                 int endIndex = Math.Min(this.lines[i].Count, startCharIndex + this.TabLength);
6636                 string wasteText = this.lines[i].Text.Substring(startCharIndex, endIndex-startCharIndex);
6637 
6638                 // Only select the first whitespace characters
6639                 endIndex = Math.Min(endIndex, startCharIndex + wasteText.Length - wasteText.TrimStart().Length);
6640 
6641                 // Select the characters to remove
6642                 this.Selection = new Range(this, new Place(startCharIndex, i), new Place(endIndex, i));
6643 
6644                 // Remember characters to remove for first and last line
6645                 int numberOfWhitespacesToRemove = endIndex - startCharIndex;
6646                 if (i == currentSelection.Start.iLine)
6647                 {
6648                     numberOfDeletedWhitespacesOfFirstLine = numberOfWhitespacesToRemove;
6649                 }
6650                 if (i == currentSelection.End.iLine)
6651                 {
6652                     numberOfDeletetWhitespacesOfLastLine = numberOfWhitespacesToRemove;
6653                 }
6654 
6655                 // Remove marked/selected whitespace characters
6656                 if(!Selection.IsEmpty)
6657                     this.ClearSelected();
6658             }
6659 
6660             // Restore selection
6661             if (Selection.ColumnSelectionMode == false)
6662             {
6663                 int newSelectionStartCharacterIndex = Math.Max(0, currentSelection.Start.iChar - numberOfDeletedWhitespacesOfFirstLine);
6664                 int newSelectionEndCharacterIndex = Math.Max(0, currentSelection.End.iChar - numberOfDeletetWhitespacesOfLastLine);
6665                 this.Selection.Start = new Place(newSelectionStartCharacterIndex, currentSelection.Start.iLine);
6666                 this.Selection.End = new Place(newSelectionEndCharacterIndex, currentSelection.End.iLine);
6667             }
6668             else
6669             {
6670                 Selection = old;
6671             }
6672             lines.Manager.EndAutoUndoCommands();
6673 
6674             needRecalc = true;
6675             Selection.EndUpdate();
6676             EndUpdate();
6677             Invalidate();
6678         }
6679 
6680         /// <summary>
6681         /// Remove TAB in front of the caret ot the selected line.
6682         /// </summary>
DecreaseIndentOfSingleLine()6683         protected virtual void DecreaseIndentOfSingleLine()
6684         {
6685             if (this.Selection.Start.iLine != this.Selection.End.iLine)
6686                 return;
6687 
6688             // Remeber current selection infos
6689             Range currentSelection = this.Selection.Clone();
6690             int currentLineIndex = this.Selection.Start.iLine;
6691             int currentLeftSelectionStartIndex = Math.Min(this.Selection.Start.iChar, this.Selection.End.iChar);
6692 
6693             // Determine number of whitespaces to remove
6694             string lineText = this.lines[currentLineIndex].Text;
6695             Match whitespacesLeftOfSelectionStartMatch = new Regex(@"\s*", RegexOptions.RightToLeft).Match(lineText, currentLeftSelectionStartIndex);
6696             int leftOffset = whitespacesLeftOfSelectionStartMatch.Index;
6697             int countOfWhitespaces = whitespacesLeftOfSelectionStartMatch.Length;
6698             int numberOfCharactersToRemove = 0;
6699             if (countOfWhitespaces > 0)
6700             {
6701                 int remainder = (this.TabLength > 0)
6702                     ? currentLeftSelectionStartIndex % this.TabLength
6703                     : 0;
6704                 numberOfCharactersToRemove = (remainder != 0)
6705                     ? Math.Min(remainder, countOfWhitespaces)
6706                     : Math.Min(this.TabLength, countOfWhitespaces);
6707             }
6708 
6709             // Remove whitespaces if available
6710             if (numberOfCharactersToRemove > 0)
6711             {
6712                 // Start selection update
6713                 this.BeginUpdate();
6714                 this.Selection.BeginUpdate();
6715                 lines.Manager.BeginAutoUndoCommands();
6716                 lines.Manager.ExecuteCommand(new SelectCommand(TextSource));//remember selection
6717 
6718                 // Remove whitespaces
6719                 this.Selection.Start = new Place(leftOffset, currentLineIndex);
6720                 this.Selection.End = new Place(leftOffset + numberOfCharactersToRemove, currentLineIndex);
6721                 ClearSelected();
6722 
6723                 // Restore selection
6724                 int newSelectionStartCharacterIndex = currentSelection.Start.iChar - numberOfCharactersToRemove;
6725                 int newSelectionEndCharacterIndex = currentSelection.End.iChar - numberOfCharactersToRemove;
6726                 this.Selection.Start = new Place(newSelectionStartCharacterIndex, currentLineIndex);
6727                 this.Selection.End = new Place(newSelectionEndCharacterIndex, currentLineIndex);
6728 
6729                 lines.Manager.ExecuteCommand(new SelectCommand(TextSource));//remember selection
6730                 // End selection update
6731                 lines.Manager.EndAutoUndoCommands();
6732                 this.Selection.EndUpdate();
6733                 this.EndUpdate();
6734             }
6735 
6736             Invalidate();
6737         }
6738 
6739 
6740         /// <summary>
6741         /// Insert autoindents into selected lines
6742         /// </summary>
DoAutoIndent()6743         public virtual void DoAutoIndent()
6744         {
6745             if (Selection.ColumnSelectionMode)
6746                 return;
6747             Range r = Selection.Clone();
6748             r.Normalize();
6749             //
6750             BeginUpdate();
6751             Selection.BeginUpdate();
6752             lines.Manager.BeginAutoUndoCommands();
6753             //
6754             for (int i = r.Start.iLine; i <= r.End.iLine; i++)
6755                 DoAutoIndent(i);
6756             //
6757             lines.Manager.EndAutoUndoCommands();
6758             Selection.Start = r.Start;
6759             Selection.End = r.End;
6760             Selection.Expand();
6761             //
6762             Selection.EndUpdate();
6763             EndUpdate();
6764         }
6765 
6766         /// <summary>
6767         /// Insert prefix into front of seletcted lines
6768         /// </summary>
InsertLinePrefix(string prefix)6769         public virtual void InsertLinePrefix(string prefix)
6770         {
6771             int from = Math.Min(Selection.Start.iLine, Selection.End.iLine);
6772             int to = Math.Max(Selection.Start.iLine, Selection.End.iLine);
6773             BeginUpdate();
6774             Selection.BeginUpdate();
6775             lines.Manager.BeginAutoUndoCommands();
6776             lines.Manager.ExecuteCommand(new SelectCommand(TextSource));
6777             int spaces = GetMinStartSpacesCount(from, to);
6778             for (int i = from; i <= to; i++)
6779             {
6780                 Selection.Start = new Place(spaces, i);
6781                 lines.Manager.ExecuteCommand(new InsertTextCommand(TextSource, prefix));
6782             }
6783             Selection.Start = new Place(0, from);
6784             Selection.End = new Place(lines[to].Count, to);
6785             needRecalc = true;
6786             lines.Manager.EndAutoUndoCommands();
6787             Selection.EndUpdate();
6788             EndUpdate();
6789             Invalidate();
6790         }
6791 
6792         /// <summary>
6793         /// Remove prefix from front of selected lines
6794         /// This method ignores forward spaces of the line
6795         /// </summary>
RemoveLinePrefix(string prefix)6796         public virtual void RemoveLinePrefix(string prefix)
6797         {
6798             int from = Math.Min(Selection.Start.iLine, Selection.End.iLine);
6799             int to = Math.Max(Selection.Start.iLine, Selection.End.iLine);
6800             BeginUpdate();
6801             Selection.BeginUpdate();
6802             lines.Manager.BeginAutoUndoCommands();
6803             lines.Manager.ExecuteCommand(new SelectCommand(TextSource));
6804             for (int i = from; i <= to; i++)
6805             {
6806                 string text = lines[i].Text;
6807                 string trimmedText = text.TrimStart();
6808                 if (trimmedText.StartsWith(prefix))
6809                 {
6810                     int spaces = text.Length - trimmedText.Length;
6811                     Selection.Start = new Place(spaces, i);
6812                     Selection.End = new Place(spaces + prefix.Length, i);
6813                     ClearSelected();
6814                 }
6815             }
6816             Selection.Start = new Place(0, from);
6817             Selection.End = new Place(lines[to].Count, to);
6818             needRecalc = true;
6819             lines.Manager.EndAutoUndoCommands();
6820             Selection.EndUpdate();
6821             EndUpdate();
6822         }
6823 
6824         /// <summary>
6825         /// Begins AutoUndo block.
6826         /// All changes of text between BeginAutoUndo() and EndAutoUndo() will be canceled in one operation Undo.
6827         /// </summary>
BeginAutoUndo()6828         public void BeginAutoUndo()
6829         {
6830             lines.Manager.BeginAutoUndoCommands();
6831         }
6832 
6833         /// <summary>
6834         /// Ends AutoUndo block.
6835         /// All changes of text between BeginAutoUndo() and EndAutoUndo() will be canceled in one operation Undo.
6836         /// </summary>
EndAutoUndo()6837         public void EndAutoUndo()
6838         {
6839             lines.Manager.EndAutoUndoCommands();
6840         }
6841 
OnVisualMarkerClick(MouseEventArgs args, StyleVisualMarker marker)6842         public virtual void OnVisualMarkerClick(MouseEventArgs args, StyleVisualMarker marker)
6843         {
6844             if (VisualMarkerClick != null)
6845                 VisualMarkerClick(this, new VisualMarkerEventArgs(marker.Style, marker, args));
6846             marker.Style.OnVisualMarkerClick(this, new VisualMarkerEventArgs(marker.Style, marker, args));
6847         }
6848 
OnMarkerClick(MouseEventArgs args, VisualMarker marker)6849         protected virtual void OnMarkerClick(MouseEventArgs args, VisualMarker marker)
6850         {
6851             if (marker is StyleVisualMarker)
6852             {
6853                 OnVisualMarkerClick(args, marker as StyleVisualMarker);
6854                 return;
6855             }
6856             if (marker is CollapseFoldingMarker)
6857             {
6858                 CollapseFoldingBlock((marker as CollapseFoldingMarker).iLine);
6859                 return;
6860             }
6861 
6862             if (marker is ExpandFoldingMarker)
6863             {
6864                 ExpandFoldedBlock((marker as ExpandFoldingMarker).iLine);
6865                 return;
6866             }
6867 
6868             if (marker is FoldedAreaMarker)
6869             {
6870                 //select folded block
6871                 int iStart = (marker as FoldedAreaMarker).iLine;
6872                 int iEnd = FindEndOfFoldingBlock(iStart);
6873                 if (iEnd < 0)
6874                     return;
6875                 Selection.BeginUpdate();
6876                 Selection.Start = new Place(0, iStart);
6877                 Selection.End = new Place(lines[iEnd].Count, iEnd);
6878                 Selection.EndUpdate();
6879                 Invalidate();
6880                 return;
6881             }
6882         }
6883 
OnMarkerDoubleClick(VisualMarker marker)6884         protected virtual void OnMarkerDoubleClick(VisualMarker marker)
6885         {
6886             if (marker is FoldedAreaMarker)
6887             {
6888                 ExpandFoldedBlock((marker as FoldedAreaMarker).iLine);
6889                 Invalidate();
6890                 return;
6891             }
6892         }
6893 
ClearBracketsPositions()6894         private void ClearBracketsPositions()
6895         {
6896             leftBracketPosition = null;
6897             rightBracketPosition = null;
6898             leftBracketPosition2 = null;
6899             rightBracketPosition2 = null;
6900         }
6901 
6902         /// <summary>
6903         /// Highlights brackets around caret
6904         /// </summary>
HighlightBrackets(char LeftBracket, char RightBracket, ref Range leftBracketPosition, ref Range rightBracketPosition)6905         private void HighlightBrackets(char LeftBracket, char RightBracket, ref Range leftBracketPosition, ref Range rightBracketPosition)
6906         {
6907             switch(BracketsHighlightStrategy)
6908             {
6909                 case BracketsHighlightStrategy.Strategy1: HighlightBrackets1(LeftBracket, RightBracket, ref leftBracketPosition, ref rightBracketPosition); break;
6910                 case BracketsHighlightStrategy.Strategy2: HighlightBrackets2(LeftBracket, RightBracket, ref leftBracketPosition, ref rightBracketPosition); break;
6911             }
6912         }
6913 
HighlightBrackets1(char LeftBracket, char RightBracket, ref Range leftBracketPosition, ref Range rightBracketPosition)6914         private void HighlightBrackets1(char LeftBracket, char RightBracket, ref Range leftBracketPosition, ref Range rightBracketPosition)
6915         {
6916             if (!Selection.IsEmpty)
6917                 return;
6918             if (LinesCount == 0)
6919                 return;
6920             //
6921             Range oldLeftBracketPosition = leftBracketPosition;
6922             Range oldRightBracketPosition = rightBracketPosition;
6923             var range = GetBracketsRange(Selection.Start, LeftBracket, RightBracket);
6924 
6925             if(range != null)
6926             {
6927                 leftBracketPosition = new Range(this, range.Start, new Place(range.Start.iChar + 1, range.Start.iLine));
6928                 rightBracketPosition = new Range(this, new Place(range.End.iChar - 1, range.End.iLine), range.End);
6929             }
6930 
6931             if (oldLeftBracketPosition != leftBracketPosition ||
6932                 oldRightBracketPosition != rightBracketPosition)
6933                 Invalidate();
6934         }
6935 
6936         /// <summary>
6937         /// Returns range between brackets (or null if not found)
6938         /// </summary>
GetBracketsRange(Place placeInsideBrackets, char leftBracket, char rightBracket)6939         public Range GetBracketsRange(Place placeInsideBrackets, char leftBracket, char rightBracket)
6940         {
6941             var startRange = new Range(this, placeInsideBrackets, placeInsideBrackets);
6942             var range = startRange.Clone();
6943 
6944             Range leftBracketPosition = null;
6945             Range rightBracketPosition = null;
6946 
6947             int counter = 0;
6948             int maxIterations = maxBracketSearchIterations;
6949             while (range.GoLeftThroughFolded()) //move caret left
6950             {
6951                 if (range.CharAfterStart == leftBracket) counter++;
6952                 if (range.CharAfterStart == rightBracket) counter--;
6953                 if (counter == 1)
6954                 {
6955                     //highlighting
6956                     range.End = new Place(range.Start.iChar + 1, range.Start.iLine);
6957                     leftBracketPosition = range;
6958                     break;
6959                 }
6960                 //
6961                 maxIterations--;
6962                 if (maxIterations <= 0) break;
6963             }
6964             //
6965             range = startRange.Clone();
6966             counter = 0;
6967             maxIterations = maxBracketSearchIterations;
6968             do
6969             {
6970                 if (range.CharAfterStart == leftBracket) counter++;
6971                 if (range.CharAfterStart == rightBracket) counter--;
6972                 if (counter == -1)
6973                 {
6974                     //highlighting
6975                     range.End = new Place(range.Start.iChar + 1, range.Start.iLine);
6976                     rightBracketPosition = range;
6977                     break;
6978                 }
6979                 //
6980                 maxIterations--;
6981                 if (maxIterations <= 0) break;
6982             } while (range.GoRightThroughFolded()); //move caret right
6983 
6984             if (leftBracketPosition != null && rightBracketPosition != null)
6985                 return new Range(this, leftBracketPosition.Start, rightBracketPosition.End);
6986             else
6987                 return null;
6988         }
6989 
HighlightBrackets2(char LeftBracket, char RightBracket, ref Range leftBracketPosition, ref Range rightBracketPosition)6990         private void HighlightBrackets2(char LeftBracket, char RightBracket, ref Range leftBracketPosition, ref Range rightBracketPosition)
6991         {
6992             if (!Selection.IsEmpty)
6993                 return;
6994             if (LinesCount == 0)
6995                 return;
6996             //
6997             Range oldLeftBracketPosition = leftBracketPosition;
6998             Range oldRightBracketPosition = rightBracketPosition;
6999             Range range = Selection.Clone(); //need clone because we will move caret
7000 
7001             bool found = false;
7002             int counter = 0;
7003             int maxIterations = maxBracketSearchIterations;
7004             if (range.CharBeforeStart == RightBracket)
7005             {
7006                 rightBracketPosition = new Range(this, range.Start.iChar - 1, range.Start.iLine, range.Start.iChar, range.Start.iLine);
7007                 while (range.GoLeftThroughFolded()) //move caret left
7008                 {
7009                     if (range.CharAfterStart == LeftBracket) counter++;
7010                     if (range.CharAfterStart == RightBracket) counter--;
7011                     if (counter == 0)
7012                     {
7013                         //highlighting
7014                         range.End = new Place(range.Start.iChar + 1, range.Start.iLine);
7015                         leftBracketPosition = range;
7016                         found = true;
7017                         break;
7018                     }
7019                     //
7020                     maxIterations--;
7021                     if (maxIterations <= 0) break;
7022                 }
7023             }
7024             //
7025             range = Selection.Clone(); //need clone because we will move caret
7026             counter = 0;
7027             maxIterations = maxBracketSearchIterations;
7028             if(!found)
7029             if (range.CharAfterStart == LeftBracket)
7030             {
7031                 leftBracketPosition = new Range(this, range.Start.iChar, range.Start.iLine, range.Start.iChar + 1, range.Start.iLine);
7032                 do
7033                 {
7034                     if (range.CharAfterStart == LeftBracket) counter++;
7035                     if (range.CharAfterStart == RightBracket) counter--;
7036                     if (counter == 0)
7037                     {
7038                         //highlighting
7039                         range.End = new Place(range.Start.iChar + 1, range.Start.iLine);
7040                         rightBracketPosition = range;
7041                         found = true;
7042                         break;
7043                     }
7044                     //
7045                     maxIterations--;
7046                     if (maxIterations <= 0) break;
7047                 } while (range.GoRightThroughFolded()); //move caret right
7048             }
7049 
7050             if (oldLeftBracketPosition != leftBracketPosition || oldRightBracketPosition != rightBracketPosition)
7051                 Invalidate();
7052         }
7053 
7054         /// <summary>
7055         /// Selectes next fragment for given regex.
7056         /// </summary>
SelectNext(string regexPattern, bool backward = false, RegexOptions options = RegexOptions.None)7057         public bool SelectNext(string regexPattern, bool backward = false, RegexOptions options = RegexOptions.None)
7058         {
7059             var sel = Selection.Clone();
7060             sel.Normalize();
7061             var range1 = backward ? new Range(this, Range.Start, sel.Start) : new Range(this, sel.End, Range.End);
7062 
7063             Range res = null;
7064             foreach(var r in range1.GetRanges(regexPattern, options))
7065             {
7066                 res = r;
7067                 if (!backward) break;
7068             }
7069 
7070             if (res == null) return false;
7071             Selection = res;
7072             Invalidate();
7073             return true;
7074         }
7075 
OnSyntaxHighlight(TextChangedEventArgs args)7076         public virtual void OnSyntaxHighlight(TextChangedEventArgs args)
7077         {
7078             #if debug
7079             Stopwatch sw = Stopwatch.StartNew();
7080             #endif
7081 
7082             Range range;
7083 
7084             switch (HighlightingRangeType)
7085             {
7086                 case HighlightingRangeType.VisibleRange:
7087                     range = VisibleRange.GetUnionWith(args.ChangedRange);
7088                     break;
7089                 case HighlightingRangeType.AllTextRange:
7090                     range = Range;
7091                     break;
7092                 default:
7093                     range = args.ChangedRange;
7094                     break;
7095             }
7096 
7097             if (SyntaxHighlighter != null)
7098             {
7099                 if (Language == Language.Custom && SyntaxDescriptor != null)
7100                     SyntaxHighlighter.HighlightSyntax(SyntaxDescriptor, range);
7101                 else
7102                     SyntaxHighlighter.HighlightSyntax(Language, range);
7103             }
7104 
7105 #if debug
7106             Console.WriteLine("OnSyntaxHighlight: "+ sw.ElapsedMilliseconds);
7107 #endif
7108         }
7109 
InitializeComponent()7110         private void InitializeComponent()
7111         {
7112             SuspendLayout();
7113             //
7114             // FastColoredTextBox
7115             //
7116             Name = "FastColoredTextBox";
7117             ResumeLayout(false);
7118         }
7119 
7120         /// <summary>
7121         /// Prints range of text
7122         /// </summary>
Print(Range range, PrintDialogSettings settings)7123         public virtual void Print(Range range, PrintDialogSettings settings)
7124         {
7125             //prepare export with wordwrapping
7126             var exporter = new ExportToHTML();
7127             exporter.UseBr = true;
7128             exporter.UseForwardNbsp = true;
7129             exporter.UseNbsp = true;
7130             exporter.UseStyleTag = false;
7131             exporter.IncludeLineNumbers = settings.IncludeLineNumbers;
7132 
7133             if (range == null)
7134                 range = Range;
7135 
7136             if (range.Text == string.Empty)
7137                 return;
7138 
7139             //change visible range
7140             visibleRange = range;
7141             try
7142             {
7143                 //call handlers for VisibleRange
7144                 if (VisibleRangeChanged != null)
7145                     VisibleRangeChanged(this, new EventArgs());
7146                 if (VisibleRangeChangedDelayed != null)
7147                     VisibleRangeChangedDelayed(this, new EventArgs());
7148             }
7149             finally
7150             {
7151                 //restore visible range
7152                 visibleRange = null;
7153             }
7154 
7155             //generate HTML
7156             string HTML = exporter.GetHtml(range);
7157             HTML = "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=UTF-8\"><head><title>" +
7158                    PrepareHtmlText(settings.Title) + "</title></head>" + HTML +"<br>"+ SelectHTMLRangeScript();
7159             string tempFile = Path.GetTempPath() + "fctb.html";
7160             File.WriteAllText(tempFile, HTML);
7161 
7162             //clear wb page setup settings
7163             SetPageSetupSettings(settings);
7164 
7165             //create wb
7166             var wb = new WebBrowser();
7167             wb.Tag = settings;
7168             wb.Visible = false;
7169             wb.Location = new Point(-1000, -1000);
7170             wb.Parent = this;
7171             wb.StatusTextChanged += wb_StatusTextChanged;
7172             wb.Navigate(tempFile);
7173         }
7174 
PrepareHtmlText(string s)7175         protected virtual string PrepareHtmlText(string s)
7176         {
7177             return s.Replace("<", "&lt;").Replace(">", "&gt;").Replace("&", "&amp;");
7178         }
7179 
wb_StatusTextChanged(object sender, EventArgs e)7180         private void wb_StatusTextChanged(object sender, EventArgs e)
7181         {
7182             var wb = sender as WebBrowser;
7183             if (wb.StatusText.Contains("#print"))
7184             {
7185                 var settings = wb.Tag as PrintDialogSettings;
7186                 try
7187                 {
7188                     //show print dialog
7189                     if (settings.ShowPrintPreviewDialog)
7190                         wb.ShowPrintPreviewDialog();
7191                     else
7192                     {
7193                         if (settings.ShowPageSetupDialog)
7194                             wb.ShowPageSetupDialog();
7195 
7196                         if (settings.ShowPrintDialog)
7197                             wb.ShowPrintDialog();
7198                         else
7199                             wb.Print();
7200                     }
7201                 }
7202                 finally
7203                 {
7204                     //destroy webbrowser
7205                     wb.Parent = null;
7206                     wb.Dispose();
7207                 }
7208             }
7209         }
7210 
7211         /// <summary>
7212         /// Prints all text
7213         /// </summary>
Print(PrintDialogSettings settings)7214         public void Print(PrintDialogSettings settings)
7215         {
7216             Print(Range, settings);
7217         }
7218 
7219         /// <summary>
7220         /// Prints all text, without any dialog windows
7221         /// </summary>
Print()7222         public void Print()
7223         {
7224             Print(Range,
7225                   new PrintDialogSettings
7226                       {ShowPageSetupDialog = false, ShowPrintDialog = false, ShowPrintPreviewDialog = false});
7227         }
7228 
SelectHTMLRangeScript()7229         private string SelectHTMLRangeScript()
7230         {
7231             Range sel = Selection.Clone();
7232             sel.Normalize();
7233             int start = PlaceToPosition(sel.Start) - sel.Start.iLine;
7234             int len = sel.Text.Length - (sel.End.iLine - sel.Start.iLine);
7235             return string.Format(
7236                 @"<script type=""text/javascript"">
7237 try{{
7238     var sel = document.selection;
7239     var rng = sel.createRange();
7240     rng.moveStart(""character"", {0});
7241     rng.moveEnd(""character"", {1});
7242     rng.select();
7243 }}catch(ex){{}}
7244 window.status = ""#print"";
7245 </script>",
7246                 start, len);
7247         }
7248 
SetPageSetupSettings(PrintDialogSettings settings)7249         private static void SetPageSetupSettings(PrintDialogSettings settings)
7250         {
7251             RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Internet Explorer\PageSetup", true);
7252             if (key != null)
7253             {
7254                 key.SetValue("footer", settings.Footer);
7255                 key.SetValue("header", settings.Header);
7256             }
7257         }
7258 
Dispose(bool disposing)7259         protected override void Dispose(bool disposing)
7260         {
7261             base.Dispose(disposing);
7262             if (disposing)
7263             {
7264                 if (SyntaxHighlighter != null)
7265                     SyntaxHighlighter.Dispose();
7266                 timer.Dispose();
7267                 timer2.Dispose();
7268                 middleClickScrollingTimer.Dispose();
7269 
7270                 if (findForm != null)
7271                     findForm.Dispose();
7272 
7273                 if (replaceForm != null)
7274                     replaceForm.Dispose();
7275                 /*
7276                 if (Font != null)
7277                     Font.Dispose();
7278 
7279                 if (originalFont != null)
7280                     originalFont.Dispose();*/
7281 
7282                 if (TextSource != null)
7283                     TextSource.Dispose();
7284 
7285                 if (ToolTip != null)
7286                     ToolTip.Dispose();
7287 
7288                 if (SyntaxDescriptor != null)
7289                     SyntaxDescriptor.Dispose();
7290             }
7291         }
7292 
OnPaintLine(PaintLineEventArgs e)7293         protected virtual void OnPaintLine(PaintLineEventArgs e)
7294         {
7295             if (PaintLine != null)
7296                 PaintLine(this, e);
7297         }
7298 
OnLineInserted(int index)7299         internal void OnLineInserted(int index)
7300         {
7301             OnLineInserted(index, 1);
7302         }
7303 
OnLineInserted(int index, int count)7304         internal void OnLineInserted(int index, int count)
7305         {
7306             if (LineInserted != null)
7307                 LineInserted(this, new LineInsertedEventArgs(index, count));
7308         }
7309 
OnLineRemoved(int index, int count, List<int> removedLineIds)7310         internal void OnLineRemoved(int index, int count, List<int> removedLineIds)
7311         {
7312             if (count > 0)
7313                 if (LineRemoved != null)
7314                     LineRemoved(this, new LineRemovedEventArgs(index, count, removedLineIds));
7315         }
7316 
7317         /// <summary>
7318         /// Open text file
7319         /// </summary>
OpenFile(string fileName, Encoding enc)7320         public void OpenFile(string fileName, Encoding enc)
7321         {
7322             var ts = CreateTextSource();
7323             try
7324             {
7325                 InitTextSource(ts);
7326                 Text = File.ReadAllText(fileName, enc);
7327                 ClearUndo();
7328                 IsChanged = false;
7329                 OnVisibleRangeChanged();
7330             }
7331             catch
7332             {
7333                 InitTextSource(CreateTextSource());
7334                 lines.InsertLine(0, TextSource.CreateLine());
7335                 IsChanged = false;
7336                 throw;
7337             }
7338             Selection.Start = Place.Empty;
7339             DoSelectionVisible();
7340         }
7341 
7342         /// <summary>
7343         /// Open text file (with automatic encoding detector)
7344         /// </summary>
OpenFile(string fileName)7345         public void OpenFile(string fileName)
7346         {
7347             try
7348             {
7349                 var enc = EncodingDetector.DetectTextFileEncoding(fileName);
7350                 if (enc != null)
7351                     OpenFile(fileName, enc);
7352                 else
7353                     OpenFile(fileName, Encoding.Default);
7354             }
7355             catch
7356             {
7357                 InitTextSource(CreateTextSource());
7358                 lines.InsertLine(0, TextSource.CreateLine());
7359                 IsChanged = false;
7360                 throw;
7361             }
7362         }
7363 
7364         /// <summary>
7365         /// Open file binding mode
7366         /// </summary>
7367         /// <param name="fileName"></param>
7368         /// <param name="enc"></param>
OpenBindingFile(string fileName, Encoding enc)7369         public void OpenBindingFile(string fileName, Encoding enc)
7370         {
7371             var fts = new FileTextSource(this);
7372             try
7373             {
7374                 InitTextSource(fts);
7375                 fts.OpenFile(fileName, enc);
7376                 IsChanged = false;
7377                 OnVisibleRangeChanged();
7378             }
7379             catch
7380             {
7381                 fts.CloseFile();
7382                 InitTextSource(CreateTextSource());
7383                 lines.InsertLine(0, TextSource.CreateLine());
7384                 IsChanged = false;
7385                 throw;
7386             }
7387             Invalidate();
7388         }
7389 
7390         /// <summary>
7391         /// Close file binding mode
7392         /// </summary>
CloseBindingFile()7393         public void CloseBindingFile()
7394         {
7395             if (lines is FileTextSource)
7396             {
7397                 var fts = lines as FileTextSource;
7398                 fts.CloseFile();
7399 
7400                 InitTextSource(CreateTextSource());
7401                 lines.InsertLine(0, TextSource.CreateLine());
7402                 IsChanged = false;
7403                 Invalidate();
7404             }
7405         }
7406 
7407         /// <summary>
7408         /// Save text to the file
7409         /// </summary>
7410         /// <param name="fileName"></param>
7411         /// <param name="enc"></param>
SaveToFile(string fileName, Encoding enc)7412         public void SaveToFile(string fileName, Encoding enc)
7413         {
7414             lines.SaveToFile(fileName, enc);
7415             IsChanged = false;
7416             OnVisibleRangeChanged();
7417             UpdateScrollbars();
7418         }
7419 
7420         /// <summary>
7421         /// Set VisibleState of line
7422         /// </summary>
SetVisibleState(int iLine, VisibleState state)7423         public void SetVisibleState(int iLine, VisibleState state)
7424         {
7425             LineInfo li = LineInfos[iLine];
7426             li.VisibleState = state;
7427             LineInfos[iLine] = li;
7428             needRecalc = true;
7429         }
7430 
7431         /// <summary>
7432         /// Returns VisibleState of the line
7433         /// </summary>
GetVisibleState(int iLine)7434         public VisibleState GetVisibleState(int iLine)
7435         {
7436             return LineInfos[iLine].VisibleState;
7437         }
7438 
7439         /// <summary>
7440         /// Shows Goto dialog form
7441         /// </summary>
ShowGoToDialog()7442         public void ShowGoToDialog()
7443         {
7444             var form = new GoToForm();
7445             form.StartPosition = FormStartPosition.CenterParent;
7446             form.TotalLineCount = LinesCount;
7447             form.SelectedLineNumber = Selection.Start.iLine + 1;
7448 
7449             if (form.ShowDialog(this) == DialogResult.OK)
7450             {
7451                 int line = Math.Min(LinesCount - 1, Math.Max(0, form.SelectedLineNumber - 1));
7452                 Selection = new Range(this, 0, line, 0, line);
7453                 DoSelectionVisible();
7454             }
7455         }
7456 
7457         /// <summary>
7458         /// Occurs when undo/redo stack is changed
7459         /// </summary>
OnUndoRedoStateChanged()7460         public void OnUndoRedoStateChanged()
7461         {
7462             if (UndoRedoStateChanged != null)
7463                 UndoRedoStateChanged(this, EventArgs.Empty);
7464         }
7465 
7466         /// <summary>
7467         /// Search lines by regex pattern
7468         /// </summary>
FindLines(string searchPattern, RegexOptions options)7469         public List<int> FindLines(string searchPattern, RegexOptions options)
7470         {
7471             var iLines = new List<int>();
7472             foreach (Range r in Range.GetRangesByLines(searchPattern, options))
7473                 iLines.Add(r.Start.iLine);
7474 
7475             return iLines;
7476         }
7477 
7478         /// <summary>
7479         /// Removes given lines
7480         /// </summary>
RemoveLines(List<int> iLines)7481         public void RemoveLines(List<int> iLines)
7482         {
7483             TextSource.Manager.ExecuteCommand(new RemoveLinesCommand(TextSource, iLines));
7484             if (iLines.Count > 0)
7485                 IsChanged = true;
7486             if (LinesCount == 0)
7487                 Text = "";
7488             NeedRecalc();
7489             Invalidate();
7490         }
7491 
ISupportInitialize.BeginInit()7492         void ISupportInitialize.BeginInit()
7493         {
7494             //
7495         }
7496 
ISupportInitialize.EndInit()7497         void ISupportInitialize.EndInit()
7498         {
7499             OnTextChanged();
7500             Selection.Start = Place.Empty;
7501             DoCaretVisible();
7502             IsChanged = false;
7503             ClearUndo();
7504         }
7505 
7506         #region Drag and drop
7507 
7508         private bool IsDragDrop { get; set; }
7509 
7510 
OnDragEnter(DragEventArgs e)7511         protected override void OnDragEnter(DragEventArgs e)
7512         {
7513             if (e.Data.GetDataPresent(DataFormats.Text) && AllowDrop)
7514             {
7515                 e.Effect = DragDropEffects.Copy;
7516                 IsDragDrop = true;
7517             }
7518             base.OnDragEnter(e);
7519         }
7520 
OnDragDrop(DragEventArgs e)7521         protected override void OnDragDrop(DragEventArgs e)
7522         {
7523             if (ReadOnly || !AllowDrop)
7524             {
7525                 IsDragDrop = false;
7526                 return;
7527             }
7528 
7529             if (e.Data.GetDataPresent(DataFormats.Text))
7530             {
7531                 if (ParentForm != null)
7532                     ParentForm.Activate();
7533                 Focus();
7534                 Point p = PointToClient(new Point(e.X, e.Y));
7535                 var text = e.Data.GetData(DataFormats.Text).ToString();
7536                 var place = PointToPlace(p);
7537                 DoDragDrop(place, text);
7538                 IsDragDrop = false;
7539             }
7540             base.OnDragDrop(e);
7541         }
7542 
DoDragDrop_old(Place place, string text)7543         private void DoDragDrop_old(Place place, string text)
7544         {
7545             Range insertRange = new Range(this, place, place);
7546 
7547             // Abort, if insertRange is read only
7548             if (insertRange.ReadOnly)
7549                 return;
7550 
7551             // Abort, if dragged range contains target place
7552             if ((draggedRange != null) && (draggedRange.Contains(place) == true))
7553                 return;
7554 
7555             // Determine, if the dragged string should be copied or moved
7556             bool copyMode =
7557                 (draggedRange == null) ||       // drag from outside
7558                 (draggedRange.ReadOnly) ||      // dragged range is read only
7559                 ((ModifierKeys & Keys.Control) != Keys.None);
7560 
7561             //drag from outside?
7562             if (draggedRange == null)
7563             {
7564                 Selection.BeginUpdate();
7565                 // Insert text
7566                 Selection.Start = place;
7567                 InsertText(text);
7568                 // Select inserted text
7569                 Selection = new Range(this, place, Selection.Start);
7570                 Selection.EndUpdate();
7571                 return;
7572             }
7573 
7574             //drag from me
7575             Place caretPositionAfterInserting;
7576             BeginAutoUndo();
7577             Selection.BeginUpdate();
7578 
7579             //remember dragged selection for undo/redo
7580             Selection = draggedRange;
7581             lines.Manager.ExecuteCommand(new SelectCommand(lines));
7582             //
7583             if (draggedRange.ColumnSelectionMode)
7584             {
7585                 draggedRange.Normalize();
7586                 insertRange = new Range(this, place, new Place(place.iChar, place.iLine + draggedRange.End.iLine - draggedRange.Start.iLine)) { ColumnSelectionMode = true };
7587                 for (int i = LinesCount; i <= insertRange.End.iLine; i++)
7588                 {
7589                     Selection.GoLast(false);
7590                     InsertChar('\n');
7591                 }
7592             }
7593 
7594             if (!insertRange.ReadOnly)
7595             {
7596                 if (place < draggedRange.Start)
7597                 {
7598                     // Delete dragged range if not in copy mode
7599                     if (copyMode == false)
7600                     {
7601                         Selection = draggedRange;
7602                         ClearSelected();
7603                     }
7604 
7605                     // Insert text
7606                     Selection = insertRange;
7607                     Selection.ColumnSelectionMode = insertRange.ColumnSelectionMode;
7608                     InsertText(text);
7609                     caretPositionAfterInserting = Selection.Start;
7610                 }
7611                 else
7612                 {
7613                     // Insert text
7614                     Selection = insertRange;
7615                     Selection.ColumnSelectionMode = insertRange.ColumnSelectionMode;
7616                     InsertText(text);
7617                     caretPositionAfterInserting = Selection.Start;
7618                     var lineLength = this[caretPositionAfterInserting.iLine].Count;
7619 
7620                     // Delete dragged range if not in copy mode
7621                     if (copyMode == false)
7622                     {
7623                         Selection = draggedRange;
7624                         ClearSelected();
7625                     }
7626 
7627                     var shift = lineLength - this[caretPositionAfterInserting.iLine].Count;
7628                     caretPositionAfterInserting.iChar = caretPositionAfterInserting.iChar - shift;
7629                     place.iChar = place.iChar - shift;
7630                 }
7631 
7632                 // Select inserted text
7633                 if (!draggedRange.ColumnSelectionMode)
7634                 {
7635                     Selection = new Range(this, place, caretPositionAfterInserting);
7636                 }
7637                 else
7638                 {
7639                     draggedRange.Normalize();
7640                     Selection = new Range(this, place,
7641                                             new Place(place.iChar + draggedRange.End.iChar - draggedRange.Start.iChar,
7642                                                     place.iLine + draggedRange.End.iLine - draggedRange.Start.iLine)) { ColumnSelectionMode = true };
7643                 }
7644             }
7645 
7646             Selection.EndUpdate();
7647             EndAutoUndo();
7648             draggedRange = null;
7649         }
7650 
DoDragDrop(Place place, string text)7651         protected virtual void DoDragDrop(Place place, string text)
7652         {
7653             Range insertRange = new Range(this, place, place);
7654 
7655             // Abort, if insertRange is read only
7656             if (insertRange.ReadOnly)
7657                 return;
7658 
7659             // Abort, if dragged range contains target place
7660             if ((draggedRange != null) && (draggedRange.Contains(place) == true))
7661                 return;
7662 
7663             // Determine, if the dragged string should be copied or moved
7664             bool copyMode =
7665                 (draggedRange == null) ||       // drag from outside
7666                 (draggedRange.ReadOnly) ||      // dragged range is read only
7667                 ((ModifierKeys & Keys.Control) != Keys.None);
7668 
7669             if (draggedRange == null)//drag from outside
7670             {
7671                 Selection.BeginUpdate();
7672                 // Insert text
7673                 Selection.Start = place;
7674                 InsertText(text);
7675                 // Select inserted text
7676                 Selection = new Range(this, place, Selection.Start);
7677                 Selection.EndUpdate();
7678             }
7679             else//drag from me
7680             {
7681                 if (!draggedRange.Contains(place))
7682                 {
7683                     BeginAutoUndo();
7684 
7685                     //remember dragged selection for undo/redo
7686                     Selection = draggedRange;
7687                     lines.Manager.ExecuteCommand(new SelectCommand(lines));
7688                     //
7689                     if (draggedRange.ColumnSelectionMode)
7690                     {
7691                         draggedRange.Normalize();
7692                         insertRange = new Range(this, place, new Place(place.iChar, place.iLine + draggedRange.End.iLine - draggedRange.Start.iLine)) { ColumnSelectionMode = true };
7693                         for (int i = LinesCount; i <= insertRange.End.iLine; i++)
7694                         {
7695                             Selection.GoLast(false);
7696                             InsertChar('\n');
7697                         }
7698                     }
7699 
7700                     if (!insertRange.ReadOnly)
7701                     {
7702                         if (place < draggedRange.Start)
7703                         {
7704                             // Delete dragged range if not in copy mode
7705                             if (copyMode == false)
7706                             {
7707                                 Selection = draggedRange;
7708                                 ClearSelected();
7709                             }
7710 
7711                             // Insert text
7712                             Selection = insertRange;
7713                             Selection.ColumnSelectionMode = insertRange.ColumnSelectionMode;
7714                             InsertText(text);
7715                         }
7716                         else
7717                         {
7718                             // Insert text
7719                             Selection = insertRange;
7720                             Selection.ColumnSelectionMode = insertRange.ColumnSelectionMode;
7721                             InsertText(text);
7722 
7723                             // Delete dragged range if not in copy mode
7724                             if (copyMode == false)
7725                             {
7726                                 Selection = draggedRange;
7727                                 ClearSelected();
7728                             }
7729                         }
7730                     }
7731 
7732                     // Selection start and end position
7733                     Place startPosition = place;
7734                     Place endPosition = Selection.Start;
7735 
7736                     // Correct selection
7737                     Range dR = (draggedRange.End > draggedRange.Start)  // dragged selection
7738                         ? this.GetRange(draggedRange.Start, draggedRange.End)
7739                         : this.GetRange(draggedRange.End, draggedRange.Start);
7740                     Place tP = place; // targetPlace
7741                     int tS_S_Line;  // targetSelection.Start.iLine
7742                     int tS_S_Char;  // targetSelection.Start.iChar
7743                     int tS_E_Line;  // targetSelection.End.iLine
7744                     int tS_E_Char;  // targetSelection.End.iChar
7745                     if ((place > draggedRange.Start) && (copyMode == false))
7746                     {
7747                         if (draggedRange.ColumnSelectionMode == false)
7748                         {
7749                             // Normal selection mode:
7750 
7751                             // Determine character/column position of target selection
7752                             if (dR.Start.iLine != dR.End.iLine) // If more then one line was selected/dragged ...
7753                             {
7754                                 tS_S_Char = (dR.End.iLine != tP.iLine)
7755                                     ? tP.iChar
7756                                     : dR.Start.iChar + (tP.iChar - dR.End.iChar);
7757                                 tS_E_Char = dR.End.iChar;
7758                             }
7759                             else // only one line was selected/dragged
7760                             {
7761                                 if (dR.End.iLine == tP.iLine)
7762                                 {
7763                                     tS_S_Char = tP.iChar - dR.Text.Length;
7764                                     tS_E_Char = tP.iChar;
7765                                 }
7766                                 else
7767                                 {
7768                                     tS_S_Char = tP.iChar;
7769                                     tS_E_Char = tP.iChar + dR.Text.Length;
7770                                 }
7771                             }
7772 
7773                             // Determine line/row of target selection
7774                             if (dR.End.iLine != tP.iLine)
7775                             {
7776                                 tS_S_Line = tP.iLine - (dR.End.iLine - dR.Start.iLine);
7777                                 tS_E_Line = tP.iLine;
7778                             }
7779                             else
7780                             {
7781                                 tS_S_Line = dR.Start.iLine;
7782                                 tS_E_Line = dR.End.iLine;
7783                             }
7784 
7785                             startPosition = new Place(tS_S_Char, tS_S_Line);
7786                             endPosition = new Place(tS_E_Char, tS_E_Line);
7787                         }
7788                     }
7789 
7790 
7791                     // Select inserted text
7792                     if (!draggedRange.ColumnSelectionMode)
7793                         Selection = new Range(this, startPosition, endPosition);
7794                     else
7795                     {
7796                         if ((copyMode == false) &&
7797                             (place.iLine >= dR.Start.iLine) && (place.iLine <= dR.End.iLine) &&
7798                             (place.iChar >= dR.End.iChar))
7799                         {
7800                             tS_S_Char = tP.iChar - (dR.End.iChar - dR.Start.iChar);
7801                             tS_E_Char = tP.iChar;
7802                         }
7803                         else
7804                         {
7805                             tS_S_Char = tP.iChar;
7806                             tS_E_Char = tP.iChar + (dR.End.iChar - dR.Start.iChar);
7807                         }
7808                         tS_S_Line = tP.iLine;
7809                         tS_E_Line = tP.iLine + (dR.End.iLine - dR.Start.iLine);
7810 
7811                         startPosition = new Place(tS_S_Char, tS_S_Line);
7812                         endPosition = new Place(tS_E_Char, tS_E_Line);
7813                         Selection = new Range(this, startPosition, endPosition)
7814                         {
7815                             ColumnSelectionMode = true
7816                         };
7817                     }
7818 
7819                     EndAutoUndo();
7820                 }
7821 
7822                 this.selection.Inverse();
7823                 OnSelectionChanged();
7824             }
7825             draggedRange = null;
7826         }
7827 
OnDragOver(DragEventArgs e)7828         protected override void OnDragOver(DragEventArgs e)
7829         {
7830             if (e.Data.GetDataPresent(DataFormats.Text))
7831             {
7832                 Point p = PointToClient(new Point(e.X, e.Y));
7833                 Selection.Start = PointToPlace(p);
7834                 if (p.Y < 6 && VerticalScroll.Visible && VerticalScroll.Value > 0)
7835                     VerticalScroll.Value = Math.Max(0, VerticalScroll.Value - charHeight);
7836 
7837                 DoCaretVisible();
7838                 Invalidate();
7839             }
7840             base.OnDragOver(e);
7841         }
7842 
OnDragLeave(EventArgs e)7843         protected override void OnDragLeave(EventArgs e)
7844         {
7845             IsDragDrop = false;
7846             base.OnDragLeave(e);
7847         }
7848 
7849         #endregion
7850 
7851         #region MiddleClickScrolling
7852 
7853         private bool middleClickScrollingActivated;
7854         private Point middleClickScrollingOriginPoint;
7855         private Point middleClickScrollingOriginScroll;
7856         private readonly Timer middleClickScrollingTimer = new Timer();
7857         private ScrollDirection middleClickScollDirection = ScrollDirection.None;
7858         private const int WM_SETREDRAW = 0xB;
7859 
7860         /// <summary>
7861         /// Activates the scrolling mode (middle click button).
7862         /// </summary>
7863         /// <param name="e">MouseEventArgs</param>
ActivateMiddleClickScrollingMode(MouseEventArgs e)7864         private void ActivateMiddleClickScrollingMode(MouseEventArgs e)
7865         {
7866             if (!middleClickScrollingActivated)
7867             {
7868                 if ((!HorizontalScroll.Visible) && (!VerticalScroll.Visible))
7869                 if (ShowScrollBars)
7870                     return;
7871                 middleClickScrollingActivated = true;
7872                 middleClickScrollingOriginPoint = e.Location;
7873                 middleClickScrollingOriginScroll = new Point(HorizontalScroll.Value, VerticalScroll.Value);
7874                 middleClickScrollingTimer.Interval = 50;
7875                 middleClickScrollingTimer.Enabled = true;
7876                 Capture = true;
7877                 // Refresh the control
7878                 Refresh();
7879                 // Disable drawing
7880                 NativeMethodsWrapper.SendMessage(Handle, WM_SETREDRAW, 0, 0);
7881             }
7882         }
7883 
7884         /// <summary>
7885         /// Deactivates the scrolling mode (middle click button).
7886         /// </summary>
DeactivateMiddleClickScrollingMode()7887         private void DeactivateMiddleClickScrollingMode()
7888         {
7889             if (middleClickScrollingActivated)
7890             {
7891                 middleClickScrollingActivated = false;
7892                 middleClickScrollingTimer.Enabled = false;
7893                 Capture = false;
7894                 base.Cursor = defaultCursor;
7895                 // Enable drawing
7896                 NativeMethodsWrapper.SendMessage(Handle, WM_SETREDRAW, 1, 0);
7897                 Invalidate();
7898             }
7899         }
7900 
7901         /// <summary>
7902         /// Restore scrolls
7903         /// </summary>
RestoreScrollsAfterMiddleClickScrollingMode()7904         private void RestoreScrollsAfterMiddleClickScrollingMode()
7905         {
7906             var xea = new ScrollEventArgs(ScrollEventType.ThumbPosition,
7907                 HorizontalScroll.Value,
7908                 middleClickScrollingOriginScroll.X,
7909                 ScrollOrientation.HorizontalScroll);
7910             OnScroll(xea);
7911 
7912             var yea = new ScrollEventArgs(ScrollEventType.ThumbPosition,
7913                 VerticalScroll.Value,
7914                 middleClickScrollingOriginScroll.Y,
7915                 ScrollOrientation.VerticalScroll);
7916             OnScroll(yea);
7917         }
7918 
middleClickScrollingTimer_Tick(object sender, EventArgs e)7919         void middleClickScrollingTimer_Tick(object sender, EventArgs e)
7920         {
7921             if (IsDisposed)
7922                 return;
7923 
7924             if (!middleClickScrollingActivated)
7925                 return;
7926 
7927             Point currentMouseLocation = PointToClient(Cursor.Position);
7928 
7929             Capture = true;
7930 
7931             // Calculate angle and distance between current position point and origin point
7932             int distanceX = this.middleClickScrollingOriginPoint.X - currentMouseLocation.X;
7933             int distanceY = this.middleClickScrollingOriginPoint.Y - currentMouseLocation.Y;
7934 
7935             if (!VerticalScroll.Visible && ShowScrollBars) distanceY = 0;
7936             if (!HorizontalScroll.Visible && ShowScrollBars) distanceX = 0;
7937 
7938             double angleInDegree = 180 - Math.Atan2(distanceY, distanceX) * 180 / Math.PI;
7939             double distance = Math.Sqrt(Math.Pow(distanceX, 2) + Math.Pow(distanceY, 2));
7940 
7941             // determine scrolling direction depending on the angle
7942             if (distance > 10)
7943             {
7944                 if (angleInDegree >= 325 || angleInDegree <= 35)
7945                     this.middleClickScollDirection = ScrollDirection.Right;
7946                 else if (angleInDegree <= 55)
7947                     this.middleClickScollDirection = ScrollDirection.Right | ScrollDirection.Up;
7948                 else if (angleInDegree <= 125)
7949                     this.middleClickScollDirection = ScrollDirection.Up;
7950                 else if (angleInDegree <= 145)
7951                     this.middleClickScollDirection = ScrollDirection.Up | ScrollDirection.Left;
7952                 else if (angleInDegree <= 215)
7953                     this.middleClickScollDirection = ScrollDirection.Left;
7954                 else if (angleInDegree <= 235)
7955                     this.middleClickScollDirection = ScrollDirection.Left | ScrollDirection.Down;
7956                 else if (angleInDegree <= 305)
7957                     this.middleClickScollDirection = ScrollDirection.Down;
7958                 else
7959                     this.middleClickScollDirection = ScrollDirection.Down | ScrollDirection.Right;
7960             }
7961             else
7962             {
7963                 this.middleClickScollDirection = ScrollDirection.None;
7964             }
7965 
7966             // Set mouse cursor
7967             switch (this.middleClickScollDirection)
7968             {
7969                 case ScrollDirection.Right: base.Cursor = Cursors.PanEast; break;
7970                 case ScrollDirection.Right | ScrollDirection.Up: base.Cursor = Cursors.PanNE; break;
7971                 case ScrollDirection.Up: base.Cursor = Cursors.PanNorth; break;
7972                 case ScrollDirection.Up | ScrollDirection.Left: base.Cursor = Cursors.PanNW; break;
7973                 case ScrollDirection.Left: base.Cursor = Cursors.PanWest; break;
7974                 case ScrollDirection.Left | ScrollDirection.Down: base.Cursor = Cursors.PanSW; break;
7975                 case ScrollDirection.Down: base.Cursor = Cursors.PanSouth; break;
7976                 case ScrollDirection.Down | ScrollDirection.Right: base.Cursor = Cursors.PanSE; break;
7977                 default: base.Cursor = defaultCursor; return;
7978             }
7979 
7980             var xScrollOffset = (int)(-distanceX / 5.0);
7981             var yScrollOffset = (int)(-distanceY / 5.0);
7982 
7983             var xea = new ScrollEventArgs(xScrollOffset < 0 ? ScrollEventType.SmallIncrement : ScrollEventType.SmallDecrement,
7984                 HorizontalScroll.Value,
7985                 HorizontalScroll.Value + xScrollOffset,
7986                 ScrollOrientation.HorizontalScroll);
7987 
7988             var yea = new ScrollEventArgs(yScrollOffset < 0 ? ScrollEventType.SmallDecrement : ScrollEventType.SmallIncrement,
7989                 VerticalScroll.Value,
7990                 VerticalScroll.Value + yScrollOffset,
7991                 ScrollOrientation.VerticalScroll);
7992 
7993             if ((middleClickScollDirection & (ScrollDirection.Down | ScrollDirection.Up)) > 0)
7994                 //DoScrollVertical(1 + Math.Abs(yScrollOffset), Math.Sign(distanceY));
7995                 OnScroll(yea, false);
7996 
7997             if ((middleClickScollDirection & (ScrollDirection.Right | ScrollDirection.Left)) > 0)
7998                 OnScroll(xea);
7999 
8000             // Enable drawing
8001             NativeMethodsWrapper.SendMessage(Handle, WM_SETREDRAW, 1, 0);
8002             // Refresh the control
8003             Refresh();
8004             // Disable drawing
8005             NativeMethodsWrapper.SendMessage(Handle, WM_SETREDRAW, 0, 0);
8006         }
8007 
DrawMiddleClickScrolling(Graphics gr)8008         private void DrawMiddleClickScrolling(Graphics gr)
8009         {
8010             // If mouse scrolling mode activated draw the scrolling cursor image
8011             bool ableToScrollVertically = this.VerticalScroll.Visible || !ShowScrollBars;
8012             bool ableToScrollHorizontally = this.HorizontalScroll.Visible || !ShowScrollBars;
8013 
8014             // Calculate inverse color
8015             Color inverseColor = Color.FromArgb(100, (byte)~this.BackColor.R, (byte)~this.BackColor.G, (byte)~this.BackColor.B);
8016             using (SolidBrush inverseColorBrush = new SolidBrush(inverseColor))
8017             {
8018                 var p = middleClickScrollingOriginPoint;
8019 
8020                 var state = gr.Save();
8021 
8022                 gr.SmoothingMode = SmoothingMode.HighQuality;
8023                 gr.TranslateTransform(p.X, p.Y);
8024                 gr.FillEllipse(inverseColorBrush, -2, -2, 4, 4);
8025 
8026                 if (ableToScrollVertically) DrawTriangle(gr, inverseColorBrush);
8027                 gr.RotateTransform(90);
8028                 if (ableToScrollHorizontally) DrawTriangle(gr, inverseColorBrush);
8029                 gr.RotateTransform(90);
8030                 if (ableToScrollVertically) DrawTriangle(gr, inverseColorBrush);
8031                 gr.RotateTransform(90);
8032                 if (ableToScrollHorizontally) DrawTriangle(gr, inverseColorBrush);
8033 
8034                 gr.Restore(state);
8035             }
8036         }
8037 
DrawTriangle(Graphics g, Brush brush)8038         private void DrawTriangle(Graphics g, Brush brush)
8039         {
8040             const int size = 5;
8041             var points = new Point[] { new Point(size, 2 * size), new Point(0, 3 * size), new Point(-size, 2 * size) };
8042             g.FillPolygon(brush, points);
8043         }
8044 
8045         #endregion
8046 
8047 
8048         #region Nested type: LineYComparer
8049 
8050         private class LineYComparer : IComparer<LineInfo>
8051         {
8052             private readonly int Y;
8053 
LineYComparer(int Y)8054             public LineYComparer(int Y)
8055             {
8056                 this.Y = Y;
8057             }
8058 
8059             #region IComparer<LineInfo> Members
8060 
Compare(LineInfo x, LineInfo y)8061             public int Compare(LineInfo x, LineInfo y)
8062             {
8063                 if (x.startY == -10)
8064                     return -y.startY.CompareTo(Y);
8065                 else
8066                     return x.startY.CompareTo(Y);
8067             }
8068 
8069             #endregion
8070         }
8071 
8072         #endregion
8073     }
8074 
8075     public class PaintLineEventArgs : PaintEventArgs
8076     {
PaintLineEventArgs(int iLine, Rectangle rect, Graphics gr, Rectangle clipRect)8077         public PaintLineEventArgs(int iLine, Rectangle rect, Graphics gr, Rectangle clipRect) : base(gr, clipRect)
8078         {
8079             LineIndex = iLine;
8080             LineRect = rect;
8081         }
8082 
8083         public int LineIndex { get; private set; }
8084         public Rectangle LineRect { get; private set; }
8085     }
8086 
8087     public class LineInsertedEventArgs : EventArgs
8088     {
LineInsertedEventArgs(int index, int count)8089         public LineInsertedEventArgs(int index, int count)
8090         {
8091             Index = index;
8092             Count = count;
8093         }
8094 
8095         /// <summary>
8096         /// Inserted line index
8097         /// </summary>
8098         public int Index { get; private set; }
8099 
8100         /// <summary>
8101         /// Count of inserted lines
8102         /// </summary>
8103         public int Count { get; private set; }
8104     }
8105 
8106     public class LineRemovedEventArgs : EventArgs
8107     {
LineRemovedEventArgs(int index, int count, List<int> removedLineIds)8108         public LineRemovedEventArgs(int index, int count, List<int> removedLineIds)
8109         {
8110             Index = index;
8111             Count = count;
8112             RemovedLineUniqueIds = removedLineIds;
8113         }
8114 
8115         /// <summary>
8116         /// Removed line index
8117         /// </summary>
8118         public int Index { get; private set; }
8119 
8120         /// <summary>
8121         /// Count of removed lines
8122         /// </summary>
8123         public int Count { get; private set; }
8124 
8125         /// <summary>
8126         /// UniqueIds of removed lines
8127         /// </summary>
8128         public List<int> RemovedLineUniqueIds { get; private set; }
8129     }
8130 
8131     /// <summary>
8132     /// TextChanged event argument
8133     /// </summary>
8134     public class TextChangedEventArgs : EventArgs
8135     {
8136         /// <summary>
8137         /// Constructor
8138         /// </summary>
TextChangedEventArgs(Range changedRange)8139         public TextChangedEventArgs(Range changedRange)
8140         {
8141             ChangedRange = changedRange;
8142         }
8143 
8144         /// <summary>
8145         /// This range contains changed area of text
8146         /// </summary>
8147         public Range ChangedRange { get; set; }
8148     }
8149 
8150     public class TextChangingEventArgs : EventArgs
8151     {
8152         public string InsertingText { get; set; }
8153 
8154         /// <summary>
8155         /// Set to true if you want to cancel text inserting
8156         /// </summary>
8157         public bool Cancel { get; set; }
8158     }
8159 
8160     public class WordWrapNeededEventArgs : EventArgs
8161     {
8162         public List<int> CutOffPositions { get; private set;}
8163         public bool ImeAllowed { get; private set;}
8164         public Line Line { get; private set; }
8165 
WordWrapNeededEventArgs(List<int> cutOffPositions, bool imeAllowed, Line line)8166         public WordWrapNeededEventArgs(List<int> cutOffPositions, bool imeAllowed, Line line)
8167         {
8168             this.CutOffPositions = cutOffPositions;
8169             this.ImeAllowed = imeAllowed;
8170             this.Line = line;
8171         }
8172     }
8173 
8174     public enum WordWrapMode
8175     {
8176         /// <summary>
8177         /// Word wrapping by control width
8178         /// </summary>
8179         WordWrapControlWidth,
8180 
8181         /// <summary>
8182         /// Word wrapping by preferred line width (PreferredLineWidth)
8183         /// </summary>
8184         WordWrapPreferredWidth,
8185 
8186         /// <summary>
8187         /// Char wrapping by control width
8188         /// </summary>
8189         CharWrapControlWidth,
8190 
8191         /// <summary>
8192         /// Char wrapping by preferred line width (PreferredLineWidth)
8193         /// </summary>
8194         CharWrapPreferredWidth,
8195 
8196         /// <summary>
8197         /// Custom wrap (by event WordWrapNeeded)
8198         /// </summary>
8199         Custom
8200     }
8201 
8202     public class PrintDialogSettings
8203     {
PrintDialogSettings()8204         public PrintDialogSettings()
8205         {
8206             ShowPrintPreviewDialog = true;
8207             Title = "";
8208             Footer = "";
8209             Header = "";
8210         }
8211 
8212         public bool ShowPageSetupDialog { get; set; }
8213         public bool ShowPrintDialog { get; set; }
8214         public bool ShowPrintPreviewDialog { get; set; }
8215 
8216         /// <summary>
8217         /// Title of page. If you want to print Title on the page, insert code &amp;w in Footer or Header.
8218         /// </summary>
8219         public string Title { get; set; }
8220 
8221         /// <summary>
8222         /// Footer of page.
8223         /// Here you can use special codes: &amp;w (Window title), &amp;D, &amp;d (Date), &amp;t(), &amp;4 (Time), &amp;p (Current page number), &amp;P (Total number of pages),  &amp;&amp; (A single ampersand), &amp;b (Right justify text, Center text. If &amp;b occurs once, then anything after the &amp;b is right justified. If &amp;b occurs twice, then anything between the two &amp;b is centered, and anything after the second &amp;b is right justified).
8224         /// More detailed see <see cref="http://msdn.microsoft.com/en-us/library/aa969429(v=vs.85).aspx">here</see>
8225         /// </summary>
8226         public string Footer { get; set; }
8227 
8228         /// <summary>
8229         /// Header of page
8230         /// Here you can use special codes: &amp;w (Window title), &amp;D, &amp;d (Date), &amp;t(), &amp;4 (Time), &amp;p (Current page number), &amp;P (Total number of pages),  &amp;&amp; (A single ampersand), &amp;b (Right justify text, Center text. If &amp;b occurs once, then anything after the &amp;b is right justified. If &amp;b occurs twice, then anything between the two &amp;b is centered, and anything after the second &amp;b is right justified).
8231         /// More detailed see <see cref="http://msdn.microsoft.com/en-us/library/aa969429(v=vs.85).aspx">here</see>
8232         /// </summary>
8233         public string Header { get; set; }
8234 
8235         /// <summary>
8236         /// Prints line numbers
8237         /// </summary>
8238         public bool IncludeLineNumbers { get; set; }
8239     }
8240 
8241     public class AutoIndentEventArgs : EventArgs
8242     {
AutoIndentEventArgs(int iLine, string lineText, string prevLineText, int tabLength, int currentIndentation)8243         public AutoIndentEventArgs(int iLine, string lineText, string prevLineText, int tabLength, int currentIndentation)
8244         {
8245             this.iLine = iLine;
8246             LineText = lineText;
8247             PrevLineText = prevLineText;
8248             TabLength = tabLength;
8249             AbsoluteIndentation = currentIndentation;
8250         }
8251 
8252         public int iLine { get; internal set; }
8253         public int TabLength { get; internal set; }
8254         public string LineText { get; internal set; }
8255         public string PrevLineText { get; internal set; }
8256 
8257         /// <summary>
8258         /// Additional spaces count for this line, relative to previous line
8259         /// </summary>
8260         public int Shift { get; set; }
8261 
8262         /// <summary>
8263         /// Additional spaces count for next line, relative to previous line
8264         /// </summary>
8265         public int ShiftNextLines { get; set; }
8266 
8267         /// <summary>
8268         /// Absolute indentation of current line. You can change this property if you want to set absolute indentation.
8269         /// </summary>
8270         public int AbsoluteIndentation { get; set; }
8271     }
8272 
8273     /// <summary>
8274     /// Type of highlighting
8275     /// </summary>
8276     public enum HighlightingRangeType
8277     {
8278         /// <summary>
8279         /// Highlight only changed range of text. Highest performance.
8280         /// </summary>
8281         ChangedRange,
8282 
8283         /// <summary>
8284         /// Highlight visible range of text. Middle performance.
8285         /// </summary>
8286         VisibleRange,
8287 
8288         /// <summary>
8289         /// Highlight all (visible and invisible) text. Lowest performance.
8290         /// </summary>
8291         AllTextRange
8292     }
8293 
8294     /// <summary>
8295     /// Strategy of search of end of folding block
8296     /// </summary>
8297     public enum FindEndOfFoldingBlockStrategy
8298     {
8299         Strategy1,
8300         Strategy2
8301     }
8302 
8303     /// <summary>
8304     /// Strategy of search of brackets to highlighting
8305     /// </summary>
8306     public enum BracketsHighlightStrategy
8307     {
8308         Strategy1,
8309         Strategy2
8310     }
8311 
8312     /// <summary>
8313     /// ToolTipNeeded event args
8314     /// </summary>
8315     public class ToolTipNeededEventArgs : EventArgs
8316     {
ToolTipNeededEventArgs(Place place, string hoveredWord)8317         public ToolTipNeededEventArgs(Place place, string hoveredWord)
8318         {
8319             HoveredWord = hoveredWord;
8320             Place = place;
8321         }
8322 
8323         public Place Place { get; private set; }
8324         public string HoveredWord { get; private set; }
8325         public string ToolTipTitle { get; set; }
8326         public string ToolTipText { get; set; }
8327         public ToolTipIcon ToolTipIcon { get; set; }
8328     }
8329 
8330     /// <summary>
8331     /// HintClick event args
8332     /// </summary>
8333     public class HintClickEventArgs : EventArgs
8334     {
HintClickEventArgs(Hint hint)8335         public HintClickEventArgs(Hint hint)
8336         {
8337             Hint = hint;
8338         }
8339 
8340         public Hint Hint { get; private set; }
8341     }
8342 
8343     /// <summary>
8344     /// CustomAction event args
8345     /// </summary>
8346     public class CustomActionEventArgs : EventArgs
8347     {
8348         public FCTBAction Action { get; private set; }
8349 
CustomActionEventArgs(FCTBAction action)8350         public CustomActionEventArgs(FCTBAction action)
8351         {
8352             Action = action;
8353         }
8354     }
8355 
8356     public enum TextAreaBorderType
8357     {
8358         None,
8359         Single,
8360         Shadow
8361     }
8362 
8363     [Flags]
8364     public enum ScrollDirection : ushort
8365     {
8366         None = 0,
8367         Left = 1,
8368         Right = 2,
8369         Up = 4,
8370         Down = 8
8371     }
8372 
8373     [Serializable]
8374     public class ServiceColors
8375     {
8376         public Color CollapseMarkerForeColor { get; set; }
8377         public Color CollapseMarkerBackColor { get; set; }
8378         public Color CollapseMarkerBorderColor { get; set; }
8379         public Color ExpandMarkerForeColor { get; set; }
8380         public Color ExpandMarkerBackColor { get; set; }
8381         public Color ExpandMarkerBorderColor { get; set; }
8382 
ServiceColors()8383         public ServiceColors()
8384         {
8385             CollapseMarkerForeColor = Color.Silver;
8386             CollapseMarkerBackColor = Color.White;
8387             CollapseMarkerBorderColor = Color.Silver;
8388             ExpandMarkerForeColor = Color.Red;
8389             ExpandMarkerBackColor = Color.White;
8390             ExpandMarkerBorderColor = Color.Silver;
8391         }
8392     }
8393 
8394 #if Styles32
8395     /// <summary>
8396     /// Style index mask (32 styles)
8397     /// </summary>
8398     [Flags]
8399     public enum StyleIndex : uint
8400     {
8401         None = 0,
8402         Style0 = 0x1,
8403         Style1 = 0x2,
8404         Style2 = 0x4,
8405         Style3 = 0x8,
8406         Style4 = 0x10,
8407         Style5 = 0x20,
8408         Style6 = 0x40,
8409         Style7 = 0x80,
8410         Style8 = 0x100,
8411         Style9 = 0x200,
8412         Style10 = 0x400,
8413         Style11 = 0x800,
8414         Style12 = 0x1000,
8415         Style13 = 0x2000,
8416         Style14 = 0x4000,
8417         Style15 = 0x8000,
8418 
8419         Style16 = 0x10000,
8420         Style17 = 0x20000,
8421         Style18 = 0x40000,
8422         Style19 = 0x80000,
8423         Style20 = 0x100000,
8424         Style21 = 0x200000,
8425         Style22 = 0x400000,
8426         Style23 = 0x800000,
8427         Style24 = 0x1000000,
8428         Style25 = 0x2000000,
8429         Style26 = 0x4000000,
8430         Style27 = 0x8000000,
8431         Style28 = 0x10000000,
8432         Style29 = 0x20000000,
8433         Style30 = 0x40000000,
8434         Style31 = 0x80000000,
8435 
8436         All = 0xffffffff
8437     }
8438 #else
8439     /// <summary>
8440     /// Style index mask (16 styles)
8441     /// </summary>
8442     [Flags]
8443     public enum StyleIndex : ushort
8444     {
8445         None = 0,
8446         Style0 = 0x1,
8447         Style1 = 0x2,
8448         Style2 = 0x4,
8449         Style3 = 0x8,
8450         Style4 = 0x10,
8451         Style5 = 0x20,
8452         Style6 = 0x40,
8453         Style7 = 0x80,
8454         Style8 = 0x100,
8455         Style9 = 0x200,
8456         Style10 = 0x400,
8457         Style11 = 0x800,
8458         Style12 = 0x1000,
8459         Style13 = 0x2000,
8460         Style14 = 0x4000,
8461         Style15 = 0x8000,
8462         All = 0xffff
8463     }
8464 #endif
8465 
8466 }
8467