1 // =================================
   2 // Copyright (c) 2021 Seppo Laakko
   3 // Distributed under the MIT license
   4 // =================================
   5 
   6 using System;
   7 using System.Collections;
   8 using System.IO;
   9 
  10 namespace System.Windows
  11 {
  12     public static class WordSeparators
  13     {
  14         static WordSeparators()
  15         {
  16             wordSeparators = u"`~!@#$%^&*()-=+[{]}\\|;:'\",.<>/?";
  17         }
  18         public static nothrow bool IsWordSeparatorChar(uchar c)
  19         {
  20             return wordSeparators.Find(c) != -1;
  21         }
  22         private static ustring wordSeparators;
  23     }
  24 
  25     public nothrow bool IsWordSeparator(uchar c)
  26     {
  27         return WordSeparators.IsWordSeparatorChar(c);
  28     }
  29 
  30     public static class CCStopChars
  31     {
  32         static CCStopChars()
  33         {
  34             ccStopChars = u" ,()[]{};\"'<=|&^!+/%~:";
  35         }
  36         public static nothrow bool IsCCStopChar(uchar c)
  37         {
  38             return ccStopChars.Find(c) != -1;
  39         }
  40         private static ustring ccStopChars;
  41     }
  42 
  43     public nothrow bool IsCCStopChar(uchar c)
  44     {
  45         return CCStopChars.IsCCStopChar(c);
  46     }
  47     public nothrow bool IsEmptyOrSpaceLine(const ustring& line)
  48     {
  49         if (line.IsEmpty()) return true;
  50         for (uchar c : line)
  51         {
  52             if (c != ' ') return false;
  53         }
  54         return true;
  55     }
  56 
  57     public nothrow System.Windows.Color DefaultTextViewSelectionBackgroundColor()
  58     {
  59         return System.Windows.Color(153u201u239u);
  60     }
  61 
  62     public class SourcePos
  63     {
  64         public nothrow SourcePos() : line(0)column(0)
  65         {
  66         }
  67         public nothrow SourcePos(int line_int column_) : line(line_)column(column_)
  68         {
  69         }
  70         public nothrow bool IsValid() const
  71         {
  72             return line != 0 && column != 0;
  73         }
  74         public int line;
  75         public int column;
  76     }
  77 
  78     public nothrow bool operator==(const SourcePos& leftconst SourcePos& right)
  79     {
  80         return left.line == right.line && left.column == right.column;
  81     }
  82 
  83     public nothrow bool operator<(const SourcePos& leftconst SourcePos& right)
  84     {
  85         if (left.line < right.line) return true;
  86         if (left.line > right.line) return false;
  87         return left.column < right.column;
  88     }
  89 
  90     public class Selection
  91     {
  92         public enum Fix : sbyte
  93         {
  94             nonestartend
  95         }
  96         public nothrow Selection() : fixed(Fix.none)start()end()
  97         {
  98         }
  99         public nothrow bool IsEmpty() const
 100         {
 101             return !start.IsValid() && !end.IsValid();
 102         }
 103         public Fix fixed;
 104         public SourcePos start;
 105         public SourcePos end;
 106     }
 107 
 108     public class SelectionData
 109     {
 110         public nothrow SelectionData() : selectedText()indent(0)numTrailingSpaces(0)
 111         {
 112         }
 113         public nothrow SelectionData(const ustring& selectedText_int indent_int numTrailingSpaces_) : selectedText(selectedText_)indent(indent_)numTrailingSpaces(numTrailingSpaces_)
 114         {
 115         }
 116         public ustring selectedText;
 117         public int indent;
 118         public int numTrailingSpaces;
 119     }
 120 
 121     public const uint defaultCaretTimerPeriod = 5000u;
 122 
 123     public class LineEventArgs
 124     {
 125         public nothrow LineEventArgs(int lineIndex_int indentLineIndex_) : lineIndex(lineIndex_)indentLineIndex(indentLineIndex_)
 126         {
 127         }
 128         public int lineIndex;
 129         public int indentLineIndex;
 130     }
 131 
 132     public class delegate void CaretPosChangedEventHandler();
 133     public class delegate void LinesChangedEventHandler();
 134     public class delegate void LineChangedEventHandler(LineEventArgs& args);
 135     public class delegate void LineDeletedEventHandler(LineEventArgs& args);
 136     public class delegate void LineInsertedEventHandler(LineEventArgs& args);
 137     public class delegate void GotoCaretLineEventHandler(ControlEventArgs& args);
 138     public class delegate void SelectionChangedEventHandler();
 139     public class delegate void DirtyChangedEventHandler();
 140     public class delegate void CCDirtyChangedEventHandler();
 141     public class delegate void CCTextChangedEventHandler();
 142     public class delegate void CCEventHandler();
 143     public class delegate void CCNextEventHandler();
 144     public class delegate void CCPrevEventHandler();
 145     public class delegate void CCNextPageEventHandler();
 146     public class delegate void CCPrevPageEventHandler();
 147     public class delegate void CCSelectEventHandler();
 148     public class delegate void EscapePressedHandler();
 149     public class delegate void CopyEventHandler();
 150     public class delegate void CutEventHandler();
 151     public class delegate void PasteEventHandler();
 152 
 153     public nothrow ControlCreateParams& TextViewControlCreateParams(ControlCreateParams& controlCreateParams)
 154     {
 155         return controlCreateParams.SetWindowClassName("System.Windows.TextView").SetWindowClassStyle(DoubleClickWindowClassStyle()).
 156             SetWindowStyle(cast<WindowStyle>(DefaultChildWindowStyle() | WindowStyle.WS_TABSTOP)).
 157             SetWindowClassBackgroundColor(SystemColor.COLOR_WINDOW).SetBackgroundColor(Color.White());
 158     }
 159 
 160     public class TextViewCreateParams
 161     {
 162         public nothrow TextViewCreateParams(ControlCreateParams& controlCreateParams_) : 
 163             controlCreateParams(controlCreateParams_)
 164             fontFamilyName("Consolas")
 165             fontSize(10.0f)
 166             padding()
 167             textColor(Color.Black())
 168             selectionBackgroundColor(DefaultTextViewSelectionBackgroundColor())
 169             indentSize(1)
 170         {
 171         }
 172         public nothrow TextViewCreateParams& Defaults()
 173         {
 174             return *this;
 175         }
 176         public nothrow TextViewCreateParams& SetFontFamilyName(const string& fontFamilyName_)
 177         {
 178             fontFamilyName = fontFamilyName_;
 179             return *this;
 180         }
 181         public nothrow TextViewCreateParams& SetFontSize(float fontSize_)
 182         {
 183             fontSize = fontSize_;
 184             return *this;
 185         }
 186         public nothrow TextViewCreateParams& SetPadding(const Padding& padding_)
 187         {
 188             padding = padding_;
 189             return *this;
 190         }
 191         public nothrow TextViewCreateParams& SetTextColor(const Color& textColor_)
 192         {
 193             textColor = textColor_;
 194             return *this;
 195         }
 196         public nothrow TextViewCreateParams& SetSelectionBackgroundColor(const Color& selectionBackgroundColor_)
 197         {
 198             selectionBackgroundColor = selectionBackgroundColor_;
 199             return *this;
 200         }
 201         public nothrow TextViewCreateParams& SetIndentSize(int indentSize_)
 202         {
 203             indentSize = indentSize_;
 204             return *this;
 205         }
 206         public ControlCreateParams& controlCreateParams;
 207         public string fontFamilyName;
 208         public float fontSize;
 209         public Padding padding;
 210         public Color textColor;
 211         public Color selectionBackgroundColor;
 212         public int indentSize;
 213     }
 214 
 215     public class TextView : Control
 216     {
 217         private enum Flags : sbyte
 218         {
 219             none = 0changed = 1 << 0painting = 1 << 1readOnly = 1 << 2fixed = 1 << 3dirty = 1 << 4ccdirty = 1 << 5
 220             mouseExtendSelection = 1 << 6ccOpen = 1 << 7
 221         }
 222 
 223         public TextView(const FontFamily& fontFamily_float fontSize_const Color& backgroundColorconst Color& textColor_const Point& location
 224             const Size& sizeDock dockAnchors anchors) : 
 225             base("System.Windows.TextView"DoubleClickWindowClassStyle()
 226                 cast<WindowStyle>(DefaultChildWindowStyle() | WindowStyle.WS_TABSTOP)DefaultExtendedWindowStyle()backgroundColor
 227             "textView"locationsizedockanchors)flags(Flags.none)drawFormat(StringAlignment.nearStringAlignment.near)
 228             fontFamily(fontFamily_)fontSize(fontSize_)
 229             charWidth(0)charHeight(0)textWidth(0)textHeight(0)maxLineLength(0)cursor(LoadStandardCursor(StandardCursorId.IDC_IBEAM))
 230             caretLine(1)caretColumn(1)
 231             caretTimerPeriod(defaultCaretTimerPeriod)update(false)topLine(1)topLineDiff(0.0f)leftCol(1)leftColDiff(0.0f)
 232             padding()selectionBackgroundColor(DefaultTextViewSelectionBackgroundColor())textColor(textColor_)editCommandList(this)selection()
 233             indentSize(1)
 234         {
 235             Init();
 236         }
 237         public TextView(const Point& locationconst Size& sizeDock dockAnchors anchors) : 
 238             this(FontFamily("Consolas")10.0fColor.White()Color.Black()locationsizedockanchors)
 239         {
 240         }
 241         public TextView(TextViewCreateParams& createParams) : 
 242             base(createParams.controlCreateParams)
 243             flags(Flags.none)
 244             drawFormat(StringAlignment.nearStringAlignment.near)
 245             fontFamily(createParams.fontFamilyName)
 246             fontSize(createParams.fontSize)
 247             charWidth(0)charHeight(0)textWidth(0)textHeight(0)maxLineLength(0)cursor(LoadStandardCursor(StandardCursorId.IDC_IBEAM))
 248             caretLine(1)caretColumn(1)
 249             caretTimerPeriod(defaultCaretTimerPeriod)update(false)topLine(1)topLineDiff(0.0f)leftCol(1)leftColDiff(0.0f)
 250             padding(createParams.padding)selectionBackgroundColor(createParams.selectionBackgroundColor)textColor(createParams.textColor)
 251             editCommandList(this)selection()indentSize(createParams.indentSize)
 252         {
 253             Init();
 254         }
 255         private void Init()
 256         {
 257             uint caretTimeOut = 0u;
 258             bool succeeded = ReadCaretTimeoutFromRegistry(caretTimeOut);
 259             if (succeeded)
 260             {
 261                 caretTimerPeriod = caretTimeOut;
 262             }
 263             Font* font = new Font(fontFamilyfontSizeFontStyle.regularUnit.point);
 264             fonts.Add(UniquePtr<Font>(font));
 265             SetChanged();
 266             measureString = "// this file has been semiautomatically generated from 'D:/work/soulng-project/sngcm/ast/AstReader.hpp' using cpp2cm version 1.0.0";
 267         }
 268         public nothrow const System.Windows.Color& GetTextColor() const
 269         {
 270             return textColor;
 271         }
 272         public nothrow void SetTextColor(const System.Windows.Color& textColor_)
 273         {
 274             textColor = textColor_;
 275         }
 276         public nothrow const System.Windows.Color& GetSelectionBackgroundColor() const
 277         {
 278             return selectionBackgroundColor;
 279         }
 280         public nothrow void SetSelectionBackgroundColor(const System.Windows.Color& selectionBackgroundColor_)
 281         {
 282             selectionBackgroundColor = selectionBackgroundColor_;
 283         }
 284         public inline nothrow List<ustring>& Lines()
 285         {
 286             return lines;
 287         }
 288         public inline nothrow const List<ustring>& Lines() const
 289         {
 290             return lines;
 291         }
 292         public void AddLine(const ustring& line)
 293         {
 294             lines.Add(line);
 295             SetMaxLineLength();
 296         }
 297         public void SetFont(const FontFamily& fontFamily_float fontSize_)
 298         {
 299             fontFamily = fontFamily_;
 300             fontSize = fontSize_;
 301             fonts.Clear();
 302             OnFontChanged();
 303             SetChanged();
 304         }
 305         protected virtual void OnFontChanged()
 306         {
 307             Font* font = new Font(fontFamilyfontSizeFontStyle.regularUnit.point);
 308             fonts.Add(UniquePtr<Font>(font));
 309         }
 310         public nothrow void SetUndoRedoMenuItems(MenuItem* undoMenuItemMenuItem* redoMenuItem)
 311         {
 312             editCommandList.SetMenuItems(undoMenuItemredoMenuItem);
 313         }
 314         public nothrow void Select()
 315         {
 316             editCommandList.UpdateMenuItems();
 317         }
 318         public nothrow void Undo()
 319         {
 320             editCommandList.Undo();
 321         }
 322         public nothrow void Redo()
 323         {
 324             editCommandList.Redo();
 325         }
 326         public inline nothrow float CharWidth() const
 327         {
 328             return charWidth;
 329         }
 330         public inline nothrow float CharHeight() const
 331         {
 332             return charHeight;
 333         }
 334         public inline nothrow int TextWidth() const
 335         {
 336             return textWidth;
 337         }
 338         public inline nothrow int TextHeight() const
 339         {
 340             return textHeight;
 341         }
 342         public inline nothrow FontFamily& GetFontFamily() const
 343         {
 344             return fontFamily;
 345         }
 346         public inline nothrow float FontSize() const
 347         {
 348             return fontSize;
 349         }
 350         public inline nothrow const List<UniquePtr<Font>>& Fonts() const
 351         {
 352             return fonts;
 353         }
 354         public inline nothrow List<UniquePtr<Font>>& Fonts()
 355         {
 356             return fonts;
 357         }
 358         public void SetCaretLineCol(int lineint column)
 359         {
 360             if (caretLine != line || caretColumn != column)
 361             {
 362                 caretLine = line;
 363                 caretColumn = column;
 364                 SetCaretLocation();
 365             }
 366         }
 367         public nothrow Point CaretPos() const
 368         {
 369             int x = cast<int>(padding.left + (caretColumn - 1) * charWidth);
 370             int y = cast<int>(padding.top + (caretLine - 1) * charHeight);
 371             Point loc(xy);
 372             TranslateContentLocation(loc);
 373             return loc;
 374         }
 375         public nothrow Point CCPos() const
 376         {
 377             Point ccPos = CaretPos();
 378             ccPos.Offset(0cast<int>(charHeight + 0.5));
 379             return ccPos;
 380         }
 381         public inline nothrow int TopLine() const
 382         {
 383             return topLine;
 384         }
 385         public inline nothrow float TopLineDiff() const
 386         {
 387             return topLineDiff;
 388         }
 389         public inline nothrow int LeftColumn() const
 390         {
 391             return leftCol;
 392         }
 393         public inline nothrow float LeftColumnDiff() const
 394         {
 395             return leftColDiff;
 396         }
 397         public inline nothrow int CaretLine() const
 398         {
 399             return caretLine;
 400         }
 401         public inline nothrow int CaretColumn() const
 402         {
 403             return caretColumn - LineNumberFieldLength();
 404         }
 405         public void SetTopLineCol(int lineint column)
 406         {
 407             Point newOrigin(cast<int>((column - 1) * charWidth)cast<int>((line - 1) * charHeight));
 408             topLine = cast<int>(newOrigin.y / charHeight + 1.5f);
 409             topLineDiff = (topLine - 1) * charHeight - newOrigin.y;
 410             leftCol = cast<int>(newOrigin.x / charWidth + 1.5f);
 411             leftColDiff = (leftCol - 1) * charWidth - newOrigin.x;
 412             SetContentLocation(newOrigin);
 413             Invalidate();
 414         }
 415         public inline nothrow int GetVisibleLineCount() const
 416         {
 417             Size size = GetSize();
 418             return cast<int>(size.h / charHeight);
 419         }
 420         public inline nothrow int GetVisibleColumnCount() const
 421         {
 422             Size size = GetSize();
 423             return cast<int>(size.w / charWidth);
 424         }
 425         public inline nothrow bool IsLinePartiallyVisible(int line) const
 426         {
 427             return line >= (topLine - 1) && line < (topLine + GetVisibleLineCount() + 1);
 428         }
 429         public inline nothrow bool IsLineVisible(int line) const
 430         {
 431             return line >= topLine && line < topLine + GetVisibleLineCount();
 432         }
 433         public nothrow void GetLineColumn(const Point& contentLocationint& lineint& column) const
 434         {
 435             line = cast<int>(contentLocation.y / charHeight + 1);
 436             column = cast<int>(contentLocation.x / charWidth + 1) - LineNumberFieldLength();
 437         }
 438         public void EnsureLineVisible(int line)
 439         {
 440             Invalidate();
 441             Application.ProcessMessages();
 442             if (IsLineVisible(line))
 443             {
 444                 return;
 445             }
 446             int tl = Max(cast<int>(1)line - GetVisibleLineCount() / 2);
 447             SetTopLineCol(tl1);
 448         }
 449         public virtual void Clear()
 450         {
 451             ustring emptyContent;
 452             SetTextContent(emptyContent);
 453         }
 454         public void SetTextContent(const ustring& textContent)
 455         {
 456             maxLineLength = 0;
 457             maxLineIndex = 0;
 458             lines = SplitTextIntoLines(textContent);
 459             lineStartIndeces = CalculateLineStartIndeces(textContent);
 460             SetMaxLineLength();
 461             OnLinesChanged();
 462             SetContentChanged();
 463             SetChanged();
 464             SetCaretLineCol(11 + LineNumberFieldLength());
 465             OnContentLocationChanged();
 466             Invalidate();
 467             update = true;
 468         }
 469         public nothrow int GetLineLength(int lineNumber)
 470         {
 471             int lineLength = 0;
 472             if (lineNumber >= 1 && lineNumber <= lines.Count())
 473             {
 474                 lineLength = cast<int>(lines[lineNumber - 1].Length());
 475             }
 476             return lineLength;
 477         }
 478         public nothrow bool Prev(int& lineint& col)
 479         {
 480             if (col > 1)
 481             {
 482                 --col;
 483                 return true;
 484             }
 485             else
 486             {
 487                 if (line > 1)
 488                 {
 489                     --line;
 490                     int lineLength = GetLineLength(line);
 491                     if (lineLength > 0)
 492                     {
 493                         col = lineLength;
 494                     }
 495                     else
 496                     {
 497                         col = 1;
 498                     }
 499                     return true;
 500                 }
 501             }
 502             return false;
 503         }
 504         public nothrow bool Next(int& lineint& col)
 505         {
 506             int lineLength = GetLineLength(line);
 507             if (col < lineLength)
 508             {
 509                 ++col;
 510                 return true;
 511             }
 512             else
 513             {
 514                 if (line < lines.Count())
 515                 {
 516                     ++line;
 517                     col = 1;
 518                     return true;
 519                 }
 520             }
 521             return false;
 522         }
 523         public nothrow void PrevWord(int& lineint& col)
 524         {
 525             if (Prev(linecol))
 526             {
 527                 uchar c = GetCharAt(linecol);
 528                 while (IsWhiteSpace(c) || IsWordSeparator(c))
 529                 {
 530                     if (col == 1 || !Prev(linecol))
 531                     {
 532                         return;
 533                     }
 534                     c = GetCharAt(linecol);
 535                 }
 536                 c = GetCharAt(linecol);
 537                 while (!IsWhiteSpace(c) && !IsWordSeparator(c))
 538                 {
 539                     if (col == 1 || !Prev(linecol))
 540                     {
 541                         return;
 542                     }
 543                     c = GetCharAt(linecol);
 544                 }
 545                 c = GetCharAt(linecol);
 546                 if (IsWhiteSpace(c) || IsWordSeparator(c))
 547                 {
 548                     Next(linecol);
 549                 }
 550             }
 551         }
 552         public nothrow void NextWord(int& lineint& col)
 553         {
 554             if (Next(linecol))
 555             {
 556                 uchar c = GetCharAt(linecol);
 557                 while (!IsWhiteSpace(c) && !IsWordSeparator(c))
 558                 {
 559                     if (col == 1 || !Next(linecol))
 560                     {
 561                         return;
 562                     }
 563                     c = GetCharAt(linecol);
 564                 }
 565                 c = GetCharAt(linecol);
 566                 while (IsWhiteSpace(c))
 567                 {
 568                     if (col == 1 || !Next(linecol))
 569                     {
 570                         return;
 571                     }
 572                     c = GetCharAt(linecol);
 573                 }
 574             }
 575         }
 576         private nothrow void GotoCaretLine()
 577         {
 578             ControlEventArgs args(this);
 579             OnGotoCaretLine(args);
 580         }
 581         protected virtual void OnGotoCaretLine(ControlEventArgs& args)
 582         {
 583             gotoCaretLineEvent.Fire(args);
 584         }
 585         public nothrow uchar GetCharAt(int lineint column) const
 586         {
 587             if (line < 1)
 588             {
 589                 line = 1;
 590             }
 591             else if (line > lines.Count())
 592             {
 593                 line = cast<int>(lines.Count());
 594             }
 595             int lineLength = GetLineLength(line);
 596             if (column < 1)
 597             {
 598                 column = 1;
 599             }
 600             else
 601             {
 602                 if (lineLength > 0 && column > lineLength)
 603                 {
 604                     column = lineLength;
 605                 }
 606             }
 607             if (line >= 1 && line <= lines.Count() && column >= 1 && column <= lineLength)
 608             {
 609                 return lines[line - 1][column - 1];
 610             }
 611             return '\0';
 612         }
 613         public void SetCaretPosByCharIndex(int charIndex)
 614         {
 615             List<int>.ConstIterator it = LowerBound(lineStartIndeces.CBegin()lineStartIndeces.CEnd()charIndex);
 616             if (it != lineStartIndeces.CBegin() && it == lineStartIndeces.CEnd())
 617             {
 618                 --it;
 619             }
 620             if (it >= lineStartIndeces.CBegin() && it != lineStartIndeces.CEnd())
 621             {
 622                 if (*it > charIndex)
 623                 {
 624                     --it;
 625                 }
 626             }
 627             int lineNumber = cast<int>(it - lineStartIndeces.CBegin() + 1);
 628             int columnNumber = 1 + LineNumberFieldLength();
 629             if (it >= lineStartIndeces.CBegin() && it != lineStartIndeces.CEnd())
 630             {
 631                 int lineStartCharIndex = *it;
 632                 columnNumber = charIndex - lineStartCharIndex + 1 + LineNumberFieldLength();
 633             }
 634             SetCaretLineCol(lineNumbercolumnNumber);
 635             ScrollToCaret();
 636         }
 637         public int GetCharIndex(int lineint column) const
 638         {
 639             if (line >= 1 && line <= lineStartIndeces.Count())
 640             {
 641                 int lineStartIndex = lineStartIndeces[line - 1];
 642                 int lineLength = GetLineLength(line);
 643                 if (column >= 1 && column <= lineLength)
 644                 {
 645                     return lineStartIndex + column - 1;
 646                 }
 647             }
 648             return -1;
 649         }
 650         protected override void OnPaint(PaintEventArgs& args)
 651         {
 652             try
 653             {
 654                 PaintContent(args.graphicsargs.clipRect);
 655                 base->OnPaint(args);
 656             }
 657             catch (const Exception& ex)
 658             {
 659                 MessageBox.Show(ex.Message());
 660             }
 661         }
 662         protected virtual void PaintContent(Graphics& graphicsconst Rect& clipRect)
 663         {
 664             if (Changed())
 665             {
 666                 ResetChanged();
 667                 Measure(graphics);
 668                 if (Focused())
 669                 {
 670                     SetCaretLocation();
 671                     ShowCaret();
 672                 }
 673                 OnContentLocationChanged();
 674             }
 675             TextRenderingHint prevRenderingHint = graphics.GetTextRenderingHint();
 676             graphics.SetTextRenderingHintChecked(TextRenderingHint.clearTypeGridFit);
 677             graphics.ClearChecked(BackgroundColor());
 678             int n = cast<int>(lines.Count());
 679             SetLineNumberFieldLength(n);
 680             int lineNumberFieldLength = LineNumberFieldLength();
 681             PointF origin(00);
 682             Size size = GetSize();
 683             for (int i = 0; i < n; ++i;)
 684             {
 685                 if (IsLinePartiallyVisible(i + 1))
 686                 {
 687                     DrawSelectionBackground(graphicsi + 1originlineNumberFieldLength);
 688                     DrawLine(graphicsiorigin);
 689                 }
 690                 origin.y = origin.y + charHeight;
 691             }
 692             graphics.SetTextRenderingHintChecked(prevRenderingHint);
 693         }
 694         private void DrawSelectionBackground(Graphics& graphicsint lineconst PointF& originint lineNumberFieldLength)
 695         {
 696             if (selection.IsEmpty()) return;
 697             if (line < selection.start.line) return;
 698             if (line > selection.end.line) return;
 699             PointF pt(origin);
 700             pt.x = pt.x + charWidth * lineNumberFieldLength;
 701             RectF rect;
 702             if (line > selection.start.line && line < selection.end.line)
 703             {
 704                 int lineLength = Max(1GetLineLength(line));
 705                 rect = RectF(ptSizeF(charWidth * lineLengthcharHeight));
 706             }
 707             else if (selection.start.line == selection.end.line)
 708             {
 709                 pt.x = pt.x + charWidth * (selection.start.column - 1);
 710                 int selectionLength = selection.end.column - selection.start.column;
 711                 rect = RectF(ptSizeF(charWidth * selectionLengthcharHeight));
 712             }
 713             else if (line == selection.start.line)
 714             {
 715                 pt.x = pt.x + charWidth * (selection.start.column - 1);
 716                 int lineLength = GetLineLength(line);
 717                 int selectionLength = lineLength - selection.start.column + 1;
 718                 rect = RectF(ptSizeF(charWidth * selectionLengthcharHeight));
 719             }
 720             else if (line == selection.end.line)
 721             {
 722                 int selectionLength = selection.end.column - 1;
 723                 rect = RectF(ptSizeF(charWidth * selectionLengthcharHeight));
 724             }
 725             Brush* brush = GetOrInsertBrush(selectionBackgroundColor);
 726             graphics.FillRectangleChecked(*brushrect);
 727         }
 728         protected virtual void DrawLine(Graphics& graphicsint lineIndexconst PointF& origin)
 729         {
 730             if (!fonts.IsEmpty())
 731             {
 732                 PointF pt(origin);
 733                 const ustring& line = lines[lineIndex];
 734                 string s(ToUtf8(line));
 735                 Brush* brush = GetOrInsertBrush(textColor);
 736                 graphics.DrawStringChecked(s*fonts[0]pt*brush);
 737             }
 738         }
 739         protected virtual void Measure(Graphics& graphics)
 740         {
 741             charWidth = 0;
 742             charHeight = 0;
 743             string ms;
 744             bool measure = false;
 745             if (IsFixed())
 746             {
 747                 ms = measureString;
 748                 maxLineLength = cast<int>(ToUtf32(measureString).Length());
 749                 measure = true;
 750             }
 751             else
 752             {
 753                 if (!lines.IsEmpty() && maxLineLength > 0)
 754                 {
 755                     ms = ToUtf8(lines[maxLineIndex]);
 756                     measure = true;
 757                 }
 758             }
 759             if (measure)
 760             {
 761                 for (const UniquePtr<Font>& font : fonts)
 762                 {
 763                     TextRenderingHint prevRenderingHint = graphics.GetTextRenderingHint();
 764                     graphics.SetTextRenderingHintChecked(TextRenderingHint.clearTypeGridFit);
 765                     RectF charRect = graphics.MeasureStringChecked(ms*fontPointF(00)drawFormat);
 766                     graphics.SetTextRenderingHintChecked(prevRenderingHint);
 767                     charWidth = Max(charWidthcharRect.size.w / maxLineLength);
 768                     charHeight = Max(charHeightcharRect.size.h);
 769                 }
 770             }
 771             SetScrollUnits(cast<int>(charHeight + 0.5)cast<int>(2 * (charWidth + 0.5)));
 772             SetTextExtent();
 773         }
 774         public void SetTextExtent()
 775         {
 776             textWidth = cast<int>(maxLineLength * charWidth);
 777             textHeight = cast<int>(lines.Count() * charHeight);
 778             SetContentSize(Size(textWidthtextHeight));
 779         }
 780         private nothrow void FixColumn(int& columnint line)
 781         {
 782             if (column < 1) column = 1;
 783             int n = GetLineLength(line);
 784             if (column > n + 1)
 785             {
 786                 column = n + 1;
 787             }
 788         }
 789         protected override void OnMouseDown(MouseEventArgs& args)
 790         {
 791             base->OnMouseDown(args);
 792             SetFocus(this);
 793             ResetSelection();
 794             if (args.buttons == MouseButtons.lbutton && !lines.IsEmpty())
 795             {
 796                 int line = 0;
 797                 int column = 0;
 798                 GetLineColumn(args.locationlinecolumn);
 799                 if (line >= 1 && line <= lines.Count())
 800                 {
 801                     FixColumn(columnline);
 802                     mouseSelectionStart = SourcePos(linecolumn);
 803                     SetMouseExtendSelection();
 804                 }
 805             }
 806             if (charHeight != 0 && charWidth != 0)
 807             {
 808                 if ((args.buttons == MouseButtons.lbutton || args.buttons == MouseButtons.rbutton) && args.clicks == 1)
 809                 {
 810                     Point loc = args.location;
 811                     int lineNumber = cast<int>(loc.y / charHeight) + 1;
 812                     lineNumber = Max(1Min(lineNumbercast<int>(lines.Count())));
 813                     int columnNumber = cast<int>(loc.x / charWidth) + 1;
 814                     columnNumber = Max(columnNumber1 + LineNumberFieldLength());
 815                     int lineLength = GetLineLength(lineNumber);
 816                     columnNumber = Min(columnNumberlineLength + 1 + LineNumberFieldLength());
 817                     if (update)
 818                     {
 819                         update = false;
 820                         Invalidate();
 821                     }
 822                     SetCaretLineCol(lineNumbercolumnNumber);
 823                     if (args.buttons == MouseButtons.rbutton)
 824                     {
 825                         RightClickEventArgs rightClickArgs(thisloc);
 826                         OnRightClick(rightClickArgs);
 827                     }
 828                 }
 829             }
 830         }
 831         protected override void OnMouseMove(MouseEventArgs& args)
 832         {
 833             base->OnMouseMove(args);
 834             if (MouseExtendSelection())
 835             {
 836                 int line = 0;
 837                 int column = 0;
 838                 GetLineColumn(args.locationlinecolumn);
 839                 if (line >= 1 && line <= lines.Count())
 840                 {
 841                     FixColumn(columnline);
 842                     mouseSelectionEnd = SourcePos(linecolumn);
 843                     if (mouseSelectionStart != mouseSelectionEnd)
 844                     {
 845                         ExtendSelection(mouseSelectionStartmouseSelectionEnd);
 846                         InvalidateLines(selection.start.lineselection.end.line);
 847                     }
 848                 }
 849             }
 850         }
 851         protected override void OnMouseUp(MouseEventArgs& args)
 852         {
 853             base->OnMouseUp(args);
 854             if (MouseExtendSelection())
 855             {
 856                 ResetMouseExtendSelection();
 857                 int line = 0;
 858                 int column = 0;
 859                 GetLineColumn(args.locationlinecolumn);
 860                 if (line >= 1 && line <= lines.Count())
 861                 {
 862                     FixColumn(columnline);
 863                     mouseSelectionEnd = SourcePos(linecolumn);
 864                     if (mouseSelectionStart != mouseSelectionEnd)
 865                     {
 866                         ExtendSelection(mouseSelectionStartmouseSelectionEnd);
 867                         InvalidateLines(selection.start.lineselection.end.line);
 868                     }
 869                 }
 870             }
 871         }
 872         protected override void OnKeyDown(KeyEventArgs& args)
 873         {
 874             base->OnKeyDown(args);
 875             if (!args.handled)
 876             {
 877                 bool scrolled = false;
 878                 int lineNumber = caretLine;
 879                 int columnNumber = caretColumn;
 880                 switch (args.key)
 881                 {
 882                     case Keys.escape:
 883                     {
 884                         OnEscape();
 885                         args.handled = true;
 886                         break;
 887                     }
 888                     case Keys.home:
 889                     {
 890                         ResetSelection();
 891                         columnNumber = 1 + LineNumberFieldLength();
 892                         args.handled = true;
 893                         break;
 894                     }
 895                     case cast<Keys>(Keys.shiftModifier | Keys.home):
 896                     {
 897                         SourcePos start(CaretLine()CaretColumn());
 898                         SourcePos end(CaretLine()1);
 899                         ExtendSelection(startend);
 900                         columnNumber = 1 + LineNumberFieldLength();
 901                         InvalidateLineCol(CaretLine()columnNumber);
 902                         args.handled = true;
 903                         break;
 904                     }
 905                     case Keys.end:
 906                     {
 907                         ResetSelection();
 908                         columnNumber = GetLineLength(lineNumber) + 1 + LineNumberFieldLength();
 909                         args.handled = true;
 910                         break;
 911                     }
 912                     case cast<Keys>(Keys.shiftModifier | Keys.end):
 913                     {
 914                         SourcePos start(CaretLine()CaretColumn());
 915                         SourcePos end(CaretLine()GetLineLength(lineNumber) + 1);
 916                         ExtendSelection(startend);
 917                         columnNumber = GetLineLength(lineNumber) + 1 + LineNumberFieldLength();
 918                         InvalidateLineCol(CaretLine()1 + LineNumberFieldLength());
 919                         args.handled = true;
 920                         break;
 921                     }
 922                     case Keys.left:
 923                     {
 924                         ResetSelection();
 925                         if (columnNumber > 1 + LineNumberFieldLength())
 926                         {
 927                             --columnNumber;
 928                         }
 929                         else if (lineNumber > 1)
 930                         {
 931                             --lineNumber;
 932                             int lineLength = GetLineLength(lineNumber);
 933                             columnNumber = lineLength + 1 + LineNumberFieldLength();
 934                         }
 935                         args.handled = true;
 936                         break;
 937                     }
 938                     case cast<Keys>(Keys.shiftModifier | Keys.left):
 939                     {
 940                         SourcePos start(CaretLine()CaretColumn());
 941                         if (columnNumber > 1 + LineNumberFieldLength())
 942                         {
 943                             SourcePos end(start);
 944                             --columnNumber;
 945                             --end.column;
 946                             ExtendSelection(startend);
 947                             InvalidateLines(selection.start.lineselection.end.line);
 948                         }
 949                         else if (lineNumber > 1)
 950                         {
 951                             SourcePos end(start);
 952                             --lineNumber;
 953                             --end.line;
 954                             int lineLength = GetLineLength(lineNumber);
 955                             columnNumber = lineLength + 1 + LineNumberFieldLength();
 956                             end.column = lineLength + 1;
 957                             ExtendSelection(startend);
 958                             InvalidateLines(selection.start.lineselection.end.line);
 959                         }
 960                         args.handled = true;
 961                         break;
 962                     }
 963                     case Keys.right:
 964                     {
 965                         ResetSelection();
 966                         if (lineNumber <= lines.Count())
 967                         {
 968                             int lineLength = GetLineLength(lineNumber);
 969                             if (columnNumber < lineLength + 1 + LineNumberFieldLength())
 970                             {
 971                                 ++columnNumber;
 972                             }
 973                             else
 974                             {
 975                                 ++lineNumber;
 976                                 columnNumber = 1 + LineNumberFieldLength();
 977                             }
 978                         }
 979                         args.handled = true;
 980                         break;
 981                     }
 982                     case cast<Keys>(Keys.shiftModifier | Keys.right):
 983                     {
 984                         SourcePos start(CaretLine()CaretColumn());
 985                         if (lineNumber <= lines.Count())
 986                         {
 987                             SourcePos end(start);
 988                             int lineLength = GetLineLength(lineNumber);
 989                             if (columnNumber < lineLength + 1 + LineNumberFieldLength())
 990                             {
 991                                 ++columnNumber;
 992                                 ++end.column;
 993                                 ExtendSelection(startend);
 994                             }
 995                             else
 996                             {
 997                                 ++lineNumber;
 998                                 ++end.line;
 999                                 columnNumber = 1 + LineNumberFieldLength();
1000                                 end.column = 1;
1001                                 ExtendSelection(startend);
1002                             }
1003                             InvalidateLines(selection.start.lineselection.end.line);
1004                         }
1005                         args.handled = true;
1006                         break;
1007                     }
1008                     case Keys.down:
1009                     {
1010                         if (CCOpen())
1011                         {
1012                             OnCCNext();
1013                         }
1014                         else
1015                         {
1016                             ResetSelection();
1017                             if (lineNumber < lines.Count())
1018                             {
1019                                 ++lineNumber;
1020                                 int lineLength = GetLineLength(lineNumber);
1021                                 columnNumber = Min(columnNumberlineLength + 1 + LineNumberFieldLength());
1022                             }
1023                             else
1024                             {
1025                                 lineNumber = cast<int>(lines.Count()) + 1;
1026                                 columnNumber = 1 + LineNumberFieldLength();
1027                             }
1028                         }
1029                         args.handled = true;
1030                         break;
1031                     }
1032                     case cast<Keys>(Keys.shiftModifier | Keys.down):
1033                     {
1034                         SourcePos start(CaretLine()CaretColumn());
1035                         SourcePos end(start);
1036                         if (lineNumber < lines.Count())
1037                         {
1038                             ++lineNumber;
1039                             ++end.line;
1040                             int lineLength = GetLineLength(lineNumber);
1041                             columnNumber = Min(columnNumberlineLength + 1 + LineNumberFieldLength());
1042                             end.column = Min(end.columnlineLength + 1);
1043                         }
1044                         else
1045                         {
1046                             lineNumber = cast<int>(lines.Count()) + 1;
1047                             end.line = cast<int>(lines.Count()) + 1;
1048                             columnNumber = 1 + LineNumberFieldLength();
1049                             end.column = 1;
1050                         }
1051                         ExtendSelection(startend);
1052                         InvalidateLines(selection.start.lineselection.end.line);
1053                         args.handled = true;
1054                         break;
1055                     }
1056                     case Keys.up:
1057                     {
1058                         if (CCOpen())
1059                         {
1060                             OnCCPrev();
1061                         }
1062                         else
1063                         {
1064                             ResetSelection();
1065                             if (lineNumber > 1)
1066                             {
1067                                 --lineNumber;
1068                                 int lineLength = GetLineLength(lineNumber);
1069                                 columnNumber = Min(columnNumberlineLength + 1 + LineNumberFieldLength());
1070                             }
1071                         }
1072                         args.handled = true;
1073                         break;
1074                     }
1075                     case cast<Keys>(Keys.shiftModifier | Keys.up):
1076                     {
1077                         if (lineNumber > 1)
1078                         {
1079                             SourcePos start(CaretLine()CaretColumn());
1080                             SourcePos end(start);
1081                             --lineNumber;
1082                             --end.line;
1083                             int lineLength = GetLineLength(lineNumber);
1084                             columnNumber = Min(columnNumberlineLength + 1 + LineNumberFieldLength());
1085                             end.column = Min(end.columnlineLength + 1);
1086                             ExtendSelection(startend);
1087                             InvalidateLines(selection.start.lineselection.end.line);
1088                         }
1089                         args.handled = true;
1090                         break;
1091                     }
1092                     case Keys.pageDown:
1093                     {
1094                         if (CCOpen())
1095                         {
1096                             OnCCNextPage();
1097                         }
1098                         else
1099                         {
1100                             ResetSelection();
1101                             Size size = GetSize();
1102                             int windowLines = cast<int>(size.h / charHeight);
1103                             lineNumber = lineNumber + windowLines;
1104                             lineNumber = Min(lineNumbercast<int>(lines.Count()) + 1);
1105                         }
1106                         args.handled = true;
1107                         break;
1108                     }
1109                     case cast<Keys>(Keys.shiftModifier | Keys.pageDown):
1110                     {
1111                         SourcePos start(CaretLine()CaretColumn());
1112                         SourcePos end(start);
1113                         Size size = GetSize();
1114                         int windowLines = cast<int>(size.h / charHeight);
1115                         lineNumber = lineNumber + windowLines;
1116                         end.line = end.line + windowLines;
1117                         lineNumber = Min(lineNumbercast<int>(lines.Count()) + 1);
1118                         end.line = Min(end.linecast<int>(lines.Count()) + 1);
1119                         ExtendSelection(startend);
1120                         InvalidateLines(selection.start.lineselection.end.line);
1121                         args.handled = true;
1122                         break;
1123                     }
1124                     case Keys.pageUp:
1125                     {
1126                         if (CCOpen())
1127                         {
1128                             OnCCPrevPage();
1129                         }
1130                         else
1131                         {
1132                             ResetSelection();
1133                             Size size = GetSize();
1134                             int windowLines = cast<int>(size.h / charHeight);
1135                             lineNumber = lineNumber - windowLines;
1136                             lineNumber = Max(lineNumber1);
1137                         }
1138                         args.handled = true;
1139                         break;
1140                     }
1141                     case cast<Keys>(Keys.shiftModifier | Keys.pageUp):
1142                     {
1143                         SourcePos start(CaretLine()CaretColumn());
1144                         SourcePos end(start);
1145                         Size size = GetSize();
1146                         int windowLines = cast<int>(size.h / charHeight);
1147                         lineNumber = lineNumber - windowLines;
1148                         end.line = end.line - windowLines;
1149                         lineNumber = Max(lineNumber1);
1150                         end.line = Max(end.line1);
1151                         ExtendSelection(startend);
1152                         InvalidateLines(selection.start.lineselection.end.line);
1153                         args.handled = true;
1154                         break;
1155                     }
1156                     case cast<Keys>(Keys.controlModifier | Keys.a):
1157                     {
1158                         ResetSelection();
1159                         SourcePos start(11);
1160                         SourcePos end(cast<int>(lines.Count() + 1)1);
1161                         ExtendSelection(startend);
1162                         InvalidateLines(selection.start.lineselection.end.line);
1163                         args.handled = true;
1164                         break;
1165                     }
1166                     case cast<Keys>(Keys.controlModifier | Keys.home):
1167                     {
1168                         ResetSelection();
1169                         lineNumber = 1;
1170                         columnNumber = 1 + LineNumberFieldLength();
1171                         args.handled = true;
1172                         break;
1173                     }
1174                     case cast<Keys>(Keys.shiftModifier | Keys.controlModifier | Keys.home):
1175                     {
1176                         SourcePos start(CaretLine()CaretColumn());
1177                         SourcePos end(start);
1178                         lineNumber = 1;
1179                         end.line = 1;
1180                         columnNumber = 1 + LineNumberFieldLength();
1181                         end.column = 1;
1182                         ExtendSelection(startend);
1183                         InvalidateLines(selection.start.lineselection.end.line);
1184                         args.handled = true;
1185                         break;
1186                     }
1187                     case cast<Keys>(Keys.controlModifier | Keys.end):
1188                     {
1189                         ResetSelection();
1190                         lineNumber = cast<int>(lines.Count() + 1);
1191                         columnNumber = 1 + LineNumberFieldLength();
1192                         args.handled = true;
1193                         break;
1194                     }
1195                     case cast<Keys>(Keys.shiftModifier | Keys.controlModifier | Keys.end):
1196                     {
1197                         SourcePos start(CaretLine()CaretColumn());
1198                         SourcePos end(start);
1199                         lineNumber = cast<int>(lines.Count() + 1);
1200                         end.line = cast<int>(lines.Count() + 1);
1201                         columnNumber = 1 + LineNumberFieldLength();
1202                         end.column = 1;
1203                         ExtendSelection(startend);
1204                         InvalidateLines(selection.start.lineselection.end.line);
1205                         args.handled = true;
1206                         break;
1207                     }
1208                     case cast<Keys>(Keys.controlModifier | Keys.left):
1209                     {
1210                         ResetSelection();
1211                         int line = lineNumber;
1212                         int col = columnNumber - LineNumberFieldLength();
1213                         PrevWord(linecol);
1214                         lineNumber = line;
1215                         columnNumber = col + LineNumberFieldLength();
1216                         args.handled = true;
1217                         break;
1218                     }
1219                     case cast<Keys>(Keys.shiftModifier | Keys.controlModifier | Keys.left):
1220                     {
1221                         SourcePos start(CaretLine()CaretColumn());
1222                         SourcePos end(start);
1223                         int line = lineNumber;
1224                         int col = columnNumber - LineNumberFieldLength();
1225                         PrevWord(linecol);
1226                         lineNumber = line;
1227                         end.line = line;
1228                         columnNumber = col + LineNumberFieldLength();
1229                         end.column = col;
1230                         ExtendSelection(startend);
1231                         InvalidateLines(selection.start.lineselection.end.line);
1232                         args.handled = true;
1233                         break;
1234                     }
1235                     case cast<Keys>(Keys.controlModifier | Keys.right):
1236                     {
1237                         ResetSelection();
1238                         int line = lineNumber;
1239                         int col = columnNumber - LineNumberFieldLength();
1240                         NextWord(linecol);
1241                         lineNumber = line;
1242                         columnNumber = col + LineNumberFieldLength();
1243                         args.handled = true;
1244                         break;
1245                     }
1246                     case cast<Keys>(Keys.shiftModifier | Keys.controlModifier | Keys.right):
1247                     {
1248                         SourcePos start(CaretLine()CaretColumn());
1249                         SourcePos end(start);
1250                         int line = lineNumber;
1251                         int col = columnNumber - LineNumberFieldLength();
1252                         NextWord(linecol);
1253                         lineNumber = line;
1254                         end.line = line;
1255                         columnNumber = col + LineNumberFieldLength();
1256                         end.column = col;
1257                         ExtendSelection(startend);
1258                         InvalidateLines(selection.start.lineselection.end.line);
1259                         args.handled = true;
1260                         break;
1261                     }
1262                     case cast<Keys>(Keys.controlModifier | Keys.down):
1263                     {
1264                         if (lines.Count() < GetVisibleLineCount())
1265                         {
1266                             args.handled = true;
1267                             return;
1268                         }
1269                         ResetSelection();
1270                         ScrollLineDown();
1271                         scrolled = true;
1272                         args.handled = true;
1273                         break;
1274                     }
1275                     case cast<Keys>(Keys.controlModifier | Keys.up):
1276                     {
1277                         if (lines.Count() < GetVisibleLineCount())
1278                         {
1279                             args.handled = true;
1280                             return;
1281                         }
1282                         ResetSelection();
1283                         ScrollLineUp();
1284                         scrolled = true;
1285                         args.handled = true;
1286                         break;
1287                     }
1288                     case cast<Keys>(Keys.controlModifier | Keys.k):
1289                     {
1290                         ResetSelection();
1291                         GotoCaretLine();
1292                         args.handled = true;
1293                         break;
1294                     }
1295                     case Keys.delete_:
1296                     {
1297                         if (!IsReadOnly())
1298                         {
1299                             if (selection.IsEmpty())
1300                             {
1301                                 int lineIndex = caretLine - 1;
1302                                 int columnIndex = CaretColumn() - 1;
1303                                 AddDeleteCharCommand(lineIndexcolumnIndex);
1304                                 DeleteChar(lineIndexcolumnIndex00false);
1305                             }
1306                             else
1307                             {
1308                                 AddRemoveSelectionCommand();
1309                                 RemoveSelection();
1310                             }
1311                             args.handled = true;
1312                             return;
1313                         }
1314                         break;
1315                     }
1316                     case Keys.back:
1317                     {
1318                         if (!IsReadOnly())
1319                         {
1320                             int lineIndex = caretLine - 1;
1321                             int columnIndex = CaretColumn() - 1;
1322                             Backspace(lineIndexcolumnIndex);
1323                             args.handled = true;
1324                             return;
1325                         }
1326                         break;
1327                     }
1328                     case Keys.enter:
1329                     {
1330                         if (CCOpen())
1331                         {
1332                             OnCCSelect();
1333                             args.handled = true;
1334                             return;
1335                         }
1336                         else
1337                         {
1338                             if (!IsReadOnly())
1339                             {
1340                                 ResetSelection();
1341                                 int lineIndex = caretLine - 1;
1342                                 int columnIndex = CaretColumn() - 1;
1343                                 AddNewLineCommand(lineIndexcolumnIndex);
1344                                 NewLine(lineIndexcolumnIndex);
1345                                 args.handled = true;
1346                                 return;
1347                             }
1348                         }
1349                         break;
1350                     }
1351                     case Keys.tab:
1352                     {
1353                         if (!IsReadOnly())
1354                         {
1355                             if (selection.IsEmpty())
1356                             {
1357                                 int lineIndex = caretLine - 1;
1358                                 int columnIndex = CaretColumn() - 1;
1359                                 AddTabCommand(lineIndexcolumnIndex);
1360                                 Tab(lineIndexcolumnIndex);
1361                             }
1362                             else
1363                             {
1364                                 AddIndentSelectionCommand();
1365                                 IndentSelection();
1366                             }
1367                             args.handled = true;
1368                             return;
1369                         }
1370                         break;
1371                     }
1372                     case cast<Keys>(Keys.shiftModifier | Keys.tab):
1373                     {
1374                         if (!IsReadOnly())
1375                         {
1376                             if (selection.IsEmpty())
1377                             {
1378                                 int lineIndex = caretLine - 1;
1379                                 int columnIndex = CaretColumn() - 1;
1380                                 AddBacktabCommand(lineIndexcolumnIndex);
1381                                 Backtab(lineIndexcolumnIndex);
1382                             }
1383                             else
1384                             {
1385                                 AddUnindentSelectionCommand();
1386                                 UnindentSelection();
1387                             }
1388                             args.handled = true;
1389                             return;
1390                         }
1391                         break;
1392                     }
1393                     case cast<Keys>(Keys.controlModifier | Keys.insert):
1394                     {
1395                         if (!selection.IsEmpty())
1396                         {
1397                             OnCopy();
1398                         }
1399                         args.handled = true;
1400                         break;
1401                     }
1402                     case cast<Keys>(Keys.shiftModifier | Keys.insert):
1403                     {
1404                         OnPaste();
1405                         args.handled = true;
1406                         break;
1407                     }
1408                     case cast<Keys>(Keys.shiftModifier | Keys.delete_):
1409                     {
1410                         if (!selection.IsEmpty())
1411                         {
1412                             OnCut();
1413                         }
1414                         args.handled = true;
1415                         break;
1416                     }
1417                     case cast<Keys>(Keys.altModifier | Keys.back):
1418                     {
1419                         Undo();
1420                         break;
1421                     }
1422                     case Keys.f4:
1423                     {
1424                         Redo();
1425                         break;
1426                     }
1427                 }
1428                 if (args.handled && !scrolled)
1429                 {
1430                     SetCaretLineCol(lineNumbercolumnNumber);
1431                     ScrollToCaret();
1432                 }
1433             }
1434         }
1435         protected override void OnKeyPress(KeyPressEventArgs& args)
1436         {
1437             base->OnKeyPress(args);
1438             if (IsReadOnly()) return;
1439             if (!args.handled && WinKeyPressed(VK_CONTROL) && args.keyChar == ' ')
1440             {
1441                 OnCC();
1442                 args.handled = true;
1443                 return;
1444             }
1445             if (!WinKeyPressed(VK_MENU) && WinKeyPressed(VK_CONTROL))
1446             {
1447                 return;
1448             }
1449             if (!args.handled)
1450             {
1451                 editCommandList.BeginGroup();
1452                 if (!selection.IsEmpty())
1453                 {
1454                     AddRemoveSelectionCommand();
1455                     RemoveSelection();
1456                 }
1457                 uchar c(args.keyChar);
1458                 int lineIndex = caretLine - 1;
1459                 int columnIndex = CaretColumn() - 1;
1460                 AddInsertCharCommand(lineIndexcolumnIndexc);
1461                 InsertChar(lineIndexcolumnIndexc);
1462                 editCommandList.EndGroup();
1463                 args.handled = true;
1464             }
1465         }
1466         protected virtual void OnEscape()
1467         {
1468             escapePressedEvent.Fire();
1469         }
1470         protected virtual void OnCCNext()
1471         {
1472             ccNextEvent.Fire();
1473         }
1474         protected virtual void OnCCPrev()
1475         {
1476             ccPrevEvent.Fire();
1477         }
1478         protected virtual void OnCCNextPage()
1479         {
1480             ccNextPageEvent.Fire();
1481         }
1482         protected virtual void OnCCPrevPage()
1483         {
1484             ccPrevPageEvent.Fire();
1485         }
1486         protected virtual void OnCCSelect()
1487         {
1488             ccSelectEvent.Fire();
1489         }
1490         private nothrow void AddInsertCharCommand(int lineIndexint columnIndexuchar c)
1491         {
1492             bool removeIndent = false;
1493             while (lineIndex >= lines.Count())
1494             {
1495                 lines.Add(ustring());
1496             }
1497             ustring& line = lines[lineIndex];
1498             if (c == '}' && line.StartsWith(ustring(' 'IndentSize())))
1499             {
1500                 removeIndent = true;
1501             }
1502             editCommandList.AddCommand(new InsertCharCommand(lineIndexcolumnIndexcremoveIndent));
1503         }
1504         public void InsertChar(int lineIndexint columnIndexuchar c)
1505         {
1506             while (lineIndex >= lines.Count())
1507             {
1508                 lines.Add(ustring());
1509             }
1510             ustring& line = lines[lineIndex];
1511             line.Insert(columnIndexc);
1512             if (c == '}' && line.StartsWith(ustring(' 'IndentSize())))
1513             {
1514                 line.Remove(0IndentSize());
1515                 columnIndex = columnIndex - IndentSize();
1516             }
1517             if (line.Length() > maxLineLength)
1518             {
1519                 maxLineLength = cast<int>(line.Length());
1520                 maxLineIndex = lineIndex;
1521                 SetTextExtent();
1522             }
1523             LineEventArgs args(lineIndex-1);
1524             OnLineChanged(args);
1525             SetCaretLineCol(lineIndex + 1columnIndex + 1 + LineNumberFieldLength());
1526             KeyEventArgs rightArgs(Keys.right);
1527             OnKeyDown(rightArgs);
1528             SetCCText(linecolumnIndex);
1529             SetDirty();
1530             SetCCDirty();
1531         }
1532         public void InsertText(int lineIndexint columnIndexconst ustring& text)
1533         {
1534             if (text.IsEmpty()) return;
1535             editCommandList.BeginGroup();
1536             if (!selection.IsEmpty())
1537             {
1538                 lineIndex = selection.start.line - 1;
1539                 columnIndex = selection.start.column - 1;
1540                 AddRemoveSelectionCommand();
1541                 RemoveSelection();
1542             }
1543             List<ustring> linesToInsert = SplitTextIntoLines(text);
1544             if (linesToInsert.Count() == 1 && !IsEmptyOrSpaceLine(lines[lineIndex]))
1545             {
1546                 AddInsertIntoLineCommand(lineIndexcolumnIndexlinesToInsert.Front());
1547                 InsertIntoLine(lineIndexcolumnIndexlinesToInsert.Front());
1548             }
1549             else
1550             {
1551                 AddInsertLinesCommand(lineIndexcolumnIndexlinesToInsert);
1552                 InsertLines(lineIndexcolumnIndexlinesToInsert);
1553             }
1554             editCommandList.EndGroup();
1555         }
1556         public nothrow void AddInsertIntoLineCommand(int lineIndexint columnIndexconst ustring& text)
1557         {
1558             editCommandList.AddCommand(new InsertIntoLineCommand(lineIndexcolumnIndextext));
1559         }
1560         public nothrow void InsertIntoLine(int lineIndexint columnIndexconst ustring& text)
1561         {
1562             lines[lineIndex].Insert(columnIndextext);
1563             LineEventArgs args(lineIndex-1);
1564             OnLineChanged(args);
1565             SetTextExtent();
1566             SetCaretLineCol(lineIndex + 11 + LineNumberFieldLength() + columnIndex + cast<int>(text.Length()));
1567             ScrollToCaret();
1568             Invalidate();
1569             InvalidateLines(lineIndex + 1lineIndex + 1);
1570             SetDirty();
1571             SetCCDirty();
1572         }
1573         public nothrow void RemoveFromLine(int lineIndexint columnIndexlong count)
1574         {
1575             lines[lineIndex].Remove(columnIndexcount);
1576             LineEventArgs args(lineIndex-1);
1577             OnLineChanged(args);
1578             SetTextExtent();
1579             SetCaretLineCol(lineIndex + 11 + LineNumberFieldLength() + columnIndex);
1580             ScrollToCaret();
1581             Invalidate();
1582             InvalidateLines(lineIndex + 1lineIndex + 1);
1583             SetDirty();
1584             SetCCDirty();
1585         }
1586         public nothrow void AddInsertLinesCommand(int lineIndexint columnIndexconst List<ustring>& linesToInsert)
1587         {
1588             editCommandList.AddCommand(new InsertLinesCommand(lineIndexcolumnIndexlinesToInsert));
1589         }
1590         public nothrow void InsertLines(int lineIndexint columnIndexconst List<ustring>& linesToInsert)
1591         {
1592             int indent = 0;
1593             if (lineIndex > 0 && lineIndex < lines.Count())
1594             {
1595                 indent = GetIndent(lines[lineIndex - 1]lineIndex - 1);
1596             }
1597             int indentLineIndex = lineIndex - 1;
1598             for (const ustring& lineToInsert : linesToInsert)
1599             {
1600                 lines.Insert(lines.Begin() + lineIndexlineToInsert);
1601                 SetLineNumberFieldLength(cast<int>(lines.Count()));
1602                 LineEventArgs insertedArgs(lineIndexindentLineIndex);
1603                 OnLineInserted(insertedArgs);
1604                 ++lineIndex;
1605             }
1606             bool lineDeleted = false;
1607             if (lineIndex < lines.Count())
1608             {
1609                 if (IsEmptyOrSpaceLine(lines[lineIndex]))
1610                 {
1611                     lines.Remove(lines.Begin() + lineIndex);
1612                     LineEventArgs args(lineIndex-1);
1613                     OnLineDeleted(args);
1614                     lineDeleted = true;
1615                 }
1616             }
1617             SetTextExtent();
1618             if (lineDeleted)
1619             {
1620                 SetCaretLineCol(lineIndex1 + LineNumberFieldLength() + cast<int>(lines[lineIndex - 1].Length()));
1621             }
1622             else
1623             {
1624                 SetCaretLineCol(lineIndex1 + LineNumberFieldLength() + indent);
1625             }
1626             ScrollToCaret();
1627             Invalidate();
1628             InvalidateLines(lineIndex + 1cast<int>(lineIndex + linesToInsert.Count() + 1));
1629             SetDirty();
1630             SetCCDirty();
1631         }
1632         public nothrow void DeleteLines(int lineIndexint columnIndexconst List<ustring>& linesToDelete)
1633         {
1634             if (linesToDelete.Count() == 1)
1635             {
1636                 ustring& line = lines[lineIndex];
1637                 line.Remove(columnIndexlinesToDelete.Front().Length());
1638                 LineEventArgs args(lineIndex-1);
1639                 OnLineChanged(args);
1640             }
1641             else
1642             {
1643                 for (int i = 0; i < linesToDelete.Count(); ++i;)
1644                 {
1645                     lines.Remove(lines.Begin() + lineIndex);
1646                     LineEventArgs deleteArgs(lineIndex-1);
1647                     OnLineDeleted(deleteArgs);
1648                 }
1649             }
1650             SetTextExtent();
1651             SetLineNumberFieldLength(cast<int>(lines.Count()));
1652             SetCaretLineCol(lineIndex1 + LineNumberFieldLength());
1653             ScrollToCaret();
1654             Invalidate();
1655             SetDirty();
1656             SetCCDirty();
1657         }
1658         private nothrow void AddDeleteCharCommand(int lineIndexint columnIndex)
1659         {
1660             if (lineIndex >= lines.Count()) return;
1661             ustring& line = lines[lineIndex];
1662             if (columnIndex < line.Length())
1663             {
1664                 uchar c = line[columnIndex];
1665                 editCommandList.AddCommand(new DeleteCharCommand(lineIndexcolumnIndexc));
1666             }
1667             else
1668             {
1669                 if (lines.Count() > lineIndex + 1)
1670                 {
1671                     editCommandList.AddCommand(new DeleteCharCommand(lineIndexcolumnIndex'\0'));
1672                 }
1673             }
1674         }
1675         public void DeleteChar(int lineIndexint columnIndexint indentint numSpacesbool removeIndent)
1676         {
1677             if (lineIndex >= lines.Count()) return;
1678             ustring& line = lines[lineIndex];
1679             if (removeIndent)
1680             {
1681                 line.Insert(0ustring(' 'IndentSize()));
1682             }
1683             if (columnIndex < line.Length())
1684             {
1685                 line.Remove(columnIndex1);
1686                 LineEventArgs args(lineIndex-1);
1687                 OnLineChanged(args);
1688                 SetCCText(linecolumnIndex);
1689             }
1690             else
1691             {
1692                 if (lines.Count() > lineIndex + 1)
1693                 {
1694                     if (numSpaces > 0)
1695                     {
1696                         line.Append(ustring(' 'numSpaces));
1697                     }
1698                     ustring nextLine = lines[lineIndex + 1];
1699                     line.Append(nextLine.Substring(indent));
1700                     LineEventArgs changedArgs(lineIndex-1);
1701                     OnLineChanged(changedArgs);
1702                     lines.Remove(lines.Begin() + lineIndex + 1);
1703                     LineEventArgs deletedArgs(lineIndex + 1-1);
1704                     OnLineDeleted(deletedArgs);
1705                     SetTextExtent();
1706                     ResetCCText();
1707                 }
1708             }
1709             SetCaretLineCol(lineIndex + 1columnIndex + 1 + LineNumberFieldLength());
1710             SetDirty();
1711             SetCCDirty();
1712         }
1713         private void Backspace(int lineIndexint columnIndex)
1714         {
1715             if (lineIndex != 0 || columnIndex != 0)
1716             {
1717                 KeyEventArgs leftArgs(Keys.left);
1718                 OnKeyDown(leftArgs);
1719                 KeyEventArgs deleteArgs(Keys.delete_);
1720                 OnKeyDown(deleteArgs);
1721             }
1722         }
1723         protected virtual nothrow int GetIndent(const ustring& lineint lineIndex)
1724         {
1725             for (int i = 0; i < line.Length(); ++i;)
1726             {
1727                 if (line[i] != ' ')
1728                 {
1729                     return i;
1730                 }
1731             }
1732             return 0;
1733         }
1734         protected virtual nothrow int RemoveIndent(int lineIndex) const
1735         {
1736             return 0;
1737         }
1738         public nothrow void AddNewLineCommand(int lineIndexint columnIndex)
1739         {
1740             while (lineIndex >= lines.Count())
1741             {
1742                 lines.Add(ustring());
1743             }
1744             ustring& line = lines[lineIndex];
1745             int indent = 0;
1746             bool countIndent = false;
1747             int i = columnIndex - 1;
1748             while (i >= 0)
1749             {
1750                 if (line[i] != ' ')
1751                 {
1752                     countIndent = true;
1753                     break;
1754                 }
1755                 --i;
1756             }
1757             if (countIndent)
1758             {
1759                 for (int i = 0; i < columnIndex - 1; ++i;)
1760                 {
1761                     if (line[i] == ' ') ++indent; else break;
1762                 }
1763             }
1764             int numSpaces = 0;
1765             i = columnIndex - 1;
1766             while (i >= 0 && line[i] == ' ')
1767             {
1768                 ++numSpaces;
1769                 --i;
1770             }
1771             editCommandList.AddCommand(new NewLineCommand(lineIndexcolumnIndexindentnumSpaces));
1772         }
1773         public void NewLine(int lineIndexint columnIndex)
1774         {
1775             while (lineIndex >= lines.Count())
1776             {
1777                 lines.Add(ustring());
1778             }
1779             ustring& line = lines[lineIndex];
1780             if (columnIndex > line.Length())
1781             {
1782                 columnIndex = cast<int>(line.Length());
1783             }
1784             ustring toInsert = TrimEnd(line.Substring(columnIndex));
1785             bool lineChanged = false;
1786             if (!toInsert.IsEmpty())
1787             {
1788                 line.Remove(columnIndexline.Length() - columnIndex);
1789                 lineChanged = true;
1790             }
1791             ustring trimmedLine = TrimEnd(line);
1792             if (trimmedLine.Length() != line.Length())
1793             {
1794                 Swap(linetrimmedLine);
1795                 lineChanged = true;
1796             }
1797             if (lineChanged)
1798             {
1799                 LineEventArgs changedArgs(lineIndex-1);
1800                 OnLineChanged(changedArgs);
1801             }
1802             lines.Insert(lines.Begin() + lineIndex + 1toInsert);
1803             SetLineNumberFieldLength(cast<int>(lines.Count()));
1804             int indentLineIndex = lineIndex;
1805             while (indentLineIndex >= 0 && IsEmptyOrSpaceLine(lines[indentLineIndex]))
1806             {
1807                 --indentLineIndex;
1808             }
1809             if (indentLineIndex < 0)
1810             {
1811                 indentLineIndex = 0;
1812             }
1813             LineEventArgs insertedArgs(lineIndex + 1indentLineIndex);
1814             OnLineInserted(insertedArgs);
1815             SetTextExtent();
1816             SetCaretLineCol(lineIndex + 1 + 11 + LineNumberFieldLength() + GetIndent(lines[indentLineIndex]indentLineIndex));
1817             ScrollToCaret();
1818             Invalidate();
1819             SetDirty();
1820             SetCCDirty();
1821         }
1822         public inline nothrow int IndentSize() const
1823         {
1824             return indentSize;
1825         }
1826         public void SetIndentSize(int indentSize_)
1827         {
1828             indentSize = indentSize_;
1829         }
1830         private void AddTabCommand(int lineIndexint columnIndex)
1831         {
1832             editCommandList.AddCommand(new TabCommand(lineIndexcolumnIndex));
1833         }
1834         public void Tab(int lineIndexint columnIndex)
1835         {
1836             while (lineIndex >= lines.Count())
1837             {
1838                 lines.Add(ustring());
1839             }
1840             ustring& line = lines[lineIndex];
1841             line.Insert(columnIndexustring(' 'IndentSize()));
1842             if (line.Length() > maxLineLength)
1843             {
1844                 maxLineLength = cast<int>(line.Length());
1845                 maxLineIndex = lineIndex;
1846                 SetTextExtent();
1847             }
1848             LineEventArgs args(lineIndex-1);
1849             OnLineChanged(args);
1850             SetCaretLineCol(lineIndex + 1columnIndex + 1 + LineNumberFieldLength() + IndentSize());
1851             ScrollToCaret();
1852             InvalidateLineCol(lineIndex + 1columnIndex + 1);
1853             SetDirty();
1854             SetCCDirty();
1855         }
1856         private void AddBacktabCommand(int lineIndexint columnIndex)
1857         {
1858             ustring& line = lines[lineIndex];
1859             int targetCol = Max(cast<int>(1)columnIndex - IndentSize() + 1);
1860             int numSpaces = 0;
1861             for (int i = columnIndex; i >= targetCol; --i;)
1862             {
1863                 if (line[i - 1] == ' ')
1864                 {
1865                     ++numSpaces;
1866                 }
1867                 else
1868                 {
1869                     break;
1870                 }
1871             }
1872             editCommandList.AddCommand(new BacktabCommand(lineIndexcolumnIndexnumSpaces));
1873         }
1874         public void Backtab(int lineIndexint columnIndex)
1875         {
1876             if (lineIndex >= lines.Count()) return;
1877             ustring& line = lines[lineIndex];
1878             int targetCol = Max(cast<int>(1)columnIndex - IndentSize() + 1);
1879             int numSpaces = 0;
1880             int col = 0;
1881             for (int i = columnIndex; i >= targetCol; --i;)
1882             {
1883                 if (line[i - 1] == ' ')
1884                 {
1885                     col = i - 1;
1886                     ++numSpaces;
1887                 }
1888                 else
1889                 {
1890                     break;
1891                 }
1892             }
1893             if (numSpaces > 0)
1894             {
1895                 line.Remove(colnumSpaces);
1896                 LineEventArgs args(lineIndex-1);
1897                 OnLineChanged(args);
1898                 SetCaretLineCol(lineIndex + 1columnIndex + 1 + LineNumberFieldLength() - numSpaces);
1899                 ScrollToCaret();
1900                 InvalidateLineCol(lineIndex + 11 + col + LineNumberFieldLength());
1901                 SetDirty();
1902                 SetCCDirty();
1903             }
1904         }
1905         public nothrow void AddSpaces(int lineIndexint columnIndexint numSpaces)
1906         {
1907             ustring& line = lines[lineIndex];
1908             line.Insert(columnIndex - numSpacesustring(' 'numSpaces));
1909             LineEventArgs args(lineIndex-1);
1910             OnLineChanged(args);
1911             SetCaretLineCol(lineIndex + 1columnIndex + 1 + LineNumberFieldLength() - numSpaces);
1912             ScrollToCaret();
1913             InvalidateLineCol(lineIndex + 11 + LineNumberFieldLength());
1914             SetDirty();
1915             SetCCDirty();
1916         }
1917         public nothrow void RemoveSpaces(int lineIndexint columnIndexint numSpaces)
1918         {
1919             ustring& line = lines[lineIndex];
1920             line.Remove(columnIndex - numSpacesnumSpaces);
1921             LineEventArgs args(lineIndex-1);
1922             OnLineChanged(args);
1923             SetCaretLineCol(lineIndex + 1columnIndex + 1 + LineNumberFieldLength() - numSpaces);
1924             ScrollToCaret();
1925             InvalidateLineCol(lineIndex + 11 + LineNumberFieldLength());
1926             SetDirty();
1927             SetCCDirty();
1928         }
1929         protected virtual void OnCopy()
1930         {
1931             copyEvent.Fire();
1932         }
1933         protected virtual void OnPaste()
1934         {
1935             pasteEvent.Fire();
1936         }
1937         protected virtual void OnCut()
1938         {
1939             cutEvent.Fire();
1940         }
1941         protected override nothrow void SetContentLocationInternal(const Point& contentLocation)
1942         {
1943             topLine = cast<int>(contentLocation.y / charHeight + 1.5f);
1944             topLineDiff = (topLine - 1) * charHeight - contentLocation.y;
1945             leftCol = cast<int>(contentLocation.x / charWidth + 1.5f);
1946             leftColDiff = (leftCol - 1) * charWidth - contentLocation.x;
1947             base->SetContentLocationInternal(contentLocation);
1948         }
1949         public void ScrollToCaret()
1950         {
1951             if (lines.IsEmpty() || charHeight == 0) return;
1952             Size size = GetSize();
1953             int windowLines = cast<int>(size.h / charHeight);
1954             int windowCols = cast<int>(size.w / charWidth);
1955             Point currentOrigin = ContentLocation();
1956             int topLineNumber = cast<int>(currentOrigin.y / charHeight + 1);
1957             int leftColNumber = cast<int>(currentOrigin.x / charWidth + 1);
1958             int oldTopLineNumber = topLineNumber;
1959             if (caretLine > topLineNumber)
1960             {
1961                 while (caretLine - topLineNumber + 1 >= windowLines)
1962                 {
1963                     ++topLineNumber;
1964                 }
1965             }
1966             else if (caretLine < topLineNumber)
1967             {
1968                 topLineNumber = caretLine;
1969             }
1970             else
1971             {
1972                 topLineNumber = Max(cast<int>(1)caretLine - 1);
1973             }
1974             int oldLeftColNumber = leftColNumber;
1975             if (caretColumn >= leftColNumber)
1976             {
1977                 while (caretColumn - leftColNumber + 2 >= windowCols)
1978                 {
1979                     ++leftColNumber;
1980                 }
1981             }
1982             else
1983             {
1984                 if (caretColumn == 1 + LineNumberFieldLength())
1985                 {
1986                     leftColNumber = 1;
1987                 }
1988                 else
1989                 {
1990                     leftColNumber = caretColumn;
1991                 }
1992             }
1993             if (update || caretLine == 1 || topLineNumber != oldTopLineNumber || leftColNumber != oldLeftColNumber)
1994             {
1995                 update = false;
1996                 Point newOrigin(cast<int>((leftColNumber - 1) * charWidth)cast<int>((topLineNumber - 1) * charHeight));
1997                 topLine = topLineNumber;
1998                 topLineDiff = 0.0f;
1999                 leftCol = leftColNumber;
2000                 leftColDiff = 0.0f;
2001                 SetContentLocation(newOrigin);
2002                 SetCaretLocation();
2003                 Invalidate();
2004             }
2005         }
2006         public virtual nothrow int LineNumberFieldLength() const
2007         {
2008             return 0;
2009         }
2010         protected virtual nothrow void SetLineNumberFieldLength(int lineCount)
2011         {
2012         }
2013         protected override void CreateCaret()
2014         {
2015             if (charHeight != 0)
2016             {
2017                 System.Windows.API.CreateCaret(Handle()null1cast<int>(charHeight));
2018             }
2019             else
2020             {
2021                 base->CreateCaret();
2022             }
2023             SetTimer(1ucaretTimerPeriod);
2024         }
2025         protected override void OnTimer(TimerEventArgs& args)
2026         {
2027             base->OnTimer(args);
2028             if (Focused())
2029             {
2030                 HideCaret();
2031                 ShowCaret();
2032             }
2033         }
2034         protected override void OnLostFocus()
2035         {
2036             base->OnLostFocus();
2037             KillTimer(1u);
2038         }
2039         protected override void OnClick()
2040         {
2041             base->OnClick();
2042             SetFocus();
2043             ResetSelection();
2044         }
2045         protected override void OnMouseDoubleClick(MouseEventArgs& args)
2046         {
2047             base->OnMouseDoubleClick(args);
2048             ResetMouseExtendSelection();
2049             mouseSelectionStart = SourcePos();
2050             mouseSelectionEnd = SourcePos();
2051             SetFocus();
2052             ResetSelection();
2053             int line = 0;
2054             int column = 0;
2055             GetLineColumn(args.locationlinecolumn);
2056             uchar c = GetCharAt(linecolumn);
2057             while (!IsWhiteSpace(c) && !IsWordSeparator(c))
2058             {
2059                 if (column == 1 || !Prev(linecolumn))
2060                 {
2061                     break;
2062                 }
2063                 c = GetCharAt(linecolumn);
2064             }
2065             c = GetCharAt(linecolumn);
2066             if (IsWhiteSpace(c) || IsWordSeparator(c))
2067             {
2068                 Next(linecolumn);
2069             }
2070             SourcePos start(linecolumn);
2071             c = GetCharAt(linecolumn);
2072             while (!IsWhiteSpace(c) && !IsWordSeparator(c))
2073             {
2074                 if (!Next(linecolumn))
2075                 {
2076                     break;
2077                 }
2078                 c = GetCharAt(linecolumn);
2079             }
2080             if (!IsWhiteSpace(c) && !IsWordSeparator(c))
2081             {
2082                 column = column + 1;
2083             }
2084             SourcePos end(linecolumn);
2085             ExtendSelection(startend);
2086             SetCaretLineCol(start.linestart.column + LineNumberFieldLength());
2087             ScrollToCaret();
2088             InvalidateLineCol(start.linestart.column);
2089         }
2090         protected override void SetCursor()
2091         {
2092             SetCursor(cursor);
2093         }
2094         protected override void SetCaretLocation()
2095         {
2096             int x = cast<int>(padding.left + (caretColumn - 1) * charWidth);
2097             int y = cast<int>(padding.top + (caretLine - 1) * charHeight);
2098             Point caretPos(xy);
2099             TranslateContentLocation(caretPos);
2100             if (CaretCreated())
2101             {
2102                 SetCaretPos(caretPos);
2103                 OnCaretPosChanged();
2104             }
2105         }
2106         protected virtual void OnCaretPosChanged()
2107         {
2108             caretPosChangedEvent.Fire();
2109         }
2110         protected virtual void OnLinesChanged()
2111         {
2112             linesChangedEvent.Fire();
2113         }
2114         protected virtual void OnLineChanged(LineEventArgs& args)
2115         {
2116             lineChangedEvent.Fire(args);
2117             InvalidateLineCol(args.lineIndex + 11 + LineNumberFieldLength());
2118         }
2119         protected virtual void OnLineDeleted(LineEventArgs& args)
2120         {
2121             lineDeletedEvent.Fire(args);
2122             Invalidate();
2123         }
2124         protected virtual void OnLineInserted(LineEventArgs& args)
2125         {
2126             lineInsertedEvent.Fire(args);
2127             int lineIndex = args.lineIndex;
2128             ustring& line = Lines()[lineIndex];
2129             int indent = 0;
2130             if (args.indentLineIndex >= 0 && args.indentLineIndex < Lines().Count())
2131             {
2132                 indent = GetIndent(Lines()[args.indentLineIndex]args.indentLineIndex);
2133             }
2134             if (indent != 0)
2135             {
2136                 line.Insert(0ustring(' 'indent));
2137             }
2138             Invalidate();
2139         }
2140         public inline nothrow int MaxLineLength() const
2141         {
2142             return maxLineLength;
2143         }
2144         public inline nothrow int MaxLineIndex() const
2145         {
2146             return maxLineIndex;
2147         }
2148         protected nothrow void SetMaxLineLength()
2149         {
2150             maxLineLength = 0;
2151             maxLineIndex = 0;
2152             int n = cast<int>(lines.Count());
2153             for (int i = 0; i < n; ++i;)
2154             {
2155                 const ustring& line = lines[i];
2156                 if (line.Length() > maxLineLength)
2157                 {
2158                     maxLineLength = cast<int>(line.Length());
2159                     maxLineIndex = i;
2160                 }
2161             }
2162         }
2163         public inline nothrow const Padding& GetPadding() const
2164         {
2165             return padding;
2166         }
2167         public nothrow void SetPadding(const Padding& padding_)
2168         {
2169             if (padding != padding_)
2170             {
2171                 padding = padding_;
2172                 Invalidate();
2173             }
2174         }
2175         protected virtual void OnSelectionChanged()
2176         {
2177             selectionChangedEvent.Fire();
2178         }
2179         protected virtual void OnDirtyChanged()
2180         {
2181             dirtyChangedEvent.Fire();
2182         }
2183         protected virtual void OnCCDirtyChanged()
2184         {
2185             ccdirtyChangedEvent.Fire();
2186         }
2187         protected virtual void OnCC()
2188         {
2189             ccEvent.Fire();
2190         }
2191         public void SaveText(const string& filePath)
2192         {
2193             StreamWriter writer = File.CreateText(filePath);
2194             for (const ustring& line : lines)
2195             {
2196                 writer.WriteLine(line);
2197             }
2198         }
2199         public nothrow void SetCCText(const ustring& lineint columnIndex)
2200         {
2201             cctext.Clear();
2202             while (columnIndex >= line.Length())
2203             {
2204                 --columnIndex;
2205             }
2206             while (columnIndex >= 0)
2207             {
2208                 if (IsCCStopChar(line[columnIndex]))
2209                 {
2210                     break;
2211                 }
2212                 cctext.Append(line[columnIndex]);
2213                 --columnIndex;
2214             }
2215             Reverse(cctext.Begin()cctext.End());
2216             OnCCTextChanged();
2217         }
2218         public nothrow void ResetCCText()
2219         {
2220             cctext.Clear();
2221             OnCCTextChanged();
2222         }
2223         protected virtual nothrow void OnCCTextChanged()
2224         {
2225             cctextChangedEvent.Fire();
2226         }
2227         public inline nothrow const ustring& GetCCText() const
2228         {
2229             return cctext;
2230         }
2231         public nothrow void ReplaceCCText(const ustring& replacement)
2232         {
2233             int caretLineIndex = Max(0caretLine - 1);
2234             int caretColumnIndex = Max(0caretColumn - 1);
2235             if (caretLineIndex < lines.Count())
2236             {
2237                 ustring& line = lines[caretLineIndex];
2238                 while (caretColumnIndex > line.Length())
2239                 {
2240                     --caretColumnIndex;
2241                 }
2242                 int endColumnIndex = Max(0caretColumnIndex);
2243                 while (caretColumnIndex > 0)
2244                 {
2245                     if (caretColumnIndex < line.Length())
2246                     {
2247                         if (IsCCStopChar(line[caretColumnIndex]))
2248                         {
2249                             ++caretColumnIndex;
2250                             break;
2251                         }
2252                     }
2253                     --caretColumnIndex;
2254                 }
2255                 int startColumndIndex = Max(0caretColumnIndex);
2256                 line = line.Substring(0startColumndIndex) + replacement + line.Substring(endColumnIndex);
2257                 int newEndColumnIndex = startColumndIndex + cast<int>(replacement.Length());
2258                 LineEventArgs args(caretLineIndex-1);
2259                 OnLineChanged(args);
2260                 SetCaretLineCol(caretLineIndex + 1newEndColumnIndex + 1 + LineNumberFieldLength());
2261                 ScrollToCaret();
2262                 Invalidate();
2263                 SetDirty();
2264                 SetCCDirty();
2265             }
2266         }
2267         public nothrow ustring GetCursorText() const
2268         {
2269             ustring cursorText;
2270             int caretIndex = Max(0caretColumn - 1);
2271             long n = lines.Count();
2272             for (long i = 0; i < n; ++i;)
2273             {
2274                 const ustring& line = lines[i];
2275                 int lineNumber = cast<int>(i + 1);
2276                 if (lineNumber == caretLine)
2277                 {
2278                     int startIndex = caretIndex;
2279                     while (startIndex > 0)
2280                     {
2281                         if (startIndex < line.Length())
2282                         {
2283                             bool exit = false;
2284                             switch (line[startIndex])
2285                             {
2286                                 case ';':
2287                                 case '{':
2288                                 case '}':
2289                                 {
2290                                     ++startIndex;
2291                                     exit = true;
2292                                     break;
2293                                 }
2294                             }
2295                             if (exit)
2296                             {
2297                                 break;
2298                             }
2299                         }
2300                         --startIndex;
2301                     }
2302                     cursorText.Append(line.Substring(0startIndex)).Append('$').Append(line.Substring(caretIndex)).Append('\n');
2303                 }
2304                 else
2305                 {
2306                     cursorText.Append(line).Append('\n');
2307                 }
2308             }
2309             return cursorText;
2310         }
2311         public nothrow void SetSelection(const Selection& selection_)
2312         {
2313             selection = selection_;
2314             Invalidate();
2315         }
2316         public nothrow void ResetSelection()
2317         {
2318             if (!selection.IsEmpty())
2319             {
2320                 selection = Selection();
2321                 OnSelectionChanged();
2322                 Invalidate();
2323             }
2324         }
2325         public nothrow bool IsSelectionEmpty() const
2326         {
2327             return selection.IsEmpty();
2328         }
2329         public nothrow SelectionData GetSelection() const
2330         {
2331             if (selection.IsEmpty()) return SelectionData();
2332             if (selection.start.line == selection.end.line)
2333             {
2334                 ustring s = lines[selection.start.line - 1].Substring(selection.start.column - 1selection.end.column - selection.start.column);
2335                 int indent = MinIndent(s);
2336                 SelectionData selectionData(Unindent(sindent)indent0);
2337                 return selectionData;
2338             }
2339             else
2340             {
2341                 int numTrailingSpaces = 0;
2342                 ustring s = lines[selection.start.line - 1].Substring(selection.start.column - 1).Append(u"\n");
2343                 for (int i = selection.start.line; i < selection.end.line - 1; ++i;)
2344                 {
2345                     s.Append(lines[i]).Append(u"\n");
2346                 }
2347                 if (selection.end.line - 1 < lines.Count())
2348                 {
2349                     if (!lines[selection.end.line - 1].Substring(0selection.end.column - 1).IsEmpty())
2350                     {
2351                         ustring lastLine = lines[selection.end.line - 1].Substring(0selection.end.column - 1);
2352                         numTrailingSpaces = GetNumTrailingSpaces(lastLine);
2353                         s.Append(lastLine).Append(u"\n");
2354                     }
2355                 }
2356                 else
2357                 {
2358                     int i = selection.end.line - 1;
2359                     while (i >= lines.Count())
2360                     {
2361                         s.Append(u"\n");
2362                         --i;
2363                     }
2364                 }
2365                 int indent = MinIndent(s);
2366                 SelectionData selectionData(Unindent(sindent)indentnumTrailingSpaces);
2367                 return selectionData;
2368             }
2369         }
2370         public nothrow void InsertSelection(const Selection& selectionToInsertconst SelectionData& selectionDatabool wholeLine)
2371         {
2372             if (selectionToInsert.IsEmpty()) return;
2373             if (selectionToInsert.start.line == selectionToInsert.end.line)
2374             {
2375                 if (wholeLine)
2376                 {
2377                     int lineIndex = selectionToInsert.start.line - 1;
2378                     ustring selectedText = selectionData.selectedText;
2379                     if (selectionData.indent > 0)
2380                     {
2381                         selectedText.Insert(0ustring(' 'selectionData.indent));
2382                     }
2383                     lines.Insert(lines.Begin() + lineIndexselectedText);
2384                     LineEventArgs insertArgs(lineIndex-1);
2385                     OnLineInserted(insertArgs);
2386                     SetCaretLineCol(lineIndex + 11 + LineNumberFieldLength());
2387                 }
2388                 else
2389                 {
2390                     int lineIndex = selectionToInsert.start.line - 1;
2391                     ustring selectedText = selectionData.selectedText;
2392                     if (selectionData.indent > 0)
2393                     {
2394                         selectedText.Insert(0ustring(' 'selectionData.indent));
2395                     }
2396                     lines[lineIndex].Insert(selectionToInsert.start.column - 1selectedText);
2397                     LineEventArgs changeArgs(lineIndex-1);
2398                     OnLineChanged(changeArgs);
2399                     SetCaretLineCol(lineIndex + 1selectionToInsert.start.column + LineNumberFieldLength());
2400                 }
2401             }
2402             else
2403             {
2404                 List<ustring> selectionLines = SplitTextIntoLines(selectionData.selectedText);
2405                 int startLineIndex = selectionToInsert.start.line - 1;
2406                 int endLineIndex = selectionToInsert.end.line - 1;
2407                 int lineCount =  endLineIndex - startLineIndex + 1;
2408                 if (selectionToInsert.start.column > 1)
2409                 {
2410                     ustring firstSelectionLine = selectionLines[0];
2411                     if (selectionData.indent > 0)
2412                     {
2413                         firstSelectionLine.Insert(0ustring(' 'selectionData.indent));
2414                     }
2415                     lines[startLineIndex].Insert(selectionToInsert.start.column - 1firstSelectionLine);
2416                     LineEventArgs changeArgs(startLineIndex-1);
2417                     OnLineChanged(changeArgs);
2418                     ++startLineIndex;
2419                 }
2420                 else
2421                 {
2422                     ustring firstSelectionLine = selectionLines[0];
2423                     if (selectionData.indent > 0)
2424                     {
2425                         firstSelectionLine.Insert(0ustring(' 'selectionData.indent));
2426                     }
2427                     lines.Insert(lines.Begin() + startLineIndexfirstSelectionLine);
2428                     LineEventArgs insertArgs(startLineIndex-1);
2429                     OnLineInserted(insertArgs);
2430                     ++startLineIndex;
2431                 }
2432                 int n = endLineIndex;
2433                 for (int i = startLineIndex; i < n; ++i;)
2434                 {
2435                     ustring selectionLine = selectionLines[i - startLineIndex + 1];
2436                     if (selectionData.indent > 0)
2437                     {
2438                         selectionLine.Insert(0ustring(' 'selectionData.indent));
2439                     }
2440                     lines.Insert(lines.Begin() + iselectionLine);
2441                     LineEventArgs insertArgs(i-1);
2442                     OnLineInserted(insertArgs);
2443                 }
2444                 ustring lastLine;
2445                 if (selectionLines.Count() >= lineCount)
2446                 {
2447                     lastLine = selectionLines.Back();
2448                     if (selectionData.indent > 0)
2449                     {
2450                         lastLine.Insert(0ustring(' 'selectionData.indent));
2451                     }
2452                     lastLine.Append(' 'selectionData.numTrailingSpaces);
2453                 }
2454                 if (wholeLine)
2455                 {
2456                     lines.Insert(lines.Begin() + endLineIndexlastLine);
2457                     LineEventArgs insertArgs(endLineIndex-1);
2458                     OnLineInserted(insertArgs);
2459                 }
2460                 else
2461                 {
2462                     lines[endLineIndex].Insert(0lastLine);
2463                     LineEventArgs changeArgs(endLineIndex-1);
2464                     OnLineChanged(changeArgs);
2465                 }
2466             }
2467             selection = selectionToInsert;
2468             SetCaretLineCol(selection.end.lineselection.end.column + LineNumberFieldLength());
2469             Invalidate();
2470             SetDirty();
2471             SetCCDirty();
2472         }
2473         public nothrow void AddRemoveSelectionCommand()
2474         {
2475             if (selection.IsEmpty()) return;
2476             bool wholeLine = false;
2477             SelectionData selectionData = GetSelection();
2478             if (selection.start.line == selection.end.line)
2479             {
2480                 if (selection.end.column - selection.start.column >= GetLineLength(selection.start.line))
2481                 {
2482                     wholeLine = true;
2483                 }
2484             }
2485             else
2486             {
2487                 int endLineIndex = selection.end.line - 1;
2488                 if (selection.end.column > GetLineLength(endLineIndex + 1))
2489                 {
2490                     wholeLine = true;
2491                 }
2492             }
2493             editCommandList.AddCommand(new RemoveSelectionCommand(selectionselectionDatawholeLine));
2494         }
2495         public nothrow void RemoveSelection()
2496         {
2497             if (selection.IsEmpty()) return;
2498             if (selection.start.line == selection.end.line)
2499             {
2500                 if (selection.end.column - selection.start.column >= GetLineLength(selection.start.line))
2501                 {
2502                     int lineIndex = selection.start.line - 1;
2503                     lines.Remove(lines.Begin() + lineIndex);
2504                     LineEventArgs deleteArgs(lineIndex-1);
2505                     OnLineDeleted(deleteArgs);
2506                     SetCaretLineCol(selection.start.line1 + LineNumberFieldLength());
2507                 }
2508                 else
2509                 {
2510                     int lineIndex = selection.start.line - 1;
2511                     lines[lineIndex].Remove(selection.start.column - 1selection.end.column - selection.start.column);
2512                     LineEventArgs changeArgs(lineIndex-1);
2513                     OnLineChanged(changeArgs);
2514                     SetCaretLineCol(lineIndex + 1selection.start.column + LineNumberFieldLength());
2515                 }
2516             }
2517             else
2518             {
2519                 int startLineIndex = selection.start.line - 1;
2520                 int endLineIndex = selection.end.line - 1;
2521                 if (selection.start.column > 1)
2522                 {
2523                     lines[startLineIndex].Remove(selection.start.column - 1GetLineLength(startLineIndex + 1) - selection.start.column + 1);
2524                     LineEventArgs changeArgs(startLineIndex-1);
2525                     OnLineChanged(changeArgs);
2526                     ++startLineIndex;
2527                 }
2528                 else
2529                 {
2530                     lines.Remove(lines.Begin() + startLineIndex);
2531                     --endLineIndex;
2532                     LineEventArgs deleteArgs(startLineIndex-1);
2533                     OnLineDeleted(deleteArgs);
2534                 }
2535                 int n = endLineIndex;
2536                 for (int i = startLineIndex; i < n; ++i;)
2537                 {
2538                     lines.Remove(lines.Begin() + startLineIndex);
2539                     --endLineIndex;
2540                     LineEventArgs deleteArgs(startLineIndex-1);
2541                     OnLineDeleted(deleteArgs);
2542                 }
2543                 if (endLineIndex >= 0 && endLineIndex < lines.Count())
2544                 {
2545                     if (selection.end.column > GetLineLength(endLineIndex + 1))
2546                     {
2547                         lines.Remove(lines.Begin() + endLineIndex);
2548                         LineEventArgs deleteArgs(endLineIndex-1);
2549                         OnLineDeleted(deleteArgs);
2550                     }
2551                     else
2552                     {
2553                         lines[endLineIndex].Remove(0selection.end.column - 1);
2554                         LineEventArgs changeArgs(endLineIndex-1);
2555                         OnLineChanged(changeArgs);
2556                     }
2557                 }
2558                 SetCaretLineCol(selection.start.lineselection.start.column + LineNumberFieldLength());
2559             }
2560             ResetSelection();
2561             Invalidate();
2562             SetDirty();
2563             SetCCDirty();
2564             SetFocus();
2565         }
2566         private nothrow void AddIndentSelectionCommand()
2567         {
2568             editCommandList.AddCommand(new IndentSelectionCommand(selection));
2569         }
2570         public nothrow void IndentSelection()
2571         {
2572             if (selection.IsEmpty()) return;
2573             int startLineIndex = selection.start.line - 1;
2574             int endLineIndex = selection.end.line - 1;
2575             ustring indentString(' 'IndentSize());
2576             for (int i = startLineIndex; i <= endLineIndex; ++i;)
2577             {
2578                 if (lines[i].IsEmpty()) continue;
2579                 if (i == selection.end.line - 1 && lines[i].Substring(0selection.end.column - 1).IsEmpty()) continue;
2580                 lines[i].Insert(0indentString);
2581                 LineEventArgs changeArgs(i-1);
2582                 OnLineChanged(changeArgs);
2583             }
2584             InvalidateLines(selection.start.lineselection.end.line);
2585             SetDirty();
2586             SetCCDirty();
2587         }
2588         public nothrow void AddUnindentSelectionCommand()
2589         {
2590             editCommandList.AddCommand(new UnindentSelectionCommand(selection));
2591         }
2592         public nothrow void UnindentSelection()
2593         {
2594             if (selection.IsEmpty()) return;
2595             int startLineIndex = selection.start.line - 1;
2596             int endLineIndex = selection.end.line - 1;
2597             ustring indentString(' 'IndentSize());
2598             for (int i = startLineIndex; i <= endLineIndex; ++i;)
2599             {
2600                 ustring line = lines[i];
2601                 if (i == endLineIndex)
2602                 {
2603                     line = line.Substring(0selection.end.column - 1);
2604                 }
2605                 if (line.StartsWith(indentString))
2606                 {
2607                     lines[i].Remove(0IndentSize());
2608                     LineEventArgs changeArgs(i-1);
2609                     OnLineChanged(changeArgs);
2610                 }
2611             }
2612             InvalidateLines(selection.start.lineselection.end.line);
2613             SetDirty();
2614             SetCCDirty();
2615         }
2616         public nothrow void ExtendSelection(const SourcePos& startconst SourcePos& end)
2617         {
2618             switch (selection.fixed)
2619             {
2620                 case Selection.Fix.none:
2621                 {
2622                     if (start < end)
2623                     {
2624                         selection.fixed = Selection.Fix.start;
2625                         selection.start = start;
2626                         selection.end = end;
2627                     }
2628                     else
2629                     {
2630                         selection.fixed = Selection.Fix.end;
2631                         selection.end = start;
2632                         selection.start = end;
2633                     }
2634                     break;
2635                 }
2636                 case Selection.Fix.start:
2637                 {
2638                     if (end == selection.start)
2639                     {
2640                         ResetSelection();
2641                     }
2642                     else if (end > selection.start)
2643                     {
2644                         selection.end = end;
2645                     }
2646                     else
2647                     {
2648                         selection.fixed = Selection.Fix.end;
2649                         selection.end = start;
2650                         selection.start = end;
2651                     }
2652                     break;
2653                 }
2654                 case Selection.Fix.end:
2655                 {
2656                     if (end == selection.end)
2657                     {
2658                         ResetSelection();
2659                     }
2660                     else if (end < selection.end)
2661                     {
2662                         selection.start = end;
2663                     }
2664                     else
2665                     {
2666                         selection.fixed = Selection.Fix.start;
2667                         selection.start = start;
2668                         selection.end = end;
2669                     }
2670                     break;
2671                 }
2672             }
2673             OnSelectionChanged();
2674         }
2675         public Brush* GetOrInsertBrush(const Color& color)
2676         {
2677             HashMap<ColorBrush*>.ConstIterator it = colorBrushMap.CFind(color);
2678             if (it != colorBrushMap.CEnd())
2679             {
2680                 return it->second;
2681             }
2682             Brush* brush = new SolidBrush(color);
2683             brushes.Add(UniquePtr<Brush>(brush));
2684             colorBrushMap[color] = brush;
2685             return brush;
2686         }
2687         protected inline nothrow bool Changed() const
2688         {
2689             return (flags & Flags.changed) != Flags.none;
2690         }
2691         protected inline nothrow void SetChanged()
2692         {
2693             flags = cast<Flags>(flags | Flags.changed);
2694         }
2695         protected inline nothrow void ResetChanged()
2696         {
2697             flags = cast<Flags>(flags & ~Flags.changed);
2698         }
2699         public inline nothrow bool Painting() const
2700         {
2701             return (flags &  Flags.painting) != Flags.none;
2702         }
2703         private inline nothrow void SetPainting()
2704         {
2705             flags = cast<Flags>(flags | Flags.painting);
2706         }
2707         private inline nothrow void ResetPainting()
2708         {
2709             flags = cast<Flags>(flags & ~Flags.painting);
2710         }
2711         public inline nothrow bool IsReadOnly() const
2712         {
2713             return (flags & Flags.readOnly) != Flags.none;
2714         }
2715         public nothrow void SetReadOnly()
2716         {
2717             flags = cast<Flags>(flags | Flags.readOnly);
2718         }
2719         public nothrow void ResetReadOnly()
2720         {
2721             flags = cast<Flags>(flags & ~Flags.readOnly);
2722         }
2723         public inline nothrow bool IsFixed() const
2724         {
2725             return (flags & Flags.fixed) != Flags.none;
2726         }
2727         public nothrow void SetFixed()
2728         {
2729             flags = cast<Flags>(flags | Flags.fixed);
2730         }
2731         public nothrow void ResetFixed()
2732         {
2733             flags = cast<Flags>(flags & ~Flags.fixed);
2734         }
2735         public inline nothrow bool IsDirty() const
2736         {
2737             return (flags & Flags.dirty) != Flags.none;
2738         }
2739         public nothrow void SetDirty()
2740         {
2741             if (!IsDirty())
2742             {
2743                 flags = cast<Flags>(flags | Flags.dirty);
2744                 OnDirtyChanged();
2745             }
2746         }
2747         public nothrow void ResetDirty()
2748         {
2749             if (IsDirty())
2750             {
2751                 flags = cast<Flags>(flags & ~Flags.dirty);
2752                 OnDirtyChanged();
2753             }
2754         }
2755         public inline nothrow bool IsCCDirty() const
2756         {
2757             return (flags & Flags.ccdirty) != Flags.none;
2758         }
2759         public nothrow void SetCCDirty()
2760         {
2761             if (!IsCCDirty())
2762             {
2763                 flags = cast<Flags>(flags | Flags.ccdirty);
2764                 OnCCDirtyChanged();
2765             }
2766         }
2767         public nothrow void ResetCCDirty()
2768         {
2769             if (IsCCDirty())
2770             {
2771                 flags = cast<Flags>(flags & ~Flags.ccdirty);
2772                 OnCCDirtyChanged();
2773             }
2774         }
2775         private inline nothrow bool MouseExtendSelection() const
2776         {
2777             return (flags & Flags.mouseExtendSelection) != Flags.none;
2778         }
2779         private nothrow void SetMouseExtendSelection()
2780         {
2781             flags = cast<Flags>(flags | Flags.mouseExtendSelection);
2782         }
2783         private nothrow void ResetMouseExtendSelection()
2784         {
2785             flags = cast<Flags>(flags & ~Flags.mouseExtendSelection);
2786         }
2787         public inline nothrow bool CCOpen() const
2788         {
2789             return (flags & Flags.ccOpen) != Flags.none;
2790         }
2791         public nothrow void SetCCOpen()
2792         {
2793             flags = cast<Flags>(flags | Flags.ccOpen);
2794         }
2795         public nothrow void ResetCCOpen()
2796         {
2797             flags = cast<Flags>(flags & ~Flags.ccOpen);
2798         }
2799         public nothrow Event<CaretPosChangedEventHandler>& CaretPosChangedEvent() const
2800         {
2801             return caretPosChangedEvent;
2802         }
2803         public nothrow Event<LinesChangedEventHandler>& LinesChangedEvent() const
2804         {
2805             return linesChangedEvent;
2806         }
2807         public nothrow Event<LineChangedEventHandlerLineEventArgs>& LineChangedEvent() const
2808         {
2809             return lineChangedEvent;
2810         }
2811         public nothrow Event<LineDeletedEventHandlerLineEventArgs>& LineDeletedEvent() const
2812         {
2813             return lineDeletedEvent;
2814         }
2815         public nothrow Event<LineInsertedEventHandlerLineEventArgs>& LineInsertedEvent() const
2816         {
2817             return lineInsertedEvent;
2818         }
2819         public nothrow Event<GotoCaretLineEventHandlerControlEventArgs>& GotoCaretLineEvent() const
2820         {
2821             return gotoCaretLineEvent;
2822         }
2823         public nothrow Event<SelectionChangedEventHandler>& SelectionChangedEvent() const
2824         {
2825             return selectionChangedEvent;
2826         }
2827         public nothrow Event<DirtyChangedEventHandler>& DirtyChangedEvent() const
2828         {
2829             return dirtyChangedEvent;
2830         }
2831         public nothrow Event<CCDirtyChangedEventHandler>& CCDirtyChangedEvent() const
2832         {
2833             return ccdirtyChangedEvent;
2834         }
2835         public nothrow Event<CCTextChangedEventHandler>& CCTextChangedEvent() const
2836         {
2837             return cctextChangedEvent;
2838         }
2839         public nothrow Event<CCEventHandler>& CCEvent() const
2840         {
2841             return ccEvent;
2842         }
2843         public nothrow Event<EscapePressedHandler>& EscapePressedEvent() const
2844         {
2845             return escapePressedEvent;
2846         }
2847         public nothrow Event<CCNextEventHandler>& CCNextEvent() const
2848         {
2849             return ccNextEvent;
2850         }
2851         public nothrow Event<CCPrevEventHandler>& CCPrevEvent() const
2852         {
2853             return ccPrevEvent;
2854         }
2855         public nothrow Event<CCNextPageEventHandler>& CCNextPageEvent() const
2856         {
2857             return ccNextPageEvent;
2858         }
2859         public nothrow Event<CCPrevPageEventHandler>& CCPrevPageEvent() const
2860         {
2861             return ccPrevPageEvent;
2862         }
2863         public nothrow Event<CCSelectEventHandler>& CCSelectEvent() const
2864         {
2865             return ccSelectEvent;
2866         }
2867         public nothrow Event<CopyEventHandler>& CopyEvent() const
2868         {
2869             return copyEvent;
2870         }
2871         public nothrow Event<CutEventHandler>& CutEvent() const
2872         {
2873             return cutEvent;
2874         }
2875         public nothrow Event<PasteEventHandler>& PasteEvent() const
2876         {
2877             return pasteEvent;
2878         }
2879         public void InvalidateLineCol(int lineNumberint columnNumber)
2880         {
2881             if (charHeight != 0 && charWidth != 0)
2882             {
2883                 Point pt(cast<int>(charWidth * (columnNumber - 1))cast<int>(charHeight * (lineNumber - 1)));
2884                 TranslateContentLocation(pt);
2885                 Size size = GetSize();
2886                 Size sz(size.w - pt.xcast<int>(charHeight + 1.5f));
2887                 Rect rect(ptsz);
2888                 Invalidate(rect);
2889             }
2890             else
2891             {
2892                 Invalidate();
2893             }
2894         }
2895         public void InvalidateLines(int startLineNumberint endLineNumber)
2896         {
2897             if (charHeight != 0 && charWidth != 0)
2898             {
2899                 Point pt(0cast<int>(charHeight * (startLineNumber - 1) - charHeight));
2900                 TranslateContentLocation(pt);
2901                 Size size = GetSize();
2902                 Size sz(size.wcast<int>(charHeight * (endLineNumber - startLineNumber + 1) + 2 * charHeight + 1.5f));
2903                 Rect rect(ptsz);
2904                 Invalidate(rect);
2905             }
2906             else
2907             {
2908                 Invalidate();
2909             }
2910         }
2911         public nothrow void SetFilePath(const string& filePath_)
2912         {
2913             filePath = filePath_;
2914         }
2915         public nothrow const string& FilePath() const
2916         {
2917             return filePath;
2918         }
2919         private Flags flags;
2920         private List<ustring> lines;
2921         private List<int> lineStartIndeces;
2922         private StringFormat drawFormat;
2923         private FontFamily fontFamily;
2924         private Color textColor;
2925         private List<UniquePtr<Font>> fonts;
2926         private List<UniquePtr<Brush>> brushes;
2927         private HashMap<ColorBrush*> colorBrushMap;
2928         private float fontSize;
2929         private float charWidth;
2930         private float charHeight;
2931         private int textWidth;
2932         private int textHeight;
2933         private int maxLineLength;
2934         private int maxLineIndex;
2935         private Cursor cursor;
2936         private int caretLine;
2937         private int caretColumn;
2938         private int topLine;
2939         private int leftCol;
2940         private float topLineDiff;
2941         private float leftColDiff;
2942         private uint caretTimerPeriod;
2943         private bool update;
2944         private Padding padding;
2945         private Event<CaretPosChangedEventHandler> caretPosChangedEvent;
2946         private Event<LinesChangedEventHandler> linesChangedEvent;
2947         private Event<LineChangedEventHandlerLineEventArgs> lineChangedEvent;
2948         private Event<LineDeletedEventHandlerLineEventArgs> lineDeletedEvent;
2949         private Event<LineInsertedEventHandlerLineEventArgs> lineInsertedEvent;
2950         private Event<GotoCaretLineEventHandlerControlEventArgs> gotoCaretLineEvent;
2951         private Event<SelectionChangedEventHandler> selectionChangedEvent;
2952         private Event<DirtyChangedEventHandler> dirtyChangedEvent;
2953         private Event<CCDirtyChangedEventHandler> ccdirtyChangedEvent;
2954         private Event<CCTextChangedEventHandler> cctextChangedEvent;
2955         private Event<CCEventHandler> ccEvent;
2956         private Event<CCNextEventHandler> ccNextEvent;
2957         private Event<CCPrevEventHandler> ccPrevEvent;
2958         private Event<CCNextPageEventHandler> ccNextPageEvent;
2959         private Event<CCPrevPageEventHandler> ccPrevPageEvent;
2960         private Event<CCSelectEventHandler> ccSelectEvent;
2961         private Event<EscapePressedHandler> escapePressedEvent;
2962         private Event<CopyEventHandler> copyEvent;
2963         private Event<CutEventHandler> cutEvent;
2964         private Event<PasteEventHandler> pasteEvent;
2965         private string measureString;
2966         private Selection selection;
2967         private SourcePos mouseSelectionStart;
2968         private SourcePos mouseSelectionEnd;
2969         private System.Windows.Color selectionBackgroundColor;
2970         private EditCommandList editCommandList;
2971         private int indentSize;
2972         private string filePath;
2973         private ustring cctext;
2974     }
2975 
2976     public nothrow ustring TrimEnd(const ustring& line)
2977     {
2978         long i = line.Length();
2979         while (i > 0 && IsWhiteSpace(line[i - 1]))
2980         {
2981             --i;
2982         }
2983         return line.Substring(0i);
2984     }
2985 
2986     public nothrow int GetNumTrailingSpaces(const ustring& line)
2987     {
2988         int numTrailingSpaces = 0;
2989         long i = line.Length();
2990         while (i > 0 && IsWhiteSpace(line[i - 1]))
2991         {
2992             --i;
2993             ++numTrailingSpaces;
2994         }
2995         return numTrailingSpaces;
2996     }
2997 
2998     public List<ustring> SplitTextIntoLines(const ustring& text)
2999     {
3000         List<ustring> lines;
3001         ustring line;
3002         int state = 0;
3003         for (uchar c : text)
3004         {
3005             switch (state)
3006             {
3007                 case 0:
3008                 {
3009                     switch (c)
3010                     {
3011                         case '\n':
3012                         {
3013                             lines.Add(TrimEnd(line));
3014                             line.Clear();
3015                             break;
3016                         }
3017                         case '\r':
3018                         {
3019                             state = 1;
3020                             break;
3021                         }
3022                         default:
3023                         {
3024                             line.Append(c);
3025                             break;
3026                         }
3027                     }
3028                     break;
3029                 }
3030                 case 1:
3031                 {
3032                     if (c == '\n')
3033                     {
3034                         lines.Add(TrimEnd(line));
3035                         line.Clear();
3036                         state = 0;
3037                         break;
3038                     }
3039                     break;
3040                 }
3041             }
3042         }
3043         if (!line.IsEmpty())
3044         {
3045             lines.Add(TrimEnd(line));
3046         }
3047         return lines;
3048     }
3049 
3050     public nothrow int MinIndent(const ustring& s)
3051     {
3052         if (s.IsEmpty()) return 0;
3053         int state = 0;
3054         int indent = 0;
3055         int minIndent = MaxValue<int>();
3056         for (uchar c : s)
3057         {
3058             switch (state)
3059             {
3060                 case 0:
3061                 {
3062                     if (c == ' ')
3063                     {
3064                         ++indent;
3065                     }
3066                     else if (c == '\n')
3067                     {
3068                         if (indent < minIndent)
3069                         {
3070                             minIndent = indent;
3071                         }
3072                         indent = 0;
3073                     }
3074                     else
3075                     {
3076                         if (indent < minIndent)
3077                         {
3078                             minIndent = indent;
3079                         }
3080                         indent = 0;
3081                         state = 1;
3082                     }
3083                     break;
3084                 }
3085                 case 1:
3086                 {
3087                     if (c == '\n')
3088                     {
3089                         state = 0;
3090                     }
3091                     break;
3092                 }
3093             }
3094         }
3095         if (indent > 0 && indent < minIndent)
3096         {
3097             minIndent = indent;
3098         }
3099         if (minIndent == MaxValue<int>())
3100         {
3101             minIndent = 0;
3102         }
3103         return minIndent;
3104     }
3105 
3106     public nothrow ustring Unindent(const ustring& sint indent)
3107     {
3108         if (indent == 0) return s;
3109         ustring line;
3110         ustring result;
3111         int state = 0;
3112         for (uchar c : s)
3113         {
3114             switch (state)
3115             {
3116                 case 0:
3117                 {
3118                     switch (c)
3119                     {
3120                         case '\n':
3121                         {
3122                             result.Append(line.Substring(indent)).Append('\n');
3123                             line.Clear();
3124                             break;
3125                         }
3126                         case '\r':
3127                         {
3128                             state = 1;
3129                             break;
3130                         }
3131                         default:
3132                         {
3133                             line.Append(c);
3134                             break;
3135                         }
3136                     }
3137                     break;
3138                 }
3139                 case 1:
3140                 {
3141                     if (c == '\n')
3142                     {
3143                         result.Append(line.Substring(indent)).Append('\n');
3144                         line.Clear();
3145                         state = 0;
3146                     }
3147                     break;
3148                 }
3149             }
3150         }
3151         if (!line.IsEmpty())
3152         {
3153             result.Append(line.Substring(indent));
3154         }
3155         return result;
3156     }
3157 
3158     public List<int> CalculateLineStartIndeces(const ustring& text)
3159     {
3160         List<int> indeces;
3161         int state = 0;
3162         int n = cast<int>(text.Length());
3163         for (int i = 0; i < n; ++i;)
3164         {
3165             uchar c = text[i];
3166             switch (state)
3167             {
3168                 case 0:
3169                 {
3170                     indeces.Add(i);
3171                     if (c != '\n')
3172                     {
3173                         state = 1;
3174                     }
3175                     break;
3176                 }
3177                 case 1:
3178                 {
3179                     if (c == '\n')
3180                     {
3181                         state = 0;
3182                     }
3183                     break;
3184                 }
3185             }
3186         }
3187         return indeces;
3188     }
3189 
3190     internal bool ReadCaretTimeoutFromRegistry(uint& caretTimeout)
3191     {
3192         void* currentUserKey = null;
3193         bool openSucceeded = WinRegOpenCurrentUser(&currentUserKey);
3194         if (openSucceeded)
3195         {
3196             uint value = 0u;
3197             bool getValueSucceeded = WinRegGetDWordValue(currentUserKey@"Control Panel\Desktop""CaretTimeout"value);
3198             if (getValueSucceeded)
3199             {
3200                 caretTimeout = value;
3201             }
3202             WinRegCloseKey(currentUserKey);
3203             return getValueSucceeded;
3204         }
3205         return false;
3206     }
3207 
3208 }