1 // Scintilla source code edit control
3 ** Main code for the edit control.
5 // Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
16 #define INCLUDE_DEPRECATED_FEATURES
18 #include "Scintilla.h"
20 #include "ContractionState.h"
22 #include "CellBuffer.h"
24 #include "Indicator.h"
26 #include "LineMarker.h"
28 #include "ViewStyle.h"
33 active(false), on(false), period(500) {}
36 ticking(false), ticksToWait(0), tickerID(0) {}
38 LineLayout::LineLayout(int maxLineLength_
) :
56 widthLine(wrapWidthInfinite
),
58 Resize(maxLineLength_
);
61 LineLayout::~LineLayout() {
65 void LineLayout::Resize(int maxLineLength_
) {
66 if (maxLineLength_
> maxLineLength
) {
68 chars
= new char[maxLineLength_
+ 1];
69 styles
= new char[maxLineLength_
+ 1];
70 indicators
= new char[maxLineLength_
+ 1];
71 // Extra position allocated as sometimes the Windows
72 // GetTextExtentExPoint API writes an extra element.
73 positions
= new int[maxLineLength_
+ 1 + 1];
74 maxLineLength
= maxLineLength_
;
78 void LineLayout::Free() {
91 void LineLayout::Invalidate(validLevel validity_
) {
92 if (validity
> validity_
)
96 void LineLayout::SetLineStart(int line
, int start
) {
97 if ((line
>= lenLineStarts
) && (line
!= 0)) {
98 int newMaxLines
= line
+ 20;
99 int *newLineStarts
= new int[newMaxLines
];
102 for (int i
= 0; i
< newMaxLines
; i
++) {
103 if (i
< lenLineStarts
)
104 newLineStarts
[i
] = lineStarts
[i
];
106 newLineStarts
[i
] = 0;
109 lineStarts
= newLineStarts
;
110 lenLineStarts
= newMaxLines
;
112 lineStarts
[line
] = start
;
115 void LineLayout::SetBracesHighlight(Range rangeLine
, Position braces
[],
116 char bracesMatchStyle
, int xHighlight
) {
117 if (rangeLine
.ContainsCharacter(braces
[0])) {
118 int braceOffset
= braces
[0] - rangeLine
.start
;
119 if (braceOffset
< numCharsInLine
) {
120 bracePreviousStyles
[0] = styles
[braceOffset
];
121 styles
[braceOffset
] = bracesMatchStyle
;
124 if (rangeLine
.ContainsCharacter(braces
[1])) {
125 int braceOffset
= braces
[1] - rangeLine
.start
;
126 if (braceOffset
< numCharsInLine
) {
127 bracePreviousStyles
[1] = styles
[braceOffset
];
128 styles
[braceOffset
] = bracesMatchStyle
;
131 if ((braces
[0] >= rangeLine
.start
&& braces
[1] <= rangeLine
.end
) ||
132 (braces
[1] >= rangeLine
.start
&& braces
[0] <= rangeLine
.end
)) {
133 xHighlightGuide
= xHighlight
;
137 void LineLayout::RestoreBracesHighlight(Range rangeLine
, Position braces
[]) {
138 if (rangeLine
.ContainsCharacter(braces
[0])) {
139 int braceOffset
= braces
[0] - rangeLine
.start
;
140 if (braceOffset
< numCharsInLine
) {
141 styles
[braceOffset
] = bracePreviousStyles
[0];
144 if (rangeLine
.ContainsCharacter(braces
[1])) {
145 int braceOffset
= braces
[1] - rangeLine
.start
;
146 if (braceOffset
< numCharsInLine
) {
147 styles
[braceOffset
] = bracePreviousStyles
[1];
153 LineLayoutCache::LineLayoutCache() :
154 level(0), length(0), size(0), cache(0),
155 allInvalidated(false), styleClock(-1) {
159 LineLayoutCache::~LineLayoutCache() {
163 void LineLayoutCache::Allocate(int length_
) {
164 allInvalidated
= false;
168 size
= (size
/ 16 + 1) * 16;
171 cache
= new LineLayout
* [size
];
173 for (int i
= 0; i
< size
; i
++)
177 void LineLayoutCache::AllocateForLevel(int linesOnScreen
, int linesInDoc
) {
178 int lengthForLevel
= 0;
179 if (level
== llcCaret
) {
181 } else if (level
== llcPage
) {
182 lengthForLevel
= linesOnScreen
+ 1;
183 } else if (level
== llcDocument
) {
184 lengthForLevel
= linesInDoc
;
186 if (lengthForLevel
> size
) {
188 } else if (lengthForLevel
< length
) {
189 for (int i
= lengthForLevel
; i
< length
; i
++) {
195 Allocate(lengthForLevel
);
199 void LineLayoutCache::Deallocate() {
200 for (int i
= 0; i
< length
; i
++)
207 void LineLayoutCache::Invalidate(LineLayout::validLevel validity_
) {
208 if (cache
&& !allInvalidated
) {
209 for (int i
= 0; i
< length
; i
++) {
211 cache
[i
]->Invalidate(validity_
);
214 if (validity_
== LineLayout::llInvalid
) {
215 allInvalidated
= true;
220 void LineLayoutCache::SetLevel(int level_
) {
221 allInvalidated
= false;
222 if ((level_
!= -1) && (level
!= level_
)) {
228 LineLayout
*LineLayoutCache::Retrieve(int lineNumber
, int lineCaret
, int maxChars
, int styleClock_
,
229 int linesOnScreen
, int linesInDoc
) {
230 AllocateForLevel(linesOnScreen
, linesInDoc
);
231 if (styleClock
!= styleClock_
) {
232 Invalidate(LineLayout::llCheckTextAndStyle
);
233 styleClock
= styleClock_
;
235 allInvalidated
= false;
238 if (((level
== llcCaret
) || (level
== llcPage
)) && (lineNumber
== lineCaret
)) {
240 } else if (level
== llcPage
) {
241 pos
= lineNumber
% length
;
242 } else if (level
== llcDocument
) {
246 if (cache
&& (pos
< length
)) {
248 if ((cache
[pos
]->lineNumber
!= lineNumber
) ||
249 (cache
[pos
]->maxLineLength
< maxChars
)) {
255 cache
[pos
] = new LineLayout(maxChars
);
258 cache
[pos
]->lineNumber
= lineNumber
;
259 cache
[pos
]->inCache
= true;
266 ret
= new LineLayout(maxChars
);
267 ret
->lineNumber
= lineNumber
;
273 void LineLayoutCache::Dispose(LineLayout
*ll
) {
274 allInvalidated
= false;
287 printMagnification
= 0;
288 printColourMode
= SC_PRINT_NORMAL
;
289 printWrapState
= eWrapWord
;
290 cursorMode
= SC_CURSORNORMAL
;
291 controlCharSymbol
= 0; /* Draw the control characters */
294 hideSelection
= false;
295 inOverstrike
= false;
297 mouseDownCaptures
= true;
303 dwellDelay
= SC_TIME_FOREVER
;
304 ticksToDwell
= SC_TIME_FOREVER
;
309 dropWentOutside
= false;
310 posDrag
= invalidPosition
;
311 posDrop
= invalidPosition
;
312 selectionType
= selChar
;
316 originalAnchorPos
= 0;
321 primarySelection
= true;
323 caretXPolicy
= CARET_SLOP
| CARET_EVEN
;
326 caretYPolicy
= CARET_EVEN
;
333 horizontalScrollBarVisible
= true;
335 verticalScrollBarVisible
= true;
336 endAtLastLine
= true;
338 pixmapLine
= Surface::Allocate();
339 pixmapSelMargin
= Surface::Allocate();
340 pixmapSelPattern
= Surface::Allocate();
341 pixmapIndentGuide
= Surface::Allocate();
342 pixmapIndentGuideHighlight
= Surface::Allocate();
355 braces
[0] = invalidPosition
;
356 braces
[1] = invalidPosition
;
357 bracesMatchStyle
= STYLE_BRACEBAD
;
358 highlightGuideColumn
= 0;
362 paintState
= notPainting
;
364 modEventMask
= SC_MODEVENTMASKALL
;
366 pdoc
= new Document();
368 pdoc
->AddWatcher(this, 0);
370 recordingMacro
= false;
373 wrapState
= eWrapNone
;
374 wrapWidth
= LineLayout::wrapWidthInfinite
;
375 docLineLastWrapped
= -1;
380 llc
.SetLevel(LineLayoutCache::llcCaret
);
384 pdoc
->RemoveWatcher(this, 0);
389 delete pixmapSelMargin
;
390 delete pixmapSelPattern
;
391 delete pixmapIndentGuide
;
392 delete pixmapIndentGuideHighlight
;
395 void Editor::Finalise() {
399 void Editor::DropGraphics() {
400 pixmapLine
->Release();
401 pixmapSelMargin
->Release();
402 pixmapSelPattern
->Release();
403 pixmapIndentGuide
->Release();
406 void Editor::InvalidateStyleData() {
410 llc
.Invalidate(LineLayout::llInvalid
);
413 void Editor::InvalidateStyleRedraw() {
415 InvalidateStyleData();
419 void Editor::RefreshColourPalette(Palette
&pal
, bool want
) {
420 vs
.RefreshColourPalette(pal
, want
);
423 void Editor::RefreshStyleData() {
426 AutoSurface
surface(this);
428 vs
.Refresh(*surface
);
429 RefreshColourPalette(palette
, true);
430 palette
.Allocate(wMain
);
431 RefreshColourPalette(palette
, false);
437 PRectangle
Editor::GetClientRectangle() {
438 return wMain
.GetClientPosition();
441 PRectangle
Editor::GetTextRectangle() {
442 PRectangle rc
= GetClientRectangle();
443 rc
.left
+= vs
.fixedColumnWidth
;
444 rc
.right
-= vs
.rightMarginWidth
;
448 int Editor::LinesOnScreen() {
449 PRectangle rcClient
= GetClientRectangle();
450 int htClient
= rcClient
.bottom
- rcClient
.top
;
451 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
452 return htClient
/ vs
.lineHeight
;
455 int Editor::LinesToScroll() {
456 int retVal
= LinesOnScreen() - 1;
463 int Editor::MaxScrollPos() {
464 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
465 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
466 int retVal
= cs
.LinesDisplayed();
468 retVal
-= LinesOnScreen();
479 static inline bool IsControlCharacter(char ch
) {
480 // iscntrl returns true for lots of chars > 127 which are displayable
481 return ch
>= 0 && ch
< ' ';
484 const char *ControlCharacterString(unsigned char ch
) {
485 const char *reps
[] = {
486 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
487 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
488 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
489 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
491 if (ch
< (sizeof(reps
) / sizeof(reps
[0]))) {
498 // Convenience class to ensure LineLayout objects are always disposed.
499 class AutoLineLayout
{
500 LineLayoutCache
&llc
;
502 AutoLineLayout
&operator=(const AutoLineLayout
&) { return * this; }
504 AutoLineLayout(LineLayoutCache
&llc_
, LineLayout
*ll_
) : llc(llc_
), ll(ll_
) {}
509 LineLayout
*operator->() const {
512 operator LineLayout
*() const {
515 void Set(LineLayout
*ll_
) {
521 Point
Editor::LocationFromPosition(int pos
) {
524 if (pos
== INVALID_POSITION
)
526 int line
= pdoc
->LineFromPosition(pos
);
527 int lineVisible
= cs
.DisplayFromDoc(line
);
528 //Platform::DebugPrintf("line=%d\n", line);
529 AutoSurface
surface(this);
530 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
532 // -1 because of adding in for visible lines in following loop.
533 pt
.y
= (lineVisible
- topLine
- 1) * vs
.lineHeight
;
535 unsigned int posLineStart
= pdoc
->LineStart(line
);
536 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
537 int posInLine
= pos
- posLineStart
;
538 // In case of very long line put x at arbitrary large position
539 if (posInLine
> ll
->maxLineLength
) {
540 pt
.x
= ll
->positions
[ll
->maxLineLength
] - ll
->positions
[ll
->LineStart(ll
->lines
)];
542 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
543 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
544 pt
.x
= ll
->positions
[posInLine
] - ll
->positions
[ll
->LineStart(subLine
)];
546 if (posInLine
>= ll
->LineStart(subLine
)) {
547 pt
.y
+= vs
.lineHeight
;
550 pt
.x
+= vs
.fixedColumnWidth
- xOffset
;
555 int Editor::XFromPosition(int pos
) {
556 Point pt
= LocationFromPosition(pos
);
557 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
560 int Editor::LineFromLocation(Point pt
) {
561 return cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
564 void Editor::SetTopLine(int topLineNew
) {
565 topLine
= topLineNew
;
566 posTopLine
= pdoc
->LineStart(topLine
);
569 static inline bool IsEOLChar(char ch
) {
570 return (ch
== '\r') || (ch
== '\n');
573 int Editor::PositionFromLocation(Point pt
) {
575 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
576 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
577 if (pt
.y
< 0) { // Division rounds towards 0
578 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
582 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
583 if (lineDoc
>= pdoc
->LinesTotal())
584 return pdoc
->Length();
585 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
586 int retVal
= posLineStart
;
587 AutoSurface
surface(this);
588 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
590 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
591 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
592 int subLine
= visibleLine
- lineStartSet
;
593 if (subLine
< ll
->lines
) {
594 int lineStart
= ll
->LineStart(subLine
);
595 int lineEnd
= ll
->LineStart(subLine
+ 1);
596 int subLineStart
= ll
->positions
[lineStart
];
597 for (int i
= lineStart
; i
< lineEnd
; i
++) {
598 if (pt
.x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
599 IsEOLChar(ll
->chars
[i
])) {
600 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
603 return lineEnd
+ posLineStart
;
605 retVal
= ll
->numCharsInLine
+ posLineStart
;
610 // Like PositionFromLocation but INVALID_POSITION returned when not near any text.
611 int Editor::PositionFromLocationClose(Point pt
) {
613 PRectangle rcClient
= GetTextRectangle();
614 if (!rcClient
.Contains(pt
))
615 return INVALID_POSITION
;
616 if (pt
.x
< vs
.fixedColumnWidth
)
617 return INVALID_POSITION
;
619 return INVALID_POSITION
;
620 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
621 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
622 if (pt
.y
< 0) { // Division rounds towards 0
623 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
625 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
627 return INVALID_POSITION
;
628 if (lineDoc
>= pdoc
->LinesTotal())
629 return INVALID_POSITION
;
630 AutoSurface
surface(this);
631 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
633 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
634 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
635 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
636 int subLine
= visibleLine
- lineStartSet
;
637 if (subLine
< ll
->lines
) {
638 int lineStart
= ll
->LineStart(subLine
);
639 int lineEnd
= ll
->LineStart(subLine
+ 1);
640 int subLineStart
= ll
->positions
[lineStart
];
641 for (int i
= lineStart
; i
< lineEnd
; i
++) {
642 if (pt
.x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
643 IsEOLChar(ll
->chars
[i
])) {
644 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
650 return INVALID_POSITION
;
654 * Find the document position corresponding to an x coordinate on a particular document line.
655 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
657 int Editor::PositionFromLineX(int lineDoc
, int x
) {
659 if (lineDoc
>= pdoc
->LinesTotal())
660 return pdoc
->Length();
661 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
662 AutoSurface
surface(this);
663 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
666 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
667 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
668 retVal
= ll
->numCharsInLine
+ posLineStart
;
670 int lineStart
= ll
->LineStart(subLine
);
671 int lineEnd
= ll
->LineStart(subLine
+ 1);
672 int subLineStart
= ll
->positions
[lineStart
];
673 for (int i
= lineStart
; i
< lineEnd
; i
++) {
674 if (x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
675 IsEOLChar(ll
->chars
[i
])) {
676 retVal
= pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
684 // If painting then abandon the painting because a wider redraw is needed.
685 // Return true if calling code should stop drawing
686 bool Editor::AbandonPaint() {
687 if ((paintState
== painting
) && !paintingAllText
) {
688 paintState
= paintAbandoned
;
690 return paintState
== paintAbandoned
;
693 void Editor::RedrawRect(PRectangle rc
) {
694 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
696 // Clip the redraw rectangle into the client area
697 PRectangle rcClient
= GetClientRectangle();
698 if (rc
.top
< rcClient
.top
)
699 rc
.top
= rcClient
.top
;
700 if (rc
.bottom
> rcClient
.bottom
)
701 rc
.bottom
= rcClient
.bottom
;
702 if (rc
.left
< rcClient
.left
)
703 rc
.left
= rcClient
.left
;
704 if (rc
.right
> rcClient
.right
)
705 rc
.right
= rcClient
.right
;
707 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
708 wMain
.InvalidateRectangle(rc
);
712 void Editor::Redraw() {
713 //Platform::DebugPrintf("Redraw all\n");
714 PRectangle rcClient
= GetClientRectangle();
715 wMain
.InvalidateRectangle(rcClient
);
716 //wMain.InvalidateAll();
719 void Editor::RedrawSelMargin() {
720 if (!AbandonPaint()) {
724 PRectangle rcSelMargin
= GetClientRectangle();
725 rcSelMargin
.right
= vs
.fixedColumnWidth
;
726 wMain
.InvalidateRectangle(rcSelMargin
);
731 PRectangle
Editor::RectangleFromRange(int start
, int end
) {
738 int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(minPos
));
739 int lineDocMax
= pdoc
->LineFromPosition(maxPos
);
740 int maxLine
= cs
.DisplayFromDoc(lineDocMax
) + cs
.GetHeight(lineDocMax
) - 1;
741 PRectangle rcClient
= GetTextRectangle();
743 rc
.left
= vs
.fixedColumnWidth
;
744 rc
.top
= (minLine
- topLine
) * vs
.lineHeight
;
747 rc
.right
= rcClient
.right
;
748 rc
.bottom
= (maxLine
- topLine
+ 1) * vs
.lineHeight
;
749 // Ensure PRectangle is within 16 bit space
750 rc
.top
= Platform::Clamp(rc
.top
, -32000, 32000);
751 rc
.bottom
= Platform::Clamp(rc
.bottom
, -32000, 32000);
756 void Editor::InvalidateRange(int start
, int end
) {
757 RedrawRect(RectangleFromRange(start
, end
));
760 int Editor::CurrentPosition() {
764 bool Editor::SelectionEmpty() {
765 return anchor
== currentPos
;
768 int Editor::SelectionStart(int line
) {
769 if ((line
== -1) || (selType
== selStream
)) {
770 return Platform::Minimum(currentPos
, anchor
);
771 } else { // selType == selRectangle
772 int selStart
= SelectionStart();
773 int selEnd
= SelectionEnd();
774 int lineStart
= pdoc
->LineFromPosition(selStart
);
775 int lineEnd
= pdoc
->LineFromPosition(selEnd
);
776 if (line
< lineStart
|| line
> lineEnd
) {
779 int minX
= Platform::Minimum(xStartSelect
, xEndSelect
);
780 return PositionFromLineX(line
, minX
);
785 int Editor::SelectionEnd(int line
) {
786 if ((line
== -1) || (selType
== selStream
)) {
787 return Platform::Maximum(currentPos
, anchor
);
788 } else { // selType == selRectangle
789 int selStart
= SelectionStart();
790 int selEnd
= SelectionEnd();
791 int lineStart
= pdoc
->LineFromPosition(selStart
);
792 int lineEnd
= pdoc
->LineFromPosition(selEnd
);
793 if (line
< lineStart
|| line
> lineEnd
) {
796 int maxX
= Platform::Maximum(xStartSelect
, xEndSelect
);
797 // measure line and return character closest to minx
798 return PositionFromLineX(line
, maxX
);
803 void Editor::SetSelection(int currentPos_
, int anchor_
) {
804 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
805 anchor_
= pdoc
->ClampPositionIntoDocument(anchor_
);
806 if ((currentPos
!= currentPos_
) || (anchor
!= anchor_
)) {
807 int firstAffected
= anchor
;
808 if (firstAffected
> currentPos
)
809 firstAffected
= currentPos
;
810 if (firstAffected
> anchor_
)
811 firstAffected
= anchor_
;
812 if (firstAffected
> currentPos_
)
813 firstAffected
= currentPos_
;
814 int lastAffected
= anchor
;
815 if (lastAffected
< currentPos
)
816 lastAffected
= currentPos
;
817 if (lastAffected
< anchor_
)
818 lastAffected
= anchor_
;
819 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
820 lastAffected
= (currentPos_
+ 1);
821 currentPos
= currentPos_
;
824 InvalidateRange(firstAffected
, lastAffected
);
829 void Editor::SetSelection(int currentPos_
) {
830 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
831 if (currentPos
!= currentPos_
) {
832 int firstAffected
= anchor
;
833 if (firstAffected
> currentPos
)
834 firstAffected
= currentPos
;
835 if (firstAffected
> currentPos_
)
836 firstAffected
= currentPos_
;
837 int lastAffected
= anchor
;
838 if (lastAffected
< currentPos
)
839 lastAffected
= currentPos
;
840 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
841 lastAffected
= (currentPos_
+ 1);
842 currentPos
= currentPos_
;
844 InvalidateRange(firstAffected
, lastAffected
);
849 void Editor::SetEmptySelection(int currentPos_
) {
851 SetSelection(currentPos_
, currentPos_
);
854 bool Editor::RangeContainsProtected(int start
, int end
) const {
855 if (vs
.ProtectionActive()) {
861 int mask
= pdoc
->stylingBitsMask
;
862 for (int pos
= start
; pos
< end
; pos
++) {
863 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected())
870 bool Editor::SelectionContainsProtected() const {
871 // TODO: make support rectangular selection
872 return RangeContainsProtected(anchor
, currentPos
);
875 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) {
876 // Asks document to find a good position and then moves out of any invisible positions
877 pos
= pdoc
->MovePositionOutsideChar(pos
, moveDir
, checkLineEnd
);
878 if (vs
.ProtectionActive()) {
879 int mask
= pdoc
->stylingBitsMask
;
881 if ((pos
> 0) && vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()) {
882 while ((pos
< pdoc
->Length()) &&
883 (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected()))
886 } else if (moveDir
< 0) {
887 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected()) {
889 (vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()))
897 int Editor::MovePositionTo(int newPos
, bool extend
, bool ensureVisible
) {
898 int delta
= newPos
- currentPos
;
899 newPos
= pdoc
->ClampPositionIntoDocument(newPos
);
900 newPos
= MovePositionOutsideChar(newPos
, delta
);
902 SetSelection(newPos
);
904 SetEmptySelection(newPos
);
906 ShowCaretAtCurrentPosition();
908 EnsureCaretVisible();
913 int Editor::MovePositionSoVisible(int pos
, int moveDir
) {
914 pos
= pdoc
->ClampPositionIntoDocument(pos
);
915 pos
= MovePositionOutsideChar(pos
, moveDir
);
916 int lineDoc
= pdoc
->LineFromPosition(pos
);
917 if (cs
.GetVisible(lineDoc
)) {
920 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
922 // lineDisplay is already line before fold as lines in fold use display line of line after fold
923 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
924 return pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
));
926 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
927 return pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
));
932 // Choose the x position that the caret will try to stick to as it is moves up and down
933 void Editor::SetLastXChosen() {
934 Point pt
= LocationFromPosition(currentPos
);
938 void Editor::ScrollTo(int line
, bool moveThumb
) {
939 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
940 if (topLineNew
!= topLine
) {
941 // Try to optimise small scrolls
942 int linesToMove
= topLine
- topLineNew
;
943 SetTopLine(topLineNew
);
944 ShowCaretAtCurrentPosition();
945 // Perform redraw rather than scroll if many lines would be redrawn anyway.
946 if (abs(linesToMove
) <= 10) {
947 ScrollText(linesToMove
);
952 SetVerticalScrollPos();
957 void Editor::ScrollText(int /* linesToMove */) {
958 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
962 void Editor::HorizontalScrollTo(int xPos
) {
963 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
966 if ((wrapState
== eWrapNone
) && (xOffset
!= xPos
)) {
968 SetHorizontalScrollPos();
969 RedrawRect(GetClientRectangle());
973 void Editor::MoveCaretInsideView(bool ensureVisible
) {
974 PRectangle rcClient
= GetTextRectangle();
975 Point pt
= LocationFromPosition(currentPos
);
976 if (pt
.y
< rcClient
.top
) {
977 MovePositionTo(PositionFromLocation(
978 Point(lastXChosen
, rcClient
.top
)),
979 false, ensureVisible
);
980 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
981 int yOfLastLineFullyDisplayed
= rcClient
.top
+ (LinesOnScreen() - 1) * vs
.lineHeight
;
982 MovePositionTo(PositionFromLocation(
983 Point(lastXChosen
, rcClient
.top
+ yOfLastLineFullyDisplayed
)),
984 false, ensureVisible
);
988 int Editor::DisplayFromPosition(int pos
) {
989 int lineDoc
= pdoc
->LineFromPosition(pos
);
990 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
991 AutoSurface
surface(this);
992 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
994 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
995 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
996 int posInLine
= pos
- posLineStart
;
997 lineDisplay
--; // To make up for first increment ahead.
998 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
999 if (posInLine
>= ll
->LineStart(subLine
)) {
1008 * Ensure the caret is reasonably visible in context.
1010 Caret policy in SciTE
1012 If slop is set, we can define a slop value.
1013 This value defines an unwanted zone (UZ) where the caret is... unwanted.
1014 This zone is defined as a number of pixels near the vertical margins,
1015 and as a number of lines near the horizontal margins.
1016 By keeping the caret away from the edges, it is seen within its context,
1017 so it is likely that the identifier that the caret is on can be completely seen,
1018 and that the current line is seen with some of the lines following it which are
1019 often dependent on that line.
1021 If strict is set, the policy is enforced... strictly.
1022 The caret is centred on the display if slop is not set,
1023 and cannot go in the UZ if slop is set.
1025 If jumps is set, the display is moved more energetically
1026 so the caret can move in the same direction longer before the policy is applied again.
1027 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1029 If even is not set, instead of having symmetrical UZs,
1030 the left and bottom UZs are extended up to right and top UZs respectively.
1031 This way, we favour the displaying of useful information: the begining of lines,
1032 where most code reside, and the lines after the caret, eg. the body of a function.
1035 slop | strict | jumps | even | Caret can go to the margin | When reaching limit (caret going out of
1036 | | | | | visibility or going into the UZ) display is...
1037 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1038 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1039 0 | 0 | 0 | 1 | Yes | moved by one position
1040 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1041 0 | 0 | 1 | 1 | Yes | centred on the caret
1042 0 | 1 | - | 0 | Caret is always on top/on right of display | -
1043 0 | 1 | - | 1 | No, caret is always centred | -
1044 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1045 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1046 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1047 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1048 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1049 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1050 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1052 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
1053 //Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " ");
1054 PRectangle rcClient
= GetTextRectangle();
1055 //int rcClientFullWidth = rcClient.Width();
1056 int posCaret
= currentPos
;
1060 Point pt
= LocationFromPosition(posCaret
);
1061 Point ptBottomCaret
= pt
;
1062 ptBottomCaret
.y
+= vs
.lineHeight
- 1;
1063 int lineCaret
= DisplayFromPosition(posCaret
);
1064 bool bSlop
, bStrict
, bJump
, bEven
;
1066 // Vertical positioning
1067 if (vert
&& (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
> rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1068 int linesOnScreen
= LinesOnScreen();
1069 int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1070 int newTopLine
= topLine
;
1071 bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1072 bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1073 bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1074 bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1076 // It should be possible to scroll the window to show the caret,
1077 // but this fails to remove the caret on GTK+
1078 if (bSlop
) { // A margin is defined
1081 int yMarginT
, yMarginB
;
1083 // In drag mode, avoid moves
1084 // otherwise, a double click will select several lines.
1085 yMarginT
= yMarginB
= 0;
1087 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1088 // a maximum of slightly less than half the heigth of the text area.
1089 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1091 yMarginB
= yMarginT
;
1093 yMarginB
= linesOnScreen
- yMarginT
- 1;
1099 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1103 yMoveB
= linesOnScreen
- yMoveT
- 1;
1105 if (lineCaret
< topLine
+ yMarginT
) {
1106 // Caret goes too high
1107 newTopLine
= lineCaret
- yMoveT
;
1108 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1109 // Caret goes too low
1110 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1112 } else { // Not strict
1113 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1114 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1118 yMoveB
= linesOnScreen
- yMoveT
- 1;
1120 if (lineCaret
< topLine
) {
1121 // Caret goes too high
1122 newTopLine
= lineCaret
- yMoveT
;
1123 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1124 // Caret goes too low
1125 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1129 if (!bStrict
&& !bJump
) {
1131 if (lineCaret
< topLine
) {
1132 // Caret goes too high
1133 newTopLine
= lineCaret
;
1134 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1135 // Caret goes too low
1137 newTopLine
= lineCaret
- linesOnScreen
+ 1;
1139 newTopLine
= lineCaret
;
1142 } else { // Strict or going out of display
1144 // Always center caret
1145 newTopLine
= lineCaret
- halfScreen
;
1147 // Always put caret on top of display
1148 newTopLine
= lineCaret
;
1152 newTopLine
= Platform::Clamp(newTopLine
, 0, MaxScrollPos());
1153 if (newTopLine
!= topLine
) {
1155 SetTopLine(newTopLine
);
1156 SetVerticalScrollPos();
1160 // Horizontal positioning
1161 if (horiz
&& (wrapState
== eWrapNone
)) {
1162 int halfScreen
= Platform::Maximum(rcClient
.Width() - 4, 4) / 2;
1163 int xOffsetNew
= xOffset
;
1164 bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1165 bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1166 bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1167 bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1169 if (bSlop
) { // A margin is defined
1172 int xMarginL
, xMarginR
;
1174 // In drag mode, avoid moves unless very near of the margin
1175 // otherwise, a simple click will select text.
1176 xMarginL
= xMarginR
= 2;
1178 // xMargin must equal to caretXSlop, with a minimum of 2 and
1179 // a maximum of slightly less than half the width of the text area.
1180 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1182 xMarginL
= xMarginR
;
1184 xMarginL
= rcClient
.Width() - xMarginR
- 4;
1187 if (bJump
&& bEven
) {
1188 // Jump is used only in even mode
1189 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1191 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1193 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1194 // Caret is on the left of the display
1195 if (bJump
&& bEven
) {
1196 xOffsetNew
-= xMoveL
;
1198 // Move just enough to allow to display the caret
1199 xOffsetNew
-= (rcClient
.left
+ xMarginL
) - pt
.x
;
1201 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1202 // Caret is on the right of the display
1203 if (bJump
&& bEven
) {
1204 xOffsetNew
+= xMoveR
;
1206 // Move just enough to allow to display the caret
1207 xOffsetNew
+= pt
.x
- (rcClient
.right
- xMarginR
) + 1;
1210 } else { // Not strict
1211 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1212 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1216 xMoveL
= rcClient
.Width() - xMoveR
- 4;
1218 if (pt
.x
< rcClient
.left
) {
1219 // Caret is on the left of the display
1220 xOffsetNew
-= xMoveL
;
1221 } else if (pt
.x
>= rcClient
.right
) {
1222 // Caret is on the right of the display
1223 xOffsetNew
+= xMoveR
;
1228 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1229 // Strict or going out of display
1232 xOffsetNew
+= pt
.x
- rcClient
.left
- halfScreen
;
1234 // Put caret on right
1235 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1238 // Move just enough to allow to display the caret
1239 if (pt
.x
< rcClient
.left
) {
1240 // Caret is on the left of the display
1242 xOffsetNew
-= rcClient
.left
- pt
.x
;
1244 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1246 } else if (pt
.x
>= rcClient
.right
) {
1247 // Caret is on the right of the display
1248 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1252 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1253 if (pt
.x
+ xOffset
< rcClient
.left
+ xOffsetNew
) {
1254 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.left
;
1255 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ xOffsetNew
) {
1256 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.right
+ 1;
1258 if (xOffsetNew
< 0) {
1261 if (xOffset
!= xOffsetNew
) {
1262 xOffset
= xOffsetNew
;
1263 if (xOffsetNew
> 0) {
1264 PRectangle rcText
= GetTextRectangle();
1265 if (horizontalScrollBarVisible
== true &&
1266 rcText
.Width() + xOffset
> scrollWidth
) {
1267 scrollWidth
= xOffset
+ rcText
.Width();
1271 SetHorizontalScrollPos();
1277 void Editor::ShowCaretAtCurrentPosition() {
1279 caret
.active
= true;
1283 caret
.active
= false;
1289 void Editor::DropCaret() {
1290 caret
.active
= false;
1294 void Editor::InvalidateCaret() {
1296 InvalidateRange(posDrag
, posDrag
+ 1);
1298 InvalidateRange(currentPos
, currentPos
+ 1);
1301 void Editor::NeedWrapping(int docLineStartWrapping
) {
1302 if (docLineLastWrapped
> (docLineStartWrapping
- 1)) {
1303 docLineLastWrapped
= docLineStartWrapping
- 1;
1304 if (docLineLastWrapped
< -1)
1305 docLineLastWrapped
= -1;
1306 llc
.Invalidate(LineLayout::llPositions
);
1310 // Check if wrapping needed and perform any needed wrapping.
1311 // Return true if wrapping occurred.
1312 bool Editor::WrapLines() {
1313 int goodTopLine
= topLine
;
1314 bool wrapOccurred
= false;
1315 if (docLineLastWrapped
< pdoc
->LinesTotal()) {
1316 if (wrapState
== eWrapNone
) {
1317 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1318 wrapWidth
= LineLayout::wrapWidthInfinite
;
1319 for (int lineDoc
= 0; lineDoc
< pdoc
->LinesTotal(); lineDoc
++) {
1320 cs
.SetHeight(lineDoc
, 1);
1322 wrapOccurred
= true;
1324 docLineLastWrapped
= 0x7ffffff;
1327 int lineDocTop
= cs
.DocFromDisplay(topLine
);
1328 int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1329 PRectangle rcTextArea
= GetClientRectangle();
1330 rcTextArea
.left
= vs
.fixedColumnWidth
;
1331 rcTextArea
.right
-= vs
.rightMarginWidth
;
1332 wrapWidth
= rcTextArea
.Width();
1333 // Ensure all of the document is styled.
1334 pdoc
->EnsureStyledTo(pdoc
->Length());
1335 AutoSurface
surface(this);
1337 int lastLineToWrap
= pdoc
->LinesTotal();
1338 while (docLineLastWrapped
<= lastLineToWrap
) {
1339 docLineLastWrapped
++;
1340 AutoLineLayout
ll(llc
, RetrieveLineLayout(docLineLastWrapped
));
1341 int linesWrapped
= 1;
1343 LayoutLine(docLineLastWrapped
, surface
, vs
, ll
, wrapWidth
);
1344 linesWrapped
= ll
->lines
;
1346 if (cs
.SetHeight(docLineLastWrapped
, linesWrapped
)) {
1347 wrapOccurred
= true;
1351 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
);
1352 if (subLineTop
< cs
.GetHeight(lineDocTop
))
1353 goodTopLine
+= subLineTop
;
1355 goodTopLine
+= cs
.GetHeight(lineDocTop
);
1356 //double durWrap = et.Duration(true);
1357 //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap);
1362 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1363 SetVerticalScrollPos();
1365 return wrapOccurred
;
1368 void Editor::LinesJoin() {
1369 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1370 pdoc
->BeginUndoAction();
1371 bool prevNonWS
= true;
1372 for (int pos
= targetStart
; pos
< targetEnd
; pos
++) {
1373 if (IsEOLChar(pdoc
->CharAt(pos
))) {
1374 targetEnd
-= pdoc
->LenChar(pos
);
1377 // Ensure at least one space separating previous lines
1378 pdoc
->InsertChar(pos
, ' ');
1381 prevNonWS
= pdoc
->CharAt(pos
) != ' ';
1384 pdoc
->EndUndoAction();
1388 const char *StringFromEOLMode(int eolMode
) {
1389 if (eolMode
== SC_EOL_CRLF
) {
1391 } else if (eolMode
== SC_EOL_CR
) {
1398 void Editor::LinesSplit(int pixelWidth
) {
1399 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1400 if (pixelWidth
== 0) {
1401 PRectangle rcText
= GetTextRectangle();
1402 pixelWidth
= rcText
.Width();
1404 int lineStart
= pdoc
->LineFromPosition(targetStart
);
1405 int lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1406 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1407 pdoc
->BeginUndoAction();
1408 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
1409 AutoSurface
surface(this);
1410 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
1411 if (surface
&& ll
) {
1412 unsigned int posLineStart
= pdoc
->LineStart(line
);
1413 LayoutLine(line
, surface
, vs
, ll
, pixelWidth
);
1414 for (int subLine
= 1; subLine
< ll
->lines
; subLine
++) {
1415 pdoc
->InsertString(posLineStart
+ (subLine
- 1) * strlen(eol
) +
1416 ll
->LineStart(subLine
), eol
);
1417 targetEnd
+= static_cast<int>(strlen(eol
));
1421 pdoc
->EndUndoAction();
1425 int Editor::SubstituteMarkerIfEmpty(int markerCheck
, int markerDefault
) {
1426 if (vs
.markers
[markerCheck
].markType
== SC_MARK_EMPTY
)
1427 return markerDefault
;
1431 // Avoid 64 bit compiler warnings.
1432 // Scintilla does not support text buffers larger than 2**31
1433 static int istrlen(const char *s
) {
1434 return static_cast<int>(strlen(s
));
1437 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1438 if (vs
.fixedColumnWidth
== 0)
1441 PRectangle rcMargin
= GetClientRectangle();
1442 rcMargin
.right
= vs
.fixedColumnWidth
;
1444 if (!rc
.Intersects(rcMargin
))
1449 surface
= pixmapSelMargin
;
1451 surface
= surfWindow
;
1454 PRectangle rcSelMargin
= rcMargin
;
1455 rcSelMargin
.right
= rcMargin
.left
;
1457 for (int margin
= 0; margin
< vs
.margins
; margin
++) {
1458 if (vs
.ms
[margin
].width
> 0) {
1460 rcSelMargin
.left
= rcSelMargin
.right
;
1461 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
1463 if (vs
.ms
[margin
].symbol
) {
1464 /* alternate scheme:
1465 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
1466 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1468 // Required because of special way brush is created for selection margin
1469 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
1471 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
1472 // Required because of special way brush is created for selection margin
1473 surface
->FillRectangle(rcSelMargin
, *pixmapSelPattern
);
1475 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1477 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1480 int visibleLine
= topLine
;
1483 // Work out whether the top line is whitespace located after a
1484 // lessening of fold level which implies a 'fold tail' but which should not
1485 // be displayed until the last of a sequence of whitespace.
1486 bool needWhiteClosure
= false;
1487 int level
= pdoc
->GetLevel(cs
.DocFromDisplay(topLine
));
1488 if (level
& SC_FOLDLEVELWHITEFLAG
) {
1489 int lineBack
= cs
.DocFromDisplay(topLine
);
1490 int levelPrev
= level
;
1491 while ((lineBack
> 0) && (levelPrev
& SC_FOLDLEVELWHITEFLAG
)) {
1493 levelPrev
= pdoc
->GetLevel(lineBack
);
1495 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
1496 if ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelPrev
& SC_FOLDLEVELNUMBERMASK
))
1497 needWhiteClosure
= true;
1501 // Old code does not know about new markers needed to distinguish all cases
1502 int folderOpenMid
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID
,
1503 SC_MARKNUM_FOLDEROPEN
);
1504 int folderEnd
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND
,
1507 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
1509 PLATFORM_ASSERT(visibleLine
< cs
.LinesDisplayed());
1511 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
1512 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
1513 bool firstSubLine
= visibleLine
== cs
.DisplayFromDoc(lineDoc
);
1515 // Decide which fold indicator should be displayed
1516 level
= pdoc
->GetLevel(lineDoc
);
1517 int levelNext
= pdoc
->GetLevel(lineDoc
+ 1);
1518 int marks
= pdoc
->GetMark(lineDoc
);
1521 int levelNum
= level
& SC_FOLDLEVELNUMBERMASK
;
1522 int levelNextNum
= levelNext
& SC_FOLDLEVELNUMBERMASK
;
1523 if (level
& SC_FOLDLEVELHEADERFLAG
) {
1525 if (cs
.GetExpanded(lineDoc
)) {
1526 if (levelNum
== SC_FOLDLEVELBASE
)
1527 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
1529 marks
|= 1 << folderOpenMid
;
1531 if (levelNum
== SC_FOLDLEVELBASE
)
1532 marks
|= 1 << SC_MARKNUM_FOLDER
;
1534 marks
|= 1 << folderEnd
;
1537 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1539 needWhiteClosure
= false;
1540 } else if (level
& SC_FOLDLEVELWHITEFLAG
) {
1541 if (needWhiteClosure
) {
1542 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1543 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1544 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1545 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1546 needWhiteClosure
= false;
1548 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1549 needWhiteClosure
= false;
1551 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1552 if (levelNextNum
< levelNum
) {
1553 if (levelNextNum
> SC_FOLDLEVELBASE
) {
1554 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1556 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1559 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1562 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1563 if (levelNextNum
< levelNum
) {
1564 needWhiteClosure
= false;
1565 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1566 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1567 needWhiteClosure
= true;
1568 } else if (levelNextNum
> SC_FOLDLEVELBASE
) {
1569 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1571 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1574 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1578 marks
&= vs
.ms
[margin
].mask
;
1579 PRectangle rcMarker
= rcSelMargin
;
1580 rcMarker
.top
= yposScreen
;
1581 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
1582 if (!vs
.ms
[margin
].symbol
) {
1586 sprintf(number
, "%d", lineDoc
+ 1);
1587 if (foldFlags
& SC_FOLDFLAG_LEVELNUMBERS
) {
1588 int lev
= pdoc
->GetLevel(lineDoc
);
1589 sprintf(number
, "%c%c %03X %03X",
1590 (lev
& SC_FOLDLEVELHEADERFLAG
) ? 'H' : '_',
1591 (lev
& SC_FOLDLEVELWHITEFLAG
) ? 'W' : '_',
1592 lev
& SC_FOLDLEVELNUMBERMASK
,
1596 PRectangle rcNumber
= rcMarker
;
1598 int width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
1599 int xpos
= rcNumber
.right
- width
- 3;
1600 rcNumber
.left
= xpos
;
1601 surface
->DrawTextNoClip(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
1602 rcNumber
.top
+ vs
.maxAscent
, number
, istrlen(number
),
1603 vs
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
1604 vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1608 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1610 vs
.markers
[markBit
].Draw(surface
, rcMarker
, vs
.styles
[STYLE_LINENUMBER
].font
);
1617 yposScreen
+= vs
.lineHeight
;
1622 PRectangle rcBlankMargin
= rcMargin
;
1623 rcBlankMargin
.left
= rcSelMargin
.right
;
1624 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1627 surfWindow
->Copy(rcMargin
, Point(), *pixmapSelMargin
);
1631 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
1632 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
1633 int xhead
= rcTab
.right
- 1 - ydiff
;
1634 if (xhead
<= rcTab
.left
) {
1635 ydiff
-= rcTab
.left
- xhead
- 1;
1636 xhead
= rcTab
.left
- 1;
1638 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
1639 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
1641 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1642 surface
->LineTo(rcTab
.right
- 1, ymid
);
1643 surface
->LineTo(xhead
, ymid
- ydiff
);
1644 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1645 surface
->LineTo(xhead
, ymid
+ ydiff
);
1648 static bool IsSpaceOrTab(char ch
) {
1649 return ch
== ' ' || ch
== '\t';
1652 LineLayout
*Editor::RetrieveLineLayout(int lineNumber
) {
1653 int posLineStart
= pdoc
->LineStart(lineNumber
);
1654 int posLineEnd
= pdoc
->LineStart(lineNumber
+ 1);
1655 int lineCaret
= pdoc
->LineFromPosition(currentPos
);
1656 return llc
.Retrieve(lineNumber
, lineCaret
,
1657 posLineEnd
- posLineStart
, pdoc
->GetStyleClock(),
1658 LinesOnScreen() + 1, pdoc
->LinesTotal());
1662 * Fill in the LineLayout data for the given line.
1663 * Copy the given @a line and its styles from the document into local arrays.
1664 * Also determine the x position at which each character starts.
1666 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
*ll
, int width
) {
1669 int posLineStart
= pdoc
->LineStart(line
);
1670 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1671 // If the line is very long, limit the treatment to a length that should fit in the viewport
1672 if (posLineEnd
> (posLineStart
+ ll
->maxLineLength
)) {
1673 posLineEnd
= posLineStart
+ ll
->maxLineLength
;
1675 if (ll
->validity
== LineLayout::llCheckTextAndStyle
) {
1677 for (int cid
= posLineStart
; cid
< posLineEnd
; cid
++) {
1678 char chDoc
= pdoc
->CharAt(cid
);
1679 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
1683 if (lineLength
== ll
->numCharsInLine
) {
1684 int numCharsInLine
= 0;
1685 // See if chars, styles, indicators, are all the same
1686 bool allSame
= true;
1688 int styleMask
= pdoc
->stylingBitsMask
;
1689 // Check base line layout
1690 for (int charInDoc
= posLineStart
; allSame
&& (charInDoc
< posLineEnd
); charInDoc
++) {
1691 char chDoc
= pdoc
->CharAt(charInDoc
);
1692 styleByte
= pdoc
->StyleAt(charInDoc
);
1693 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
!= '\r'))) {
1694 allSame
= allSame
&&
1695 (ll
->styles
[numCharsInLine
] == static_cast<char>(styleByte
& styleMask
));
1696 allSame
= allSame
&&
1697 (ll
->indicators
[numCharsInLine
] == static_cast<char>(styleByte
& ~styleMask
));
1698 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
1699 allSame
= allSame
&&
1700 (ll
->chars
[numCharsInLine
] == static_cast<char>(toupper(chDoc
)));
1701 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1702 allSame
= allSame
&&
1703 (ll
->chars
[numCharsInLine
] == static_cast<char>(tolower(chDoc
)));
1705 allSame
= allSame
&&
1706 (ll
->chars
[numCharsInLine
] == chDoc
);
1711 ll
->validity
= LineLayout::llPositions
;
1713 ll
->validity
= LineLayout::llInvalid
;
1716 ll
->validity
= LineLayout::llInvalid
;
1719 if (ll
->validity
== LineLayout::llInvalid
) {
1720 ll
->widthLine
= LineLayout::wrapWidthInfinite
;
1722 int numCharsInLine
= 0;
1723 if (vstyle
.edgeState
== EDGE_BACKGROUND
) {
1724 ll
->edgeColumn
= pdoc
->FindColumn(line
, theEdge
);
1725 if (ll
->edgeColumn
>= posLineStart
) {
1726 ll
->edgeColumn
-= posLineStart
;
1729 ll
->edgeColumn
= -1;
1733 int styleMask
= pdoc
->stylingBitsMask
;
1734 // Fill base line layout
1735 for (int charInDoc
= posLineStart
; charInDoc
< posLineEnd
; charInDoc
++) {
1736 char chDoc
= pdoc
->CharAt(charInDoc
);
1737 styleByte
= pdoc
->StyleAt(charInDoc
);
1738 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
1739 ll
->chars
[numCharsInLine
] = chDoc
;
1740 ll
->styles
[numCharsInLine
] = static_cast<char>(styleByte
& styleMask
);
1741 ll
->indicators
[numCharsInLine
] = static_cast<char>(styleByte
& ~styleMask
);
1742 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
1743 ll
->chars
[numCharsInLine
] = static_cast<char>(toupper(chDoc
));
1744 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1745 ll
->chars
[numCharsInLine
] = static_cast<char>(tolower(chDoc
));
1749 ll
->xHighlightGuide
= 0;
1750 // Extra element at the end of the line to hold end x position and act as
1751 ll
->chars
[numCharsInLine
] = 0; // Also triggers processing in the loops as this is a control character
1752 ll
->styles
[numCharsInLine
] = styleByte
; // For eolFilled
1753 ll
->indicators
[numCharsInLine
] = 0;
1755 // Layout the line, determining the position of each character,
1756 // with an extra element at the end for the end of the line.
1757 int startseg
= 0; // Start of the current segment, in char. number
1758 int startsegx
= 0; // Start of the current segment, in pixels
1759 ll
->positions
[0] = 0;
1760 unsigned int tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
1761 bool lastSegItalics
= false;
1762 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
1764 bool isControlNext
= IsControlCharacter(ll
->chars
[0]);
1765 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
1766 bool isControl
= isControlNext
;
1767 isControlNext
= IsControlCharacter(ll
->chars
[charInLine
+ 1]);
1768 if ((ll
->styles
[charInLine
] != ll
->styles
[charInLine
+ 1]) ||
1769 isControl
|| isControlNext
) {
1770 ll
->positions
[startseg
] = 0;
1771 if (vstyle
.styles
[ll
->styles
[charInLine
]].visible
) {
1773 if (ll
->chars
[charInLine
] == '\t') {
1774 ll
->positions
[charInLine
+ 1] = ((((startsegx
+ 2) /
1775 tabWidth
) + 1) * tabWidth
) - startsegx
;
1776 } else if (controlCharSymbol
< 32) {
1777 const char *ctrlChar
= ControlCharacterString(ll
->chars
[charInLine
]);
1778 // +3 For a blank on front and rounded edge each side:
1779 ll
->positions
[charInLine
+ 1] = surface
->WidthText(ctrlCharsFont
, ctrlChar
, istrlen(ctrlChar
)) + 3;
1781 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
1782 surface
->MeasureWidths(ctrlCharsFont
, cc
, 1,
1783 ll
->positions
+ startseg
+ 1);
1785 lastSegItalics
= false;
1786 } else { // Regular character
1787 int lenSeg
= charInLine
- startseg
+ 1;
1788 if ((lenSeg
== 1) && (' ' == ll
->chars
[startseg
])) {
1789 lastSegItalics
= false;
1790 // Over half the segments are single characters and of these about half are space characters.
1791 ll
->positions
[charInLine
+ 1] = vstyle
.styles
[ll
->styles
[charInLine
]].spaceWidth
;
1793 lastSegItalics
= vstyle
.styles
[ll
->styles
[charInLine
]].italic
;
1794 surface
->MeasureWidths(vstyle
.styles
[ll
->styles
[charInLine
]].font
, ll
->chars
+ startseg
,
1795 lenSeg
, ll
->positions
+ startseg
+ 1);
1798 } else { // invisible
1799 for (int posToZero
= startseg
; posToZero
<= (charInLine
+ 1); posToZero
++) {
1800 ll
->positions
[posToZero
] = 0;
1803 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
1804 ll
->positions
[posToIncrease
] += startsegx
;
1806 startsegx
= ll
->positions
[charInLine
+ 1];
1807 startseg
= charInLine
+ 1;
1810 // Small hack to make lines that end with italics not cut off the edge of the last character
1811 if ((startseg
> 0) && lastSegItalics
) {
1812 ll
->positions
[startseg
] += 2;
1814 ll
->numCharsInLine
= numCharsInLine
;
1815 ll
->validity
= LineLayout::llPositions
;
1817 // Hard to cope when too narrow, so just assume there is space
1821 if ((ll
->validity
== LineLayout::llPositions
) || (ll
->widthLine
!= width
)) {
1822 ll
->widthLine
= width
;
1823 if (width
== LineLayout::wrapWidthInfinite
) {
1825 } else if (width
> ll
->positions
[ll
->numCharsInLine
]) {
1826 // Simple common case where line does not need wrapping.
1830 // Calculate line start positions based upon width.
1831 // For now this is simplistic - wraps on byte rather than character and
1832 // in the middle of words. Should search for spaces or style changes.
1833 int lastGoodBreak
= 0;
1834 int lastLineStart
= 0;
1835 int startOffset
= 0;
1837 while (p
< ll
->numCharsInLine
) {
1838 if ((ll
->positions
[p
+ 1] - startOffset
) >= width
) {
1839 if (lastGoodBreak
== lastLineStart
) {
1840 // Try moving to start of last character
1842 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
1845 if (lastGoodBreak
== lastLineStart
) {
1846 // Ensure at least one character on line.
1847 lastGoodBreak
= pdoc
->MovePositionOutsideChar(lastGoodBreak
+ posLineStart
+ 1, 1)
1851 lastLineStart
= lastGoodBreak
;
1853 ll
->SetLineStart(ll
->lines
, lastGoodBreak
);
1854 startOffset
= ll
->positions
[lastGoodBreak
];
1855 p
= lastGoodBreak
+ 1;
1859 if (ll
->styles
[p
] != ll
->styles
[p
- 1]) {
1861 } else if (IsSpaceOrTab(ll
->chars
[p
- 1]) && !IsSpaceOrTab(ll
->chars
[p
])) {
1869 ll
->validity
= LineLayout::llLines
;
1873 ColourAllocated
Editor::TextBackground(ViewStyle
&vsDraw
, bool overrideBackground
,
1874 ColourAllocated background
, bool inSelection
, bool inHotspot
, int styleMain
, int i
, LineLayout
*ll
) {
1876 if (vsDraw
.selbackset
) {
1877 if (primarySelection
)
1878 return vsDraw
.selbackground
.allocated
;
1880 return vsDraw
.selbackground2
.allocated
;
1883 if ((vsDraw
.edgeState
== EDGE_BACKGROUND
) &&
1884 (i
>= ll
->edgeColumn
) &&
1885 !IsEOLChar(ll
->chars
[i
]))
1886 return vsDraw
.edgecolour
.allocated
;
1888 return vsDraw
.hotspotBackground
.allocated
;
1889 if (overrideBackground
)
1892 return vsDraw
.styles
[styleMain
].back
.allocated
;
1895 void Editor::DrawIndentGuide(Surface
*surface
, int lineVisible
, int lineHeight
, int start
, PRectangle rcSegment
, bool highlight
) {
1896 Point
from(0, ((lineVisible
& 1) && (lineHeight
& 1)) ? 1 : 0);
1897 PRectangle
rcCopyArea(start
+ 1, rcSegment
.top
, start
+ 2, rcSegment
.bottom
);
1898 surface
->Copy(rcCopyArea
, from
,
1899 highlight
? *pixmapIndentGuideHighlight
: *pixmapIndentGuide
);
1902 void Editor::DrawEOL(Surface
*surface
, ViewStyle
&vsDraw
, PRectangle rcLine
, LineLayout
*ll
,
1903 int line
, int lineEnd
, int xStart
, int subLine
, int subLineStart
,
1904 bool overrideBackground
, ColourAllocated background
) {
1906 int styleMask
= pdoc
->stylingBitsMask
;
1907 PRectangle rcSegment
= rcLine
;
1909 // Fill in a PRectangle representing the end of line characters
1910 int xEol
= ll
->positions
[lineEnd
] - subLineStart
;
1911 rcSegment
.left
= xEol
+ xStart
;
1912 rcSegment
.right
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
1913 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1914 bool eolInSelection
= (subLine
== (ll
->lines
- 1)) &&
1915 (posLineEnd
> ll
->selStart
) && (posLineEnd
<= ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
1916 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1)) {
1917 if (primarySelection
)
1918 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground
.allocated
);
1920 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground2
.allocated
);
1921 } else if (overrideBackground
) {
1922 surface
->FillRectangle(rcSegment
, background
);
1924 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
1927 rcSegment
.left
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
1928 rcSegment
.right
= rcLine
.right
;
1929 if (overrideBackground
) {
1930 surface
->FillRectangle(rcSegment
, background
);
1931 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
1932 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
1934 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
1938 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int lineVisible
, int xStart
,
1939 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
1941 PRectangle rcSegment
= rcLine
;
1943 // Using one font for all control characters so it can be controlled independently to ensure
1944 // the box goes around the characters tightly. Seems to be no way to work out what height
1945 // is taken by an individual character - internal leading gives varying results.
1946 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
1948 // See if something overrides the line background color: Either if caret is on the line
1949 // and background color is set for that, or if a marker is defined that forces its background
1950 // color onto the line, or if a marker is defined but has no selection margin in which to
1951 // display itself. These are checked in order with the earlier taking precedence. When
1952 // multiple markers cause background override, the color for the highest numbered one is used.
1953 bool overrideBackground
= false;
1954 ColourAllocated background
;
1955 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& ll
->containsCaret
) {
1956 overrideBackground
= true;
1957 background
= vsDraw
.caretLineBackground
.allocated
;
1959 if (!overrideBackground
) {
1960 int marks
= pdoc
->GetMark(line
);
1961 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1962 if ((marks
& 1) && vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
) {
1963 background
= vsDraw
.markers
[markBit
].back
.allocated
;
1964 overrideBackground
= true;
1969 if (!overrideBackground
) {
1970 if (vsDraw
.maskInLine
) {
1971 int marks
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
1973 overrideBackground
= true;
1974 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1976 background
= vsDraw
.markers
[markBit
].back
.allocated
;
1984 bool drawWhitespaceBackground
= (vsDraw
.viewWhitespace
!= wsInvisible
) &&
1985 (!overrideBackground
) && (vsDraw
.whitespaceBackgroundSet
);
1987 bool inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
1988 int indentWidth
= pdoc
->indentInChars
* vsDraw
.spaceWidth
;
1989 if (indentWidth
== 0)
1990 indentWidth
= pdoc
->tabInChars
* vsDraw
.spaceWidth
;
1992 int posLineStart
= pdoc
->LineStart(line
);
1994 int startseg
= ll
->LineStart(subLine
);
1995 int subLineStart
= ll
->positions
[startseg
];
1998 if (subLine
< ll
->lines
) {
1999 lineStart
= ll
->LineStart(subLine
);
2000 lineEnd
= ll
->LineStart(subLine
+ 1);
2004 // Background drawing loop
2005 for (i
= lineStart
; twoPhaseDraw
&& (i
< lineEnd
); i
++) {
2007 int iDoc
= i
+ posLineStart
;
2008 // If there is the end of a style run for any reason
2009 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
2010 i
== (lineEnd
- 1) ||
2011 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
2012 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
2013 (i
== (ll
->edgeColumn
- 1))) {
2014 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2015 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2016 // Only try to draw if really visible - enhances performance by not calling environment to
2017 // draw strings that are completely past the right side of the window.
2018 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2019 int styleMain
= ll
->styles
[i
];
2020 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2021 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2022 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2023 if (ll
->chars
[i
] == '\t') {
2025 if (drawWhitespaceBackground
&&
2026 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2027 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2028 surface
->FillRectangle(rcSegment
, textBack
);
2029 } else if (IsControlCharacter(ll
->chars
[i
])) {
2030 // Control character display
2031 inIndentation
= false;
2032 surface
->FillRectangle(rcSegment
, textBack
);
2034 // Normal text display
2035 surface
->FillRectangle(rcSegment
, textBack
);
2036 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2037 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
2038 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2039 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2040 if (drawWhitespaceBackground
&&
2041 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2042 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
,
2043 ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2044 surface
->FillRectangle(rcSpace
, vsDraw
.whitespaceBackground
.allocated
);
2047 inIndentation
= false;
2058 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2059 xStart
, subLine
, subLineStart
, overrideBackground
, background
);
2062 inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2063 startseg
= ll
->LineStart(subLine
);
2064 // Foreground drawing loop
2065 for (i
= lineStart
; i
< lineEnd
; i
++) {
2067 int iDoc
= i
+ posLineStart
;
2068 // If there is the end of a style run for any reason
2069 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
2070 i
== (lineEnd
- 1) ||
2071 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
2072 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
2073 (i
== (ll
->edgeColumn
- 1))) {
2074 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2075 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2076 // Only try to draw if really visible - enhances performance by not calling environment to
2077 // draw strings that are completely past the right side of the window.
2078 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2079 int styleMain
= ll
->styles
[i
];
2080 ColourAllocated textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
2081 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
2082 //hotspot foreground
2083 if (ll
->hsStart
!= -1 && iDoc
>= ll
->hsStart
&& iDoc
< hsEnd
) {
2084 if (vsDraw
.hotspotForegroundSet
)
2085 textFore
= vsDraw
.hotspotForeground
.allocated
;
2087 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2088 if (inSelection
&& (vsDraw
.selforeset
)) {
2089 textFore
= vsDraw
.selforeground
.allocated
;
2091 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2092 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2093 if (ll
->chars
[i
] == '\t') {
2095 if (!twoPhaseDraw
) {
2096 if (drawWhitespaceBackground
&&
2097 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2098 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2099 surface
->FillRectangle(rcSegment
, textBack
);
2101 if ((vsDraw
.viewWhitespace
!= wsInvisible
) || ((inIndentation
&& vsDraw
.viewIndentationGuides
))) {
2102 if (vsDraw
.whitespaceForegroundSet
)
2103 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2104 surface
->PenColour(textFore
);
2106 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
2107 for (int xIG
= ll
->positions
[i
] / indentWidth
* indentWidth
; xIG
< ll
->positions
[i
+ 1]; xIG
+= indentWidth
) {
2108 if (xIG
>= ll
->positions
[i
] && xIG
> 0) {
2109 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIG
+ xStart
, rcSegment
,
2110 (ll
->xHighlightGuide
== xIG
));
2114 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2115 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2116 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
2117 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
2118 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
2121 } else if (IsControlCharacter(ll
->chars
[i
])) {
2122 // Control character display
2123 inIndentation
= false;
2124 if (controlCharSymbol
< 32) {
2125 // Draw the character
2126 const char *ctrlChar
= ControlCharacterString(ll
->chars
[i
]);
2127 if (!twoPhaseDraw
) {
2128 surface
->FillRectangle(rcSegment
, textBack
);
2130 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
2131 surface
->InternalLeading(ctrlCharsFont
);
2132 PRectangle rcCChar
= rcSegment
;
2133 rcCChar
.left
= rcCChar
.left
+ 1;
2134 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
2135 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
2136 PRectangle rcCentral
= rcCChar
;
2139 surface
->FillRectangle(rcCentral
, textFore
);
2140 PRectangle rcChar
= rcCChar
;
2143 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
2144 rcSegment
.top
+ vsDraw
.maxAscent
, ctrlChar
, istrlen(ctrlChar
),
2145 textBack
, textFore
);
2147 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
2148 surface
->DrawTextNoClip(rcSegment
, ctrlCharsFont
,
2149 rcSegment
.top
+ vsDraw
.maxAscent
,
2150 cc
, 1, textBack
, textFore
);
2153 // Normal text display
2154 if (vsDraw
.styles
[styleMain
].visible
) {
2156 surface
->DrawTextTransparent(rcSegment
, textFont
,
2157 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2158 i
- startseg
+ 1, textFore
);
2160 surface
->DrawTextNoClip(rcSegment
, textFont
,
2161 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2162 i
- startseg
+ 1, textFore
, textBack
);
2165 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2166 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
2167 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2168 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2169 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2170 if (vsDraw
.whitespaceForegroundSet
)
2171 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2172 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2173 int xmid
= (ll
->positions
[cpos
+ startseg
] + ll
->positions
[cpos
+ startseg
+ 1]) / 2;
2174 if (!twoPhaseDraw
&& drawWhitespaceBackground
&&
2175 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2176 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2177 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
, ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2178 surface
->FillRectangle(rcSpace
, textBack
);
2180 PRectangle
rcDot(xmid
+ xStart
- subLineStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
2181 rcDot
.right
= rcDot
.left
+ 1;
2182 rcDot
.bottom
= rcDot
.top
+ 1;
2183 surface
->FillRectangle(rcDot
, textFore
);
2186 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
2187 int startSpace
= ll
->positions
[cpos
+ startseg
];
2188 if (startSpace
> 0 && (startSpace
% indentWidth
== 0)) {
2189 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, startSpace
+ xStart
, rcSegment
,
2190 (ll
->xHighlightGuide
== ll
->positions
[cpos
+ startseg
]));
2194 inIndentation
= false;
2199 if (ll
->hsStart
!= -1 && vsDraw
.hotspotUnderline
&& iDoc
>= ll
->hsStart
&& iDoc
< ll
->hsEnd
) {
2200 PRectangle rcUL
= rcSegment
;
2201 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2202 rcUL
.bottom
= rcUL
.top
+ 1;
2203 if (vsDraw
.hotspotForegroundSet
)
2204 surface
->FillRectangle(rcUL
, vsDraw
.hotspotForeground
.allocated
);
2206 surface
->FillRectangle(rcUL
, textFore
);
2207 } else if (vsDraw
.styles
[styleMain
].underline
) {
2208 PRectangle rcUL
= rcSegment
;
2209 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2210 rcUL
.bottom
= rcUL
.top
+ 1;
2211 surface
->FillRectangle(rcUL
, textFore
);
2219 int indStart
[INDIC_MAX
+ 1] = {0};
2220 for (int indica
= 0; indica
<= INDIC_MAX
; indica
++)
2221 indStart
[indica
] = 0;
2223 for (int indicPos
= 0; indicPos
< ll
->numCharsInLine
; indicPos
++) {
2224 if (ll
->indicators
[indicPos
] != ll
->indicators
[indicPos
+ 1]) {
2225 int mask
= 1 << pdoc
->stylingBits
;
2226 for (int indicnum
= 0; mask
< 0x100; indicnum
++) {
2227 if ((ll
->indicators
[indicPos
+ 1] & mask
) && !(ll
->indicators
[indicPos
] & mask
)) {
2228 indStart
[indicnum
] = ll
->positions
[indicPos
+ 1];
2230 if (!(ll
->indicators
[indicPos
+ 1] & mask
) && (ll
->indicators
[indicPos
] & mask
)) {
2232 indStart
[indicnum
] + xStart
,
2233 rcLine
.top
+ vsDraw
.maxAscent
,
2234 ll
->positions
[indicPos
+ 1] + xStart
,
2235 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
2236 vsDraw
.indicators
[indicnum
].Draw(surface
, rcIndic
);
2242 // End of the drawing of the current line
2244 if (!twoPhaseDraw
) {
2245 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2246 xStart
, subLine
, subLineStart
, overrideBackground
, background
);
2249 if (vsDraw
.edgeState
== EDGE_LINE
) {
2250 int edgeX
= theEdge
* vsDraw
.spaceWidth
;
2251 rcSegment
.left
= edgeX
+ xStart
;
2252 rcSegment
.right
= rcSegment
.left
+ 1;
2253 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
.allocated
);
2257 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
2258 if (!pixmapSelPattern
->Initialised()) {
2259 const int patternSize
= 8;
2260 pixmapSelPattern
->InitPixMap(patternSize
, patternSize
, surfaceWindow
, wMain
.GetID());
2261 // This complex procedure is to reproduce the checkerboard dithered pattern used by windows
2262 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
2263 // way between the chrome colour and the chrome highlight colour making a nice transition
2264 // between the window chrome and the content area. And it works in low colour depths.
2265 PRectangle
rcPattern(0, 0, patternSize
, patternSize
);
2267 // Initialize default colours based on the chrome colour scheme. Typically the highlight is white.
2268 ColourAllocated colourFMFill
= vs
.selbar
.allocated
;
2269 ColourAllocated colourFMStripes
= vs
.selbarlight
.allocated
;
2271 if (!(vs
.selbarlight
.desired
== ColourDesired(0xff, 0xff, 0xff))) {
2272 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
2273 // (Typically, the highlight colour is white.)
2274 colourFMFill
= vs
.selbarlight
.allocated
;
2277 if (vs
.foldmarginColourSet
) {
2278 // override default fold margin colour
2279 colourFMFill
= vs
.foldmarginColour
.allocated
;
2281 if (vs
.foldmarginHighlightColourSet
) {
2282 // override default fold margin highlight colour
2283 colourFMStripes
= vs
.foldmarginHighlightColour
.allocated
;
2286 pixmapSelPattern
->FillRectangle(rcPattern
, colourFMFill
);
2287 pixmapSelPattern
->PenColour(colourFMStripes
);
2288 for (int stripe
= 0; stripe
< patternSize
; stripe
++) {
2289 // Alternating 1 pixel stripes is same as checkerboard.
2290 pixmapSelPattern
->MoveTo(0, stripe
* 2);
2291 pixmapSelPattern
->LineTo(patternSize
, stripe
* 2 - patternSize
);
2295 if (!pixmapIndentGuide
->Initialised()) {
2296 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
2297 pixmapIndentGuide
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2298 pixmapIndentGuideHighlight
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2299 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
2300 pixmapIndentGuide
->FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
.allocated
);
2301 pixmapIndentGuide
->PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
2302 pixmapIndentGuideHighlight
->FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
.allocated
);
2303 pixmapIndentGuideHighlight
->PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
2304 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
2305 pixmapIndentGuide
->MoveTo(0, stripe
);
2306 pixmapIndentGuide
->LineTo(2, stripe
);
2307 pixmapIndentGuideHighlight
->MoveTo(0, stripe
);
2308 pixmapIndentGuideHighlight
->LineTo(2, stripe
);
2313 if (!pixmapLine
->Initialised()) {
2314 PRectangle rcClient
= GetClientRectangle();
2315 pixmapLine
->InitPixMap(rcClient
.Width(), rcClient
.Height(),
2316 surfaceWindow
, wMain
.GetID());
2317 pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
2318 rcClient
.Height(), surfaceWindow
, wMain
.GetID());
2323 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
2324 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
2325 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
2329 RefreshPixMaps(surfaceWindow
);
2331 PRectangle rcClient
= GetClientRectangle();
2332 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
2333 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
2335 surfaceWindow
->SetPalette(&palette
, true);
2336 pixmapLine
->SetPalette(&palette
, !hasFocus
);
2338 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
2339 // The area to be painted plus one extra line is styled.
2340 // The extra line is to determine when a style change, such as starting a comment flows on to other lines.
2341 int lineStyleLast
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
2342 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
2343 int endPosPaint
= pdoc
->Length();
2344 if (lineStyleLast
< cs
.LinesDisplayed())
2345 endPosPaint
= pdoc
->LineStart(cs
.DocFromDisplay(lineStyleLast
+ 1));
2347 int xStart
= vs
.fixedColumnWidth
- xOffset
;
2350 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
2351 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
2353 // Ensure we are styled as far as we are painting.
2354 pdoc
->EnsureStyledTo(endPosPaint
);
2355 bool paintAbandonedByStyling
= paintState
== paintAbandoned
;
2358 needUpdateUI
= false;
2361 PaintSelMargin(surfaceWindow
, rcArea
);
2364 // The wrapping process has changed the height of some lines so abandon this
2365 // paint for a complete repaint.
2366 if (AbandonPaint()) {
2369 RefreshPixMaps(surfaceWindow
); // In case pixmaps invalidated by scrollbar change
2371 PLATFORM_ASSERT(pixmapSelPattern
->Initialised());
2373 PRectangle rcRightMargin
= rcClient
;
2374 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
2375 if (rcArea
.Intersects(rcRightMargin
)) {
2376 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2379 if (paintState
== paintAbandoned
) {
2380 // Either styling or NotifyUpdateUI noticed that painting is needed
2381 // outside the current painting rectangle
2382 //Platform::DebugPrintf("Abandoning paint\n");
2383 if (wrapState
!= eWrapNone
) {
2384 if (paintAbandonedByStyling
) {
2385 // Styling has spilled over a line end, such as occurs by starting a multiline
2386 // comment. The width of subsequent text may have changed, so rewrap.
2387 NeedWrapping(cs
.DocFromDisplay(topLine
));
2392 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
2395 if (rcArea
.right
> vs
.fixedColumnWidth
) {
2397 Surface
*surface
= surfaceWindow
;
2399 surface
= pixmapLine
;
2400 PLATFORM_ASSERT(pixmapLine
->Initialised());
2402 surface
->SetUnicodeMode(IsUnicodeMode());
2403 surface
->SetDBCSMode(CodePage());
2405 int visibleLine
= topLine
+ screenLinePaintFirst
;
2407 int posCaret
= currentPos
;
2410 int lineCaret
= pdoc
->LineFromPosition(posCaret
);
2412 // Remove selection margin from drawing area so text will not be drawn
2413 // on it in unbuffered mode.
2414 PRectangle rcTextArea
= rcClient
;
2415 rcTextArea
.left
= vs
.fixedColumnWidth
;
2416 rcTextArea
.right
-= vs
.rightMarginWidth
;
2417 surfaceWindow
->SetClip(rcTextArea
);
2419 // Loop on visible lines
2420 //double durLayout = 0.0;
2421 //double durPaint = 0.0;
2422 //double durCopy = 0.0;
2423 //ElapsedTime etWhole;
2424 int lineDocPrevious
= -1; // Used to avoid laying out one document line multiple times
2425 AutoLineLayout
ll(llc
, 0);
2426 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
2428 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
2429 // Only visible lines should be handled by the code within the loop
2430 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
2431 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
2432 int subLine
= visibleLine
- lineStartSet
;
2434 // Copy this line and its styles from the document into local arrays
2435 // and determine the x position at which each character starts.
2437 if (lineDoc
!= lineDocPrevious
) {
2438 ll
.Set(RetrieveLineLayout(lineDoc
));
2439 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
2440 lineDocPrevious
= lineDoc
;
2442 //durLayout += et.Duration(true);
2445 ll
->selStart
= SelectionStart(lineDoc
);
2446 ll
->selEnd
= SelectionEnd(lineDoc
);
2447 ll
->containsCaret
= lineDoc
== lineCaret
;
2448 if (hideSelection
) {
2451 ll
->containsCaret
= false;
2454 GetHotSpotRange(ll
->hsStart
, ll
->hsEnd
);
2456 PRectangle rcLine
= rcClient
;
2458 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
2460 Range
rangeLine(pdoc
->LineStart(lineDoc
), pdoc
->LineStart(lineDoc
+ 1));
2461 // Highlight the current braces if any
2462 ll
->SetBracesHighlight(rangeLine
, braces
, static_cast<char>(bracesMatchStyle
),
2463 highlightGuideColumn
* vs
.spaceWidth
);
2466 DrawLine(surface
, vs
, lineDoc
, visibleLine
, xStart
, rcLine
, ll
, subLine
);
2467 //durPaint += et.Duration(true);
2469 // Restore the precvious styles for the brace highlights in case layout is in cache.
2470 ll
->RestoreBracesHighlight(rangeLine
, braces
);
2472 bool expanded
= cs
.GetExpanded(lineDoc
);
2473 if ((foldFlags
& SC_FOLDFLAG_BOX
) == 0) {
2474 // Paint the line above the fold
2475 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_EXPANDED
))
2477 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_CONTRACTED
))) {
2478 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2479 PRectangle rcFoldLine
= rcLine
;
2480 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2481 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2484 // Paint the line below the fold
2485 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_EXPANDED
))
2487 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2488 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2489 PRectangle rcFoldLine
= rcLine
;
2490 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2491 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2495 int FoldLevelCurr
= (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2496 int FoldLevelPrev
= (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2497 int FoldLevelFlags
= (pdoc
->GetLevel(lineDoc
) & ~SC_FOLDLEVELNUMBERMASK
) & ~(0xFFF0000);
2498 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
2499 // Draw line above fold
2500 if ((FoldLevelPrev
< FoldLevelCurr
)
2502 (FoldLevelFlags
& SC_FOLDLEVELBOXHEADERFLAG
2504 (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELBOXFOOTERFLAG
) == 0)) {
2505 PRectangle rcFoldLine
= rcLine
;
2506 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2507 rcFoldLine
.left
+= xStart
+ FoldLevelCurr
* vs
.spaceWidth
* indentationStep
- 1;
2508 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2511 // Line below the fold (or below a contracted fold)
2512 if (FoldLevelFlags
& SC_FOLDLEVELBOXFOOTERFLAG
2514 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2515 PRectangle rcFoldLine
= rcLine
;
2516 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2517 rcFoldLine
.left
+= xStart
+ (FoldLevelCurr
) * vs
.spaceWidth
* indentationStep
- 1;
2518 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2521 PRectangle rcBoxLine
= rcLine
;
2522 // Draw vertical line for every fold level
2523 for (int i
= 0; i
<= FoldLevelCurr
; i
++) {
2524 rcBoxLine
.left
= xStart
+ i
* vs
.spaceWidth
* indentationStep
- 1;
2525 rcBoxLine
.right
= rcBoxLine
.left
+ 1;
2526 surface
->FillRectangle(rcBoxLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2531 if (lineDoc
== lineCaret
) {
2532 int offset
= Platform::Minimum(posCaret
- rangeLine
.start
, ll
->maxLineLength
);
2533 if ((offset
>= ll
->LineStart(subLine
)) &&
2534 ((offset
< ll
->LineStart(subLine
+ 1)) || offset
== ll
->numCharsInLine
)) {
2535 int xposCaret
= ll
->positions
[offset
] - ll
->positions
[ll
->LineStart(subLine
)] + xStart
;
2536 int widthOverstrikeCaret
;
2537 if (posCaret
== pdoc
->Length()) { // At end of document
2538 widthOverstrikeCaret
= vs
.aveCharWidth
;
2539 } else if ((posCaret
- rangeLine
.start
) >= ll
->numCharsInLine
) { // At end of line
2540 widthOverstrikeCaret
= vs
.aveCharWidth
;
2542 widthOverstrikeCaret
= ll
->positions
[offset
+ 1] - ll
->positions
[offset
];
2544 if (widthOverstrikeCaret
< 3) // Make sure its visible
2545 widthOverstrikeCaret
= 3;
2546 if (((caret
.active
&& caret
.on
) || (posDrag
>= 0)) && xposCaret
>= 0) {
2547 PRectangle rcCaret
= rcLine
;
2548 int caretWidthOffset
= 0;
2549 if ((offset
> 0) && (vs
.caretWidth
> 1))
2550 caretWidthOffset
= 1; // Move back so overlaps both character cells.
2552 rcCaret
.left
= xposCaret
- caretWidthOffset
;
2553 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
2556 rcCaret
.top
= rcCaret
.bottom
- 2;
2557 rcCaret
.left
= xposCaret
+ 1;
2558 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
2560 rcCaret
.left
= xposCaret
- caretWidthOffset
;
2561 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
2564 surface
->FillRectangle(rcCaret
, vs
.caretcolour
.allocated
);
2570 Point
from(vs
.fixedColumnWidth
, 0);
2571 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
2572 rcClient
.right
, yposScreen
+ vs
.lineHeight
);
2573 surfaceWindow
->Copy(rcCopyArea
, from
, *pixmapLine
);
2575 //durCopy += et.Duration(true);
2578 if (!bufferedDraw
) {
2579 ypos
+= vs
.lineHeight
;
2582 yposScreen
+= vs
.lineHeight
;
2586 //if (durPaint < 0.00000001)
2587 // durPaint = 0.00000001;
2589 // Right column limit indicator
2590 PRectangle rcBeyondEOF
= rcClient
;
2591 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
2592 rcBeyondEOF
.right
= rcBeyondEOF
.right
;
2593 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
2594 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
2595 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2596 if (vs
.edgeState
== EDGE_LINE
) {
2597 int edgeX
= theEdge
* vs
.spaceWidth
;
2598 rcBeyondEOF
.left
= edgeX
+ xStart
;
2599 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
2600 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
.allocated
);
2603 //Platform::DebugPrintf(
2604 //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
2605 //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
2610 // Space (3 space characters) between line numbers and text when printing.
2611 #define lineNumberPrintSpace " "
2613 ColourDesired
InvertedLight(ColourDesired orig
) {
2614 unsigned int r
= orig
.GetRed();
2615 unsigned int g
= orig
.GetGreen();
2616 unsigned int b
= orig
.GetBlue();
2617 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
2618 unsigned int il
= 0xff - l
;
2620 return ColourDesired(0xff, 0xff, 0xff);
2624 return ColourDesired(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
2627 // This is mostly copied from the Paint method but with some things omitted
2628 // such as the margin markers, line numbers, selection and caret
2629 // Should be merged back into a combined Draw method.
2630 long Editor::FormatRange(bool draw
, RangeToFormat
*pfr
) {
2634 AutoSurface
surface(pfr
->hdc
, this);
2637 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this);
2638 if (!surfaceMeasure
) {
2642 ViewStyle
vsPrint(vs
);
2644 // Modify the view style for printing as do not normally want any of the transient features to be printed
2645 // Printing supports only the line number margin.
2646 int lineNumberIndex
= -1;
2647 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
2648 if ((!vsPrint
.ms
[margin
].symbol
) && (vsPrint
.ms
[margin
].width
> 0)) {
2649 lineNumberIndex
= margin
;
2651 vsPrint
.ms
[margin
].width
= 0;
2654 vsPrint
.showMarkedLines
= false;
2655 vsPrint
.fixedColumnWidth
= 0;
2656 vsPrint
.zoomLevel
= printMagnification
;
2657 vsPrint
.viewIndentationGuides
= false;
2658 // Don't show the selection when printing
2659 vsPrint
.selbackset
= false;
2660 vsPrint
.selforeset
= false;
2661 vsPrint
.whitespaceBackgroundSet
= false;
2662 vsPrint
.whitespaceForegroundSet
= false;
2663 vsPrint
.showCaretLineBackground
= false;
2665 // Set colours for printing according to users settings
2666 for (int sty
= 0;sty
<= STYLE_MAX
;sty
++) {
2667 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
2668 vsPrint
.styles
[sty
].fore
.desired
= InvertedLight(vsPrint
.styles
[sty
].fore
.desired
);
2669 vsPrint
.styles
[sty
].back
.desired
= InvertedLight(vsPrint
.styles
[sty
].back
.desired
);
2670 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
2671 vsPrint
.styles
[sty
].fore
.desired
= ColourDesired(0, 0, 0);
2672 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2673 } else if (printColourMode
== SC_PRINT_COLOURONWHITE
) {
2674 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2675 } else if (printColourMode
== SC_PRINT_COLOURONWHITEDEFAULTBG
) {
2676 if (sty
<= STYLE_DEFAULT
) {
2677 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2681 // White background for the line numbers
2682 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2684 vsPrint
.Refresh(*surfaceMeasure
);
2685 // Ensure colours are set up
2686 vsPrint
.RefreshColourPalette(palette
, true);
2687 vsPrint
.RefreshColourPalette(palette
, false);
2688 // Determining width must hapen after fonts have been realised in Refresh
2689 int lineNumberWidth
= 0;
2690 if (lineNumberIndex
>= 0) {
2691 lineNumberWidth
= surfaceMeasure
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
2692 "99999" lineNumberPrintSpace
, 5 + istrlen(lineNumberPrintSpace
));
2693 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
2696 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
2697 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
2698 if (linePrintLast
< linePrintStart
)
2699 linePrintLast
= linePrintStart
;
2700 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
);
2701 if (linePrintLast
> linePrintMax
)
2702 linePrintLast
= linePrintMax
;
2703 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
2704 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
2705 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
2706 int endPosPrint
= pdoc
->Length();
2707 if (linePrintLast
< pdoc
->LinesTotal())
2708 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
2710 // Ensure we are styled to where we are formatting.
2711 pdoc
->EnsureStyledTo(endPosPrint
);
2713 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
+ lineNumberWidth
;
2714 int ypos
= pfr
->rc
.top
;
2716 int lineDoc
= linePrintStart
;
2718 int nPrintPos
= pfr
->chrg
.cpMin
;
2719 int visibleLine
= 0;
2720 int widthPrint
= pfr
->rc
.Width() - lineNumberWidth
;
2721 if (printWrapState
== eWrapNone
)
2722 widthPrint
= LineLayout::wrapWidthInfinite
;
2724 while (lineDoc
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
2726 // When printing, the hdc and hdcTarget may be the same, so
2727 // changing the state of surfaceMeasure may change the underlying
2728 // state of surface. Therefore, any cached state is discarded before
2729 // using each surface.
2730 surfaceMeasure
->FlushCachedState();
2732 // Copy this line and its styles from the document into local arrays
2733 // and determine the x position at which each character starts.
2734 LineLayout
ll(8000);
2735 LayoutLine(lineDoc
, surfaceMeasure
, vsPrint
, &ll
, widthPrint
);
2739 ll
.containsCaret
= false;
2742 rcLine
.left
= pfr
->rc
.left
+ lineNumberWidth
;
2744 rcLine
.right
= pfr
->rc
.right
- 1;
2745 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
2747 // When document line is wrapped over multiple display lines, find where
2748 // to start printing from to ensure a particular position is on the first
2749 // line of the page.
2750 if (visibleLine
== 0) {
2751 int startWithinLine
= nPrintPos
- pdoc
->LineStart(lineDoc
);
2752 for (int iwl
= 0; iwl
< ll
.lines
- 1; iwl
++) {
2753 if (ll
.LineStart(iwl
) <= startWithinLine
&& ll
.LineStart(iwl
+ 1) >= startWithinLine
) {
2758 if (ll
.lines
> 1 && startWithinLine
>= ll
.LineStart(ll
.lines
- 1)) {
2759 visibleLine
= -(ll
.lines
- 1);
2763 if (draw
&& lineNumberWidth
&&
2764 (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) &&
2765 (visibleLine
>= 0)) {
2767 sprintf(number
, "%d" lineNumberPrintSpace
, lineDoc
+ 1);
2768 PRectangle rcNumber
= rcLine
;
2769 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
2771 rcNumber
.left
-= surfaceMeasure
->WidthText(
2772 vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
2773 surface
->FlushCachedState();
2774 surface
->DrawTextNoClip(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
2775 ypos
+ vsPrint
.maxAscent
, number
, istrlen(number
),
2776 vsPrint
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
2777 vsPrint
.styles
[STYLE_LINENUMBER
].back
.allocated
);
2781 surface
->FlushCachedState();
2783 for (int iwl
= 0; iwl
< ll
.lines
; iwl
++) {
2784 if (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) {
2785 if (visibleLine
>= 0) {
2788 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
2789 DrawLine(surface
, vsPrint
, lineDoc
, visibleLine
, xStart
, rcLine
, &ll
, iwl
);
2791 ypos
+= vsPrint
.lineHeight
;
2794 if (iwl
== ll
.lines
- 1)
2795 nPrintPos
= pdoc
->LineStart(lineDoc
+ 1);
2797 nPrintPos
+= ll
.LineStart(iwl
+ 1) - ll
.LineStart(iwl
);
2807 int Editor::TextWidth(int style
, const char *text
) {
2809 AutoSurface
surface(this);
2811 return surface
->WidthText(vs
.styles
[style
].font
, text
, istrlen(text
));
2817 // Empty method is overridden on GTK+ to show / hide scrollbars
2818 void Editor::ReconfigureScrollBars() {}
2820 void Editor::SetScrollBars() {
2823 int nMax
= MaxScrollPos();
2824 int nPage
= LinesOnScreen();
2825 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
2827 // TODO: ensure always showing as many lines as possible
2828 // May not be, if, for example, window made larger
2829 if (topLine
> MaxScrollPos()) {
2830 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
2831 SetVerticalScrollPos();
2835 if (!AbandonPaint())
2838 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
2841 void Editor::ChangeSize() {
2844 if (wrapState
!= eWrapNone
) {
2845 PRectangle rcTextArea
= GetClientRectangle();
2846 rcTextArea
.left
= vs
.fixedColumnWidth
;
2847 rcTextArea
.right
-= vs
.rightMarginWidth
;
2848 if (wrapWidth
!= rcTextArea
.Width()) {
2855 void Editor::AddChar(char ch
) {
2862 void Editor::AddCharUTF(char *s
, unsigned int len
, bool treatAsDBCS
) {
2863 bool wasSelection
= currentPos
!= anchor
;
2865 if (inOverstrike
&& !wasSelection
&& !RangeContainsProtected(currentPos
, currentPos
+ 1)) {
2866 if (currentPos
< (pdoc
->Length())) {
2867 if (!IsEOLChar(pdoc
->CharAt(currentPos
))) {
2868 pdoc
->DelChar(currentPos
);
2872 if (pdoc
->InsertString(currentPos
, s
, len
)) {
2873 SetEmptySelection(currentPos
+ len
);
2875 EnsureCaretVisible();
2876 // Avoid blinking during rapid typing:
2877 ShowCaretAtCurrentPosition();
2881 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
2882 static_cast<unsigned char>(s
[1]));
2884 int byte
= static_cast<unsigned char>(s
[0]);
2885 if ((byte
< 0xC0) || (1 == len
)) {
2886 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
2887 // characters when not in UTF-8 mode.
2888 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
2889 // characters representing themselves.
2891 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
2892 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
2893 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
2895 int byte2
= static_cast<unsigned char>(s
[1]);
2896 if ((byte2
& 0xC0) == 0x80) {
2897 // Two-byte-character lead-byte followed by a trail-byte.
2898 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
2900 // A two-byte-character lead-byte not followed by trail-byte
2901 // represents itself.
2902 } else if (byte
< 0xF0) {
2903 int byte2
= static_cast<unsigned char>(s
[1]);
2904 int byte3
= static_cast<unsigned char>(s
[2]);
2905 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
2906 // Three-byte-character lead byte followed by two trail bytes.
2907 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
2910 // A three-byte-character lead-byte not followed by two trail-bytes
2911 // represents itself.
2918 void Editor::ClearSelection() {
2919 if (!SelectionContainsProtected()) {
2920 if (selType
== selRectangle
) {
2921 pdoc
->BeginUndoAction();
2922 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2923 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2924 int startPos
= SelectionStart();
2925 for (int line
= lineEnd
; line
>= lineStart
; line
--) {
2926 startPos
= SelectionStart(line
);
2927 unsigned int chars
= SelectionEnd(line
) - startPos
;
2929 pdoc
->DeleteChars(startPos
, chars
);
2932 SetEmptySelection(startPos
);
2933 pdoc
->EndUndoAction();
2934 selType
= selStream
;
2936 int startPos
= SelectionStart();
2937 unsigned int chars
= SelectionEnd() - startPos
;
2938 SetEmptySelection(startPos
);
2940 pdoc
->BeginUndoAction();
2941 pdoc
->DeleteChars(startPos
, chars
);
2942 pdoc
->EndUndoAction();
2948 void Editor::ClearAll() {
2949 pdoc
->BeginUndoAction();
2950 if (0 != pdoc
->Length()) {
2951 pdoc
->DeleteChars(0, pdoc
->Length());
2953 if (!pdoc
->IsReadOnly()) {
2956 pdoc
->EndUndoAction();
2960 SetVerticalScrollPos();
2963 void Editor::ClearDocumentStyle() {
2964 pdoc
->StartStyling(0, '\377');
2965 pdoc
->SetStyleFor(pdoc
->Length(), 0);
2967 pdoc
->ClearLevels();
2970 void Editor::Cut() {
2971 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
2977 void Editor::PasteRectangular(int pos
, const char *ptr
, int len
) {
2978 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
2982 int xInsert
= XFromPosition(currentPos
);
2983 int line
= pdoc
->LineFromPosition(currentPos
);
2984 bool prevCr
= false;
2985 pdoc
->BeginUndoAction();
2986 for (int i
= 0; i
< len
; i
++) {
2987 if (IsEOLChar(ptr
[i
])) {
2988 if ((ptr
[i
] == '\r') || (!prevCr
))
2990 if (line
>= pdoc
->LinesTotal()) {
2991 if (pdoc
->eolMode
!= SC_EOL_LF
)
2992 pdoc
->InsertChar(pdoc
->Length(), '\r');
2993 if (pdoc
->eolMode
!= SC_EOL_CR
)
2994 pdoc
->InsertChar(pdoc
->Length(), '\n');
2996 // Pad the end of lines with spaces if required
2997 currentPos
= PositionFromLineX(line
, xInsert
);
2998 if ((XFromPosition(currentPos
) < xInsert
) && (i
+ 1 < len
)) {
2999 for (int i
= 0; i
< xInsert
- XFromPosition(currentPos
); i
++) {
3000 pdoc
->InsertChar(currentPos
, ' ');
3004 prevCr
= ptr
[i
] == '\r';
3006 pdoc
->InsertString(currentPos
, ptr
+ i
, 1);
3011 pdoc
->EndUndoAction();
3012 SetEmptySelection(pos
);
3015 bool Editor::CanPaste() {
3016 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
3019 void Editor::Clear() {
3020 if (currentPos
== anchor
) {
3021 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3027 SetEmptySelection(currentPos
);
3030 void Editor::SelectAll() {
3031 SetSelection(0, pdoc
->Length());
3035 void Editor::Undo() {
3036 if (pdoc
->CanUndo()) {
3038 int newPos
= pdoc
->Undo();
3039 SetEmptySelection(newPos
);
3040 EnsureCaretVisible();
3044 void Editor::Redo() {
3045 if (pdoc
->CanRedo()) {
3046 int newPos
= pdoc
->Redo();
3047 SetEmptySelection(newPos
);
3048 EnsureCaretVisible();
3052 void Editor::DelChar() {
3053 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3054 pdoc
->DelChar(currentPos
);
3056 // Avoid blinking during rapid typing:
3057 ShowCaretAtCurrentPosition();
3060 void Editor::DelCharBack(bool allowLineStartDeletion
) {
3061 if (currentPos
== anchor
) {
3062 if (!RangeContainsProtected(currentPos
- 1, currentPos
)) {
3063 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
3064 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != currentPos
)) {
3065 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3066 pdoc
->GetColumn(currentPos
) > 0 && pdoc
->backspaceUnindents
) {
3067 pdoc
->BeginUndoAction();
3068 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3069 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
3070 if (indentation
% indentationStep
== 0) {
3071 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3073 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- (indentation
% indentationStep
));
3075 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
3076 pdoc
->EndUndoAction();
3078 pdoc
->DelCharBack(currentPos
);
3084 SetEmptySelection(currentPos
);
3086 // Avoid blinking during rapid typing:
3087 ShowCaretAtCurrentPosition();
3090 void Editor::NotifyFocus(bool) {}
3092 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
3094 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
3095 scn
.position
= endStyleNeeded
;
3099 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
3100 NotifyStyleToNeeded(endStyleNeeded
);
3103 void Editor::NotifyChar(int ch
) {
3105 scn
.nmhdr
.code
= SCN_CHARADDED
;
3108 if (recordingMacro
) {
3110 txt
[0] = static_cast<char>(ch
);
3112 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
3116 void Editor::NotifySavePoint(bool isSavePoint
) {
3119 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
3121 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
3126 void Editor::NotifyModifyAttempt() {
3128 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
3132 void Editor::NotifyDoubleClick(Point
, bool) {
3134 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
3138 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3140 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
3141 scn
.position
= position
;
3142 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3143 (alt
? SCI_ALT
: 0);
3147 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3149 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
3150 scn
.position
= position
;
3151 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3152 (alt
? SCI_ALT
: 0);
3156 void Editor::NotifyUpdateUI() {
3158 scn
.nmhdr
.code
= SCN_UPDATEUI
;
3162 void Editor::NotifyPainted() {
3164 scn
.nmhdr
.code
= SCN_PAINTED
;
3168 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
3169 int marginClicked
= -1;
3171 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
3172 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
3173 marginClicked
= margin
;
3174 x
+= vs
.ms
[margin
].width
;
3176 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
3178 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
3179 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3180 (alt
? SCI_ALT
: 0);
3181 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
3182 scn
.margin
= marginClicked
;
3190 void Editor::NotifyNeedShown(int pos
, int len
) {
3192 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
3198 void Editor::NotifyDwelling(Point pt
, bool state
) {
3200 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
3201 scn
.position
= PositionFromLocationClose(pt
);
3207 void Editor::NotifyZoom() {
3209 scn
.nmhdr
.code
= SCN_ZOOM
;
3213 // Notifications from document
3214 void Editor::NotifyModifyAttempt(Document
*, void *) {
3215 //Platform::DebugPrintf("** Modify Attempt\n");
3216 NotifyModifyAttempt();
3219 void Editor::NotifyMove(int position
) {
3221 scn
.nmhdr
.code
= SCN_POSCHANGED
;
3222 scn
.position
= position
;
3226 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
3227 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
3228 NotifySavePoint(atSavePoint
);
3231 void Editor::CheckModificationForWrap(DocModification mh
) {
3232 if ((mh
.modificationType
& SC_MOD_INSERTTEXT
) ||
3233 (mh
.modificationType
& SC_MOD_DELETETEXT
)) {
3234 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
3235 if (wrapState
!= eWrapNone
) {
3236 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
3237 if (mh
.linesAdded
== 0) {
3238 AutoSurface
surface(this);
3239 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
3240 if (surface
&& ll
) {
3241 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
3242 if (cs
.GetHeight(lineDoc
) != ll
->lines
) {
3243 NeedWrapping(lineDoc
- 1);
3247 NeedWrapping(lineDoc
);
3250 NeedWrapping(lineDoc
);
3256 // Move a position so it is still after the same character as before the insertion.
3257 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
3258 if (position
> startInsertion
) {
3259 return position
+ length
;
3264 // Move a position so it is still after the same character as before the deletion if that
3265 // character is still present else after the previous surviving character.
3266 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
3267 if (position
> startDeletion
) {
3268 int endDeletion
= startDeletion
+ length
;
3269 if (position
> endDeletion
) {
3270 return position
- length
;
3272 return startDeletion
;
3279 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
3280 needUpdateUI
= true;
3281 if (paintState
== painting
) {
3282 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
3284 CheckModificationForWrap(mh
);
3285 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
3286 if (paintState
== notPainting
) {
3287 if (mh
.position
< pdoc
->LineStart(topLine
)) {
3288 // Styling performed before this view
3291 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3295 // Move selection and brace highlights
3296 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
3297 currentPos
= MovePositionForInsertion(currentPos
, mh
.position
, mh
.length
);
3298 anchor
= MovePositionForInsertion(anchor
, mh
.position
, mh
.length
);
3299 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
3300 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
3301 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
3302 currentPos
= MovePositionForDeletion(currentPos
, mh
.position
, mh
.length
);
3303 anchor
= MovePositionForDeletion(anchor
, mh
.position
, mh
.length
);
3304 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
3305 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
3307 if (cs
.LinesDisplayed() < cs
.LinesInDoc()) {
3308 // Some lines are hidden so may need shown.
3309 // TODO: check if the modified area is hidden.
3310 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
3311 NotifyNeedShown(mh
.position
, mh
.length
);
3312 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
3313 NotifyNeedShown(mh
.position
, mh
.length
);
3316 if (mh
.linesAdded
!= 0) {
3317 // Update contraction state for inserted and removed lines
3318 // lineOfPos should be calculated in context of state before modification, shouldn't it
3319 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
3320 if (mh
.linesAdded
> 0) {
3321 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
3323 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
3325 // Avoid scrolling of display if change before current display
3326 if (mh
.position
< posTopLine
) {
3327 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
3328 if (newTop
!= topLine
) {
3330 SetVerticalScrollPos();
3334 //Platform::DebugPrintf("** %x Doc Changed\n", this);
3335 // TODO: could invalidate from mh.startModification to end of screen
3336 //InvalidateRange(mh.position, mh.position + mh.length);
3337 if (paintState
== notPainting
) {
3341 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
3342 // mh.position, mh.position + mh.length);
3343 if (paintState
== notPainting
) {
3344 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3349 if (mh
.linesAdded
!= 0) {
3353 if (mh
.modificationType
& SC_MOD_CHANGEMARKER
) {
3354 if (paintState
== notPainting
) {
3359 // If client wants to see this modification
3360 if (mh
.modificationType
& modEventMask
) {
3361 if ((mh
.modificationType
& SC_MOD_CHANGESTYLE
) == 0) {
3362 // Real modification made to text of document.
3363 NotifyChange(); // Send EN_CHANGE
3367 scn
.nmhdr
.code
= SCN_MODIFIED
;
3368 scn
.position
= mh
.position
;
3369 scn
.modificationType
= mh
.modificationType
;
3371 scn
.length
= mh
.length
;
3372 scn
.linesAdded
= mh
.linesAdded
;
3374 scn
.foldLevelNow
= mh
.foldLevelNow
;
3375 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
3380 void Editor::NotifyDeleted(Document
*, void *) {
3384 void Editor::NotifyMacroRecord(unsigned int iMessage
, unsigned long wParam
, long lParam
) {
3386 // Enumerates all macroable messages
3392 case SCI_REPLACESEL
:
3394 case SCI_INSERTTEXT
:
3395 case SCI_APPENDTEXT
:
3400 case SCI_SEARCHANCHOR
:
3401 case SCI_SEARCHNEXT
:
3402 case SCI_SEARCHPREV
:
3404 case SCI_LINEDOWNEXTEND
:
3406 case SCI_PARADOWNEXTEND
:
3408 case SCI_LINEUPEXTEND
:
3410 case SCI_PARAUPEXTEND
:
3412 case SCI_CHARLEFTEXTEND
:
3414 case SCI_CHARRIGHTEXTEND
:
3416 case SCI_WORDLEFTEXTEND
:
3418 case SCI_WORDRIGHTEXTEND
:
3419 case SCI_WORDPARTLEFT
:
3420 case SCI_WORDPARTLEFTEXTEND
:
3421 case SCI_WORDPARTRIGHT
:
3422 case SCI_WORDPARTRIGHTEXTEND
:
3424 case SCI_HOMEEXTEND
:
3426 case SCI_LINEENDEXTEND
:
3428 case SCI_HOMEWRAPEXTEND
:
3429 case SCI_LINEENDWRAP
:
3430 case SCI_LINEENDWRAPEXTEND
:
3431 case SCI_DOCUMENTSTART
:
3432 case SCI_DOCUMENTSTARTEXTEND
:
3433 case SCI_DOCUMENTEND
:
3434 case SCI_DOCUMENTENDEXTEND
:
3436 case SCI_PAGEUPEXTEND
:
3438 case SCI_PAGEDOWNEXTEND
:
3439 case SCI_EDITTOGGLEOVERTYPE
:
3441 case SCI_DELETEBACK
:
3446 case SCI_VCHOMEEXTEND
:
3447 case SCI_VCHOMEWRAP
:
3448 case SCI_VCHOMEWRAPEXTEND
:
3449 case SCI_DELWORDLEFT
:
3450 case SCI_DELWORDRIGHT
:
3451 case SCI_DELLINELEFT
:
3452 case SCI_DELLINERIGHT
:
3455 case SCI_LINEDELETE
:
3456 case SCI_LINETRANSPOSE
:
3457 case SCI_LINEDUPLICATE
:
3460 case SCI_LINESCROLLDOWN
:
3461 case SCI_LINESCROLLUP
:
3462 case SCI_DELETEBACKNOTLINE
:
3463 case SCI_HOMEDISPLAY
:
3464 case SCI_HOMEDISPLAYEXTEND
:
3465 case SCI_LINEENDDISPLAY
:
3466 case SCI_LINEENDDISPLAYEXTEND
:
3469 // Filter out all others like display changes. Also, newlines are redundant
3470 // with char insert messages.
3473 // printf("Filtered out %ld of macro recording\n", iMessage);
3477 // Send notification
3479 scn
.nmhdr
.code
= SCN_MACRORECORD
;
3480 scn
.message
= iMessage
;
3481 scn
.wParam
= wParam
;
3482 scn
.lParam
= lParam
;
3486 // Force scroll and keep position relative to top of window
3487 void Editor::PageMove(int direction
, bool extend
) {
3488 Point pt
= LocationFromPosition(currentPos
);
3489 int topLineNew
= Platform::Clamp(
3490 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
3491 int newPos
= PositionFromLocation(
3492 Point(lastXChosen
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())));
3493 if (topLineNew
!= topLine
) {
3494 SetTopLine(topLineNew
);
3495 MovePositionTo(newPos
, extend
);
3497 SetVerticalScrollPos();
3499 MovePositionTo(newPos
, extend
);
3503 void Editor::ChangeCaseOfSelection(bool makeUpperCase
) {
3504 pdoc
->BeginUndoAction();
3505 int startCurrent
= currentPos
;
3506 int startAnchor
= anchor
;
3507 if (selType
== selRectangle
) {
3508 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
3509 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
3510 for (int line
= lineEnd
; line
>= lineStart
; line
--) {
3512 Range(SelectionStart(line
), SelectionEnd(line
)),
3515 // Would be nicer to keep the rectangular selection but this is complex
3516 selType
= selStream
;
3517 SetSelection(startCurrent
, startCurrent
);
3519 pdoc
->ChangeCase(Range(SelectionStart(), SelectionEnd()),
3521 SetSelection(startCurrent
, startAnchor
);
3523 pdoc
->EndUndoAction();
3526 void Editor::LineTranspose() {
3527 int line
= pdoc
->LineFromPosition(currentPos
);
3529 int startPrev
= pdoc
->LineStart(line
- 1);
3530 int endPrev
= pdoc
->LineEnd(line
- 1);
3531 int start
= pdoc
->LineStart(line
);
3532 int end
= pdoc
->LineEnd(line
);
3533 int startNext
= pdoc
->LineStart(line
+ 1);
3534 if (end
< pdoc
->Length()) {
3536 char *thisLine
= CopyRange(start
, end
);
3537 pdoc
->DeleteChars(start
, end
- start
);
3538 if (pdoc
->InsertString(startPrev
, thisLine
, end
- start
)) {
3539 MovePositionTo(startPrev
+ end
- start
);
3543 // Last line so line has no line end
3544 char *thisLine
= CopyRange(start
, end
);
3545 char *prevEnd
= CopyRange(endPrev
, start
);
3546 pdoc
->DeleteChars(endPrev
, end
- endPrev
);
3547 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
3548 if (pdoc
->InsertString(startPrev
+ end
- start
, prevEnd
, start
- endPrev
)) {
3549 MovePositionTo(startPrev
+ end
- endPrev
);
3558 void Editor::LineDuplicate() {
3559 int line
= pdoc
->LineFromPosition(currentPos
);
3560 int start
= pdoc
->LineStart(line
);
3561 int end
= pdoc
->LineEnd(line
);
3562 char *thisLine
= CopyRange(start
, end
);
3563 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
3564 pdoc
->InsertString(end
, eol
);
3565 pdoc
->InsertString(end
+ istrlen(eol
), thisLine
, end
- start
);
3569 void Editor::CancelModes() {}
3571 void Editor::NewLine() {
3573 const char *eol
= "\n";
3574 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
3576 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
3578 } // else SC_EOL_LF -> "\n" already set
3579 if (pdoc
->InsertString(currentPos
, eol
)) {
3580 SetEmptySelection(currentPos
+ istrlen(eol
));
3587 EnsureCaretVisible();
3590 void Editor::CursorUpOrDown(int direction
, bool extend
) {
3591 Point pt
= LocationFromPosition(currentPos
);
3592 int posNew
= PositionFromLocation(
3593 Point(lastXChosen
, pt
.y
+ direction
* vs
.lineHeight
));
3594 if (direction
< 0) {
3595 // Line wrapping may lead to a location on the same line, so
3596 // seek back if that is the case.
3597 // There is an equivalent case when moving down which skips
3598 // over a line but as that does not trap the user it is fine.
3599 Point ptNew
= LocationFromPosition(posNew
);
3600 while ((posNew
> 0) && (pt
.y
== ptNew
.y
)) {
3602 ptNew
= LocationFromPosition(posNew
);
3605 MovePositionTo(posNew
, extend
);
3608 int Editor::StartEndDisplayLine(int pos
, bool start
) {
3610 int line
= pdoc
->LineFromPosition(pos
);
3611 AutoSurface
surface(this);
3612 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
3613 int posRet
= INVALID_POSITION
;
3614 if (surface
&& ll
) {
3615 unsigned int posLineStart
= pdoc
->LineStart(line
);
3616 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
3617 int posInLine
= pos
- posLineStart
;
3618 if (posInLine
<= ll
->maxLineLength
) {
3619 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
3620 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
3622 posRet
= ll
->LineStart(subLine
) + posLineStart
;
3624 if (subLine
== ll
->lines
- 1)
3625 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
;
3627 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
- 1;
3633 if (posRet
== INVALID_POSITION
) {
3640 int Editor::KeyCommand(unsigned int iMessage
) {
3645 case SCI_LINEDOWNEXTEND
:
3646 CursorUpOrDown(1, true);
3649 MovePositionTo(pdoc
->ParaDown(currentPos
));
3651 case SCI_PARADOWNEXTEND
:
3652 MovePositionTo(pdoc
->ParaDown(currentPos
), true);
3654 case SCI_LINESCROLLDOWN
:
3655 ScrollTo(topLine
+ 1);
3656 MoveCaretInsideView(false);
3661 case SCI_LINEUPEXTEND
:
3662 CursorUpOrDown(-1, true);
3665 MovePositionTo(pdoc
->ParaUp(currentPos
));
3667 case SCI_PARAUPEXTEND
:
3668 MovePositionTo(pdoc
->ParaUp(currentPos
), true);
3670 case SCI_LINESCROLLUP
:
3671 ScrollTo(topLine
- 1);
3672 MoveCaretInsideView(false);
3675 if (SelectionEmpty()) {
3676 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1));
3678 MovePositionTo(SelectionStart());
3682 case SCI_CHARLEFTEXTEND
:
3683 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), true);
3687 if (SelectionEmpty()) {
3688 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1));
3690 MovePositionTo(SelectionEnd());
3694 case SCI_CHARRIGHTEXTEND
:
3695 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), true);
3699 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1));
3702 case SCI_WORDLEFTEXTEND
:
3703 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1), true);
3707 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1));
3710 case SCI_WORDRIGHTEXTEND
:
3711 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1), true);
3715 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)));
3718 case SCI_HOMEEXTEND
:
3719 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), true);
3723 MovePositionTo(pdoc
->LineEndPosition(currentPos
));
3726 case SCI_LINEENDEXTEND
:
3727 MovePositionTo(pdoc
->LineEndPosition(currentPos
), true);
3730 case SCI_HOMEWRAP
: {
3731 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
3732 if (currentPos
<= homePos
)
3733 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
3734 MovePositionTo(homePos
);
3738 case SCI_HOMEWRAPEXTEND
: {
3739 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
3740 if (currentPos
<= homePos
)
3741 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
3742 MovePositionTo(homePos
, true);
3746 case SCI_LINEENDWRAP
: {
3747 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
3748 if (currentPos
>= endPos
)
3749 endPos
= pdoc
->LineEndPosition(currentPos
);
3750 MovePositionTo(endPos
);
3754 case SCI_LINEENDWRAPEXTEND
: {
3755 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
3756 if (currentPos
>= endPos
)
3757 endPos
= pdoc
->LineEndPosition(currentPos
);
3758 MovePositionTo(endPos
, true);
3762 case SCI_DOCUMENTSTART
:
3766 case SCI_DOCUMENTSTARTEXTEND
:
3767 MovePositionTo(0, true);
3770 case SCI_DOCUMENTEND
:
3771 MovePositionTo(pdoc
->Length());
3774 case SCI_DOCUMENTENDEXTEND
:
3775 MovePositionTo(pdoc
->Length(), true);
3781 case SCI_PAGEUPEXTEND
:
3787 case SCI_PAGEDOWNEXTEND
:
3790 case SCI_EDITTOGGLEOVERTYPE
:
3791 inOverstrike
= !inOverstrike
;
3793 ShowCaretAtCurrentPosition();
3796 case SCI_CANCEL
: // Cancel any modes - handled in subclass
3797 // Also unselect text
3800 case SCI_DELETEBACK
:
3803 EnsureCaretVisible();
3805 case SCI_DELETEBACKNOTLINE
:
3808 EnsureCaretVisible();
3813 EnsureCaretVisible();
3818 EnsureCaretVisible();
3827 MovePositionTo(pdoc
->VCHomePosition(currentPos
));
3830 case SCI_VCHOMEEXTEND
:
3831 MovePositionTo(pdoc
->VCHomePosition(currentPos
), true);
3834 case SCI_VCHOMEWRAP
: {
3835 int homePos
= pdoc
->VCHomePosition(currentPos
);
3836 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
3837 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
3838 homePos
= viewLineStart
;
3840 MovePositionTo(homePos
);
3844 case SCI_VCHOMEWRAPEXTEND
: {
3845 int homePos
= pdoc
->VCHomePosition(currentPos
);
3846 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
3847 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
3848 homePos
= viewLineStart
;
3850 MovePositionTo(homePos
, true);
3855 if (vs
.zoomLevel
< 20) {
3857 InvalidateStyleRedraw();
3862 if (vs
.zoomLevel
> -10) {
3864 InvalidateStyleRedraw();
3868 case SCI_DELWORDLEFT
: {
3869 int startWord
= pdoc
->NextWordStart(currentPos
, -1);
3870 pdoc
->DeleteChars(startWord
, currentPos
- startWord
);
3874 case SCI_DELWORDRIGHT
: {
3875 int endWord
= pdoc
->NextWordStart(currentPos
, 1);
3876 pdoc
->DeleteChars(currentPos
, endWord
- currentPos
);
3879 case SCI_DELLINELEFT
: {
3880 int line
= pdoc
->LineFromPosition(currentPos
);
3881 int start
= pdoc
->LineStart(line
);
3882 pdoc
->DeleteChars(start
, currentPos
- start
);
3886 case SCI_DELLINERIGHT
: {
3887 int line
= pdoc
->LineFromPosition(currentPos
);
3888 int end
= pdoc
->LineEnd(line
);
3889 pdoc
->DeleteChars(currentPos
, end
- currentPos
);
3892 case SCI_LINECOPY
: {
3893 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
3894 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
3895 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
3896 pdoc
->LineStart(lineEnd
+ 1));
3900 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
3901 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
3902 int start
= pdoc
->LineStart(lineStart
);
3903 int end
= pdoc
->LineStart(lineEnd
+ 1);
3904 SetSelection(start
, end
);
3909 case SCI_LINEDELETE
: {
3910 int line
= pdoc
->LineFromPosition(currentPos
);
3911 int start
= pdoc
->LineStart(line
);
3912 int end
= pdoc
->LineStart(line
+ 1);
3913 pdoc
->DeleteChars(start
, end
- start
);
3916 case SCI_LINETRANSPOSE
:
3919 case SCI_LINEDUPLICATE
:
3923 ChangeCaseOfSelection(false);
3926 ChangeCaseOfSelection(true);
3928 case SCI_WORDPARTLEFT
:
3929 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1));
3932 case SCI_WORDPARTLEFTEXTEND
:
3933 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1), true);
3936 case SCI_WORDPARTRIGHT
:
3937 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1));
3940 case SCI_WORDPARTRIGHTEXTEND
:
3941 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1), true);
3944 case SCI_HOMEDISPLAY
:
3945 MovePositionTo(MovePositionSoVisible(
3946 StartEndDisplayLine(currentPos
, true), -1));
3949 case SCI_HOMEDISPLAYEXTEND
:
3950 MovePositionTo(MovePositionSoVisible(
3951 StartEndDisplayLine(currentPos
, true), -1), true);
3954 case SCI_LINEENDDISPLAY
:
3955 MovePositionTo(MovePositionSoVisible(
3956 StartEndDisplayLine(currentPos
, false), 1));
3959 case SCI_LINEENDDISPLAYEXTEND
:
3960 MovePositionTo(MovePositionSoVisible(
3961 StartEndDisplayLine(currentPos
, false), 1), true);
3968 int Editor::KeyDefault(int, int) {
3972 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
3974 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3975 (alt
? SCI_ALT
: 0);
3976 int msg
= kmap
.Find(key
, modifiers
);
3980 return WndProc(msg
, 0, 0);
3984 return KeyDefault(key
, modifiers
);
3988 void Editor::SetWhitespaceVisible(int view
) {
3989 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(view
);
3992 int Editor::GetWhitespaceVisible() {
3993 return vs
.viewWhitespace
;
3996 void Editor::Indent(bool forwards
) {
3997 //Platform::DebugPrintf("INdent %d\n", forwards);
3998 int lineOfAnchor
= pdoc
->LineFromPosition(anchor
);
3999 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
4000 if (lineOfAnchor
== lineCurrentPos
) {
4002 pdoc
->BeginUndoAction();
4004 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
4006 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4007 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
4008 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
+ indentationStep
);
4009 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4011 if (pdoc
->useTabs
) {
4012 pdoc
->InsertChar(currentPos
, '\t');
4013 SetEmptySelection(currentPos
+ 1);
4015 int numSpaces
= (pdoc
->tabInChars
) -
4016 (pdoc
->GetColumn(currentPos
) % (pdoc
->tabInChars
));
4018 numSpaces
= pdoc
->tabInChars
;
4019 for (int i
= 0; i
< numSpaces
; i
++) {
4020 pdoc
->InsertChar(currentPos
+ i
, ' ');
4022 SetEmptySelection(currentPos
+ numSpaces
);
4025 pdoc
->EndUndoAction();
4027 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
4029 pdoc
->BeginUndoAction();
4030 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4031 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
4032 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
4033 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4034 pdoc
->EndUndoAction();
4036 int newColumn
= ((pdoc
->GetColumn(currentPos
) - 1) / pdoc
->tabInChars
) *
4040 int newPos
= currentPos
;
4041 while (pdoc
->GetColumn(newPos
) > newColumn
)
4043 SetEmptySelection(newPos
);
4047 int anchorPosOnLine
= anchor
- pdoc
->LineStart(lineOfAnchor
);
4048 int currentPosPosOnLine
= currentPos
- pdoc
->LineStart(lineCurrentPos
);
4049 // Multiple lines selected so indent / dedent
4050 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
4051 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
4052 if (pdoc
->LineStart(lineBottomSel
) == anchor
|| pdoc
->LineStart(lineBottomSel
) == currentPos
)
4053 lineBottomSel
--; // If not selecting any characters on a line, do not indent
4054 pdoc
->BeginUndoAction();
4055 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
4056 pdoc
->EndUndoAction();
4057 if (lineOfAnchor
< lineCurrentPos
) {
4058 if (currentPosPosOnLine
== 0)
4059 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4061 SetSelection(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
4063 if (anchorPosOnLine
== 0)
4064 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4066 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
4072 * Search of a text in the document, in the given range.
4073 * @return The position of the found text, -1 if not found.
4075 long Editor::FindText(
4076 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4077 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4078 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
4080 TextToFind
*ft
= reinterpret_cast<TextToFind
*>(lParam
);
4081 int lengthFound
= istrlen(ft
->lpstrText
);
4082 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
4083 (wParam
& SCFIND_MATCHCASE
) != 0,
4084 (wParam
& SCFIND_WHOLEWORD
) != 0,
4085 (wParam
& SCFIND_WORDSTART
) != 0,
4086 (wParam
& SCFIND_REGEXP
) != 0,
4087 (wParam
& SCFIND_POSIX
) != 0,
4090 ft
->chrgText
.cpMin
= pos
;
4091 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
4097 * Relocatable search support : Searches relative to current selection
4098 * point and sets the selection to the found text range with
4102 * Anchor following searches at current selection start: This allows
4103 * multiple incremental interactive searches to be macro recorded
4104 * while still setting the selection to found text so the find/select
4105 * operation is self-contained.
4107 void Editor::SearchAnchor() {
4108 searchAnchor
= SelectionStart();
4112 * Find text from current search anchor: Must call @c SearchAnchor first.
4113 * Used for next text and previous text requests.
4114 * @return The position of the found text, -1 if not found.
4116 long Editor::SearchText(
4117 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
4118 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4119 ///< @c SCFIND_WORDSTART or @c SCFIND_REGEXP.
4120 sptr_t lParam
) { ///< The text to search for.
4122 const char *txt
= reinterpret_cast<char *>(lParam
);
4124 int lengthFound
= istrlen(txt
);
4125 if (iMessage
== SCI_SEARCHNEXT
) {
4126 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
4127 (wParam
& SCFIND_MATCHCASE
) != 0,
4128 (wParam
& SCFIND_WHOLEWORD
) != 0,
4129 (wParam
& SCFIND_WORDSTART
) != 0,
4130 (wParam
& SCFIND_REGEXP
) != 0,
4131 (wParam
& SCFIND_POSIX
) != 0,
4134 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
4135 (wParam
& SCFIND_MATCHCASE
) != 0,
4136 (wParam
& SCFIND_WHOLEWORD
) != 0,
4137 (wParam
& SCFIND_WORDSTART
) != 0,
4138 (wParam
& SCFIND_REGEXP
) != 0,
4139 (wParam
& SCFIND_POSIX
) != 0,
4144 SetSelection(pos
, pos
+ lengthFound
);
4151 * Search for text in the target range of the document.
4152 * @return The position of the found text, -1 if not found.
4154 long Editor::SearchInTarget(const char *text
, int length
) {
4155 int lengthFound
= length
;
4156 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
4157 (searchFlags
& SCFIND_MATCHCASE
) != 0,
4158 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
4159 (searchFlags
& SCFIND_WORDSTART
) != 0,
4160 (searchFlags
& SCFIND_REGEXP
) != 0,
4161 (searchFlags
& SCFIND_POSIX
) != 0,
4165 targetEnd
= pos
+ lengthFound
;
4170 void Editor::GoToLine(int lineNo
) {
4171 if (lineNo
> pdoc
->LinesTotal())
4172 lineNo
= pdoc
->LinesTotal();
4175 SetEmptySelection(pdoc
->LineStart(lineNo
));
4176 ShowCaretAtCurrentPosition();
4177 EnsureCaretVisible();
4180 static bool Close(Point pt1
, Point pt2
) {
4181 if (abs(pt1
.x
- pt2
.x
) > 3)
4183 if (abs(pt1
.y
- pt2
.y
) > 3)
4188 char *Editor::CopyRange(int start
, int end
) {
4191 int len
= end
- start
;
4192 text
= new char[len
+ 1];
4194 for (int i
= 0; i
< len
; i
++) {
4195 text
[i
] = pdoc
->CharAt(start
+ i
);
4203 void Editor::CopySelectionFromRange(SelectionText
*ss
, int start
, int end
) {
4204 ss
->Set(CopyRange(start
, end
), end
- start
+ 1, false);
4207 void Editor::CopySelectionRange(SelectionText
*ss
) {
4208 if (selType
== selRectangle
) {
4211 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4212 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4214 for (line
= lineStart
; line
<= lineEnd
; line
++) {
4215 size
+= SelectionEnd(line
) - SelectionStart(line
) + 1;
4216 if (pdoc
->eolMode
== SC_EOL_CRLF
)
4220 text
= new char[size
+ 1];
4223 for (line
= lineStart
; line
<= lineEnd
; line
++) {
4224 for (int i
= SelectionStart(line
);i
< SelectionEnd(line
);i
++) {
4225 text
[j
++] = pdoc
->CharAt(i
);
4227 if (pdoc
->eolMode
!= SC_EOL_LF
)
4229 if (pdoc
->eolMode
!= SC_EOL_CR
)
4235 ss
->Set(text
, size
+ 1, true);
4237 CopySelectionFromRange(ss
, SelectionStart(), SelectionEnd());
4241 void Editor::CopyRangeToClipboard(int start
, int end
) {
4242 start
= pdoc
->ClampPositionIntoDocument(start
);
4243 end
= pdoc
->ClampPositionIntoDocument(end
);
4244 SelectionText selectedText
;
4245 selectedText
.Set(CopyRange(start
, end
), end
- start
+ 1);
4246 CopyToClipboard(selectedText
);
4249 void Editor::CopyText(int length
, const char *text
) {
4250 SelectionText selectedText
;
4251 selectedText
.Copy(text
, length
);
4252 CopyToClipboard(selectedText
);
4255 void Editor::SetDragPosition(int newPos
) {
4257 newPos
= MovePositionOutsideChar(newPos
, 1);
4260 if (posDrag
!= newPos
) {
4269 void Editor::DisplayCursor(Window::Cursor c
) {
4270 if (cursorMode
== SC_CURSORNORMAL
)
4273 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
4276 void Editor::StartDrag() {
4277 // Always handled by subclasses
4278 //SetMouseCapture(true);
4279 //DisplayCursor(Window::cursorArrow);
4282 void Editor::DropAt(int position
, const char *value
, bool moving
, bool rectangular
) {
4283 //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
4285 dropWentOutside
= false;
4287 int positionWasInSelection
= PositionInSelection(position
);
4289 bool positionOnEdgeOfSelection
=
4290 (position
== SelectionStart()) || (position
== SelectionEnd());
4292 if ((!inDragDrop
) || !(0 == positionWasInSelection
) ||
4293 (positionOnEdgeOfSelection
&& !moving
)) {
4295 int selStart
= SelectionStart();
4296 int selEnd
= SelectionEnd();
4298 pdoc
->BeginUndoAction();
4300 int positionAfterDeletion
= position
;
4301 if (inDragDrop
&& moving
) {
4302 // Remove dragged out text
4304 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4305 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4306 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
4307 int startPos
= SelectionStart(line
);
4308 int endPos
= SelectionEnd(line
);
4309 if (position
>= startPos
) {
4310 if (position
> endPos
) {
4311 positionAfterDeletion
-= endPos
- startPos
;
4313 positionAfterDeletion
-= position
- startPos
;
4318 if (position
> selStart
) {
4319 positionAfterDeletion
-= selEnd
- selStart
;
4324 position
= positionAfterDeletion
;
4327 PasteRectangular(position
, value
, istrlen(value
));
4328 pdoc
->EndUndoAction();
4329 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
4330 SetSelection(position
, position
);
4332 position
= MovePositionOutsideChar(position
, currentPos
- position
);
4333 if (pdoc
->InsertString(position
, value
)) {
4334 SetSelection(position
+ istrlen(value
), position
);
4336 pdoc
->EndUndoAction();
4338 } else if (inDragDrop
) {
4339 SetSelection(position
, position
);
4343 static int BeforeInOrAfter(int val
, int minim
, int maxim
) {
4346 else if (val
> maxim
)
4352 int Editor::PositionInSelection(int pos
) {
4353 pos
= MovePositionOutsideChar(pos
, currentPos
- pos
);
4354 if (selType
== selRectangle
) {
4355 if (pos
< SelectionStart())
4357 if (pos
> SelectionEnd())
4359 int linePos
= pdoc
->LineFromPosition(pos
);
4360 return BeforeInOrAfter(pos
, SelectionStart(linePos
), SelectionEnd(linePos
));
4362 if (currentPos
> anchor
) {
4363 return BeforeInOrAfter(pos
, anchor
, currentPos
);
4364 } else if (currentPos
< anchor
) {
4365 return BeforeInOrAfter(pos
, currentPos
, anchor
);
4371 bool Editor::PointInSelection(Point pt
) {
4372 // TODO: fix up for rectangular selection
4373 int pos
= PositionFromLocation(pt
);
4374 if (0 == PositionInSelection(pos
)) {
4375 if (pos
== SelectionStart()) {
4376 // see if just before selection
4377 Point locStart
= LocationFromPosition(pos
);
4378 if (pt
.x
< locStart
.x
)
4381 if (pos
== SelectionEnd()) {
4382 // see if just after selection
4383 Point locEnd
= LocationFromPosition(pos
);
4384 if (pt
.x
> locEnd
.x
)
4392 bool Editor::PointInSelMargin(Point pt
) {
4393 // Really means: "Point in a margin"
4394 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4395 PRectangle rcSelMargin
= GetClientRectangle();
4396 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
4397 return rcSelMargin
.Contains(pt
);
4403 void Editor::LineSelection(int lineCurrent_
, int lineAnchor_
) {
4404 if (lineAnchor_
< lineCurrent_
) {
4405 SetSelection(pdoc
->LineStart(lineCurrent_
+ 1),
4406 pdoc
->LineStart(lineAnchor_
));
4407 } else if (lineAnchor_
> lineCurrent_
) {
4408 SetSelection(pdoc
->LineStart(lineCurrent_
),
4409 pdoc
->LineStart(lineAnchor_
+ 1));
4410 } else { // Same line, select it
4411 SetSelection(pdoc
->LineStart(lineAnchor_
+ 1),
4412 pdoc
->LineStart(lineAnchor_
));
4416 void Editor::DwellEnd(bool mouseMoved
) {
4418 ticksToDwell
= dwellDelay
;
4420 ticksToDwell
= SC_TIME_FOREVER
;
4421 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4423 NotifyDwelling(ptMouseLast
, dwelling
);
4427 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
4428 //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
4430 int newPos
= PositionFromLocation(pt
);
4431 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
4434 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
4438 bool inSelMargin
= PointInSelMargin(pt
);
4439 if (shift
& !inSelMargin
) {
4440 SetSelection(newPos
);
4442 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
4443 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
4444 SetMouseCapture(true);
4445 SetEmptySelection(newPos
);
4446 bool doubleClick
= false;
4447 // Stop mouse button bounce changing selection type
4448 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
4449 if (selectionType
== selChar
) {
4450 selectionType
= selWord
;
4452 } else if (selectionType
== selWord
) {
4453 selectionType
= selLine
;
4455 selectionType
= selChar
;
4456 originalAnchorPos
= currentPos
;
4460 if (selectionType
== selWord
) {
4461 if (currentPos
>= originalAnchorPos
) { // Moved forward
4462 SetSelection(pdoc
->ExtendWordSelect(currentPos
, 1),
4463 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
4464 } else { // Moved backward
4465 SetSelection(pdoc
->ExtendWordSelect(currentPos
, -1),
4466 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
4468 } else if (selectionType
== selLine
) {
4469 lineAnchor
= LineFromLocation(pt
);
4470 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
4471 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
4473 SetEmptySelection(currentPos
);
4475 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
4477 NotifyDoubleClick(pt
, shift
);
4478 if (PositionIsHotspot(newPos
))
4479 NotifyHotSpotDoubleClicked(newPos
, shift
, ctrl
, alt
);
4481 } else { // Single click
4483 selType
= selStream
;
4486 lastClickTime
= curTime
;
4490 lineAnchor
= LineFromLocation(pt
);
4491 // Single click in margin: select whole line
4492 LineSelection(lineAnchor
, lineAnchor
);
4493 SetSelection(pdoc
->LineStart(lineAnchor
+ 1),
4494 pdoc
->LineStart(lineAnchor
));
4496 // Single shift+click in margin: select from line anchor to clicked line
4497 if (anchor
> currentPos
)
4498 lineAnchor
= pdoc
->LineFromPosition(anchor
- 1);
4500 lineAnchor
= pdoc
->LineFromPosition(anchor
);
4501 int lineStart
= LineFromLocation(pt
);
4502 LineSelection(lineStart
, lineAnchor
);
4503 //lineAnchor = lineStart; // Keep the same anchor for ButtonMove
4506 SetDragPosition(invalidPosition
);
4507 SetMouseCapture(true);
4508 selectionType
= selLine
;
4510 if (PositionIsHotspot(newPos
)) {
4511 NotifyHotSpotClicked(newPos
, shift
, ctrl
, alt
);
4514 inDragDrop
= PointInSelection(pt
);
4517 SetMouseCapture(false);
4518 SetDragPosition(newPos
);
4519 CopySelectionRange(&drag
);
4522 xStartSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4523 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4524 SetDragPosition(invalidPosition
);
4525 SetMouseCapture(true);
4527 SetEmptySelection(newPos
);
4528 selType
= alt
? selRectangle
: selStream
;
4529 selectionType
= selChar
;
4530 originalAnchorPos
= currentPos
;
4534 lastClickTime
= curTime
;
4536 ShowCaretAtCurrentPosition();
4539 bool Editor::PositionIsHotspot(int position
) {
4540 return vs
.styles
[pdoc
->StyleAt(position
)].hotspot
;
4543 bool Editor::PointIsHotspot(Point pt
) {
4544 int pos
= PositionFromLocation(pt
);
4545 return PositionIsHotspot(pos
);
4548 void Editor::SetHotSpotRange(Point
*pt
) {
4550 int pos
= PositionFromLocation(*pt
);
4552 // If we don't limit this to word characters then the
4553 // range can encompass more than the run range and then
4554 // the underline will not be drawn properly.
4555 int hsStart_
= pdoc
->ExtendStyleRange(pos
, -1);
4556 int hsEnd_
= pdoc
->ExtendStyleRange(pos
, 1);
4558 // Only invalidate the range if the hotspot range has changed...
4559 if (hsStart_
!= hsStart
|| hsEnd_
!= hsEnd
) {
4560 if (hsStart
!= -1) {
4561 InvalidateRange(hsStart
, hsEnd
);
4565 InvalidateRange(hsStart
, hsEnd
);
4568 if (hsStart
!= -1) {
4569 int hsStart_
= hsStart
;
4573 InvalidateRange(hsStart_
, hsEnd_
);
4581 void Editor::GetHotSpotRange(int& hsStart_
, int& hsEnd_
) {
4586 void Editor::ButtonMove(Point pt
) {
4587 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
4591 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
4592 if (HaveMouseCapture()) {
4594 // Slow down autoscrolling/selection
4595 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
4596 if (autoScrollTimer
.ticksToWait
> 0)
4598 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
4601 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4602 int movePos
= PositionFromLocation(pt
);
4603 movePos
= MovePositionOutsideChar(movePos
, currentPos
- movePos
);
4605 SetDragPosition(movePos
);
4607 if (selectionType
== selChar
) {
4608 SetSelection(movePos
);
4609 } else if (selectionType
== selWord
) {
4610 // Continue selecting by word
4611 if (movePos
>= originalAnchorPos
) { // Moved forward
4612 SetSelection(pdoc
->ExtendWordSelect(movePos
, 1),
4613 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
4614 } else { // Moved backward
4615 SetSelection(pdoc
->ExtendWordSelect(movePos
, -1),
4616 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
4619 // Continue selecting by line
4620 int lineMove
= LineFromLocation(pt
);
4621 LineSelection(lineMove
, lineAnchor
);
4626 PRectangle rcClient
= GetClientRectangle();
4627 if (pt
.y
> rcClient
.bottom
) {
4628 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
4630 lineMove
= cs
.DisplayFromDoc(pdoc
->LinesTotal() - 1);
4632 ScrollTo(lineMove
- LinesOnScreen() + 5);
4634 } else if (pt
.y
< rcClient
.top
) {
4635 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
4636 ScrollTo(lineMove
- 5);
4639 EnsureCaretVisible(false, false, true);
4641 if (hsStart
!= -1 && !PositionIsHotspot(movePos
))
4642 SetHotSpotRange(NULL
);
4645 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4646 if (PointInSelMargin(pt
)) {
4647 DisplayCursor(Window::cursorReverseArrow
);
4648 return; // No need to test for selection
4651 // Display regular (drag) cursor over selection
4652 if (PointInSelection(pt
)) {
4653 DisplayCursor(Window::cursorArrow
);
4654 } else if (PointIsHotspot(pt
)) {
4655 DisplayCursor(Window::cursorHand
);
4656 SetHotSpotRange(&pt
);
4658 DisplayCursor(Window::cursorText
);
4659 SetHotSpotRange(NULL
);
4665 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
4666 //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
4667 if (HaveMouseCapture()) {
4668 if (PointInSelMargin(pt
)) {
4669 DisplayCursor(Window::cursorReverseArrow
);
4671 DisplayCursor(Window::cursorText
);
4672 SetHotSpotRange(NULL
);
4674 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4676 SetMouseCapture(false);
4677 int newPos
= PositionFromLocation(pt
);
4678 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
4680 int selStart
= SelectionStart();
4681 int selEnd
= SelectionEnd();
4682 if (selStart
< selEnd
) {
4685 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
4686 SetSelection(newPos
, newPos
+ drag
.len
);
4688 } else if (newPos
< selStart
) {
4689 pdoc
->DeleteChars(selStart
, drag
.len
);
4690 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
4691 SetSelection(newPos
, newPos
+ drag
.len
);
4693 } else if (newPos
> selEnd
) {
4694 pdoc
->DeleteChars(selStart
, drag
.len
);
4696 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
4697 SetSelection(newPos
, newPos
+ drag
.len
);
4700 SetEmptySelection(newPos
);
4704 selectionType
= selChar
;
4707 if (selectionType
== selChar
) {
4708 SetSelection(newPos
);
4711 lastClickTime
= curTime
;
4714 if (selType
== selStream
) {
4718 EnsureCaretVisible(false);
4722 // Called frequently to perform background UI including
4723 // caret blinking and automatic scrolling.
4724 void Editor::Tick() {
4725 if (HaveMouseCapture()) {
4727 ButtonMove(ptMouseLast
);
4729 if (caret
.period
> 0) {
4730 timer
.ticksToWait
-= timer
.tickSize
;
4731 if (timer
.ticksToWait
<= 0) {
4732 caret
.on
= !caret
.on
;
4733 timer
.ticksToWait
= caret
.period
;
4737 if ((dwellDelay
< SC_TIME_FOREVER
) &&
4738 (ticksToDwell
> 0) &&
4739 (!HaveMouseCapture())) {
4740 ticksToDwell
-= timer
.tickSize
;
4741 if (ticksToDwell
<= 0) {
4743 NotifyDwelling(ptMouseLast
, dwelling
);
4748 void Editor::SetFocusState(bool focusState
) {
4749 hasFocus
= focusState
;
4750 NotifyFocus(hasFocus
);
4752 ShowCaretAtCurrentPosition();
4759 static bool IsIn(int a
, int minimum
, int maximum
) {
4760 return (a
>= minimum
) && (a
<= maximum
);
4763 static bool IsOverlap(int mina
, int maxa
, int minb
, int maxb
) {
4765 IsIn(mina
, minb
, maxb
) ||
4766 IsIn(maxa
, minb
, maxb
) ||
4767 IsIn(minb
, mina
, maxa
) ||
4768 IsIn(maxb
, mina
, maxa
);
4771 void Editor::CheckForChangeOutsidePaint(Range r
) {
4772 if (paintState
== painting
&& !paintingAllText
) {
4773 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
4777 PRectangle rcText
= GetTextRectangle();
4778 // Determine number of lines displayed including a possible partially displayed last line
4779 int linesDisplayed
= (rcText
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1;
4780 int bottomLine
= topLine
+ linesDisplayed
- 1;
4782 int lineRangeStart
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.start
));
4783 int lineRangeEnd
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.end
));
4784 if (!IsOverlap(topLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
4785 //Platform::DebugPrintf("No overlap (%d-%d) with window(%d-%d)\n",
4786 // lineRangeStart, lineRangeEnd, topLine, bottomLine);
4790 // Assert rcPaint contained within or equal to rcText
4791 if (rcPaint
.top
> rcText
.top
) {
4792 // does range intersect rcText.top .. rcPaint.top
4793 int paintTopLine
= ((rcPaint
.top
- rcText
.top
- 1) / vs
.lineHeight
) + topLine
;
4794 // paintTopLine is the top line of the paint rectangle or the line just above if that line is completely inside the paint rectangle
4795 if (IsOverlap(topLine
, paintTopLine
, lineRangeStart
, lineRangeEnd
)) {
4796 //Platform::DebugPrintf("Change (%d-%d) in top npv(%d-%d)\n",
4797 // lineRangeStart, lineRangeEnd, topLine, paintTopLine);
4802 if (rcPaint
.bottom
< rcText
.bottom
) {
4803 // does range intersect rcPaint.bottom .. rcText.bottom
4804 int paintBottomLine
= ((rcPaint
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1) + topLine
;
4805 // paintTopLine is the bottom line of the paint rectangle or the line just below if that line is completely inside the paint rectangle
4806 if (IsOverlap(paintBottomLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
4807 //Platform::DebugPrintf("Change (%d-%d) in bottom npv(%d-%d)\n",
4808 // lineRangeStart, lineRangeEnd, paintBottomLine, bottomLine);
4816 char BraceOpposite(char ch
) {
4839 // TODO: should be able to extend styled region to find matching brace
4840 // TODO: may need to make DBCS safe
4841 // so should be moved into Document
4842 int Editor::BraceMatch(int position
, int /*maxReStyle*/) {
4843 char chBrace
= pdoc
->CharAt(position
);
4844 char chSeek
= BraceOpposite(chBrace
);
4847 char styBrace
= static_cast<char>(
4848 pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
4850 if (chBrace
== '(' || chBrace
== '[' || chBrace
== '{' || chBrace
== '<')
4853 position
= position
+ direction
;
4854 while ((position
>= 0) && (position
< pdoc
->Length())) {
4855 char chAtPos
= pdoc
->CharAt(position
);
4856 char styAtPos
= static_cast<char>(pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
4857 if ((position
> pdoc
->GetEndStyled()) || (styAtPos
== styBrace
)) {
4858 if (chAtPos
== chBrace
)
4860 if (chAtPos
== chSeek
)
4865 position
= position
+ direction
;
4870 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
4871 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
4872 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
4873 CheckForChangeOutsidePaint(Range(braces
[0]));
4874 CheckForChangeOutsidePaint(Range(pos0
));
4877 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
4878 CheckForChangeOutsidePaint(Range(braces
[1]));
4879 CheckForChangeOutsidePaint(Range(pos1
));
4882 bracesMatchStyle
= matchStyle
;
4883 if (paintState
== notPainting
) {
4889 void Editor::SetDocPointer(Document
*document
) {
4890 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
4891 pdoc
->RemoveWatcher(this, 0);
4893 if (document
== NULL
) {
4894 pdoc
= new Document();
4900 // Ensure all positions within document
4906 // Reset the contraction state to fully shown.
4908 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
4912 pdoc
->AddWatcher(this, 0);
4917 // Recursively expand a fold, making lines visible except where they have an unexpanded parent
4918 void Editor::Expand(int &line
, bool doExpand
) {
4919 int lineMaxSubord
= pdoc
->GetLastChild(line
);
4921 while (line
<= lineMaxSubord
) {
4923 cs
.SetVisible(line
, line
, true);
4924 int level
= pdoc
->GetLevel(line
);
4925 if (level
& SC_FOLDLEVELHEADERFLAG
) {
4926 if (doExpand
&& cs
.GetExpanded(line
)) {
4929 Expand(line
, false);
4937 void Editor::ToggleContraction(int line
) {
4938 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
4939 if (cs
.GetExpanded(line
)) {
4940 int lineMaxSubord
= pdoc
->GetLastChild(line
);
4941 cs
.SetExpanded(line
, 0);
4942 if (lineMaxSubord
> line
) {
4943 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
4948 cs
.SetExpanded(line
, 1);
4956 // Recurse up from this line to find any folds that prevent this line from being visible
4957 // and unfold them all->
4958 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
4960 // In case in need of wrapping to ensure DisplayFromDoc works.
4963 if (!cs
.GetVisible(lineDoc
)) {
4964 int lineParent
= pdoc
->GetFoldParent(lineDoc
);
4965 if (lineParent
>= 0) {
4966 if (lineDoc
!= lineParent
)
4967 EnsureLineVisible(lineParent
, enforcePolicy
);
4968 if (!cs
.GetExpanded(lineParent
)) {
4969 cs
.SetExpanded(lineParent
, 1);
4970 Expand(lineParent
, true);
4976 if (enforcePolicy
) {
4977 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
4978 if (visiblePolicy
& VISIBLE_SLOP
) {
4979 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
4980 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
4981 SetVerticalScrollPos();
4983 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
4984 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
4985 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
4986 SetVerticalScrollPos();
4990 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
4991 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
4992 SetVerticalScrollPos();
4999 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
5000 pdoc
->BeginUndoAction();
5002 length
= istrlen(text
);
5003 if (replacePatterns
) {
5004 text
= pdoc
->SubstituteByPosition(text
, &length
);
5008 if (targetStart
!= targetEnd
)
5009 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
5010 targetEnd
= targetStart
;
5011 pdoc
->InsertString(targetStart
, text
, length
);
5012 targetEnd
= targetStart
+ length
;
5013 pdoc
->EndUndoAction();
5017 bool Editor::IsUnicodeMode() const {
5018 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
5021 int Editor::CodePage() const {
5023 return pdoc
->dbcsCodePage
;
5028 static bool ValidMargin(unsigned long wParam
) {
5029 return wParam
< ViewStyle::margins
;
5032 static char *CharPtrFromSPtr(sptr_t lParam
) {
5033 return reinterpret_cast<char *>(lParam
);
5036 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5037 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
5039 // Optional macro recording hook
5041 NotifyMacroRecord(iMessage
, wParam
, lParam
);
5050 char *ptr
= CharPtrFromSPtr(lParam
);
5051 unsigned int iChar
= 0;
5052 for (; iChar
< wParam
- 1; iChar
++)
5053 ptr
[iChar
] = pdoc
->CharAt(iChar
);
5061 pdoc
->DeleteChars(0, pdoc
->Length());
5062 SetEmptySelection(0);
5063 pdoc
->InsertString(0, CharPtrFromSPtr(lParam
));
5067 case SCI_GETTEXTLENGTH
:
5068 return pdoc
->Length();
5080 CopyRangeToClipboard(wParam
, lParam
);
5084 CopyText(wParam
, CharPtrFromSPtr(lParam
));
5090 EnsureCaretVisible();
5096 EnsureCaretVisible();
5105 return pdoc
->CanUndo() ? 1 : 0;
5107 case SCI_EMPTYUNDOBUFFER
:
5108 pdoc
->DeleteUndoHistory();
5111 case SCI_GETFIRSTVISIBLELINE
:
5114 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
5118 int lineStart
= pdoc
->LineStart(wParam
);
5119 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
5120 char *ptr
= CharPtrFromSPtr(lParam
);
5122 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
5123 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5128 case SCI_GETLINECOUNT
:
5129 if (pdoc
->LinesTotal() == 0)
5132 return pdoc
->LinesTotal();
5135 return !pdoc
->IsSavePoint();
5138 int nStart
= static_cast<int>(wParam
);
5139 int nEnd
= static_cast<int>(lParam
);
5141 nEnd
= pdoc
->Length();
5143 nStart
= nEnd
; // Remove selection
5144 selType
= selStream
;
5145 SetSelection(nEnd
, nStart
);
5146 EnsureCaretVisible();
5150 case SCI_GETSELTEXT
: {
5153 SelectionText selectedText
;
5154 CopySelectionRange(&selectedText
);
5155 char *ptr
= CharPtrFromSPtr(lParam
);
5157 if (selectedText
.len
) {
5158 for (; iChar
< selectedText
.len
; iChar
++)
5159 ptr
[iChar
] = selectedText
.s
[iChar
];
5167 case SCI_LINEFROMPOSITION
:
5168 if (static_cast<int>(wParam
) < 0)
5170 return pdoc
->LineFromPosition(wParam
);
5172 case SCI_POSITIONFROMLINE
:
5173 if (static_cast<int>(wParam
) < 0)
5174 wParam
= pdoc
->LineFromPosition(SelectionStart());
5176 return 0; // Even if there is no text, there is a first line that starts at 0
5177 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
5179 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
5181 return pdoc
->LineStart(wParam
);
5183 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
5184 case SCI_LINELENGTH
:
5185 if ((static_cast<int>(wParam
) < 0) ||
5186 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
5188 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
5190 case SCI_REPLACESEL
: {
5193 pdoc
->BeginUndoAction();
5195 char *replacement
= CharPtrFromSPtr(lParam
);
5196 pdoc
->InsertString(currentPos
, replacement
);
5197 pdoc
->EndUndoAction();
5198 SetEmptySelection(currentPos
+ istrlen(replacement
));
5199 EnsureCaretVisible();
5203 case SCI_SETTARGETSTART
:
5204 targetStart
= wParam
;
5207 case SCI_GETTARGETSTART
:
5210 case SCI_SETTARGETEND
:
5214 case SCI_GETTARGETEND
:
5217 case SCI_TARGETFROMSELECTION
:
5218 if (currentPos
< anchor
) {
5219 targetStart
= currentPos
;
5222 targetStart
= anchor
;
5223 targetEnd
= currentPos
;
5227 case SCI_REPLACETARGET
:
5228 PLATFORM_ASSERT(lParam
);
5229 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), wParam
);
5231 case SCI_REPLACETARGETRE
:
5232 PLATFORM_ASSERT(lParam
);
5233 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), wParam
);
5235 case SCI_SEARCHINTARGET
:
5236 PLATFORM_ASSERT(lParam
);
5237 return SearchInTarget(CharPtrFromSPtr(lParam
), wParam
);
5239 case SCI_SETSEARCHFLAGS
:
5240 searchFlags
= wParam
;
5243 case SCI_GETSEARCHFLAGS
:
5246 case SCI_POSITIONBEFORE
:
5247 return pdoc
->MovePositionOutsideChar(wParam
-1, -1, true);
5249 case SCI_POSITIONAFTER
:
5250 return pdoc
->MovePositionOutsideChar(wParam
+1, 1, true);
5252 case SCI_LINESCROLL
:
5253 ScrollTo(topLine
+ lParam
);
5254 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
5257 case SCI_SETXOFFSET
:
5259 SetHorizontalScrollPos();
5263 case SCI_GETXOFFSET
:
5266 case SCI_CHOOSECARETX
:
5270 case SCI_SCROLLCARET
:
5271 EnsureCaretVisible();
5274 case SCI_SETREADONLY
:
5275 pdoc
->SetReadOnly(wParam
!= 0);
5278 case SCI_GETREADONLY
:
5279 return pdoc
->IsReadOnly();
5284 case SCI_POINTXFROMPOSITION
:
5288 Point pt
= LocationFromPosition(lParam
);
5292 case SCI_POINTYFROMPOSITION
:
5296 Point pt
= LocationFromPosition(lParam
);
5301 return FindText(wParam
, lParam
);
5303 case SCI_GETTEXTRANGE
: {
5306 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
5307 int cpMax
= tr
->chrg
.cpMax
;
5309 cpMax
= pdoc
->Length();
5310 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
5311 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
5312 // Spec says copied text is terminated with a NUL
5313 tr
->lpstrText
[len
] = '\0';
5314 return len
; // Not including NUL
5317 case SCI_HIDESELECTION
:
5318 hideSelection
= wParam
!= 0;
5322 case SCI_FORMATRANGE
:
5323 return FormatRange(wParam
!= 0, reinterpret_cast<RangeToFormat
*>(lParam
));
5325 case SCI_GETMARGINLEFT
:
5326 return vs
.leftMarginWidth
;
5328 case SCI_GETMARGINRIGHT
:
5329 return vs
.rightMarginWidth
;
5331 case SCI_SETMARGINLEFT
:
5332 vs
.leftMarginWidth
= lParam
;
5333 InvalidateStyleRedraw();
5336 case SCI_SETMARGINRIGHT
:
5337 vs
.rightMarginWidth
= lParam
;
5338 InvalidateStyleRedraw();
5341 // Control specific mesages
5346 pdoc
->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam
), wParam
);
5347 SetEmptySelection(currentPos
+ wParam
);
5351 case SCI_ADDSTYLEDTEXT
: {
5354 pdoc
->InsertStyledString(CurrentPosition() * 2, CharPtrFromSPtr(lParam
), wParam
);
5355 SetEmptySelection(currentPos
+ wParam
/ 2);
5359 case SCI_INSERTTEXT
: {
5362 int insertPos
= wParam
;
5363 if (static_cast<short>(wParam
) == -1)
5364 insertPos
= CurrentPosition();
5365 int newCurrent
= CurrentPosition();
5366 char *sz
= CharPtrFromSPtr(lParam
);
5367 pdoc
->InsertString(insertPos
, sz
);
5368 if (newCurrent
> insertPos
)
5369 newCurrent
+= istrlen(sz
);
5370 SetEmptySelection(newCurrent
);
5374 case SCI_APPENDTEXT
:
5375 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), wParam
);
5382 case SCI_CLEARDOCUMENTSTYLE
:
5383 ClearDocumentStyle();
5386 case SCI_SETUNDOCOLLECTION
:
5387 pdoc
->SetUndoCollection(wParam
!= 0);
5390 case SCI_GETUNDOCOLLECTION
:
5391 return pdoc
->IsCollectingUndo();
5393 case SCI_BEGINUNDOACTION
:
5394 pdoc
->BeginUndoAction();
5397 case SCI_ENDUNDOACTION
:
5398 pdoc
->EndUndoAction();
5401 case SCI_GETCARETPERIOD
:
5402 return caret
.period
;
5404 case SCI_SETCARETPERIOD
:
5405 caret
.period
= wParam
;
5408 case SCI_SETWORDCHARS
: {
5411 pdoc
->SetWordChars(reinterpret_cast<unsigned char *>(lParam
));
5416 return pdoc
->Length();
5419 return pdoc
->CharAt(wParam
);
5421 case SCI_SETCURRENTPOS
:
5422 SetSelection(wParam
, anchor
);
5425 case SCI_GETCURRENTPOS
:
5429 SetSelection(currentPos
, wParam
);
5435 case SCI_SETSELECTIONSTART
:
5436 SetSelection(Platform::Maximum(currentPos
, wParam
), wParam
);
5439 case SCI_GETSELECTIONSTART
:
5440 return Platform::Minimum(anchor
, currentPos
);
5442 case SCI_SETSELECTIONEND
:
5443 SetSelection(wParam
, Platform::Minimum(anchor
, wParam
));
5446 case SCI_GETSELECTIONEND
:
5447 return Platform::Maximum(anchor
, currentPos
);
5449 case SCI_SETPRINTMAGNIFICATION
:
5450 printMagnification
= wParam
;
5453 case SCI_GETPRINTMAGNIFICATION
:
5454 return printMagnification
;
5456 case SCI_SETPRINTCOLOURMODE
:
5457 printColourMode
= wParam
;
5460 case SCI_GETPRINTCOLOURMODE
:
5461 return printColourMode
;
5463 case SCI_SETPRINTWRAPMODE
:
5464 printWrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
5467 case SCI_GETPRINTWRAPMODE
:
5468 return printWrapState
;
5470 case SCI_GETSTYLEAT
:
5471 if (static_cast<short>(wParam
) >= pdoc
->Length())
5474 return pdoc
->StyleAt(wParam
);
5484 case SCI_SETSAVEPOINT
:
5485 pdoc
->SetSavePoint();
5488 case SCI_GETSTYLEDTEXT
: {
5491 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
5493 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
5494 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
5495 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
5497 tr
->lpstrText
[iPlace
] = '\0';
5498 tr
->lpstrText
[iPlace
+ 1] = '\0';
5503 return pdoc
->CanRedo() ? 1 : 0;
5505 case SCI_MARKERLINEFROMHANDLE
:
5506 return pdoc
->LineFromHandle(wParam
);
5508 case SCI_MARKERDELETEHANDLE
:
5509 pdoc
->DeleteMarkFromHandle(wParam
);
5513 return vs
.viewWhitespace
;
5516 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
5520 case SCI_POSITIONFROMPOINT
:
5521 return PositionFromLocation(Point(wParam
, lParam
));
5523 case SCI_POSITIONFROMPOINTCLOSE
:
5524 return PositionFromLocationClose(Point(wParam
, lParam
));
5531 SetEmptySelection(wParam
);
5532 EnsureCaretVisible();
5536 case SCI_GETCURLINE
: {
5540 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
5541 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
5542 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
5543 char *ptr
= CharPtrFromSPtr(lParam
);
5544 unsigned int iPlace
= 0;
5545 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
5546 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5549 return currentPos
- lineStart
;
5552 case SCI_GETENDSTYLED
:
5553 return pdoc
->GetEndStyled();
5555 case SCI_GETEOLMODE
:
5556 return pdoc
->eolMode
;
5558 case SCI_SETEOLMODE
:
5559 pdoc
->eolMode
= wParam
;
5562 case SCI_STARTSTYLING
:
5563 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
5566 case SCI_SETSTYLING
:
5567 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
5570 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
5573 pdoc
->SetStyles(wParam
, CharPtrFromSPtr(lParam
));
5576 case SCI_SETBUFFEREDDRAW
:
5577 bufferedDraw
= wParam
!= 0;
5580 case SCI_GETBUFFEREDDRAW
:
5581 return bufferedDraw
;
5583 case SCI_GETTWOPHASEDRAW
:
5584 return twoPhaseDraw
;
5586 case SCI_SETTWOPHASEDRAW
:
5587 twoPhaseDraw
= wParam
!= 0;
5588 InvalidateStyleRedraw();
5591 case SCI_SETTABWIDTH
:
5593 pdoc
->tabInChars
= wParam
;
5594 InvalidateStyleRedraw();
5597 case SCI_GETTABWIDTH
:
5598 return pdoc
->tabInChars
;
5601 pdoc
->indentInChars
= wParam
;
5602 InvalidateStyleRedraw();
5606 return pdoc
->indentInChars
;
5608 case SCI_SETUSETABS
:
5609 pdoc
->useTabs
= wParam
!= 0;
5610 InvalidateStyleRedraw();
5613 case SCI_GETUSETABS
:
5614 return pdoc
->useTabs
;
5616 case SCI_SETLINEINDENTATION
:
5617 pdoc
->SetLineIndentation(wParam
, lParam
);
5620 case SCI_GETLINEINDENTATION
:
5621 return pdoc
->GetLineIndentation(wParam
);
5623 case SCI_GETLINEINDENTPOSITION
:
5624 return pdoc
->GetLineIndentPosition(wParam
);
5626 case SCI_SETTABINDENTS
:
5627 pdoc
->tabIndents
= wParam
!= 0;
5630 case SCI_GETTABINDENTS
:
5631 return pdoc
->tabIndents
;
5633 case SCI_SETBACKSPACEUNINDENTS
:
5634 pdoc
->backspaceUnindents
= wParam
!= 0;
5637 case SCI_GETBACKSPACEUNINDENTS
:
5638 return pdoc
->backspaceUnindents
;
5640 case SCI_SETMOUSEDWELLTIME
:
5641 dwellDelay
= wParam
;
5642 ticksToDwell
= dwellDelay
;
5645 case SCI_GETMOUSEDWELLTIME
:
5648 case SCI_WORDSTARTPOSITION
:
5649 return pdoc
->ExtendWordSelect(wParam
, -1, lParam
!= 0);
5651 case SCI_WORDENDPOSITION
:
5652 return pdoc
->ExtendWordSelect(wParam
, 1, lParam
!= 0);
5654 case SCI_SETWRAPMODE
:
5655 wrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
5657 InvalidateStyleRedraw();
5658 ReconfigureScrollBars();
5661 case SCI_GETWRAPMODE
:
5664 case SCI_SETLAYOUTCACHE
:
5665 llc
.SetLevel(wParam
);
5668 case SCI_GETLAYOUTCACHE
:
5669 return llc
.GetLevel();
5671 case SCI_SETSCROLLWIDTH
:
5672 PLATFORM_ASSERT(wParam
> 0);
5673 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
5674 scrollWidth
= wParam
;
5679 case SCI_GETSCROLLWIDTH
:
5686 case SCI_LINESSPLIT
:
5691 PLATFORM_ASSERT(wParam
<= STYLE_MAX
);
5692 PLATFORM_ASSERT(lParam
);
5693 return TextWidth(wParam
, CharPtrFromSPtr(lParam
));
5695 case SCI_TEXTHEIGHT
:
5696 return vs
.lineHeight
;
5698 case SCI_SETENDATLASTLINE
:
5699 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
5700 if (endAtLastLine
!= (wParam
!= 0)) {
5701 endAtLastLine
= wParam
!= 0;
5706 case SCI_GETENDATLASTLINE
:
5707 return endAtLastLine
;
5710 return pdoc
->GetColumn(wParam
);
5712 case SCI_SETHSCROLLBAR
:
5713 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
5714 horizontalScrollBarVisible
= wParam
!= 0;
5716 ReconfigureScrollBars();
5720 case SCI_GETHSCROLLBAR
:
5721 return horizontalScrollBarVisible
;
5723 case SCI_SETVSCROLLBAR
:
5724 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
5725 verticalScrollBarVisible
= wParam
!= 0;
5727 ReconfigureScrollBars();
5731 case SCI_GETVSCROLLBAR
:
5732 return verticalScrollBarVisible
;
5734 case SCI_SETINDENTATIONGUIDES
:
5735 vs
.viewIndentationGuides
= wParam
!= 0;
5739 case SCI_GETINDENTATIONGUIDES
:
5740 return vs
.viewIndentationGuides
;
5742 case SCI_SETHIGHLIGHTGUIDE
:
5743 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
5744 highlightGuideColumn
= wParam
;
5749 case SCI_GETHIGHLIGHTGUIDE
:
5750 return highlightGuideColumn
;
5752 case SCI_GETLINEENDPOSITION
:
5753 return pdoc
->LineEnd(wParam
);
5755 case SCI_SETCODEPAGE
:
5756 pdoc
->dbcsCodePage
= wParam
;
5757 InvalidateStyleRedraw();
5760 case SCI_GETCODEPAGE
:
5761 return pdoc
->dbcsCodePage
;
5763 case SCI_SETUSEPALETTE
:
5764 palette
.allowRealization
= wParam
!= 0;
5765 InvalidateStyleRedraw();
5768 case SCI_GETUSEPALETTE
:
5769 return palette
.allowRealization
;
5771 // Marker definition and setting
5772 case SCI_MARKERDEFINE
:
5773 if (wParam
<= MARKER_MAX
)
5774 vs
.markers
[wParam
].markType
= lParam
;
5775 InvalidateStyleData();
5778 case SCI_MARKERSETFORE
:
5779 if (wParam
<= MARKER_MAX
)
5780 vs
.markers
[wParam
].fore
.desired
= ColourDesired(lParam
);
5781 InvalidateStyleData();
5784 case SCI_MARKERSETBACK
:
5785 if (wParam
<= MARKER_MAX
)
5786 vs
.markers
[wParam
].back
.desired
= ColourDesired(lParam
);
5787 InvalidateStyleData();
5790 case SCI_MARKERADD
: {
5791 int markerID
= pdoc
->AddMark(wParam
, lParam
);
5795 case SCI_MARKERDELETE
:
5796 pdoc
->DeleteMark(wParam
, lParam
);
5799 case SCI_MARKERDELETEALL
:
5800 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
5804 return pdoc
->GetMark(wParam
);
5806 case SCI_MARKERNEXT
: {
5807 int lt
= pdoc
->LinesTotal();
5808 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
5809 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
5815 case SCI_MARKERPREVIOUS
: {
5816 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
5817 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
5823 case SCI_MARKERDEFINEPIXMAP
:
5824 if (wParam
<= MARKER_MAX
) {
5825 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
5827 InvalidateStyleData();
5831 case SCI_SETMARGINTYPEN
:
5832 if (ValidMargin(wParam
)) {
5833 vs
.ms
[wParam
].symbol
= (lParam
== SC_MARGIN_SYMBOL
);
5834 InvalidateStyleRedraw();
5838 case SCI_GETMARGINTYPEN
:
5839 if (ValidMargin(wParam
))
5840 return vs
.ms
[wParam
].symbol
? SC_MARGIN_SYMBOL
: SC_MARGIN_NUMBER
;
5844 case SCI_SETMARGINWIDTHN
:
5845 if (ValidMargin(wParam
)) {
5846 vs
.ms
[wParam
].width
= lParam
;
5847 InvalidateStyleRedraw();
5851 case SCI_GETMARGINWIDTHN
:
5852 if (ValidMargin(wParam
))
5853 return vs
.ms
[wParam
].width
;
5857 case SCI_SETMARGINMASKN
:
5858 if (ValidMargin(wParam
)) {
5859 vs
.ms
[wParam
].mask
= lParam
;
5860 InvalidateStyleRedraw();
5864 case SCI_GETMARGINMASKN
:
5865 if (ValidMargin(wParam
))
5866 return vs
.ms
[wParam
].mask
;
5870 case SCI_SETMARGINSENSITIVEN
:
5871 if (ValidMargin(wParam
)) {
5872 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
5873 InvalidateStyleRedraw();
5877 case SCI_GETMARGINSENSITIVEN
:
5878 if (ValidMargin(wParam
))
5879 return vs
.ms
[wParam
].sensitive
? 1 : 0;
5883 case SCI_STYLECLEARALL
:
5885 InvalidateStyleRedraw();
5888 case SCI_STYLESETFORE
:
5889 if (wParam
<= STYLE_MAX
) {
5890 vs
.styles
[wParam
].fore
.desired
= ColourDesired(lParam
);
5891 InvalidateStyleRedraw();
5894 case SCI_STYLESETBACK
:
5895 if (wParam
<= STYLE_MAX
) {
5896 vs
.styles
[wParam
].back
.desired
= ColourDesired(lParam
);
5897 InvalidateStyleRedraw();
5900 case SCI_STYLESETBOLD
:
5901 if (wParam
<= STYLE_MAX
) {
5902 vs
.styles
[wParam
].bold
= lParam
!= 0;
5903 InvalidateStyleRedraw();
5906 case SCI_STYLESETITALIC
:
5907 if (wParam
<= STYLE_MAX
) {
5908 vs
.styles
[wParam
].italic
= lParam
!= 0;
5909 InvalidateStyleRedraw();
5912 case SCI_STYLESETEOLFILLED
:
5913 if (wParam
<= STYLE_MAX
) {
5914 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
5915 InvalidateStyleRedraw();
5918 case SCI_STYLESETSIZE
:
5919 if (wParam
<= STYLE_MAX
) {
5920 vs
.styles
[wParam
].size
= lParam
;
5921 InvalidateStyleRedraw();
5924 case SCI_STYLESETFONT
:
5927 if (wParam
<= STYLE_MAX
) {
5928 vs
.SetStyleFontName(wParam
, CharPtrFromSPtr(lParam
));
5929 InvalidateStyleRedraw();
5932 case SCI_STYLESETUNDERLINE
:
5933 if (wParam
<= STYLE_MAX
) {
5934 vs
.styles
[wParam
].underline
= lParam
!= 0;
5935 InvalidateStyleRedraw();
5938 case SCI_STYLESETCASE
:
5939 if (wParam
<= STYLE_MAX
) {
5940 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
5941 InvalidateStyleRedraw();
5944 case SCI_STYLESETCHARACTERSET
:
5945 if (wParam
<= STYLE_MAX
) {
5946 vs
.styles
[wParam
].characterSet
= lParam
;
5947 InvalidateStyleRedraw();
5950 case SCI_STYLESETVISIBLE
:
5951 if (wParam
<= STYLE_MAX
) {
5952 vs
.styles
[wParam
].visible
= lParam
!= 0;
5953 InvalidateStyleRedraw();
5956 case SCI_STYLESETCHANGEABLE
:
5957 if (wParam
<= STYLE_MAX
) {
5958 vs
.styles
[wParam
].changeable
= lParam
!= 0;
5959 InvalidateStyleRedraw();
5962 case SCI_STYLESETHOTSPOT
:
5963 if (wParam
<= STYLE_MAX
) {
5964 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
5965 InvalidateStyleRedraw();
5969 case SCI_STYLERESETDEFAULT
:
5970 vs
.ResetDefaultStyle();
5971 InvalidateStyleRedraw();
5973 case SCI_SETSTYLEBITS
:
5974 pdoc
->SetStylingBits(wParam
);
5977 case SCI_GETSTYLEBITS
:
5978 return pdoc
->stylingBits
;
5980 case SCI_SETLINESTATE
:
5981 return pdoc
->SetLineState(wParam
, lParam
);
5983 case SCI_GETLINESTATE
:
5984 return pdoc
->GetLineState(wParam
);
5986 case SCI_GETMAXLINESTATE
:
5987 return pdoc
->GetMaxLineState();
5989 case SCI_GETCARETLINEVISIBLE
:
5990 return vs
.showCaretLineBackground
;
5991 case SCI_SETCARETLINEVISIBLE
:
5992 vs
.showCaretLineBackground
= wParam
!= 0;
5993 InvalidateStyleRedraw();
5995 case SCI_GETCARETLINEBACK
:
5996 return vs
.caretLineBackground
.desired
.AsLong();
5997 case SCI_SETCARETLINEBACK
:
5998 vs
.caretLineBackground
.desired
= wParam
;
5999 InvalidateStyleRedraw();
6004 case SCI_VISIBLEFROMDOCLINE
:
6005 return cs
.DisplayFromDoc(wParam
);
6007 case SCI_DOCLINEFROMVISIBLE
:
6008 return cs
.DocFromDisplay(wParam
);
6010 case SCI_SETFOLDLEVEL
: {
6011 int prev
= pdoc
->SetLevel(wParam
, lParam
);
6017 case SCI_GETFOLDLEVEL
:
6018 return pdoc
->GetLevel(wParam
);
6020 case SCI_GETLASTCHILD
:
6021 return pdoc
->GetLastChild(wParam
, lParam
);
6023 case SCI_GETFOLDPARENT
:
6024 return pdoc
->GetFoldParent(wParam
);
6027 cs
.SetVisible(wParam
, lParam
, true);
6033 cs
.SetVisible(wParam
, lParam
, false);
6038 case SCI_GETLINEVISIBLE
:
6039 return cs
.GetVisible(wParam
);
6041 case SCI_SETFOLDEXPANDED
:
6042 if (cs
.SetExpanded(wParam
, lParam
!= 0)) {
6047 case SCI_GETFOLDEXPANDED
:
6048 return cs
.GetExpanded(wParam
);
6050 case SCI_SETFOLDFLAGS
:
6055 case SCI_TOGGLEFOLD
:
6056 ToggleContraction(wParam
);
6059 case SCI_ENSUREVISIBLE
:
6060 EnsureLineVisible(wParam
, false);
6063 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
6064 EnsureLineVisible(wParam
, true);
6067 case SCI_SEARCHANCHOR
:
6071 case SCI_SEARCHNEXT
:
6072 case SCI_SEARCHPREV
:
6073 return SearchText(iMessage
, wParam
, lParam
);
6075 #ifdef INCLUDE_DEPRECATED_FEATURES
6076 case SCI_SETCARETPOLICY
: // Deprecated
6077 caretXPolicy
= caretYPolicy
= wParam
;
6078 caretXSlop
= caretYSlop
= lParam
;
6082 case SCI_SETXCARETPOLICY
:
6083 caretXPolicy
= wParam
;
6084 caretXSlop
= lParam
;
6087 case SCI_SETYCARETPOLICY
:
6088 caretYPolicy
= wParam
;
6089 caretYSlop
= lParam
;
6092 case SCI_SETVISIBLEPOLICY
:
6093 visiblePolicy
= wParam
;
6094 visibleSlop
= lParam
;
6097 case SCI_LINESONSCREEN
:
6098 return LinesOnScreen();
6100 case SCI_SETSELFORE
:
6101 vs
.selforeset
= wParam
!= 0;
6102 vs
.selforeground
.desired
= ColourDesired(lParam
);
6103 InvalidateStyleRedraw();
6106 case SCI_SETSELBACK
:
6107 vs
.selbackset
= wParam
!= 0;
6108 vs
.selbackground
.desired
= ColourDesired(lParam
);
6109 InvalidateStyleRedraw();
6112 case SCI_SETWHITESPACEFORE
:
6113 vs
.whitespaceForegroundSet
= wParam
!= 0;
6114 vs
.whitespaceForeground
.desired
= ColourDesired(lParam
);
6115 InvalidateStyleRedraw();
6118 case SCI_SETWHITESPACEBACK
:
6119 vs
.whitespaceBackgroundSet
= wParam
!= 0;
6120 vs
.whitespaceBackground
.desired
= ColourDesired(lParam
);
6121 InvalidateStyleRedraw();
6124 case SCI_SETCARETFORE
:
6125 vs
.caretcolour
.desired
= ColourDesired(wParam
);
6126 InvalidateStyleRedraw();
6129 case SCI_GETCARETFORE
:
6130 return vs
.caretcolour
.desired
.AsLong();
6132 case SCI_SETCARETWIDTH
:
6135 else if (wParam
>= 3)
6138 vs
.caretWidth
= wParam
;
6139 InvalidateStyleRedraw();
6142 case SCI_GETCARETWIDTH
:
6143 return vs
.caretWidth
;
6145 case SCI_ASSIGNCMDKEY
:
6146 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6147 Platform::HighShortFromLong(wParam
), lParam
);
6150 case SCI_CLEARCMDKEY
:
6151 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6152 Platform::HighShortFromLong(wParam
), SCI_NULL
);
6155 case SCI_CLEARALLCMDKEYS
:
6159 case SCI_INDICSETSTYLE
:
6160 if (wParam
<= INDIC_MAX
) {
6161 vs
.indicators
[wParam
].style
= lParam
;
6162 InvalidateStyleRedraw();
6166 case SCI_INDICGETSTYLE
:
6167 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
6169 case SCI_INDICSETFORE
:
6170 if (wParam
<= INDIC_MAX
) {
6171 vs
.indicators
[wParam
].fore
.desired
= ColourDesired(lParam
);
6172 InvalidateStyleRedraw();
6176 case SCI_INDICGETFORE
:
6177 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
6180 case SCI_LINEDOWNEXTEND
:
6182 case SCI_PARADOWNEXTEND
:
6184 case SCI_LINEUPEXTEND
:
6186 case SCI_PARAUPEXTEND
:
6188 case SCI_CHARLEFTEXTEND
:
6190 case SCI_CHARRIGHTEXTEND
:
6192 case SCI_WORDLEFTEXTEND
:
6194 case SCI_WORDRIGHTEXTEND
:
6196 case SCI_HOMEEXTEND
:
6198 case SCI_LINEENDEXTEND
:
6200 case SCI_HOMEWRAPEXTEND
:
6201 case SCI_LINEENDWRAP
:
6202 case SCI_LINEENDWRAPEXTEND
:
6203 case SCI_DOCUMENTSTART
:
6204 case SCI_DOCUMENTSTARTEXTEND
:
6205 case SCI_DOCUMENTEND
:
6206 case SCI_DOCUMENTENDEXTEND
:
6208 case SCI_PAGEUPEXTEND
:
6210 case SCI_PAGEDOWNEXTEND
:
6211 case SCI_EDITTOGGLEOVERTYPE
:
6213 case SCI_DELETEBACK
:
6219 case SCI_VCHOMEEXTEND
:
6220 case SCI_VCHOMEWRAP
:
6221 case SCI_VCHOMEWRAPEXTEND
:
6224 case SCI_DELWORDLEFT
:
6225 case SCI_DELWORDRIGHT
:
6226 case SCI_DELLINELEFT
:
6227 case SCI_DELLINERIGHT
:
6230 case SCI_LINEDELETE
:
6231 case SCI_LINETRANSPOSE
:
6232 case SCI_LINEDUPLICATE
:
6235 case SCI_LINESCROLLDOWN
:
6236 case SCI_LINESCROLLUP
:
6237 case SCI_WORDPARTLEFT
:
6238 case SCI_WORDPARTLEFTEXTEND
:
6239 case SCI_WORDPARTRIGHT
:
6240 case SCI_WORDPARTRIGHTEXTEND
:
6241 case SCI_DELETEBACKNOTLINE
:
6242 case SCI_HOMEDISPLAY
:
6243 case SCI_HOMEDISPLAYEXTEND
:
6244 case SCI_LINEENDDISPLAY
:
6245 case SCI_LINEENDDISPLAYEXTEND
:
6246 return KeyCommand(iMessage
);
6248 case SCI_BRACEHIGHLIGHT
:
6249 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
6252 case SCI_BRACEBADLIGHT
:
6253 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
6256 case SCI_BRACEMATCH
:
6257 // wParam is position of char to find brace for,
6258 // lParam is maximum amount of text to restyle to find it
6259 return BraceMatch(wParam
, lParam
);
6261 case SCI_GETVIEWEOL
:
6264 case SCI_SETVIEWEOL
:
6265 vs
.viewEOL
= wParam
!= 0;
6266 InvalidateStyleRedraw();
6270 vs
.zoomLevel
= wParam
;
6271 InvalidateStyleRedraw();
6276 return vs
.zoomLevel
;
6278 case SCI_GETEDGECOLUMN
:
6281 case SCI_SETEDGECOLUMN
:
6283 InvalidateStyleRedraw();
6286 case SCI_GETEDGEMODE
:
6287 return vs
.edgeState
;
6289 case SCI_SETEDGEMODE
:
6290 vs
.edgeState
= wParam
;
6291 InvalidateStyleRedraw();
6294 case SCI_GETEDGECOLOUR
:
6295 return vs
.edgecolour
.desired
.AsLong();
6297 case SCI_SETEDGECOLOUR
:
6298 vs
.edgecolour
.desired
= ColourDesired(wParam
);
6299 InvalidateStyleRedraw();
6302 case SCI_GETDOCPOINTER
:
6303 return reinterpret_cast<sptr_t
>(pdoc
);
6305 case SCI_SETDOCPOINTER
:
6307 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
6310 case SCI_CREATEDOCUMENT
: {
6311 Document
*doc
= new Document();
6315 return reinterpret_cast<sptr_t
>(doc
);
6318 case SCI_ADDREFDOCUMENT
:
6319 (reinterpret_cast<Document
*>(lParam
))->AddRef();
6322 case SCI_RELEASEDOCUMENT
:
6323 (reinterpret_cast<Document
*>(lParam
))->Release();
6326 case SCI_SETMODEVENTMASK
:
6327 modEventMask
= wParam
;
6330 case SCI_GETMODEVENTMASK
:
6331 return modEventMask
;
6333 case SCI_CONVERTEOLS
:
6334 pdoc
->ConvertLineEnds(wParam
);
6335 SetSelection(currentPos
, anchor
); // Ensure selection inside document
6338 case SCI_SELECTIONISRECTANGLE
:
6339 return (selType
== selRectangle
) ? 1 : 0;
6341 case SCI_SETOVERTYPE
:
6342 inOverstrike
= wParam
!= 0;
6345 case SCI_GETOVERTYPE
:
6346 return inOverstrike
? 1 : 0;
6349 SetFocusState(wParam
!= 0);
6356 errorStatus
= wParam
;
6362 case SCI_SETMOUSEDOWNCAPTURES
:
6363 mouseDownCaptures
= wParam
!= 0;
6366 case SCI_GETMOUSEDOWNCAPTURES
:
6367 return mouseDownCaptures
;
6370 cursorMode
= wParam
;
6371 DisplayCursor(Window::cursorText
);
6377 case SCI_SETCONTROLCHARSYMBOL
:
6378 controlCharSymbol
= wParam
;
6381 case SCI_GETCONTROLCHARSYMBOL
:
6382 return controlCharSymbol
;
6384 case SCI_STARTRECORD
:
6385 recordingMacro
= true;
6388 case SCI_STOPRECORD
:
6389 recordingMacro
= false;
6392 case SCI_MOVECARETINSIDEVIEW
:
6393 MoveCaretInsideView();
6396 case SCI_SETFOLDMARGINCOLOUR
:
6397 vs
.foldmarginColourSet
= wParam
!= 0;
6398 vs
.foldmarginColour
.desired
= ColourDesired(lParam
);
6399 InvalidateStyleRedraw();
6402 case SCI_SETFOLDMARGINHICOLOUR
:
6403 vs
.foldmarginHighlightColourSet
= wParam
!= 0;
6404 vs
.foldmarginHighlightColour
.desired
= ColourDesired(lParam
);
6405 InvalidateStyleRedraw();
6408 case SCI_SETHOTSPOTACTIVEFORE
:
6409 vs
.hotspotForegroundSet
= wParam
!= 0;
6410 vs
.hotspotForeground
.desired
= ColourDesired(lParam
);
6411 InvalidateStyleRedraw();
6414 case SCI_SETHOTSPOTACTIVEBACK
:
6415 vs
.hotspotBackgroundSet
= wParam
!= 0;
6416 vs
.hotspotBackground
.desired
= ColourDesired(lParam
);
6417 InvalidateStyleRedraw();
6420 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
6421 vs
.hotspotUnderline
= wParam
!= 0;
6422 InvalidateStyleRedraw();
6426 return DefWndProc(iMessage
, wParam
, lParam
);
6428 //Platform::DebugPrintf("end wnd proc\n");