1
2
3
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(153u, 201u, 239u);
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& left, const SourcePos& right)
79 {
80 return left.line == right.line && left.column == right.column;
81 }
82
83 public nothrow bool operator<(const SourcePos& left, const 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 none, start, end
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 = 0, changed = 1 << 0, painting = 1 << 1, readOnly = 1 << 2, fixed = 1 << 3, dirty = 1 << 4, ccdirty = 1 << 5,
220 mouseExtendSelection = 1 << 6, ccOpen = 1 << 7
221 }
222
223 public TextView(const FontFamily& fontFamily_, float fontSize_, const Color& backgroundColor, const Color& textColor_, const Point& location,
224 const Size& size, Dock dock, Anchors anchors) :
225 base("System.Windows.TextView", DoubleClickWindowClassStyle(),
226 cast<WindowStyle>(DefaultChildWindowStyle() | WindowStyle.WS_TABSTOP), DefaultExtendedWindowStyle(), backgroundColor,
227 "textView", location, size, dock, anchors), flags(Flags.none), drawFormat(StringAlignment.near, StringAlignment.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& location, const Size& size, Dock dock, Anchors anchors) :
238 this(FontFamily("Consolas"), 10.0f, Color.White(), Color.Black(), location, size, dock, anchors)
239 {
240 }
241 public TextView(TextViewCreateParams& createParams) :
242 base(createParams.controlCreateParams),
243 flags(Flags.none),
244 drawFormat(StringAlignment.near, StringAlignment.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(fontFamily, fontSize, FontStyle.regular, Unit.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(fontFamily, fontSize, FontStyle.regular, Unit.point);
308 fonts.Add(UniquePtr<Font>(font));
309 }
310 public nothrow void SetUndoRedoMenuItems(MenuItem* undoMenuItem, MenuItem* redoMenuItem)
311 {
312 editCommandList.SetMenuItems(undoMenuItem, redoMenuItem);
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 line, int 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(x, y);
372 TranslateContentLocation(loc);
373 return loc;
374 }
375 public nothrow Point CCPos() const
376 {
377 Point ccPos = CaretPos();
378 ccPos.Offset(0, cast<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 line, int 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& contentLocation, int& line, int& 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(tl, 1);
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(1, 1 + 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& line, int& 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& line, int& 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& line, int& col)
524 {
525 if (Prev(line, col))
526 {
527 uchar c = GetCharAt(line, col);
528 while (IsWhiteSpace(c) || IsWordSeparator(c))
529 {
530 if (col == 1 || !Prev(line, col))
531 {
532 return;
533 }
534 c = GetCharAt(line, col);
535 }
536 c = GetCharAt(line, col);
537 while (!IsWhiteSpace(c) && !IsWordSeparator(c))
538 {
539 if (col == 1 || !Prev(line, col))
540 {
541 return;
542 }
543 c = GetCharAt(line, col);
544 }
545 c = GetCharAt(line, col);
546 if (IsWhiteSpace(c) || IsWordSeparator(c))
547 {
548 Next(line, col);
549 }
550 }
551 }
552 public nothrow void NextWord(int& line, int& col)
553 {
554 if (Next(line, col))
555 {
556 uchar c = GetCharAt(line, col);
557 while (!IsWhiteSpace(c) && !IsWordSeparator(c))
558 {
559 if (col == 1 || !Next(line, col))
560 {
561 return;
562 }
563 c = GetCharAt(line, col);
564 }
565 c = GetCharAt(line, col);
566 while (IsWhiteSpace(c))
567 {
568 if (col == 1 || !Next(line, col))
569 {
570 return;
571 }
572 c = GetCharAt(line, col);
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 line, int 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(lineNumber, columnNumber);
635 ScrollToCaret();
636 }
637 public int GetCharIndex(int line, int 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.graphics, args.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& graphics, const 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(0, 0);
682 Size size = GetSize();
683 for (int i = 0; i < n; ++i;)
684 {
685 if (IsLinePartiallyVisible(i + 1))
686 {
687 DrawSelectionBackground(graphics, i + 1, origin, lineNumberFieldLength);
688 DrawLine(graphics, i, origin);
689 }
690 origin.y = origin.y + charHeight;
691 }
692 graphics.SetTextRenderingHintChecked(prevRenderingHint);
693 }
694 private void DrawSelectionBackground(Graphics& graphics, int line, const PointF& origin, int 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(1, GetLineLength(line));
705 rect = RectF(pt, SizeF(charWidth * lineLength, charHeight));
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(pt, SizeF(charWidth * selectionLength, charHeight));
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(pt, SizeF(charWidth * selectionLength, charHeight));
719 }
720 else if (line == selection.end.line)
721 {
722 int selectionLength = selection.end.column - 1;
723 rect = RectF(pt, SizeF(charWidth * selectionLength, charHeight));
724 }
725 Brush* brush = GetOrInsertBrush(selectionBackgroundColor);
726 graphics.FillRectangleChecked(*brush, rect);
727 }
728 protected virtual void DrawLine(Graphics& graphics, int lineIndex, const 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, *font, PointF(0, 0), drawFormat);
766 graphics.SetTextRenderingHintChecked(prevRenderingHint);
767 charWidth = Max(charWidth, charRect.size.w / maxLineLength);
768 charHeight = Max(charHeight, charRect.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(textWidth, textHeight));
779 }
780 private nothrow void FixColumn(int& column, int 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.location, line, column);
799 if (line >= 1 && line <= lines.Count())
800 {
801 FixColumn(column, line);
802 mouseSelectionStart = SourcePos(line, column);
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(1, Min(lineNumber, cast<int>(lines.Count())));
813 int columnNumber = cast<int>(loc.x / charWidth) + 1;
814 columnNumber = Max(columnNumber, 1 + LineNumberFieldLength());
815 int lineLength = GetLineLength(lineNumber);
816 columnNumber = Min(columnNumber, lineLength + 1 + LineNumberFieldLength());
817 if (update)
818 {
819 update = false;
820 Invalidate();
821 }
822 SetCaretLineCol(lineNumber, columnNumber);
823 if (args.buttons == MouseButtons.rbutton)
824 {
825 RightClickEventArgs rightClickArgs(this, loc);
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.location, line, column);
839 if (line >= 1 && line <= lines.Count())
840 {
841 FixColumn(column, line);
842 mouseSelectionEnd = SourcePos(line, column);
843 if (mouseSelectionStart != mouseSelectionEnd)
844 {
845 ExtendSelection(mouseSelectionStart, mouseSelectionEnd);
846 InvalidateLines(selection.start.line, selection.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.location, line, column);
860 if (line >= 1 && line <= lines.Count())
861 {
862 FixColumn(column, line);
863 mouseSelectionEnd = SourcePos(line, column);
864 if (mouseSelectionStart != mouseSelectionEnd)
865 {
866 ExtendSelection(mouseSelectionStart, mouseSelectionEnd);
867 InvalidateLines(selection.start.line, selection.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(start, end);
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(start, end);
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(start, end);
947 InvalidateLines(selection.start.line, selection.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(start, end);
958 InvalidateLines(selection.start.line, selection.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(start, end);
994 }
995 else
996 {
997 ++lineNumber;
998 ++end.line;
999 columnNumber = 1 + LineNumberFieldLength();
1000 end.column = 1;
1001 ExtendSelection(start, end);
1002 }
1003 InvalidateLines(selection.start.line, selection.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(columnNumber, lineLength + 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(columnNumber, lineLength + 1 + LineNumberFieldLength());
1042 end.column = Min(end.column, lineLength + 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(start, end);
1052 InvalidateLines(selection.start.line, selection.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(columnNumber, lineLength + 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(columnNumber, lineLength + 1 + LineNumberFieldLength());
1085 end.column = Min(end.column, lineLength + 1);
1086 ExtendSelection(start, end);
1087 InvalidateLines(selection.start.line, selection.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(lineNumber, cast<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(lineNumber, cast<int>(lines.Count()) + 1);
1118 end.line = Min(end.line, cast<int>(lines.Count()) + 1);
1119 ExtendSelection(start, end);
1120 InvalidateLines(selection.start.line, selection.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(lineNumber, 1);
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(lineNumber, 1);
1150 end.line = Max(end.line, 1);
1151 ExtendSelection(start, end);
1152 InvalidateLines(selection.start.line, selection.end.line);
1153 args.handled = true;
1154 break;
1155 }
1156 case cast<Keys>(Keys.controlModifier | Keys.a):
1157 {
1158 ResetSelection();
1159 SourcePos start(1, 1);
1160 SourcePos end(cast<int>(lines.Count() + 1), 1);
1161 ExtendSelection(start, end);
1162 InvalidateLines(selection.start.line, selection.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(start, end);
1183 InvalidateLines(selection.start.line, selection.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(start, end);
1204 InvalidateLines(selection.start.line, selection.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(line, col);
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(line, col);
1226 lineNumber = line;
1227 end.line = line;
1228 columnNumber = col + LineNumberFieldLength();
1229 end.column = col;
1230 ExtendSelection(start, end);
1231 InvalidateLines(selection.start.line, selection.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(line, col);
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(line, col);
1253 lineNumber = line;
1254 end.line = line;
1255 columnNumber = col + LineNumberFieldLength();
1256 end.column = col;
1257 ExtendSelection(start, end);
1258 InvalidateLines(selection.start.line, selection.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(lineIndex, columnIndex);
1304 DeleteChar(lineIndex, columnIndex, 0, 0, false);
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(lineIndex, columnIndex);
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(lineIndex, columnIndex);
1344 NewLine(lineIndex, columnIndex);
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(lineIndex, columnIndex);
1360 Tab(lineIndex, columnIndex);
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(lineIndex, columnIndex);
1381 Backtab(lineIndex, columnIndex);
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(lineNumber, columnNumber);
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(lineIndex, columnIndex, c);
1461 InsertChar(lineIndex, columnIndex, c);
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 lineIndex, int columnIndex, uchar 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(lineIndex, columnIndex, c, removeIndent));
1503 }
1504 public void InsertChar(int lineIndex, int columnIndex, uchar c)
1505 {
1506 while (lineIndex >= lines.Count())
1507 {
1508 lines.Add(ustring());
1509 }
1510 ustring& line = lines[lineIndex];
1511 line.Insert(columnIndex, c);
1512 if (c == '}' && line.StartsWith(ustring(' ', IndentSize())))
1513 {
1514 line.Remove(0, IndentSize());
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 + 1, columnIndex + 1 + LineNumberFieldLength());
1526 KeyEventArgs rightArgs(Keys.right);
1527 OnKeyDown(rightArgs);
1528 SetCCText(line, columnIndex);
1529 SetDirty();
1530 SetCCDirty();
1531 }
1532 public void InsertText(int lineIndex, int columnIndex, const 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(lineIndex, columnIndex, linesToInsert.Front());
1547 InsertIntoLine(lineIndex, columnIndex, linesToInsert.Front());
1548 }
1549 else
1550 {
1551 AddInsertLinesCommand(lineIndex, columnIndex, linesToInsert);
1552 InsertLines(lineIndex, columnIndex, linesToInsert);
1553 }
1554 editCommandList.EndGroup();
1555 }
1556 public nothrow void AddInsertIntoLineCommand(int lineIndex, int columnIndex, const ustring& text)
1557 {
1558 editCommandList.AddCommand(new InsertIntoLineCommand(lineIndex, columnIndex, text));
1559 }
1560 public nothrow void InsertIntoLine(int lineIndex, int columnIndex, const ustring& text)
1561 {
1562 lines[lineIndex].Insert(columnIndex, text);
1563 LineEventArgs args(lineIndex, -1);
1564 OnLineChanged(args);
1565 SetTextExtent();
1566 SetCaretLineCol(lineIndex + 1, 1 + LineNumberFieldLength() + columnIndex + cast<int>(text.Length()));
1567 ScrollToCaret();
1568 Invalidate();
1569 InvalidateLines(lineIndex + 1, lineIndex + 1);
1570 SetDirty();
1571 SetCCDirty();
1572 }
1573 public nothrow void RemoveFromLine(int lineIndex, int columnIndex, long count)
1574 {
1575 lines[lineIndex].Remove(columnIndex, count);
1576 LineEventArgs args(lineIndex, -1);
1577 OnLineChanged(args);
1578 SetTextExtent();
1579 SetCaretLineCol(lineIndex + 1, 1 + LineNumberFieldLength() + columnIndex);
1580 ScrollToCaret();
1581 Invalidate();
1582 InvalidateLines(lineIndex + 1, lineIndex + 1);
1583 SetDirty();
1584 SetCCDirty();
1585 }
1586 public nothrow void AddInsertLinesCommand(int lineIndex, int columnIndex, const List<ustring>& linesToInsert)
1587 {
1588 editCommandList.AddCommand(new InsertLinesCommand(lineIndex, columnIndex, linesToInsert));
1589 }
1590 public nothrow void InsertLines(int lineIndex, int columnIndex, const 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() + lineIndex, lineToInsert);
1601 SetLineNumberFieldLength(cast<int>(lines.Count()));
1602 LineEventArgs insertedArgs(lineIndex, indentLineIndex);
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(lineIndex, 1 + LineNumberFieldLength() + cast<int>(lines[lineIndex - 1].Length()));
1621 }
1622 else
1623 {
1624 SetCaretLineCol(lineIndex, 1 + LineNumberFieldLength() + indent);
1625 }
1626 ScrollToCaret();
1627 Invalidate();
1628 InvalidateLines(lineIndex + 1, cast<int>(lineIndex + linesToInsert.Count() + 1));
1629 SetDirty();
1630 SetCCDirty();
1631 }
1632 public nothrow void DeleteLines(int lineIndex, int columnIndex, const List<ustring>& linesToDelete)
1633 {
1634 if (linesToDelete.Count() == 1)
1635 {
1636 ustring& line = lines[lineIndex];
1637 line.Remove(columnIndex, linesToDelete.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(lineIndex, 1 + LineNumberFieldLength());
1653 ScrollToCaret();
1654 Invalidate();
1655 SetDirty();
1656 SetCCDirty();
1657 }
1658 private nothrow void AddDeleteCharCommand(int lineIndex, int 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(lineIndex, columnIndex, c));
1666 }
1667 else
1668 {
1669 if (lines.Count() > lineIndex + 1)
1670 {
1671 editCommandList.AddCommand(new DeleteCharCommand(lineIndex, columnIndex, '\0'));
1672 }
1673 }
1674 }
1675 public void DeleteChar(int lineIndex, int columnIndex, int indent, int numSpaces, bool removeIndent)
1676 {
1677 if (lineIndex >= lines.Count()) return;
1678 ustring& line = lines[lineIndex];
1679 if (removeIndent)
1680 {
1681 line.Insert(0, ustring(' ', IndentSize()));
1682 }
1683 if (columnIndex < line.Length())
1684 {
1685 line.Remove(columnIndex, 1);
1686 LineEventArgs args(lineIndex, -1);
1687 OnLineChanged(args);
1688 SetCCText(line, columnIndex);
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 + 1, columnIndex + 1 + LineNumberFieldLength());
1710 SetDirty();
1711 SetCCDirty();
1712 }
1713 private void Backspace(int lineIndex, int 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& line, int 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 lineIndex, int 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(lineIndex, columnIndex, indent, numSpaces));
1772 }
1773 public void NewLine(int lineIndex, int 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(columnIndex, line.Length() - columnIndex);
1789 lineChanged = true;
1790 }
1791 ustring trimmedLine = TrimEnd(line);
1792 if (trimmedLine.Length() != line.Length())
1793 {
1794 Swap(line, trimmedLine);
1795 lineChanged = true;
1796 }
1797 if (lineChanged)
1798 {
1799 LineEventArgs changedArgs(lineIndex, -1);
1800 OnLineChanged(changedArgs);
1801 }
1802 lines.Insert(lines.Begin() + lineIndex + 1, toInsert);
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 + 1, indentLineIndex);
1814 OnLineInserted(insertedArgs);
1815 SetTextExtent();
1816 SetCaretLineCol(lineIndex + 1 + 1, 1 + 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 lineIndex, int columnIndex)
1831 {
1832 editCommandList.AddCommand(new TabCommand(lineIndex, columnIndex));
1833 }
1834 public void Tab(int lineIndex, int columnIndex)
1835 {
1836 while (lineIndex >= lines.Count())
1837 {
1838 lines.Add(ustring());
1839 }
1840 ustring& line = lines[lineIndex];
1841 line.Insert(columnIndex, ustring(' ', 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 + 1, columnIndex + 1 + LineNumberFieldLength() + IndentSize());
1851 ScrollToCaret();
1852 InvalidateLineCol(lineIndex + 1, columnIndex + 1);
1853 SetDirty();
1854 SetCCDirty();
1855 }
1856 private void AddBacktabCommand(int lineIndex, int 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(lineIndex, columnIndex, numSpaces));
1873 }
1874 public void Backtab(int lineIndex, int 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(col, numSpaces);
1896 LineEventArgs args(lineIndex, -1);
1897 OnLineChanged(args);
1898 SetCaretLineCol(lineIndex + 1, columnIndex + 1 + LineNumberFieldLength() - numSpaces);
1899 ScrollToCaret();
1900 InvalidateLineCol(lineIndex + 1, 1 + col + LineNumberFieldLength());
1901 SetDirty();
1902 SetCCDirty();
1903 }
1904 }
1905 public nothrow void AddSpaces(int lineIndex, int columnIndex, int numSpaces)
1906 {
1907 ustring& line = lines[lineIndex];
1908 line.Insert(columnIndex - numSpaces, ustring(' ', numSpaces));
1909 LineEventArgs args(lineIndex, -1);
1910 OnLineChanged(args);
1911 SetCaretLineCol(lineIndex + 1, columnIndex + 1 + LineNumberFieldLength() - numSpaces);
1912 ScrollToCaret();
1913 InvalidateLineCol(lineIndex + 1, 1 + LineNumberFieldLength());
1914 SetDirty();
1915 SetCCDirty();
1916 }
1917 public nothrow void RemoveSpaces(int lineIndex, int columnIndex, int numSpaces)
1918 {
1919 ustring& line = lines[lineIndex];
1920 line.Remove(columnIndex - numSpaces, numSpaces);
1921 LineEventArgs args(lineIndex, -1);
1922 OnLineChanged(args);
1923 SetCaretLineCol(lineIndex + 1, columnIndex + 1 + LineNumberFieldLength() - numSpaces);
1924 ScrollToCaret();
1925 InvalidateLineCol(lineIndex + 1, 1 + 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(), null, 1, cast<int>(charHeight));
2018 }
2019 else
2020 {
2021 base->CreateCaret();
2022 }
2023 SetTimer(1u, caretTimerPeriod);
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.location, line, column);
2056 uchar c = GetCharAt(line, column);
2057 while (!IsWhiteSpace(c) && !IsWordSeparator(c))
2058 {
2059 if (column == 1 || !Prev(line, column))
2060 {
2061 break;
2062 }
2063 c = GetCharAt(line, column);
2064 }
2065 c = GetCharAt(line, column);
2066 if (IsWhiteSpace(c) || IsWordSeparator(c))
2067 {
2068 Next(line, column);
2069 }
2070 SourcePos start(line, column);
2071 c = GetCharAt(line, column);
2072 while (!IsWhiteSpace(c) && !IsWordSeparator(c))
2073 {
2074 if (!Next(line, column))
2075 {
2076 break;
2077 }
2078 c = GetCharAt(line, column);
2079 }
2080 if (!IsWhiteSpace(c) && !IsWordSeparator(c))
2081 {
2082 column = column + 1;
2083 }
2084 SourcePos end(line, column);
2085 ExtendSelection(start, end);
2086 SetCaretLineCol(start.line, start.column + LineNumberFieldLength());
2087 ScrollToCaret();
2088 InvalidateLineCol(start.line, start.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(x, y);
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 + 1, 1 + 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(0, ustring(' ', 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& line, int 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(0, caretLine - 1);
2234 int caretColumnIndex = Max(0, caretColumn - 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(0, caretColumnIndex);
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(0, caretColumnIndex);
2256 line = line.Substring(0, startColumndIndex) + replacement + line.Substring(endColumnIndex);
2257 int newEndColumnIndex = startColumndIndex + cast<int>(replacement.Length());
2258 LineEventArgs args(caretLineIndex, -1);
2259 OnLineChanged(args);
2260 SetCaretLineCol(caretLineIndex + 1, newEndColumnIndex + 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(0, caretColumn - 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(0, startIndex)).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 - 1, selection.end.column - selection.start.column);
2335 int indent = MinIndent(s);
2336 SelectionData selectionData(Unindent(s, indent), indent, 0);
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(0, selection.end.column - 1).IsEmpty())
2350 {
2351 ustring lastLine = lines[selection.end.line - 1].Substring(0, selection.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(s, indent), indent, numTrailingSpaces);
2367 return selectionData;
2368 }
2369 }
2370 public nothrow void InsertSelection(const Selection& selectionToInsert, const SelectionData& selectionData, bool 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(0, ustring(' ', selectionData.indent));
2382 }
2383 lines.Insert(lines.Begin() + lineIndex, selectedText);
2384 LineEventArgs insertArgs(lineIndex, -1);
2385 OnLineInserted(insertArgs);
2386 SetCaretLineCol(lineIndex + 1, 1 + 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(0, ustring(' ', selectionData.indent));
2395 }
2396 lines[lineIndex].Insert(selectionToInsert.start.column - 1, selectedText);
2397 LineEventArgs changeArgs(lineIndex, -1);
2398 OnLineChanged(changeArgs);
2399 SetCaretLineCol(lineIndex + 1, selectionToInsert.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(0, ustring(' ', selectionData.indent));
2414 }
2415 lines[startLineIndex].Insert(selectionToInsert.start.column - 1, firstSelectionLine);
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(0, ustring(' ', selectionData.indent));
2426 }
2427 lines.Insert(lines.Begin() + startLineIndex, firstSelectionLine);
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(0, ustring(' ', selectionData.indent));
2439 }
2440 lines.Insert(lines.Begin() + i, selectionLine);
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(0, ustring(' ', selectionData.indent));
2451 }
2452 lastLine.Append(' ', selectionData.numTrailingSpaces);
2453 }
2454 if (wholeLine)
2455 {
2456 lines.Insert(lines.Begin() + endLineIndex, lastLine);
2457 LineEventArgs insertArgs(endLineIndex, -1);
2458 OnLineInserted(insertArgs);
2459 }
2460 else
2461 {
2462 lines[endLineIndex].Insert(0, lastLine);
2463 LineEventArgs changeArgs(endLineIndex, -1);
2464 OnLineChanged(changeArgs);
2465 }
2466 }
2467 selection = selectionToInsert;
2468 SetCaretLineCol(selection.end.line, selection.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(selection, selectionData, wholeLine));
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.line, 1 + LineNumberFieldLength());
2507 }
2508 else
2509 {
2510 int lineIndex = selection.start.line - 1;
2511 lines[lineIndex].Remove(selection.start.column - 1, selection.end.column - selection.start.column);
2512 LineEventArgs changeArgs(lineIndex, -1);
2513 OnLineChanged(changeArgs);
2514 SetCaretLineCol(lineIndex + 1, selection.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 - 1, GetLineLength(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(0, selection.end.column - 1);
2554 LineEventArgs changeArgs(endLineIndex, -1);
2555 OnLineChanged(changeArgs);
2556 }
2557 }
2558 SetCaretLineCol(selection.start.line, selection.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(0, selection.end.column - 1).IsEmpty()) continue;
2580 lines[i].Insert(0, indentString);
2581 LineEventArgs changeArgs(i, -1);
2582 OnLineChanged(changeArgs);
2583 }
2584 InvalidateLines(selection.start.line, selection.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(0, selection.end.column - 1);
2604 }
2605 if (line.StartsWith(indentString))
2606 {
2607 lines[i].Remove(0, IndentSize());
2608 LineEventArgs changeArgs(i, -1);
2609 OnLineChanged(changeArgs);
2610 }
2611 }
2612 InvalidateLines(selection.start.line, selection.end.line);
2613 SetDirty();
2614 SetCCDirty();
2615 }
2616 public nothrow void ExtendSelection(const SourcePos& start, const 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<Color, Brush*>.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<LineChangedEventHandler, LineEventArgs>& LineChangedEvent() const
2808 {
2809 return lineChangedEvent;
2810 }
2811 public nothrow Event<LineDeletedEventHandler, LineEventArgs>& LineDeletedEvent() const
2812 {
2813 return lineDeletedEvent;
2814 }
2815 public nothrow Event<LineInsertedEventHandler, LineEventArgs>& LineInsertedEvent() const
2816 {
2817 return lineInsertedEvent;
2818 }
2819 public nothrow Event<GotoCaretLineEventHandler, ControlEventArgs>& 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 lineNumber, int 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.x, cast<int>(charHeight + 1.5f));
2887 Rect rect(pt, sz);
2888 Invalidate(rect);
2889 }
2890 else
2891 {
2892 Invalidate();
2893 }
2894 }
2895 public void InvalidateLines(int startLineNumber, int endLineNumber)
2896 {
2897 if (charHeight != 0 && charWidth != 0)
2898 {
2899 Point pt(0, cast<int>(charHeight * (startLineNumber - 1) - charHeight));
2900 TranslateContentLocation(pt);
2901 Size size = GetSize();
2902 Size sz(size.w, cast<int>(charHeight * (endLineNumber - startLineNumber + 1) + 2 * charHeight + 1.5f));
2903 Rect rect(pt, sz);
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<Color, Brush*> 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<LineChangedEventHandler, LineEventArgs> lineChangedEvent;
2948 private Event<LineDeletedEventHandler, LineEventArgs> lineDeletedEvent;
2949 private Event<LineInsertedEventHandler, LineEventArgs> lineInsertedEvent;
2950 private Event<GotoCaretLineEventHandler, ControlEventArgs> 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(0, i);
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& s, int 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(¤tUserKey);
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 }