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("<", "<").Replace(">", ">").Replace("&", "&"); 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 &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: &w (Window title), &D, &d (Date), &t(), &4 (Time), &p (Current page number), &P (Total number of pages), && (A single ampersand), &b (Right justify text, Center text. If &b occurs once, then anything after the &b is right justified. If &b occurs twice, then anything between the two &b is centered, and anything after the second &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: &w (Window title), &D, &d (Date), &t(), &4 (Time), &p (Current page number), &P (Total number of pages), && (A single ampersand), &b (Right justify text, Center text. If &b occurs once, then anything after the &b is right justified. If &b occurs twice, then anything between the two &b is centered, and anything after the second &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