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
+= 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 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1432 if (vs
.fixedColumnWidth
== 0)
1435 PRectangle rcMargin
= GetClientRectangle();
1436 rcMargin
.right
= vs
.fixedColumnWidth
;
1438 if (!rc
.Intersects(rcMargin
))
1443 surface
= pixmapSelMargin
;
1445 surface
= surfWindow
;
1448 PRectangle rcSelMargin
= rcMargin
;
1449 rcSelMargin
.right
= rcMargin
.left
;
1451 for (int margin
= 0; margin
< vs
.margins
; margin
++) {
1452 if (vs
.ms
[margin
].width
> 0) {
1454 rcSelMargin
.left
= rcSelMargin
.right
;
1455 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
1457 if (vs
.ms
[margin
].symbol
) {
1458 /* alternate scheme:
1459 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
1460 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1462 // Required because of special way brush is created for selection margin
1463 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
1465 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
1466 // Required because of special way brush is created for selection margin
1467 surface
->FillRectangle(rcSelMargin
, *pixmapSelPattern
);
1469 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1471 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1474 int visibleLine
= topLine
;
1477 // Work out whether the top line is whitespace located after a
1478 // lessening of fold level which implies a 'fold tail' but which should not
1479 // be displayed until the last of a sequence of whitespace.
1480 bool needWhiteClosure
= false;
1481 int level
= pdoc
->GetLevel(cs
.DocFromDisplay(topLine
));
1482 if (level
& SC_FOLDLEVELWHITEFLAG
) {
1483 int lineBack
= cs
.DocFromDisplay(topLine
);
1484 int levelPrev
= level
;
1485 while ((lineBack
> 0) && (levelPrev
& SC_FOLDLEVELWHITEFLAG
)) {
1487 levelPrev
= pdoc
->GetLevel(lineBack
);
1489 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
1490 if ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelPrev
& SC_FOLDLEVELNUMBERMASK
))
1491 needWhiteClosure
= true;
1495 // Old code does not know about new markers needed to distinguish all cases
1496 int folderOpenMid
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID
,
1497 SC_MARKNUM_FOLDEROPEN
);
1498 int folderEnd
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND
,
1501 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
1503 PLATFORM_ASSERT(visibleLine
< cs
.LinesDisplayed());
1505 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
1506 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
1507 bool firstSubLine
= visibleLine
== cs
.DisplayFromDoc(lineDoc
);
1509 // Decide which fold indicator should be displayed
1510 level
= pdoc
->GetLevel(lineDoc
);
1511 int levelNext
= pdoc
->GetLevel(lineDoc
+ 1);
1512 int marks
= pdoc
->GetMark(lineDoc
);
1515 int levelNum
= level
& SC_FOLDLEVELNUMBERMASK
;
1516 int levelNextNum
= levelNext
& SC_FOLDLEVELNUMBERMASK
;
1517 if (level
& SC_FOLDLEVELHEADERFLAG
) {
1519 if (cs
.GetExpanded(lineDoc
)) {
1520 if (levelNum
== SC_FOLDLEVELBASE
)
1521 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
1523 marks
|= 1 << folderOpenMid
;
1525 if (levelNum
== SC_FOLDLEVELBASE
)
1526 marks
|= 1 << SC_MARKNUM_FOLDER
;
1528 marks
|= 1 << folderEnd
;
1531 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1533 needWhiteClosure
= false;
1534 } else if (level
& SC_FOLDLEVELWHITEFLAG
) {
1535 if (needWhiteClosure
) {
1536 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1537 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1538 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1539 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1540 needWhiteClosure
= false;
1542 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1543 needWhiteClosure
= false;
1545 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1546 if (levelNextNum
< levelNum
) {
1547 if (levelNextNum
> SC_FOLDLEVELBASE
) {
1548 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1550 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1553 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1556 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1557 if (levelNextNum
< levelNum
) {
1558 needWhiteClosure
= false;
1559 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1560 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1561 needWhiteClosure
= true;
1562 } else if (levelNextNum
> SC_FOLDLEVELBASE
) {
1563 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1565 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1568 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1572 marks
&= vs
.ms
[margin
].mask
;
1573 PRectangle rcMarker
= rcSelMargin
;
1574 rcMarker
.top
= yposScreen
;
1575 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
1576 if (!vs
.ms
[margin
].symbol
) {
1580 sprintf(number
, "%d", lineDoc
+ 1);
1581 if (foldFlags
& SC_FOLDFLAG_LEVELNUMBERS
) {
1582 int lev
= pdoc
->GetLevel(lineDoc
);
1583 sprintf(number
, "%c%c %03X %03X",
1584 (lev
& SC_FOLDLEVELHEADERFLAG
) ? 'H' : '_',
1585 (lev
& SC_FOLDLEVELWHITEFLAG
) ? 'W' : '_',
1586 lev
& SC_FOLDLEVELNUMBERMASK
,
1590 PRectangle rcNumber
= rcMarker
;
1592 int width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, strlen(number
));
1593 int xpos
= rcNumber
.right
- width
- 3;
1594 rcNumber
.left
= xpos
;
1595 surface
->DrawTextNoClip(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
1596 rcNumber
.top
+ vs
.maxAscent
, number
, strlen(number
),
1597 vs
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
1598 vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1602 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1604 vs
.markers
[markBit
].Draw(surface
, rcMarker
, vs
.styles
[STYLE_LINENUMBER
].font
);
1611 yposScreen
+= vs
.lineHeight
;
1616 PRectangle rcBlankMargin
= rcMargin
;
1617 rcBlankMargin
.left
= rcSelMargin
.right
;
1618 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1621 surfWindow
->Copy(rcMargin
, Point(), *pixmapSelMargin
);
1625 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
1626 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
1627 int xhead
= rcTab
.right
- 1 - ydiff
;
1628 if (xhead
<= rcTab
.left
) {
1629 ydiff
-= rcTab
.left
- xhead
- 1;
1630 xhead
= rcTab
.left
- 1;
1632 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
1633 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
1635 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1636 surface
->LineTo(rcTab
.right
- 1, ymid
);
1637 surface
->LineTo(xhead
, ymid
- ydiff
);
1638 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1639 surface
->LineTo(xhead
, ymid
+ ydiff
);
1642 static bool IsSpaceOrTab(char ch
) {
1643 return ch
== ' ' || ch
== '\t';
1646 LineLayout
*Editor::RetrieveLineLayout(int lineNumber
) {
1647 int posLineStart
= pdoc
->LineStart(lineNumber
);
1648 int posLineEnd
= pdoc
->LineStart(lineNumber
+ 1);
1649 int lineCaret
= pdoc
->LineFromPosition(currentPos
);
1650 return llc
.Retrieve(lineNumber
, lineCaret
,
1651 posLineEnd
- posLineStart
, pdoc
->GetStyleClock(),
1652 LinesOnScreen() + 1, pdoc
->LinesTotal());
1656 * Fill in the LineLayout data for the given line.
1657 * Copy the given @a line and its styles from the document into local arrays.
1658 * Also determine the x position at which each character starts.
1660 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
*ll
, int width
) {
1663 int posLineStart
= pdoc
->LineStart(line
);
1664 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1665 // If the line is very long, limit the treatment to a length that should fit in the viewport
1666 if (posLineEnd
> (posLineStart
+ ll
->maxLineLength
)) {
1667 posLineEnd
= posLineStart
+ ll
->maxLineLength
;
1669 if (ll
->validity
== LineLayout::llCheckTextAndStyle
) {
1671 for (int cid
= posLineStart
; cid
< posLineEnd
; cid
++) {
1672 char chDoc
= pdoc
->CharAt(cid
);
1673 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
1677 if (lineLength
== ll
->numCharsInLine
) {
1678 int numCharsInLine
= 0;
1679 // See if chars, styles, indicators, are all the same
1680 bool allSame
= true;
1682 int styleMask
= pdoc
->stylingBitsMask
;
1683 // Check base line layout
1684 for (int charInDoc
= posLineStart
; allSame
&& (charInDoc
< posLineEnd
); charInDoc
++) {
1685 char chDoc
= pdoc
->CharAt(charInDoc
);
1686 styleByte
= pdoc
->StyleAt(charInDoc
);
1687 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
!= '\r'))) {
1688 allSame
= allSame
&&
1689 (ll
->styles
[numCharsInLine
] == static_cast<char>(styleByte
& styleMask
));
1690 allSame
= allSame
&&
1691 (ll
->indicators
[numCharsInLine
] == static_cast<char>(styleByte
& ~styleMask
));
1692 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
1693 allSame
= allSame
&&
1694 (ll
->chars
[numCharsInLine
] == static_cast<char>(toupper(chDoc
)));
1695 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1696 allSame
= allSame
&&
1697 (ll
->chars
[numCharsInLine
] == static_cast<char>(tolower(chDoc
)));
1699 allSame
= allSame
&&
1700 (ll
->chars
[numCharsInLine
] == chDoc
);
1705 ll
->validity
= LineLayout::llPositions
;
1707 ll
->validity
= LineLayout::llInvalid
;
1710 ll
->validity
= LineLayout::llInvalid
;
1713 if (ll
->validity
== LineLayout::llInvalid
) {
1714 ll
->widthLine
= LineLayout::wrapWidthInfinite
;
1716 int numCharsInLine
= 0;
1717 if (vstyle
.edgeState
== EDGE_BACKGROUND
) {
1718 ll
->edgeColumn
= pdoc
->FindColumn(line
, theEdge
);
1719 if (ll
->edgeColumn
>= posLineStart
) {
1720 ll
->edgeColumn
-= posLineStart
;
1723 ll
->edgeColumn
= -1;
1727 int styleMask
= pdoc
->stylingBitsMask
;
1728 // Fill base line layout
1729 for (int charInDoc
= posLineStart
; charInDoc
< posLineEnd
; charInDoc
++) {
1730 char chDoc
= pdoc
->CharAt(charInDoc
);
1731 styleByte
= pdoc
->StyleAt(charInDoc
);
1732 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
1733 ll
->chars
[numCharsInLine
] = chDoc
;
1734 ll
->styles
[numCharsInLine
] = static_cast<char>(styleByte
& styleMask
);
1735 ll
->indicators
[numCharsInLine
] = static_cast<char>(styleByte
& ~styleMask
);
1736 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
1737 ll
->chars
[numCharsInLine
] = static_cast<char>(toupper(chDoc
));
1738 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1739 ll
->chars
[numCharsInLine
] = static_cast<char>(tolower(chDoc
));
1743 ll
->xHighlightGuide
= 0;
1744 // Extra element at the end of the line to hold end x position and act as
1745 ll
->chars
[numCharsInLine
] = 0; // Also triggers processing in the loops as this is a control character
1746 ll
->styles
[numCharsInLine
] = styleByte
; // For eolFilled
1747 ll
->indicators
[numCharsInLine
] = 0;
1749 // Layout the line, determining the position of each character,
1750 // with an extra element at the end for the end of the line.
1751 int startseg
= 0; // Start of the current segment, in char. number
1752 int startsegx
= 0; // Start of the current segment, in pixels
1753 ll
->positions
[0] = 0;
1754 unsigned int tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
1755 bool lastSegItalics
= false;
1756 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
1758 bool isControlNext
= IsControlCharacter(ll
->chars
[0]);
1759 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
1760 bool isControl
= isControlNext
;
1761 isControlNext
= IsControlCharacter(ll
->chars
[charInLine
+ 1]);
1762 if ((ll
->styles
[charInLine
] != ll
->styles
[charInLine
+ 1]) ||
1763 isControl
|| isControlNext
) {
1764 ll
->positions
[startseg
] = 0;
1765 if (vstyle
.styles
[ll
->styles
[charInLine
]].visible
) {
1767 if (ll
->chars
[charInLine
] == '\t') {
1768 ll
->positions
[charInLine
+ 1] = ((((startsegx
+ 2) /
1769 tabWidth
) + 1) * tabWidth
) - startsegx
;
1770 } else if (controlCharSymbol
< 32) {
1771 const char *ctrlChar
= ControlCharacterString(ll
->chars
[charInLine
]);
1772 // +3 For a blank on front and rounded edge each side:
1773 ll
->positions
[charInLine
+ 1] = surface
->WidthText(ctrlCharsFont
, ctrlChar
, strlen(ctrlChar
)) + 3;
1775 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
1776 surface
->MeasureWidths(ctrlCharsFont
, cc
, 1,
1777 ll
->positions
+ startseg
+ 1);
1779 lastSegItalics
= false;
1780 } else { // Regular character
1781 int lenSeg
= charInLine
- startseg
+ 1;
1782 if ((lenSeg
== 1) && (' ' == ll
->chars
[startseg
])) {
1783 lastSegItalics
= false;
1784 // Over half the segments are single characters and of these about half are space characters.
1785 ll
->positions
[charInLine
+ 1] = vstyle
.styles
[ll
->styles
[charInLine
]].spaceWidth
;
1787 lastSegItalics
= vstyle
.styles
[ll
->styles
[charInLine
]].italic
;
1788 surface
->MeasureWidths(vstyle
.styles
[ll
->styles
[charInLine
]].font
, ll
->chars
+ startseg
,
1789 lenSeg
, ll
->positions
+ startseg
+ 1);
1792 } else { // invisible
1793 for (int posToZero
= startseg
; posToZero
<= (charInLine
+ 1); posToZero
++) {
1794 ll
->positions
[posToZero
] = 0;
1797 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
1798 ll
->positions
[posToIncrease
] += startsegx
;
1800 startsegx
= ll
->positions
[charInLine
+ 1];
1801 startseg
= charInLine
+ 1;
1804 // Small hack to make lines that end with italics not cut off the edge of the last character
1805 if ((startseg
> 0) && lastSegItalics
) {
1806 ll
->positions
[startseg
] += 2;
1808 ll
->numCharsInLine
= numCharsInLine
;
1809 ll
->validity
= LineLayout::llPositions
;
1811 // Hard to cope when too narrow, so just assume there is space
1815 if ((ll
->validity
== LineLayout::llPositions
) || (ll
->widthLine
!= width
)) {
1816 ll
->widthLine
= width
;
1817 if (width
== LineLayout::wrapWidthInfinite
) {
1819 } else if (width
> ll
->positions
[ll
->numCharsInLine
]) {
1820 // Simple common case where line does not need wrapping.
1824 // Calculate line start positions based upon width.
1825 // For now this is simplistic - wraps on byte rather than character and
1826 // in the middle of words. Should search for spaces or style changes.
1827 int lastGoodBreak
= 0;
1828 int lastLineStart
= 0;
1829 int startOffset
= 0;
1831 while (p
< ll
->numCharsInLine
) {
1832 if ((ll
->positions
[p
+ 1] - startOffset
) >= width
) {
1833 if (lastGoodBreak
== lastLineStart
) {
1834 // Try moving to start of last character
1836 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
1839 if (lastGoodBreak
== lastLineStart
) {
1840 // Ensure at least one character on line.
1841 lastGoodBreak
= pdoc
->MovePositionOutsideChar(lastGoodBreak
+ posLineStart
+ 1, 1)
1845 lastLineStart
= lastGoodBreak
;
1847 ll
->SetLineStart(ll
->lines
, lastGoodBreak
);
1848 startOffset
= ll
->positions
[lastGoodBreak
];
1849 p
= lastGoodBreak
+ 1;
1853 if (ll
->styles
[p
] != ll
->styles
[p
- 1]) {
1855 } else if (IsSpaceOrTab(ll
->chars
[p
- 1]) && !IsSpaceOrTab(ll
->chars
[p
])) {
1863 ll
->validity
= LineLayout::llLines
;
1867 ColourAllocated
Editor::TextBackground(ViewStyle
&vsDraw
, bool overrideBackground
,
1868 ColourAllocated background
, bool inSelection
, bool inHotspot
, int styleMain
, int i
, LineLayout
*ll
) {
1870 if (vsDraw
.selbackset
) {
1871 if (primarySelection
)
1872 return vsDraw
.selbackground
.allocated
;
1874 return vsDraw
.selbackground2
.allocated
;
1877 if ((vsDraw
.edgeState
== EDGE_BACKGROUND
) &&
1878 (i
>= ll
->edgeColumn
) &&
1879 !IsEOLChar(ll
->chars
[i
]))
1880 return vsDraw
.edgecolour
.allocated
;
1882 return vsDraw
.hotspotBackground
.allocated
;
1883 if (overrideBackground
)
1886 return vsDraw
.styles
[styleMain
].back
.allocated
;
1889 void Editor::DrawIndentGuide(Surface
*surface
, int lineVisible
, int lineHeight
, int start
, PRectangle rcSegment
, bool highlight
) {
1890 Point
from(0, ((lineVisible
& 1) && (lineHeight
& 1)) ? 1 : 0);
1891 PRectangle
rcCopyArea(start
+ 1, rcSegment
.top
, start
+ 2, rcSegment
.bottom
);
1892 surface
->Copy(rcCopyArea
, from
,
1893 highlight
? *pixmapIndentGuideHighlight
: *pixmapIndentGuide
);
1896 void Editor::DrawEOL(Surface
*surface
, ViewStyle
&vsDraw
, PRectangle rcLine
, LineLayout
*ll
,
1897 int line
, int lineEnd
, int xStart
, int subLine
, int subLineStart
,
1898 bool overrideBackground
, ColourAllocated background
) {
1900 int styleMask
= pdoc
->stylingBitsMask
;
1901 PRectangle rcSegment
= rcLine
;
1903 // Fill in a PRectangle representing the end of line characters
1904 int xEol
= ll
->positions
[lineEnd
] - subLineStart
;
1905 rcSegment
.left
= xEol
+ xStart
;
1906 rcSegment
.right
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
1907 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1908 bool eolInSelection
= (subLine
== (ll
->lines
- 1)) &&
1909 (posLineEnd
> ll
->selStart
) && (posLineEnd
<= ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
1910 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1)) {
1911 if (primarySelection
)
1912 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground
.allocated
);
1914 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground2
.allocated
);
1915 } else if (overrideBackground
) {
1916 surface
->FillRectangle(rcSegment
, background
);
1918 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
1921 rcSegment
.left
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
1922 rcSegment
.right
= rcLine
.right
;
1923 if (overrideBackground
) {
1924 surface
->FillRectangle(rcSegment
, background
);
1925 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
1926 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
1928 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
1932 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int lineVisible
, int xStart
,
1933 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
1935 PRectangle rcSegment
= rcLine
;
1937 // Using one font for all control characters so it can be controlled independently to ensure
1938 // the box goes around the characters tightly. Seems to be no way to work out what height
1939 // is taken by an individual character - internal leading gives varying results.
1940 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
1942 // See if something overrides the line background color: Either if caret is on the line
1943 // and background color is set for that, or if a marker is defined that forces its background
1944 // color onto the line, or if a marker is defined but has no selection margin in which to
1945 // display itself. These are checked in order with the earlier taking precedence. When
1946 // multiple markers cause background override, the color for the highest numbered one is used.
1947 bool overrideBackground
= false;
1948 ColourAllocated background
;
1949 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& ll
->containsCaret
) {
1950 overrideBackground
= true;
1951 background
= vsDraw
.caretLineBackground
.allocated
;
1953 if (!overrideBackground
) {
1954 int marks
= pdoc
->GetMark(line
);
1955 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1956 if ((marks
& 1) && vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
) {
1957 background
= vsDraw
.markers
[markBit
].back
.allocated
;
1958 overrideBackground
= true;
1963 if (!overrideBackground
) {
1964 if (vsDraw
.maskInLine
) {
1965 int marks
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
1967 overrideBackground
= true;
1968 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1970 background
= vsDraw
.markers
[markBit
].back
.allocated
;
1978 bool drawWhitespaceBackground
= (vsDraw
.viewWhitespace
!= wsInvisible
) &&
1979 (!overrideBackground
) && (vsDraw
.whitespaceBackgroundSet
);
1981 bool inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
1982 int indentWidth
= pdoc
->indentInChars
* vsDraw
.spaceWidth
;
1983 if (indentWidth
== 0)
1984 indentWidth
= pdoc
->tabInChars
* vsDraw
.spaceWidth
;
1986 int posLineStart
= pdoc
->LineStart(line
);
1988 int startseg
= ll
->LineStart(subLine
);
1989 int subLineStart
= ll
->positions
[startseg
];
1992 if (subLine
< ll
->lines
) {
1993 lineStart
= ll
->LineStart(subLine
);
1994 lineEnd
= ll
->LineStart(subLine
+ 1);
1998 // Background drawing loop
1999 for (i
= lineStart
; twoPhaseDraw
&& (i
< lineEnd
); i
++) {
2001 int iDoc
= i
+ posLineStart
;
2002 // If there is the end of a style run for any reason
2003 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
2004 i
== (lineEnd
- 1) ||
2005 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
2006 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
2007 (i
== (ll
->edgeColumn
- 1))) {
2008 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2009 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2010 // Only try to draw if really visible - enhances performance by not calling environment to
2011 // draw strings that are completely past the right side of the window.
2012 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2013 int styleMain
= ll
->styles
[i
];
2014 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2015 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2016 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2017 if (ll
->chars
[i
] == '\t') {
2019 if (drawWhitespaceBackground
&&
2020 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2021 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2022 surface
->FillRectangle(rcSegment
, textBack
);
2023 } else if (IsControlCharacter(ll
->chars
[i
])) {
2024 // Control character display
2025 inIndentation
= false;
2026 surface
->FillRectangle(rcSegment
, textBack
);
2028 // Normal text display
2029 surface
->FillRectangle(rcSegment
, textBack
);
2030 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2031 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
2032 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2033 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2034 if (drawWhitespaceBackground
&&
2035 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2036 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
,
2037 ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2038 surface
->FillRectangle(rcSpace
, vsDraw
.whitespaceBackground
.allocated
);
2041 inIndentation
= false;
2052 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2053 xStart
, subLine
, subLineStart
, overrideBackground
, background
);
2056 inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2057 startseg
= ll
->LineStart(subLine
);
2058 // Foreground drawing loop
2059 for (i
= lineStart
; i
< lineEnd
; i
++) {
2061 int iDoc
= i
+ posLineStart
;
2062 // If there is the end of a style run for any reason
2063 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
2064 i
== (lineEnd
- 1) ||
2065 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
2066 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
2067 (i
== (ll
->edgeColumn
- 1))) {
2068 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2069 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2070 // Only try to draw if really visible - enhances performance by not calling environment to
2071 // draw strings that are completely past the right side of the window.
2072 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2073 int styleMain
= ll
->styles
[i
];
2074 ColourAllocated textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
2075 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
2076 //hotspot foreground
2077 if (ll
->hsStart
!= -1 && iDoc
>= ll
->hsStart
&& iDoc
< hsEnd
) {
2078 if (vsDraw
.hotspotForegroundSet
)
2079 textFore
= vsDraw
.hotspotForeground
.allocated
;
2081 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2082 if (inSelection
&& (vsDraw
.selforeset
)) {
2083 textFore
= vsDraw
.selforeground
.allocated
;
2085 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2086 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2087 if (ll
->chars
[i
] == '\t') {
2089 if (!twoPhaseDraw
) {
2090 if (drawWhitespaceBackground
&&
2091 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2092 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2093 surface
->FillRectangle(rcSegment
, textBack
);
2095 if ((vsDraw
.viewWhitespace
!= wsInvisible
) || ((inIndentation
&& vsDraw
.viewIndentationGuides
))) {
2096 if (vsDraw
.whitespaceForegroundSet
)
2097 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2098 surface
->PenColour(textFore
);
2100 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
2101 for (int xIG
= ll
->positions
[i
] / indentWidth
* indentWidth
; xIG
< ll
->positions
[i
+ 1]; xIG
+= indentWidth
) {
2102 if (xIG
>= ll
->positions
[i
] && xIG
> 0) {
2103 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIG
+ xStart
, rcSegment
,
2104 (ll
->xHighlightGuide
== xIG
));
2108 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2109 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2110 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
2111 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
2112 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
2115 } else if (IsControlCharacter(ll
->chars
[i
])) {
2116 // Control character display
2117 inIndentation
= false;
2118 if (controlCharSymbol
< 32) {
2119 // Draw the character
2120 const char *ctrlChar
= ControlCharacterString(ll
->chars
[i
]);
2121 if (!twoPhaseDraw
) {
2122 surface
->FillRectangle(rcSegment
, textBack
);
2124 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
2125 surface
->InternalLeading(ctrlCharsFont
);
2126 PRectangle rcCChar
= rcSegment
;
2127 rcCChar
.left
= rcCChar
.left
+ 1;
2128 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
2129 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
2130 PRectangle rcCentral
= rcCChar
;
2133 surface
->FillRectangle(rcCentral
, textFore
);
2134 PRectangle rcChar
= rcCChar
;
2137 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
2138 rcSegment
.top
+ vsDraw
.maxAscent
, ctrlChar
, strlen(ctrlChar
),
2139 textBack
, textFore
);
2141 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
2142 surface
->DrawTextNoClip(rcSegment
, ctrlCharsFont
,
2143 rcSegment
.top
+ vsDraw
.maxAscent
,
2144 cc
, 1, textBack
, textFore
);
2147 // Normal text display
2148 if (vsDraw
.styles
[styleMain
].visible
) {
2150 surface
->DrawTextTransparent(rcSegment
, textFont
,
2151 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2152 i
- startseg
+ 1, textFore
);
2154 surface
->DrawTextNoClip(rcSegment
, textFont
,
2155 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2156 i
- startseg
+ 1, textFore
, textBack
);
2159 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2160 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
2161 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2162 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2163 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2164 if (vsDraw
.whitespaceForegroundSet
)
2165 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2166 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2167 int xmid
= (ll
->positions
[cpos
+ startseg
] + ll
->positions
[cpos
+ startseg
+ 1]) / 2;
2168 if (!twoPhaseDraw
&& drawWhitespaceBackground
&&
2169 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2170 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2171 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
, ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2172 surface
->FillRectangle(rcSpace
, textBack
);
2174 PRectangle
rcDot(xmid
+ xStart
- subLineStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
2175 rcDot
.right
= rcDot
.left
+ 1;
2176 rcDot
.bottom
= rcDot
.top
+ 1;
2177 surface
->FillRectangle(rcDot
, textFore
);
2180 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
2181 int startSpace
= ll
->positions
[cpos
+ startseg
];
2182 if (startSpace
> 0 && (startSpace
% indentWidth
== 0)) {
2183 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, startSpace
+ xStart
, rcSegment
,
2184 (ll
->xHighlightGuide
== ll
->positions
[cpos
+ startseg
]));
2188 inIndentation
= false;
2193 if (ll
->hsStart
!= -1 && vsDraw
.hotspotUnderline
&& iDoc
>= ll
->hsStart
&& iDoc
< ll
->hsEnd
) {
2194 PRectangle rcUL
= rcSegment
;
2195 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2196 rcUL
.bottom
= rcUL
.top
+ 1;
2197 if (vsDraw
.hotspotForegroundSet
)
2198 surface
->FillRectangle(rcUL
, vsDraw
.hotspotForeground
.allocated
);
2200 surface
->FillRectangle(rcUL
, textFore
);
2201 } else if (vsDraw
.styles
[styleMain
].underline
) {
2202 PRectangle rcUL
= rcSegment
;
2203 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2204 rcUL
.bottom
= rcUL
.top
+ 1;
2205 surface
->FillRectangle(rcUL
, textFore
);
2213 int indStart
[INDIC_MAX
+ 1] = {0};
2214 for (int indica
= 0; indica
<= INDIC_MAX
; indica
++)
2215 indStart
[indica
] = 0;
2217 for (int indicPos
= 0; indicPos
< ll
->numCharsInLine
; indicPos
++) {
2218 if (ll
->indicators
[indicPos
] != ll
->indicators
[indicPos
+ 1]) {
2219 int mask
= 1 << pdoc
->stylingBits
;
2220 for (int indicnum
= 0; mask
< 0x100; indicnum
++) {
2221 if ((ll
->indicators
[indicPos
+ 1] & mask
) && !(ll
->indicators
[indicPos
] & mask
)) {
2222 indStart
[indicnum
] = ll
->positions
[indicPos
+ 1];
2224 if (!(ll
->indicators
[indicPos
+ 1] & mask
) && (ll
->indicators
[indicPos
] & mask
)) {
2226 indStart
[indicnum
] + xStart
,
2227 rcLine
.top
+ vsDraw
.maxAscent
,
2228 ll
->positions
[indicPos
+ 1] + xStart
,
2229 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
2230 vsDraw
.indicators
[indicnum
].Draw(surface
, rcIndic
);
2236 // End of the drawing of the current line
2238 if (!twoPhaseDraw
) {
2239 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2240 xStart
, subLine
, subLineStart
, overrideBackground
, background
);
2243 if (vsDraw
.edgeState
== EDGE_LINE
) {
2244 int edgeX
= theEdge
* vsDraw
.spaceWidth
;
2245 rcSegment
.left
= edgeX
+ xStart
;
2246 rcSegment
.right
= rcSegment
.left
+ 1;
2247 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
.allocated
);
2251 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
2252 if (!pixmapSelPattern
->Initialised()) {
2253 const int patternSize
= 8;
2254 pixmapSelPattern
->InitPixMap(patternSize
, patternSize
, surfaceWindow
, wMain
.GetID());
2255 // This complex procedure is to reproduce the checkerboard dithered pattern used by windows
2256 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
2257 // way between the chrome colour and the chrome highlight colour making a nice transition
2258 // between the window chrome and the content area. And it works in low colour depths.
2259 PRectangle
rcPattern(0, 0, patternSize
, patternSize
);
2261 // Initialize default colours based on the chrome colour scheme. Typically the highlight is white.
2262 ColourAllocated colourFMFill
= vs
.selbar
.allocated
;
2263 ColourAllocated colourFMStripes
= vs
.selbarlight
.allocated
;
2265 if (!(vs
.selbarlight
.desired
== ColourDesired(0xff, 0xff, 0xff))) {
2266 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
2267 // (Typically, the highlight colour is white.)
2268 colourFMFill
= vs
.selbarlight
.allocated
;
2271 if (vs
.foldmarginColourSet
) {
2272 // override default fold margin colour
2273 colourFMFill
= vs
.foldmarginColour
.allocated
;
2275 if (vs
.foldmarginHighlightColourSet
) {
2276 // override default fold margin highlight colour
2277 colourFMStripes
= vs
.foldmarginHighlightColour
.allocated
;
2280 pixmapSelPattern
->FillRectangle(rcPattern
, colourFMFill
);
2281 pixmapSelPattern
->PenColour(colourFMStripes
);
2282 for (int stripe
= 0; stripe
< patternSize
; stripe
++) {
2283 // Alternating 1 pixel stripes is same as checkerboard.
2284 pixmapSelPattern
->MoveTo(0, stripe
* 2);
2285 pixmapSelPattern
->LineTo(patternSize
, stripe
* 2 - patternSize
);
2289 if (!pixmapIndentGuide
->Initialised()) {
2290 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
2291 pixmapIndentGuide
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2292 pixmapIndentGuideHighlight
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2293 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
2294 pixmapIndentGuide
->FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
.allocated
);
2295 pixmapIndentGuide
->PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
2296 pixmapIndentGuideHighlight
->FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
.allocated
);
2297 pixmapIndentGuideHighlight
->PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
2298 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
2299 pixmapIndentGuide
->MoveTo(0, stripe
);
2300 pixmapIndentGuide
->LineTo(2, stripe
);
2301 pixmapIndentGuideHighlight
->MoveTo(0, stripe
);
2302 pixmapIndentGuideHighlight
->LineTo(2, stripe
);
2307 if (!pixmapLine
->Initialised()) {
2308 PRectangle rcClient
= GetClientRectangle();
2309 pixmapLine
->InitPixMap(rcClient
.Width(), rcClient
.Height(),
2310 surfaceWindow
, wMain
.GetID());
2311 pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
2312 rcClient
.Height(), surfaceWindow
, wMain
.GetID());
2317 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
2318 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
2319 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
2323 RefreshPixMaps(surfaceWindow
);
2325 PRectangle rcClient
= GetClientRectangle();
2326 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
2327 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
2329 surfaceWindow
->SetPalette(&palette
, true);
2330 pixmapLine
->SetPalette(&palette
, !hasFocus
);
2332 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
2333 // The area to be painted plus one extra line is styled.
2334 // The extra line is to determine when a style change, such as starting a comment flows on to other lines.
2335 int lineStyleLast
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
2336 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
2337 int endPosPaint
= pdoc
->Length();
2338 if (lineStyleLast
< cs
.LinesDisplayed())
2339 endPosPaint
= pdoc
->LineStart(cs
.DocFromDisplay(lineStyleLast
+ 1));
2341 int xStart
= vs
.fixedColumnWidth
- xOffset
;
2344 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
2345 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
2347 // Ensure we are styled as far as we are painting.
2348 pdoc
->EnsureStyledTo(endPosPaint
);
2349 bool paintAbandonedByStyling
= paintState
== paintAbandoned
;
2352 needUpdateUI
= false;
2355 PaintSelMargin(surfaceWindow
, rcArea
);
2358 // The wrapping process has changed the height of some lines so abandon this
2359 // paint for a complete repaint.
2360 if (AbandonPaint()) {
2365 PRectangle rcRightMargin
= rcClient
;
2366 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
2367 if (rcArea
.Intersects(rcRightMargin
)) {
2368 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2371 if (paintState
== paintAbandoned
) {
2372 // Either styling or NotifyUpdateUI noticed that painting is needed
2373 // outside the current painting rectangle
2374 //Platform::DebugPrintf("Abandoning paint\n");
2375 if (wrapState
!= eWrapNone
) {
2376 if (paintAbandonedByStyling
) {
2377 // Styling has spilled over a line end, such as occurs by starting a multiline
2378 // comment. The width of subsequent text may have changed, so rewrap.
2379 NeedWrapping(cs
.DocFromDisplay(topLine
));
2384 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
2387 if (rcArea
.right
> vs
.fixedColumnWidth
) {
2389 Surface
*surface
= surfaceWindow
;
2391 surface
= pixmapLine
;
2393 surface
->SetUnicodeMode(IsUnicodeMode());
2394 surface
->SetDBCSMode(CodePage());
2396 int visibleLine
= topLine
+ screenLinePaintFirst
;
2398 int posCaret
= currentPos
;
2401 int lineCaret
= pdoc
->LineFromPosition(posCaret
);
2403 // Remove selection margin from drawing area so text will not be drawn
2404 // on it in unbuffered mode.
2405 PRectangle rcTextArea
= rcClient
;
2406 rcTextArea
.left
= vs
.fixedColumnWidth
;
2407 rcTextArea
.right
-= vs
.rightMarginWidth
;
2408 surfaceWindow
->SetClip(rcTextArea
);
2410 // Loop on visible lines
2411 //double durLayout = 0.0;
2412 //double durPaint = 0.0;
2413 //double durCopy = 0.0;
2414 //ElapsedTime etWhole;
2415 int lineDocPrevious
= -1; // Used to avoid laying out one document line multiple times
2416 AutoLineLayout
ll(llc
, 0);
2417 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
2419 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
2420 // Only visible lines should be handled by the code within the loop
2421 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
2422 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
2423 int subLine
= visibleLine
- lineStartSet
;
2425 // Copy this line and its styles from the document into local arrays
2426 // and determine the x position at which each character starts.
2428 if (lineDoc
!= lineDocPrevious
) {
2429 ll
.Set(RetrieveLineLayout(lineDoc
));
2430 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
2431 lineDocPrevious
= lineDoc
;
2433 //durLayout += et.Duration(true);
2436 ll
->selStart
= SelectionStart(lineDoc
);
2437 ll
->selEnd
= SelectionEnd(lineDoc
);
2438 ll
->containsCaret
= lineDoc
== lineCaret
;
2439 if (hideSelection
) {
2442 ll
->containsCaret
= false;
2445 GetHotSpotRange(ll
->hsStart
, ll
->hsEnd
);
2447 PRectangle rcLine
= rcClient
;
2449 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
2451 Range
rangeLine(pdoc
->LineStart(lineDoc
), pdoc
->LineStart(lineDoc
+ 1));
2452 // Highlight the current braces if any
2453 ll
->SetBracesHighlight(rangeLine
, braces
, static_cast<char>(bracesMatchStyle
),
2454 highlightGuideColumn
* vs
.spaceWidth
);
2457 DrawLine(surface
, vs
, lineDoc
, visibleLine
, xStart
, rcLine
, ll
, subLine
);
2458 //durPaint += et.Duration(true);
2460 // Restore the precvious styles for the brace highlights in case layout is in cache.
2461 ll
->RestoreBracesHighlight(rangeLine
, braces
);
2463 bool expanded
= cs
.GetExpanded(lineDoc
);
2464 if ((foldFlags
& SC_FOLDFLAG_BOX
) == 0) {
2465 // Paint the line above the fold
2466 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_EXPANDED
))
2468 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_CONTRACTED
))) {
2469 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2470 PRectangle rcFoldLine
= rcLine
;
2471 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2472 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2475 // Paint the line below the fold
2476 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_EXPANDED
))
2478 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2479 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2480 PRectangle rcFoldLine
= rcLine
;
2481 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2482 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2486 int FoldLevelCurr
= (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2487 int FoldLevelPrev
= (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2488 int FoldLevelFlags
= (pdoc
->GetLevel(lineDoc
) & ~SC_FOLDLEVELNUMBERMASK
) & ~(0xFFF0000);
2489 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
2490 // Draw line above fold
2491 if ((FoldLevelPrev
< FoldLevelCurr
)
2493 (FoldLevelFlags
& SC_FOLDLEVELBOXHEADERFLAG
2495 (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELBOXFOOTERFLAG
) == 0)) {
2496 PRectangle rcFoldLine
= rcLine
;
2497 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2498 rcFoldLine
.left
+= xStart
+ FoldLevelCurr
* vs
.spaceWidth
* indentationStep
- 1;
2499 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2502 // Line below the fold (or below a contracted fold)
2503 if (FoldLevelFlags
& SC_FOLDLEVELBOXFOOTERFLAG
2505 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2506 PRectangle rcFoldLine
= rcLine
;
2507 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2508 rcFoldLine
.left
+= xStart
+ (FoldLevelCurr
) * vs
.spaceWidth
* indentationStep
- 1;
2509 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2512 PRectangle rcBoxLine
= rcLine
;
2513 // Draw vertical line for every fold level
2514 for (int i
= 0; i
<= FoldLevelCurr
; i
++) {
2515 rcBoxLine
.left
= xStart
+ i
* vs
.spaceWidth
* indentationStep
- 1;
2516 rcBoxLine
.right
= rcBoxLine
.left
+ 1;
2517 surface
->FillRectangle(rcBoxLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2522 if (lineDoc
== lineCaret
) {
2523 int offset
= Platform::Minimum(posCaret
- rangeLine
.start
, ll
->maxLineLength
);
2524 if ((offset
>= ll
->LineStart(subLine
)) &&
2525 ((offset
< ll
->LineStart(subLine
+ 1)) || offset
== ll
->numCharsInLine
)) {
2526 int xposCaret
= ll
->positions
[offset
] - ll
->positions
[ll
->LineStart(subLine
)] + xStart
;
2527 int widthOverstrikeCaret
;
2528 if (posCaret
== pdoc
->Length()) { // At end of document
2529 widthOverstrikeCaret
= vs
.aveCharWidth
;
2530 } else if ((posCaret
- rangeLine
.start
) >= ll
->numCharsInLine
) { // At end of line
2531 widthOverstrikeCaret
= vs
.aveCharWidth
;
2533 widthOverstrikeCaret
= ll
->positions
[offset
+ 1] - ll
->positions
[offset
];
2535 if (widthOverstrikeCaret
< 3) // Make sure its visible
2536 widthOverstrikeCaret
= 3;
2537 if (((caret
.active
&& caret
.on
) || (posDrag
>= 0)) && xposCaret
>= 0) {
2538 PRectangle rcCaret
= rcLine
;
2539 int caretWidthOffset
= 0;
2540 if ((offset
> 0) && (vs
.caretWidth
> 1))
2541 caretWidthOffset
= 1; // Move back so overlaps both character cells.
2543 rcCaret
.left
= xposCaret
- caretWidthOffset
;
2544 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
2547 rcCaret
.top
= rcCaret
.bottom
- 2;
2548 rcCaret
.left
= xposCaret
+ 1;
2549 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
2551 rcCaret
.left
= xposCaret
- caretWidthOffset
;
2552 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
2555 surface
->FillRectangle(rcCaret
, vs
.caretcolour
.allocated
);
2561 Point
from(vs
.fixedColumnWidth
, 0);
2562 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
2563 rcClient
.right
, yposScreen
+ vs
.lineHeight
);
2564 surfaceWindow
->Copy(rcCopyArea
, from
, *pixmapLine
);
2566 //durCopy += et.Duration(true);
2569 if (!bufferedDraw
) {
2570 ypos
+= vs
.lineHeight
;
2573 yposScreen
+= vs
.lineHeight
;
2577 //if (durPaint < 0.00000001)
2578 // durPaint = 0.00000001;
2580 // Right column limit indicator
2581 PRectangle rcBeyondEOF
= rcClient
;
2582 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
2583 rcBeyondEOF
.right
= rcBeyondEOF
.right
;
2584 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
2585 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
2586 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2587 if (vs
.edgeState
== EDGE_LINE
) {
2588 int edgeX
= theEdge
* vs
.spaceWidth
;
2589 rcBeyondEOF
.left
= edgeX
+ xStart
;
2590 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
2591 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
.allocated
);
2594 //Platform::DebugPrintf(
2595 //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
2596 //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
2601 // Space (3 space characters) between line numbers and text when printing.
2602 #define lineNumberPrintSpace " "
2604 ColourDesired
InvertedLight(ColourDesired orig
) {
2605 unsigned int r
= orig
.GetRed();
2606 unsigned int g
= orig
.GetGreen();
2607 unsigned int b
= orig
.GetBlue();
2608 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
2609 unsigned int il
= 0xff - l
;
2611 return ColourDesired(0xff, 0xff, 0xff);
2615 return ColourDesired(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
2618 // This is mostly copied from the Paint method but with some things omitted
2619 // such as the margin markers, line numbers, selection and caret
2620 // Should be merged back into a combined Draw method.
2621 long Editor::FormatRange(bool draw
, RangeToFormat
*pfr
) {
2625 AutoSurface
surface(pfr
->hdc
, this);
2628 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this);
2629 if (!surfaceMeasure
) {
2633 ViewStyle
vsPrint(vs
);
2635 // Modify the view style for printing as do not normally want any of the transient features to be printed
2636 // Printing supports only the line number margin.
2637 int lineNumberIndex
= -1;
2638 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
2639 if ((!vsPrint
.ms
[margin
].symbol
) && (vsPrint
.ms
[margin
].width
> 0)) {
2640 lineNumberIndex
= margin
;
2642 vsPrint
.ms
[margin
].width
= 0;
2645 vsPrint
.showMarkedLines
= false;
2646 vsPrint
.fixedColumnWidth
= 0;
2647 vsPrint
.zoomLevel
= printMagnification
;
2648 vsPrint
.viewIndentationGuides
= false;
2649 // Don't show the selection when printing
2650 vsPrint
.selbackset
= false;
2651 vsPrint
.selforeset
= false;
2652 vsPrint
.whitespaceBackgroundSet
= false;
2653 vsPrint
.whitespaceForegroundSet
= false;
2654 vsPrint
.showCaretLineBackground
= false;
2656 // Set colours for printing according to users settings
2657 for (int sty
= 0;sty
<= STYLE_MAX
;sty
++) {
2658 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
2659 vsPrint
.styles
[sty
].fore
.desired
= InvertedLight(vsPrint
.styles
[sty
].fore
.desired
);
2660 vsPrint
.styles
[sty
].back
.desired
= InvertedLight(vsPrint
.styles
[sty
].back
.desired
);
2661 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
2662 vsPrint
.styles
[sty
].fore
.desired
= ColourDesired(0, 0, 0);
2663 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2664 } else if (printColourMode
== SC_PRINT_COLOURONWHITE
) {
2665 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2666 } else if (printColourMode
== SC_PRINT_COLOURONWHITEDEFAULTBG
) {
2667 if (sty
<= STYLE_DEFAULT
) {
2668 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2672 // White background for the line numbers
2673 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2675 vsPrint
.Refresh(*surfaceMeasure
);
2676 // Ensure colours are set up
2677 vsPrint
.RefreshColourPalette(palette
, true);
2678 vsPrint
.RefreshColourPalette(palette
, false);
2679 // Determining width must hapen after fonts have been realised in Refresh
2680 int lineNumberWidth
= 0;
2681 if (lineNumberIndex
>= 0) {
2682 lineNumberWidth
= surfaceMeasure
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
2683 "99999" lineNumberPrintSpace
, 5 + strlen(lineNumberPrintSpace
));
2684 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
2687 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
2688 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
2689 if (linePrintLast
< linePrintStart
)
2690 linePrintLast
= linePrintStart
;
2691 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
);
2692 if (linePrintLast
> linePrintMax
)
2693 linePrintLast
= linePrintMax
;
2694 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
2695 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
2696 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
2697 int endPosPrint
= pdoc
->Length();
2698 if (linePrintLast
< pdoc
->LinesTotal())
2699 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
2701 // Ensure we are styled to where we are formatting.
2702 pdoc
->EnsureStyledTo(endPosPrint
);
2704 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
+ lineNumberWidth
;
2705 int ypos
= pfr
->rc
.top
;
2707 int lineDoc
= linePrintStart
;
2709 int nPrintPos
= pfr
->chrg
.cpMin
;
2710 int visibleLine
= 0;
2711 int widthPrint
= pfr
->rc
.Width() - lineNumberWidth
;
2712 if (printWrapState
== eWrapNone
)
2713 widthPrint
= LineLayout::wrapWidthInfinite
;
2715 while (lineDoc
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
2717 // When printing, the hdc and hdcTarget may be the same, so
2718 // changing the state of surfaceMeasure may change the underlying
2719 // state of surface. Therefore, any cached state is discarded before
2720 // using each surface.
2721 surfaceMeasure
->FlushCachedState();
2723 // Copy this line and its styles from the document into local arrays
2724 // and determine the x position at which each character starts.
2725 LineLayout
ll(8000);
2726 LayoutLine(lineDoc
, surfaceMeasure
, vsPrint
, &ll
, widthPrint
);
2730 ll
.containsCaret
= false;
2733 rcLine
.left
= pfr
->rc
.left
+ lineNumberWidth
;
2735 rcLine
.right
= pfr
->rc
.right
- 1;
2736 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
2738 // When document line is wrapped over multiple display lines, find where
2739 // to start printing from to ensure a particular position is on the first
2740 // line of the page.
2741 if (visibleLine
== 0) {
2742 int startWithinLine
= nPrintPos
- pdoc
->LineStart(lineDoc
);
2743 for (int iwl
= 0; iwl
< ll
.lines
- 1; iwl
++) {
2744 if (ll
.LineStart(iwl
) <= startWithinLine
&& ll
.LineStart(iwl
+ 1) >= startWithinLine
) {
2749 if (ll
.lines
> 1 && startWithinLine
>= ll
.LineStart(ll
.lines
- 1)) {
2750 visibleLine
= -(ll
.lines
- 1);
2754 if (draw
&& lineNumberWidth
&&
2755 (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) &&
2756 (visibleLine
>= 0)) {
2758 sprintf(number
, "%d" lineNumberPrintSpace
, lineDoc
+ 1);
2759 PRectangle rcNumber
= rcLine
;
2760 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
2762 rcNumber
.left
-= surfaceMeasure
->WidthText(
2763 vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, strlen(number
));
2764 surface
->FlushCachedState();
2765 surface
->DrawTextNoClip(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
2766 ypos
+ vsPrint
.maxAscent
, number
, strlen(number
),
2767 vsPrint
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
2768 vsPrint
.styles
[STYLE_LINENUMBER
].back
.allocated
);
2772 surface
->FlushCachedState();
2774 for (int iwl
= 0; iwl
< ll
.lines
; iwl
++) {
2775 if (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) {
2776 if (visibleLine
>= 0) {
2779 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
2780 DrawLine(surface
, vsPrint
, lineDoc
, visibleLine
, xStart
, rcLine
, &ll
, iwl
);
2782 ypos
+= vsPrint
.lineHeight
;
2785 if (iwl
== ll
.lines
- 1)
2786 nPrintPos
= pdoc
->LineStart(lineDoc
+ 1);
2788 nPrintPos
+= ll
.LineStart(iwl
+ 1) - ll
.LineStart(iwl
);
2798 int Editor::TextWidth(int style
, const char *text
) {
2800 AutoSurface
surface(this);
2802 return surface
->WidthText(vs
.styles
[style
].font
, text
, strlen(text
));
2808 // Empty method is overridden on GTK+ to show / hide scrollbars
2809 void Editor::ReconfigureScrollBars() {}
2811 void Editor::SetScrollBars() {
2814 int nMax
= MaxScrollPos();
2815 int nPage
= LinesOnScreen();
2816 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
2818 // TODO: ensure always showing as many lines as possible
2819 // May not be, if, for example, window made larger
2820 if (topLine
> MaxScrollPos()) {
2821 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
2822 SetVerticalScrollPos();
2826 if (!AbandonPaint())
2829 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
2832 void Editor::ChangeSize() {
2835 if (wrapState
!= eWrapNone
) {
2836 PRectangle rcTextArea
= GetClientRectangle();
2837 rcTextArea
.left
= vs
.fixedColumnWidth
;
2838 rcTextArea
.right
-= vs
.rightMarginWidth
;
2839 if (wrapWidth
!= rcTextArea
.Width()) {
2846 void Editor::AddChar(char ch
) {
2853 void Editor::AddCharUTF(char *s
, unsigned int len
, bool treatAsDBCS
) {
2854 bool wasSelection
= currentPos
!= anchor
;
2856 if (inOverstrike
&& !wasSelection
&& !RangeContainsProtected(currentPos
, currentPos
+ 1)) {
2857 if (currentPos
< (pdoc
->Length())) {
2858 if (!IsEOLChar(pdoc
->CharAt(currentPos
))) {
2859 pdoc
->DelChar(currentPos
);
2863 if (pdoc
->InsertString(currentPos
, s
, len
)) {
2864 SetEmptySelection(currentPos
+ len
);
2866 EnsureCaretVisible();
2867 // Avoid blinking during rapid typing:
2868 ShowCaretAtCurrentPosition();
2872 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
2873 static_cast<unsigned char>(s
[1]));
2875 int byte
= static_cast<unsigned char>(s
[0]);
2876 if ((byte
< 0xC0) || (1 == len
)) {
2877 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
2878 // characters when not in UTF-8 mode.
2879 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
2880 // characters representing themselves.
2882 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
2883 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
2884 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
2886 int byte2
= static_cast<unsigned char>(s
[1]);
2887 if ((byte2
& 0xC0) == 0x80) {
2888 // Two-byte-character lead-byte followed by a trail-byte.
2889 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
2891 // A two-byte-character lead-byte not followed by trail-byte
2892 // represents itself.
2893 } else if (byte
< 0xF0) {
2894 int byte2
= static_cast<unsigned char>(s
[1]);
2895 int byte3
= static_cast<unsigned char>(s
[2]);
2896 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
2897 // Three-byte-character lead byte followed by two trail bytes.
2898 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
2901 // A three-byte-character lead-byte not followed by two trail-bytes
2902 // represents itself.
2909 void Editor::ClearSelection() {
2910 if (!SelectionContainsProtected()) {
2911 if (selType
== selRectangle
) {
2912 pdoc
->BeginUndoAction();
2913 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2914 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2915 int startPos
= SelectionStart();
2916 for (int line
= lineEnd
; line
>= lineStart
; line
--) {
2917 startPos
= SelectionStart(line
);
2918 unsigned int chars
= SelectionEnd(line
) - startPos
;
2920 pdoc
->DeleteChars(startPos
, chars
);
2923 SetEmptySelection(startPos
);
2924 pdoc
->EndUndoAction();
2925 selType
= selStream
;
2927 int startPos
= SelectionStart();
2928 unsigned int chars
= SelectionEnd() - startPos
;
2929 SetEmptySelection(startPos
);
2931 pdoc
->BeginUndoAction();
2932 pdoc
->DeleteChars(startPos
, chars
);
2933 pdoc
->EndUndoAction();
2939 void Editor::ClearAll() {
2940 pdoc
->BeginUndoAction();
2941 if (0 != pdoc
->Length()) {
2942 pdoc
->DeleteChars(0, pdoc
->Length());
2944 if (!pdoc
->IsReadOnly()) {
2947 pdoc
->EndUndoAction();
2951 SetVerticalScrollPos();
2954 void Editor::ClearDocumentStyle() {
2955 pdoc
->StartStyling(0, '\377');
2956 pdoc
->SetStyleFor(pdoc
->Length(), 0);
2958 pdoc
->ClearLevels();
2961 void Editor::Cut() {
2962 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
2968 void Editor::PasteRectangular(int pos
, const char *ptr
, int len
) {
2969 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
2973 int xInsert
= XFromPosition(currentPos
);
2974 int line
= pdoc
->LineFromPosition(currentPos
);
2975 bool prevCr
= false;
2976 pdoc
->BeginUndoAction();
2977 for (int i
= 0; i
< len
; i
++) {
2978 if (IsEOLChar(ptr
[i
])) {
2979 if ((ptr
[i
] == '\r') || (!prevCr
))
2981 if (line
>= pdoc
->LinesTotal()) {
2982 if (pdoc
->eolMode
!= SC_EOL_LF
)
2983 pdoc
->InsertChar(pdoc
->Length(), '\r');
2984 if (pdoc
->eolMode
!= SC_EOL_CR
)
2985 pdoc
->InsertChar(pdoc
->Length(), '\n');
2987 // Pad the end of lines with spaces if required
2988 currentPos
= PositionFromLineX(line
, xInsert
);
2989 if ((XFromPosition(currentPos
) < xInsert
) && (i
+ 1 < len
)) {
2990 for (int i
= 0; i
< xInsert
- XFromPosition(currentPos
); i
++) {
2991 pdoc
->InsertChar(currentPos
, ' ');
2995 prevCr
= ptr
[i
] == '\r';
2997 pdoc
->InsertString(currentPos
, ptr
+ i
, 1);
3002 pdoc
->EndUndoAction();
3003 SetEmptySelection(pos
);
3006 bool Editor::CanPaste() {
3007 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
3010 void Editor::Clear() {
3011 if (currentPos
== anchor
) {
3012 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3018 SetEmptySelection(currentPos
);
3021 void Editor::SelectAll() {
3022 SetSelection(0, pdoc
->Length());
3026 void Editor::Undo() {
3027 if (pdoc
->CanUndo()) {
3029 int newPos
= pdoc
->Undo();
3030 SetEmptySelection(newPos
);
3031 EnsureCaretVisible();
3035 void Editor::Redo() {
3036 if (pdoc
->CanRedo()) {
3037 int newPos
= pdoc
->Redo();
3038 SetEmptySelection(newPos
);
3039 EnsureCaretVisible();
3043 void Editor::DelChar() {
3044 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3045 pdoc
->DelChar(currentPos
);
3047 // Avoid blinking during rapid typing:
3048 ShowCaretAtCurrentPosition();
3051 void Editor::DelCharBack(bool allowLineStartDeletion
) {
3052 if (currentPos
== anchor
) {
3053 if (!RangeContainsProtected(currentPos
- 1, currentPos
)) {
3054 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
3055 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != currentPos
)) {
3056 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3057 pdoc
->GetColumn(currentPos
) > 0 && pdoc
->backspaceUnindents
) {
3058 pdoc
->BeginUndoAction();
3059 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3060 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
3061 if (indentation
% indentationStep
== 0) {
3062 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3064 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- (indentation
% indentationStep
));
3066 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
3067 pdoc
->EndUndoAction();
3069 pdoc
->DelCharBack(currentPos
);
3075 SetEmptySelection(currentPos
);
3077 // Avoid blinking during rapid typing:
3078 ShowCaretAtCurrentPosition();
3081 void Editor::NotifyFocus(bool) {}
3083 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
3085 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
3086 scn
.position
= endStyleNeeded
;
3090 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
3091 NotifyStyleToNeeded(endStyleNeeded
);
3094 void Editor::NotifyChar(int ch
) {
3096 scn
.nmhdr
.code
= SCN_CHARADDED
;
3099 if (recordingMacro
) {
3101 txt
[0] = static_cast<char>(ch
);
3103 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
3107 void Editor::NotifySavePoint(bool isSavePoint
) {
3110 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
3112 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
3117 void Editor::NotifyModifyAttempt() {
3119 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
3123 void Editor::NotifyDoubleClick(Point
, bool) {
3125 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
3129 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3131 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
3132 scn
.position
= position
;
3133 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3134 (alt
? SCI_ALT
: 0);
3138 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3140 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
3141 scn
.position
= position
;
3142 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3143 (alt
? SCI_ALT
: 0);
3147 void Editor::NotifyUpdateUI() {
3149 scn
.nmhdr
.code
= SCN_UPDATEUI
;
3153 void Editor::NotifyPainted() {
3155 scn
.nmhdr
.code
= SCN_PAINTED
;
3159 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
3160 int marginClicked
= -1;
3162 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
3163 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
3164 marginClicked
= margin
;
3165 x
+= vs
.ms
[margin
].width
;
3167 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
3169 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
3170 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3171 (alt
? SCI_ALT
: 0);
3172 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
3173 scn
.margin
= marginClicked
;
3181 void Editor::NotifyNeedShown(int pos
, int len
) {
3183 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
3189 void Editor::NotifyDwelling(Point pt
, bool state
) {
3191 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
3192 scn
.position
= PositionFromLocationClose(pt
);
3198 void Editor::NotifyZoom() {
3200 scn
.nmhdr
.code
= SCN_ZOOM
;
3204 // Notifications from document
3205 void Editor::NotifyModifyAttempt(Document
*, void *) {
3206 //Platform::DebugPrintf("** Modify Attempt\n");
3207 NotifyModifyAttempt();
3210 void Editor::NotifyMove(int position
) {
3212 scn
.nmhdr
.code
= SCN_POSCHANGED
;
3213 scn
.position
= position
;
3217 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
3218 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
3219 NotifySavePoint(atSavePoint
);
3222 void Editor::CheckModificationForWrap(DocModification mh
) {
3223 if ((mh
.modificationType
& SC_MOD_INSERTTEXT
) ||
3224 (mh
.modificationType
& SC_MOD_DELETETEXT
)) {
3225 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
3226 if (wrapState
!= eWrapNone
) {
3227 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
3228 if (mh
.linesAdded
== 0) {
3229 AutoSurface
surface(this);
3230 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
3231 if (surface
&& ll
) {
3232 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
3233 if (cs
.GetHeight(lineDoc
) != ll
->lines
) {
3234 NeedWrapping(lineDoc
- 1);
3238 NeedWrapping(lineDoc
);
3241 NeedWrapping(lineDoc
);
3247 // Move a position so it is still after the same character as before the insertion.
3248 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
3249 if (position
> startInsertion
) {
3250 return position
+ length
;
3255 // Move a position so it is still after the same character as before the deletion if that
3256 // character is still present else after the previous surviving character.
3257 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
3258 if (position
> startDeletion
) {
3259 int endDeletion
= startDeletion
+ length
;
3260 if (position
> endDeletion
) {
3261 return position
- length
;
3263 return startDeletion
;
3270 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
3271 needUpdateUI
= true;
3272 if (paintState
== painting
) {
3273 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
3275 CheckModificationForWrap(mh
);
3276 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
3277 if (paintState
== notPainting
) {
3278 if (mh
.position
< pdoc
->LineStart(topLine
)) {
3279 // Styling performed before this view
3282 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3286 // Move selection and brace highlights
3287 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
3288 currentPos
= MovePositionForInsertion(currentPos
, mh
.position
, mh
.length
);
3289 anchor
= MovePositionForInsertion(anchor
, mh
.position
, mh
.length
);
3290 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
3291 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
3292 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
3293 currentPos
= MovePositionForDeletion(currentPos
, mh
.position
, mh
.length
);
3294 anchor
= MovePositionForDeletion(anchor
, mh
.position
, mh
.length
);
3295 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
3296 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
3298 if (cs
.LinesDisplayed() < cs
.LinesInDoc()) {
3299 // Some lines are hidden so may need shown.
3300 // TODO: check if the modified area is hidden.
3301 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
3302 NotifyNeedShown(mh
.position
, mh
.length
);
3303 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
3304 NotifyNeedShown(mh
.position
, mh
.length
);
3307 if (mh
.linesAdded
!= 0) {
3308 // Update contraction state for inserted and removed lines
3309 // lineOfPos should be calculated in context of state before modification, shouldn't it
3310 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
3311 if (mh
.linesAdded
> 0) {
3312 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
3314 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
3316 // Avoid scrolling of display if change before current display
3317 if (mh
.position
< posTopLine
) {
3318 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
3319 if (newTop
!= topLine
) {
3321 SetVerticalScrollPos();
3325 //Platform::DebugPrintf("** %x Doc Changed\n", this);
3326 // TODO: could invalidate from mh.startModification to end of screen
3327 //InvalidateRange(mh.position, mh.position + mh.length);
3328 if (paintState
== notPainting
) {
3332 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
3333 // mh.position, mh.position + mh.length);
3334 if (paintState
== notPainting
) {
3335 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3340 if (mh
.linesAdded
!= 0) {
3344 if (mh
.modificationType
& SC_MOD_CHANGEMARKER
) {
3345 if (paintState
== notPainting
) {
3350 // If client wants to see this modification
3351 if (mh
.modificationType
& modEventMask
) {
3352 if ((mh
.modificationType
& SC_MOD_CHANGESTYLE
) == 0) {
3353 // Real modification made to text of document.
3354 NotifyChange(); // Send EN_CHANGE
3358 scn
.nmhdr
.code
= SCN_MODIFIED
;
3359 scn
.position
= mh
.position
;
3360 scn
.modificationType
= mh
.modificationType
;
3362 scn
.length
= mh
.length
;
3363 scn
.linesAdded
= mh
.linesAdded
;
3365 scn
.foldLevelNow
= mh
.foldLevelNow
;
3366 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
3371 void Editor::NotifyDeleted(Document
*, void *) {
3375 void Editor::NotifyMacroRecord(unsigned int iMessage
, unsigned long wParam
, long lParam
) {
3377 // Enumerates all macroable messages
3383 case SCI_REPLACESEL
:
3385 case SCI_INSERTTEXT
:
3386 case SCI_APPENDTEXT
:
3391 case SCI_SEARCHANCHOR
:
3392 case SCI_SEARCHNEXT
:
3393 case SCI_SEARCHPREV
:
3395 case SCI_LINEDOWNEXTEND
:
3397 case SCI_PARADOWNEXTEND
:
3399 case SCI_LINEUPEXTEND
:
3401 case SCI_PARAUPEXTEND
:
3403 case SCI_CHARLEFTEXTEND
:
3405 case SCI_CHARRIGHTEXTEND
:
3407 case SCI_WORDLEFTEXTEND
:
3409 case SCI_WORDRIGHTEXTEND
:
3410 case SCI_WORDPARTLEFT
:
3411 case SCI_WORDPARTLEFTEXTEND
:
3412 case SCI_WORDPARTRIGHT
:
3413 case SCI_WORDPARTRIGHTEXTEND
:
3415 case SCI_HOMEEXTEND
:
3417 case SCI_LINEENDEXTEND
:
3419 case SCI_HOMEWRAPEXTEND
:
3420 case SCI_LINEENDWRAP
:
3421 case SCI_LINEENDWRAPEXTEND
:
3422 case SCI_DOCUMENTSTART
:
3423 case SCI_DOCUMENTSTARTEXTEND
:
3424 case SCI_DOCUMENTEND
:
3425 case SCI_DOCUMENTENDEXTEND
:
3427 case SCI_PAGEUPEXTEND
:
3429 case SCI_PAGEDOWNEXTEND
:
3430 case SCI_EDITTOGGLEOVERTYPE
:
3432 case SCI_DELETEBACK
:
3437 case SCI_VCHOMEEXTEND
:
3438 case SCI_VCHOMEWRAP
:
3439 case SCI_VCHOMEWRAPEXTEND
:
3440 case SCI_DELWORDLEFT
:
3441 case SCI_DELWORDRIGHT
:
3442 case SCI_DELLINELEFT
:
3443 case SCI_DELLINERIGHT
:
3446 case SCI_LINEDELETE
:
3447 case SCI_LINETRANSPOSE
:
3448 case SCI_LINEDUPLICATE
:
3451 case SCI_LINESCROLLDOWN
:
3452 case SCI_LINESCROLLUP
:
3453 case SCI_DELETEBACKNOTLINE
:
3454 case SCI_HOMEDISPLAY
:
3455 case SCI_HOMEDISPLAYEXTEND
:
3456 case SCI_LINEENDDISPLAY
:
3457 case SCI_LINEENDDISPLAYEXTEND
:
3460 // Filter out all others like display changes. Also, newlines are redundant
3461 // with char insert messages.
3464 // printf("Filtered out %ld of macro recording\n", iMessage);
3468 // Send notification
3470 scn
.nmhdr
.code
= SCN_MACRORECORD
;
3471 scn
.message
= iMessage
;
3472 scn
.wParam
= wParam
;
3473 scn
.lParam
= lParam
;
3477 // Force scroll and keep position relative to top of window
3478 void Editor::PageMove(int direction
, bool extend
) {
3479 Point pt
= LocationFromPosition(currentPos
);
3480 int topLineNew
= Platform::Clamp(
3481 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
3482 int newPos
= PositionFromLocation(
3483 Point(lastXChosen
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())));
3484 if (topLineNew
!= topLine
) {
3485 SetTopLine(topLineNew
);
3486 MovePositionTo(newPos
, extend
);
3488 SetVerticalScrollPos();
3490 MovePositionTo(newPos
, extend
);
3494 void Editor::ChangeCaseOfSelection(bool makeUpperCase
) {
3495 pdoc
->BeginUndoAction();
3496 int startCurrent
= currentPos
;
3497 int startAnchor
= anchor
;
3498 if (selType
== selRectangle
) {
3499 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
3500 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
3501 for (int line
= lineEnd
; line
>= lineStart
; line
--) {
3503 Range(SelectionStart(line
), SelectionEnd(line
)),
3506 // Would be nicer to keep the rectangular selection but this is complex
3507 selType
= selStream
;
3508 SetSelection(startCurrent
, startCurrent
);
3510 pdoc
->ChangeCase(Range(SelectionStart(), SelectionEnd()),
3512 SetSelection(startCurrent
, startAnchor
);
3514 pdoc
->EndUndoAction();
3517 void Editor::LineTranspose() {
3518 int line
= pdoc
->LineFromPosition(currentPos
);
3520 int startPrev
= pdoc
->LineStart(line
- 1);
3521 int endPrev
= pdoc
->LineEnd(line
- 1);
3522 int start
= pdoc
->LineStart(line
);
3523 int end
= pdoc
->LineEnd(line
);
3524 int startNext
= pdoc
->LineStart(line
+ 1);
3525 if (end
< pdoc
->Length()) {
3527 char *thisLine
= CopyRange(start
, end
);
3528 pdoc
->DeleteChars(start
, end
- start
);
3529 if (pdoc
->InsertString(startPrev
, thisLine
, end
- start
)) {
3530 MovePositionTo(startPrev
+ end
- start
);
3534 // Last line so line has no line end
3535 char *thisLine
= CopyRange(start
, end
);
3536 char *prevEnd
= CopyRange(endPrev
, start
);
3537 pdoc
->DeleteChars(endPrev
, end
- endPrev
);
3538 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
3539 if (pdoc
->InsertString(startPrev
+ end
- start
, prevEnd
, start
- endPrev
)) {
3540 MovePositionTo(startPrev
+ end
- endPrev
);
3549 void Editor::LineDuplicate() {
3550 int line
= pdoc
->LineFromPosition(currentPos
);
3551 int start
= pdoc
->LineStart(line
);
3552 int end
= pdoc
->LineEnd(line
);
3553 char *thisLine
= CopyRange(start
, end
);
3554 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
3555 pdoc
->InsertString(end
, eol
);
3556 pdoc
->InsertString(end
+ strlen(eol
), thisLine
, end
- start
);
3560 void Editor::CancelModes() {}
3562 void Editor::NewLine() {
3564 const char *eol
= "\n";
3565 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
3567 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
3569 } // else SC_EOL_LF -> "\n" already set
3570 if (pdoc
->InsertString(currentPos
, eol
)) {
3571 SetEmptySelection(currentPos
+ strlen(eol
));
3578 EnsureCaretVisible();
3581 void Editor::CursorUpOrDown(int direction
, bool extend
) {
3582 Point pt
= LocationFromPosition(currentPos
);
3583 int posNew
= PositionFromLocation(
3584 Point(lastXChosen
, pt
.y
+ direction
* vs
.lineHeight
));
3585 if (direction
< 0) {
3586 // Line wrapping may lead to a location on the same line, so
3587 // seek back if that is the case.
3588 // There is an equivalent case when moving down which skips
3589 // over a line but as that does not trap the user it is fine.
3590 Point ptNew
= LocationFromPosition(posNew
);
3591 while ((posNew
> 0) && (pt
.y
== ptNew
.y
)) {
3593 ptNew
= LocationFromPosition(posNew
);
3596 MovePositionTo(posNew
, extend
);
3599 int Editor::StartEndDisplayLine(int pos
, bool start
) {
3601 int line
= pdoc
->LineFromPosition(pos
);
3602 AutoSurface
surface(this);
3603 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
3604 int posRet
= INVALID_POSITION
;
3605 if (surface
&& ll
) {
3606 unsigned int posLineStart
= pdoc
->LineStart(line
);
3607 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
3608 int posInLine
= pos
- posLineStart
;
3609 if (posInLine
<= ll
->maxLineLength
) {
3610 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
3611 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
3613 posRet
= ll
->LineStart(subLine
) + posLineStart
;
3615 if (subLine
== ll
->lines
- 1)
3616 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
;
3618 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
- 1;
3624 if (posRet
== INVALID_POSITION
) {
3631 int Editor::KeyCommand(unsigned int iMessage
) {
3636 case SCI_LINEDOWNEXTEND
:
3637 CursorUpOrDown(1, true);
3640 MovePositionTo(pdoc
->ParaDown(currentPos
));
3642 case SCI_PARADOWNEXTEND
:
3643 MovePositionTo(pdoc
->ParaDown(currentPos
), true);
3645 case SCI_LINESCROLLDOWN
:
3646 ScrollTo(topLine
+ 1);
3647 MoveCaretInsideView(false);
3652 case SCI_LINEUPEXTEND
:
3653 CursorUpOrDown(-1, true);
3656 MovePositionTo(pdoc
->ParaUp(currentPos
));
3658 case SCI_PARAUPEXTEND
:
3659 MovePositionTo(pdoc
->ParaUp(currentPos
), true);
3661 case SCI_LINESCROLLUP
:
3662 ScrollTo(topLine
- 1);
3663 MoveCaretInsideView(false);
3666 if (SelectionEmpty()) {
3667 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1));
3669 MovePositionTo(SelectionStart());
3673 case SCI_CHARLEFTEXTEND
:
3674 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), true);
3678 if (SelectionEmpty()) {
3679 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1));
3681 MovePositionTo(SelectionEnd());
3685 case SCI_CHARRIGHTEXTEND
:
3686 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), true);
3690 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1));
3693 case SCI_WORDLEFTEXTEND
:
3694 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1), true);
3698 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1));
3701 case SCI_WORDRIGHTEXTEND
:
3702 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1), true);
3706 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)));
3709 case SCI_HOMEEXTEND
:
3710 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), true);
3714 MovePositionTo(pdoc
->LineEndPosition(currentPos
));
3717 case SCI_LINEENDEXTEND
:
3718 MovePositionTo(pdoc
->LineEndPosition(currentPos
), true);
3721 case SCI_HOMEWRAP
: {
3722 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
3723 if (currentPos
<= homePos
)
3724 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
3725 MovePositionTo(homePos
);
3729 case SCI_HOMEWRAPEXTEND
: {
3730 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
3731 if (currentPos
<= homePos
)
3732 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
3733 MovePositionTo(homePos
, true);
3737 case SCI_LINEENDWRAP
: {
3738 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
3739 if (currentPos
>= endPos
)
3740 endPos
= pdoc
->LineEndPosition(currentPos
);
3741 MovePositionTo(endPos
);
3745 case SCI_LINEENDWRAPEXTEND
: {
3746 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
3747 if (currentPos
>= endPos
)
3748 endPos
= pdoc
->LineEndPosition(currentPos
);
3749 MovePositionTo(endPos
, true);
3753 case SCI_DOCUMENTSTART
:
3757 case SCI_DOCUMENTSTARTEXTEND
:
3758 MovePositionTo(0, true);
3761 case SCI_DOCUMENTEND
:
3762 MovePositionTo(pdoc
->Length());
3765 case SCI_DOCUMENTENDEXTEND
:
3766 MovePositionTo(pdoc
->Length(), true);
3772 case SCI_PAGEUPEXTEND
:
3778 case SCI_PAGEDOWNEXTEND
:
3781 case SCI_EDITTOGGLEOVERTYPE
:
3782 inOverstrike
= !inOverstrike
;
3784 ShowCaretAtCurrentPosition();
3787 case SCI_CANCEL
: // Cancel any modes - handled in subclass
3788 // Also unselect text
3791 case SCI_DELETEBACK
:
3794 EnsureCaretVisible();
3796 case SCI_DELETEBACKNOTLINE
:
3799 EnsureCaretVisible();
3804 EnsureCaretVisible();
3809 EnsureCaretVisible();
3818 MovePositionTo(pdoc
->VCHomePosition(currentPos
));
3821 case SCI_VCHOMEEXTEND
:
3822 MovePositionTo(pdoc
->VCHomePosition(currentPos
), true);
3825 case SCI_VCHOMEWRAP
: {
3826 int homePos
= pdoc
->VCHomePosition(currentPos
);
3827 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
3828 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
3829 homePos
= viewLineStart
;
3831 MovePositionTo(homePos
);
3835 case SCI_VCHOMEWRAPEXTEND
: {
3836 int homePos
= pdoc
->VCHomePosition(currentPos
);
3837 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
3838 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
3839 homePos
= viewLineStart
;
3841 MovePositionTo(homePos
, true);
3846 if (vs
.zoomLevel
< 20) {
3848 InvalidateStyleRedraw();
3853 if (vs
.zoomLevel
> -10) {
3855 InvalidateStyleRedraw();
3859 case SCI_DELWORDLEFT
: {
3860 int startWord
= pdoc
->NextWordStart(currentPos
, -1);
3861 pdoc
->DeleteChars(startWord
, currentPos
- startWord
);
3865 case SCI_DELWORDRIGHT
: {
3866 int endWord
= pdoc
->NextWordStart(currentPos
, 1);
3867 pdoc
->DeleteChars(currentPos
, endWord
- currentPos
);
3870 case SCI_DELLINELEFT
: {
3871 int line
= pdoc
->LineFromPosition(currentPos
);
3872 int start
= pdoc
->LineStart(line
);
3873 pdoc
->DeleteChars(start
, currentPos
- start
);
3877 case SCI_DELLINERIGHT
: {
3878 int line
= pdoc
->LineFromPosition(currentPos
);
3879 int end
= pdoc
->LineEnd(line
);
3880 pdoc
->DeleteChars(currentPos
, end
- currentPos
);
3883 case SCI_LINECOPY
: {
3884 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
3885 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
3886 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
3887 pdoc
->LineStart(lineEnd
+ 1));
3891 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
3892 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
3893 int start
= pdoc
->LineStart(lineStart
);
3894 int end
= pdoc
->LineStart(lineEnd
+ 1);
3895 SetSelection(start
, end
);
3900 case SCI_LINEDELETE
: {
3901 int line
= pdoc
->LineFromPosition(currentPos
);
3902 int start
= pdoc
->LineStart(line
);
3903 int end
= pdoc
->LineStart(line
+ 1);
3904 pdoc
->DeleteChars(start
, end
- start
);
3907 case SCI_LINETRANSPOSE
:
3910 case SCI_LINEDUPLICATE
:
3914 ChangeCaseOfSelection(false);
3917 ChangeCaseOfSelection(true);
3919 case SCI_WORDPARTLEFT
:
3920 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1));
3923 case SCI_WORDPARTLEFTEXTEND
:
3924 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1), true);
3927 case SCI_WORDPARTRIGHT
:
3928 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1));
3931 case SCI_WORDPARTRIGHTEXTEND
:
3932 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1), true);
3935 case SCI_HOMEDISPLAY
:
3936 MovePositionTo(MovePositionSoVisible(
3937 StartEndDisplayLine(currentPos
, true), -1));
3940 case SCI_HOMEDISPLAYEXTEND
:
3941 MovePositionTo(MovePositionSoVisible(
3942 StartEndDisplayLine(currentPos
, true), -1), true);
3945 case SCI_LINEENDDISPLAY
:
3946 MovePositionTo(MovePositionSoVisible(
3947 StartEndDisplayLine(currentPos
, false), 1));
3950 case SCI_LINEENDDISPLAYEXTEND
:
3951 MovePositionTo(MovePositionSoVisible(
3952 StartEndDisplayLine(currentPos
, false), 1), true);
3959 int Editor::KeyDefault(int, int) {
3963 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
3965 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3966 (alt
? SCI_ALT
: 0);
3967 int msg
= kmap
.Find(key
, modifiers
);
3971 return WndProc(msg
, 0, 0);
3975 return KeyDefault(key
, modifiers
);
3979 void Editor::SetWhitespaceVisible(int view
) {
3980 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(view
);
3983 int Editor::GetWhitespaceVisible() {
3984 return vs
.viewWhitespace
;
3987 void Editor::Indent(bool forwards
) {
3988 //Platform::DebugPrintf("INdent %d\n", forwards);
3989 int lineOfAnchor
= pdoc
->LineFromPosition(anchor
);
3990 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
3991 if (lineOfAnchor
== lineCurrentPos
) {
3993 pdoc
->BeginUndoAction();
3995 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
3997 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3998 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
3999 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
+ indentationStep
);
4000 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4002 if (pdoc
->useTabs
) {
4003 pdoc
->InsertChar(currentPos
, '\t');
4004 SetEmptySelection(currentPos
+ 1);
4006 int numSpaces
= (pdoc
->tabInChars
) -
4007 (pdoc
->GetColumn(currentPos
) % (pdoc
->tabInChars
));
4009 numSpaces
= pdoc
->tabInChars
;
4010 for (int i
= 0; i
< numSpaces
; i
++) {
4011 pdoc
->InsertChar(currentPos
+ i
, ' ');
4013 SetEmptySelection(currentPos
+ numSpaces
);
4016 pdoc
->EndUndoAction();
4018 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
4020 pdoc
->BeginUndoAction();
4021 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4022 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
4023 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
4024 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4025 pdoc
->EndUndoAction();
4027 int newColumn
= ((pdoc
->GetColumn(currentPos
) - 1) / pdoc
->tabInChars
) *
4031 int newPos
= currentPos
;
4032 while (pdoc
->GetColumn(newPos
) > newColumn
)
4034 SetEmptySelection(newPos
);
4038 int anchorPosOnLine
= anchor
- pdoc
->LineStart(lineOfAnchor
);
4039 int currentPosPosOnLine
= currentPos
- pdoc
->LineStart(lineCurrentPos
);
4040 // Multiple lines selected so indent / dedent
4041 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
4042 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
4043 if (pdoc
->LineStart(lineBottomSel
) == anchor
|| pdoc
->LineStart(lineBottomSel
) == currentPos
)
4044 lineBottomSel
--; // If not selecting any characters on a line, do not indent
4045 pdoc
->BeginUndoAction();
4046 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
4047 pdoc
->EndUndoAction();
4048 if (lineOfAnchor
< lineCurrentPos
) {
4049 if (currentPosPosOnLine
== 0)
4050 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4052 SetSelection(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
4054 if (anchorPosOnLine
== 0)
4055 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4057 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
4063 * Search of a text in the document, in the given range.
4064 * @return The position of the found text, -1 if not found.
4066 long Editor::FindText(
4067 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4068 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4069 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
4071 TextToFind
*ft
= reinterpret_cast<TextToFind
*>(lParam
);
4072 int lengthFound
= strlen(ft
->lpstrText
);
4073 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
4074 (wParam
& SCFIND_MATCHCASE
) != 0,
4075 (wParam
& SCFIND_WHOLEWORD
) != 0,
4076 (wParam
& SCFIND_WORDSTART
) != 0,
4077 (wParam
& SCFIND_REGEXP
) != 0,
4078 (wParam
& SCFIND_POSIX
) != 0,
4081 ft
->chrgText
.cpMin
= pos
;
4082 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
4088 * Relocatable search support : Searches relative to current selection
4089 * point and sets the selection to the found text range with
4093 * Anchor following searches at current selection start: This allows
4094 * multiple incremental interactive searches to be macro recorded
4095 * while still setting the selection to found text so the find/select
4096 * operation is self-contained.
4098 void Editor::SearchAnchor() {
4099 searchAnchor
= SelectionStart();
4103 * Find text from current search anchor: Must call @c SearchAnchor first.
4104 * Used for next text and previous text requests.
4105 * @return The position of the found text, -1 if not found.
4107 long Editor::SearchText(
4108 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
4109 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4110 ///< @c SCFIND_WORDSTART or @c SCFIND_REGEXP.
4111 sptr_t lParam
) { ///< The text to search for.
4113 const char *txt
= reinterpret_cast<char *>(lParam
);
4115 int lengthFound
= strlen(txt
);
4116 if (iMessage
== SCI_SEARCHNEXT
) {
4117 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
4118 (wParam
& SCFIND_MATCHCASE
) != 0,
4119 (wParam
& SCFIND_WHOLEWORD
) != 0,
4120 (wParam
& SCFIND_WORDSTART
) != 0,
4121 (wParam
& SCFIND_REGEXP
) != 0,
4122 (wParam
& SCFIND_POSIX
) != 0,
4125 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
4126 (wParam
& SCFIND_MATCHCASE
) != 0,
4127 (wParam
& SCFIND_WHOLEWORD
) != 0,
4128 (wParam
& SCFIND_WORDSTART
) != 0,
4129 (wParam
& SCFIND_REGEXP
) != 0,
4130 (wParam
& SCFIND_POSIX
) != 0,
4135 SetSelection(pos
, pos
+ lengthFound
);
4142 * Search for text in the target range of the document.
4143 * @return The position of the found text, -1 if not found.
4145 long Editor::SearchInTarget(const char *text
, int length
) {
4146 int lengthFound
= length
;
4147 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
4148 (searchFlags
& SCFIND_MATCHCASE
) != 0,
4149 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
4150 (searchFlags
& SCFIND_WORDSTART
) != 0,
4151 (searchFlags
& SCFIND_REGEXP
) != 0,
4152 (searchFlags
& SCFIND_POSIX
) != 0,
4156 targetEnd
= pos
+ lengthFound
;
4161 void Editor::GoToLine(int lineNo
) {
4162 if (lineNo
> pdoc
->LinesTotal())
4163 lineNo
= pdoc
->LinesTotal();
4166 SetEmptySelection(pdoc
->LineStart(lineNo
));
4167 ShowCaretAtCurrentPosition();
4168 EnsureCaretVisible();
4171 static bool Close(Point pt1
, Point pt2
) {
4172 if (abs(pt1
.x
- pt2
.x
) > 3)
4174 if (abs(pt1
.y
- pt2
.y
) > 3)
4179 char *Editor::CopyRange(int start
, int end
) {
4182 int len
= end
- start
;
4183 text
= new char[len
+ 1];
4185 for (int i
= 0; i
< len
; i
++) {
4186 text
[i
] = pdoc
->CharAt(start
+ i
);
4194 void Editor::CopySelectionFromRange(SelectionText
*ss
, int start
, int end
) {
4195 ss
->Set(CopyRange(start
, end
), end
- start
+ 1, false);
4198 void Editor::CopySelectionRange(SelectionText
*ss
) {
4199 if (selType
== selRectangle
) {
4202 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4203 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4205 for (line
= lineStart
; line
<= lineEnd
; line
++) {
4206 size
+= SelectionEnd(line
) - SelectionStart(line
) + 1;
4207 if (pdoc
->eolMode
== SC_EOL_CRLF
)
4211 text
= new char[size
+ 1];
4214 for (line
= lineStart
; line
<= lineEnd
; line
++) {
4215 for (int i
= SelectionStart(line
);i
< SelectionEnd(line
);i
++) {
4216 text
[j
++] = pdoc
->CharAt(i
);
4218 if (pdoc
->eolMode
!= SC_EOL_LF
)
4220 if (pdoc
->eolMode
!= SC_EOL_CR
)
4226 ss
->Set(text
, size
+ 1, true);
4228 CopySelectionFromRange(ss
, SelectionStart(), SelectionEnd());
4232 void Editor::CopyRangeToClipboard(int start
, int end
) {
4233 start
= pdoc
->ClampPositionIntoDocument(start
);
4234 end
= pdoc
->ClampPositionIntoDocument(end
);
4235 SelectionText selectedText
;
4236 selectedText
.Set(CopyRange(start
, end
), end
- start
+ 1);
4237 CopyToClipboard(selectedText
);
4240 void Editor::CopyText(int length
, const char *text
) {
4241 SelectionText selectedText
;
4242 selectedText
.Copy(text
, length
);
4243 CopyToClipboard(selectedText
);
4246 void Editor::SetDragPosition(int newPos
) {
4248 newPos
= MovePositionOutsideChar(newPos
, 1);
4251 if (posDrag
!= newPos
) {
4260 void Editor::DisplayCursor(Window::Cursor c
) {
4261 if (cursorMode
== SC_CURSORNORMAL
)
4264 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
4267 void Editor::StartDrag() {
4268 // Always handled by subclasses
4269 //SetMouseCapture(true);
4270 //DisplayCursor(Window::cursorArrow);
4273 void Editor::DropAt(int position
, const char *value
, bool moving
, bool rectangular
) {
4274 //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
4276 dropWentOutside
= false;
4278 int positionWasInSelection
= PositionInSelection(position
);
4280 bool positionOnEdgeOfSelection
=
4281 (position
== SelectionStart()) || (position
== SelectionEnd());
4283 if ((!inDragDrop
) || !(0 == positionWasInSelection
) ||
4284 (positionOnEdgeOfSelection
&& !moving
)) {
4286 int selStart
= SelectionStart();
4287 int selEnd
= SelectionEnd();
4289 pdoc
->BeginUndoAction();
4291 int positionAfterDeletion
= position
;
4292 if (inDragDrop
&& moving
) {
4293 // Remove dragged out text
4295 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4296 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4297 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
4298 int startPos
= SelectionStart(line
);
4299 int endPos
= SelectionEnd(line
);
4300 if (position
>= startPos
) {
4301 if (position
> endPos
) {
4302 positionAfterDeletion
-= endPos
- startPos
;
4304 positionAfterDeletion
-= position
- startPos
;
4309 if (position
> selStart
) {
4310 positionAfterDeletion
-= selEnd
- selStart
;
4315 position
= positionAfterDeletion
;
4318 PasteRectangular(position
, value
, strlen(value
));
4319 pdoc
->EndUndoAction();
4320 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
4321 SetSelection(position
, position
);
4323 position
= MovePositionOutsideChar(position
, currentPos
- position
);
4324 if (pdoc
->InsertString(position
, value
)) {
4325 SetSelection(position
+ strlen(value
), position
);
4327 pdoc
->EndUndoAction();
4329 } else if (inDragDrop
) {
4330 SetSelection(position
, position
);
4334 static int BeforeInOrAfter(int val
, int minim
, int maxim
) {
4337 else if (val
> maxim
)
4343 int Editor::PositionInSelection(int pos
) {
4344 pos
= MovePositionOutsideChar(pos
, currentPos
- pos
);
4345 if (selType
== selRectangle
) {
4346 if (pos
< SelectionStart())
4348 if (pos
> SelectionEnd())
4350 int linePos
= pdoc
->LineFromPosition(pos
);
4351 return BeforeInOrAfter(pos
, SelectionStart(linePos
), SelectionEnd(linePos
));
4353 if (currentPos
> anchor
) {
4354 return BeforeInOrAfter(pos
, anchor
, currentPos
);
4355 } else if (currentPos
< anchor
) {
4356 return BeforeInOrAfter(pos
, currentPos
, anchor
);
4362 bool Editor::PointInSelection(Point pt
) {
4363 // TODO: fix up for rectangular selection
4364 int pos
= PositionFromLocation(pt
);
4365 if (0 == PositionInSelection(pos
)) {
4366 if (pos
== SelectionStart()) {
4367 // see if just before selection
4368 Point locStart
= LocationFromPosition(pos
);
4369 if (pt
.x
< locStart
.x
)
4372 if (pos
== SelectionEnd()) {
4373 // see if just after selection
4374 Point locEnd
= LocationFromPosition(pos
);
4375 if (pt
.x
> locEnd
.x
)
4383 bool Editor::PointInSelMargin(Point pt
) {
4384 // Really means: "Point in a margin"
4385 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4386 PRectangle rcSelMargin
= GetClientRectangle();
4387 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
4388 return rcSelMargin
.Contains(pt
);
4394 void Editor::LineSelection(int lineCurrent_
, int lineAnchor_
) {
4395 if (lineAnchor_
< lineCurrent_
) {
4396 SetSelection(pdoc
->LineStart(lineCurrent_
+ 1),
4397 pdoc
->LineStart(lineAnchor_
));
4398 } else if (lineAnchor_
> lineCurrent_
) {
4399 SetSelection(pdoc
->LineStart(lineCurrent_
),
4400 pdoc
->LineStart(lineAnchor_
+ 1));
4401 } else { // Same line, select it
4402 SetSelection(pdoc
->LineStart(lineAnchor_
+ 1),
4403 pdoc
->LineStart(lineAnchor_
));
4407 void Editor::DwellEnd(bool mouseMoved
) {
4409 ticksToDwell
= dwellDelay
;
4411 ticksToDwell
= SC_TIME_FOREVER
;
4412 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4414 NotifyDwelling(ptMouseLast
, dwelling
);
4418 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
4419 //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
4421 int newPos
= PositionFromLocation(pt
);
4422 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
4425 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
4429 bool inSelMargin
= PointInSelMargin(pt
);
4430 if (shift
& !inSelMargin
) {
4431 SetSelection(newPos
);
4433 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
4434 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
4435 SetMouseCapture(true);
4436 SetEmptySelection(newPos
);
4437 bool doubleClick
= false;
4438 // Stop mouse button bounce changing selection type
4439 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
4440 if (selectionType
== selChar
) {
4441 selectionType
= selWord
;
4443 } else if (selectionType
== selWord
) {
4444 selectionType
= selLine
;
4446 selectionType
= selChar
;
4447 originalAnchorPos
= currentPos
;
4451 if (selectionType
== selWord
) {
4452 if (currentPos
>= originalAnchorPos
) { // Moved forward
4453 SetSelection(pdoc
->ExtendWordSelect(currentPos
, 1),
4454 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
4455 } else { // Moved backward
4456 SetSelection(pdoc
->ExtendWordSelect(currentPos
, -1),
4457 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
4459 } else if (selectionType
== selLine
) {
4460 lineAnchor
= LineFromLocation(pt
);
4461 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
4462 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
4464 SetEmptySelection(currentPos
);
4466 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
4468 NotifyDoubleClick(pt
, shift
);
4469 if (PositionIsHotspot(newPos
))
4470 NotifyHotSpotDoubleClicked(newPos
, shift
, ctrl
, alt
);
4472 } else { // Single click
4474 selType
= selStream
;
4477 lastClickTime
= curTime
;
4481 lineAnchor
= LineFromLocation(pt
);
4482 // Single click in margin: select whole line
4483 LineSelection(lineAnchor
, lineAnchor
);
4484 SetSelection(pdoc
->LineStart(lineAnchor
+ 1),
4485 pdoc
->LineStart(lineAnchor
));
4487 // Single shift+click in margin: select from line anchor to clicked line
4488 if (anchor
> currentPos
)
4489 lineAnchor
= pdoc
->LineFromPosition(anchor
- 1);
4491 lineAnchor
= pdoc
->LineFromPosition(anchor
);
4492 int lineStart
= LineFromLocation(pt
);
4493 LineSelection(lineStart
, lineAnchor
);
4494 //lineAnchor = lineStart; // Keep the same anchor for ButtonMove
4497 SetDragPosition(invalidPosition
);
4498 SetMouseCapture(true);
4499 selectionType
= selLine
;
4501 if (PositionIsHotspot(newPos
)) {
4502 NotifyHotSpotClicked(newPos
, shift
, ctrl
, alt
);
4505 inDragDrop
= PointInSelection(pt
);
4508 SetMouseCapture(false);
4509 SetDragPosition(newPos
);
4510 CopySelectionRange(&drag
);
4513 xStartSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4514 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4515 SetDragPosition(invalidPosition
);
4516 SetMouseCapture(true);
4518 SetEmptySelection(newPos
);
4519 selType
= alt
? selRectangle
: selStream
;
4520 selectionType
= selChar
;
4521 originalAnchorPos
= currentPos
;
4525 lastClickTime
= curTime
;
4527 ShowCaretAtCurrentPosition();
4530 bool Editor::PositionIsHotspot(int position
) {
4531 return vs
.styles
[pdoc
->StyleAt(position
)].hotspot
;
4534 bool Editor::PointIsHotspot(Point pt
) {
4535 int pos
= PositionFromLocation(pt
);
4536 return PositionIsHotspot(pos
);
4539 void Editor::SetHotSpotRange(Point
*pt
) {
4541 int pos
= PositionFromLocation(*pt
);
4543 // If we don't limit this to word characters then the
4544 // range can encompass more than the run range and then
4545 // the underline will not be drawn properly.
4546 int hsStart_
= pdoc
->ExtendStyleRange(pos
, -1);
4547 int hsEnd_
= pdoc
->ExtendStyleRange(pos
, 1);
4549 // Only invalidate the range if the hotspot range has changed...
4550 if (hsStart_
!= hsStart
|| hsEnd_
!= hsEnd
) {
4551 if (hsStart
!= -1) {
4552 InvalidateRange(hsStart
, hsEnd
);
4556 InvalidateRange(hsStart
, hsEnd
);
4559 if (hsStart
!= -1) {
4560 int hsStart_
= hsStart
;
4564 InvalidateRange(hsStart_
, hsEnd_
);
4572 void Editor::GetHotSpotRange(int& hsStart_
, int& hsEnd_
) {
4577 void Editor::ButtonMove(Point pt
) {
4578 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
4582 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
4583 if (HaveMouseCapture()) {
4585 // Slow down autoscrolling/selection
4586 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
4587 if (autoScrollTimer
.ticksToWait
> 0)
4589 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
4592 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4593 int movePos
= PositionFromLocation(pt
);
4594 movePos
= MovePositionOutsideChar(movePos
, currentPos
- movePos
);
4596 SetDragPosition(movePos
);
4598 if (selectionType
== selChar
) {
4599 SetSelection(movePos
);
4600 } else if (selectionType
== selWord
) {
4601 // Continue selecting by word
4602 if (movePos
>= originalAnchorPos
) { // Moved forward
4603 SetSelection(pdoc
->ExtendWordSelect(movePos
, 1),
4604 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
4605 } else { // Moved backward
4606 SetSelection(pdoc
->ExtendWordSelect(movePos
, -1),
4607 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
4610 // Continue selecting by line
4611 int lineMove
= LineFromLocation(pt
);
4612 LineSelection(lineMove
, lineAnchor
);
4617 PRectangle rcClient
= GetClientRectangle();
4618 if (pt
.y
> rcClient
.bottom
) {
4619 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
4621 lineMove
= cs
.DisplayFromDoc(pdoc
->LinesTotal() - 1);
4623 ScrollTo(lineMove
- LinesOnScreen() + 5);
4625 } else if (pt
.y
< rcClient
.top
) {
4626 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
4627 ScrollTo(lineMove
- 5);
4630 EnsureCaretVisible(false, false, true);
4632 if (hsStart
!= -1 && !PositionIsHotspot(movePos
))
4633 SetHotSpotRange(NULL
);
4636 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4637 if (PointInSelMargin(pt
)) {
4638 DisplayCursor(Window::cursorReverseArrow
);
4639 return; // No need to test for selection
4642 // Display regular (drag) cursor over selection
4643 if (PointInSelection(pt
)) {
4644 DisplayCursor(Window::cursorArrow
);
4645 } else if (PointIsHotspot(pt
)) {
4646 DisplayCursor(Window::cursorHand
);
4647 SetHotSpotRange(&pt
);
4649 DisplayCursor(Window::cursorText
);
4650 SetHotSpotRange(NULL
);
4656 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
4657 //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
4658 if (HaveMouseCapture()) {
4659 if (PointInSelMargin(pt
)) {
4660 DisplayCursor(Window::cursorReverseArrow
);
4662 DisplayCursor(Window::cursorText
);
4663 SetHotSpotRange(NULL
);
4665 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4667 SetMouseCapture(false);
4668 int newPos
= PositionFromLocation(pt
);
4669 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
4671 int selStart
= SelectionStart();
4672 int selEnd
= SelectionEnd();
4673 if (selStart
< selEnd
) {
4676 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
4677 SetSelection(newPos
, newPos
+ drag
.len
);
4679 } else if (newPos
< selStart
) {
4680 pdoc
->DeleteChars(selStart
, drag
.len
);
4681 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
4682 SetSelection(newPos
, newPos
+ drag
.len
);
4684 } else if (newPos
> selEnd
) {
4685 pdoc
->DeleteChars(selStart
, drag
.len
);
4687 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
4688 SetSelection(newPos
, newPos
+ drag
.len
);
4691 SetEmptySelection(newPos
);
4695 selectionType
= selChar
;
4698 if (selectionType
== selChar
) {
4699 SetSelection(newPos
);
4702 lastClickTime
= curTime
;
4705 if (selType
== selStream
) {
4709 EnsureCaretVisible(false);
4713 // Called frequently to perform background UI including
4714 // caret blinking and automatic scrolling.
4715 void Editor::Tick() {
4716 if (HaveMouseCapture()) {
4718 ButtonMove(ptMouseLast
);
4720 if (caret
.period
> 0) {
4721 timer
.ticksToWait
-= timer
.tickSize
;
4722 if (timer
.ticksToWait
<= 0) {
4723 caret
.on
= !caret
.on
;
4724 timer
.ticksToWait
= caret
.period
;
4728 if ((dwellDelay
< SC_TIME_FOREVER
) &&
4729 (ticksToDwell
> 0) &&
4730 (!HaveMouseCapture())) {
4731 ticksToDwell
-= timer
.tickSize
;
4732 if (ticksToDwell
<= 0) {
4734 NotifyDwelling(ptMouseLast
, dwelling
);
4739 void Editor::SetFocusState(bool focusState
) {
4740 hasFocus
= focusState
;
4741 NotifyFocus(hasFocus
);
4743 ShowCaretAtCurrentPosition();
4750 static bool IsIn(int a
, int minimum
, int maximum
) {
4751 return (a
>= minimum
) && (a
<= maximum
);
4754 static bool IsOverlap(int mina
, int maxa
, int minb
, int maxb
) {
4756 IsIn(mina
, minb
, maxb
) ||
4757 IsIn(maxa
, minb
, maxb
) ||
4758 IsIn(minb
, mina
, maxa
) ||
4759 IsIn(maxb
, mina
, maxa
);
4762 void Editor::CheckForChangeOutsidePaint(Range r
) {
4763 if (paintState
== painting
&& !paintingAllText
) {
4764 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
4768 PRectangle rcText
= GetTextRectangle();
4769 // Determine number of lines displayed including a possible partially displayed last line
4770 int linesDisplayed
= (rcText
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1;
4771 int bottomLine
= topLine
+ linesDisplayed
- 1;
4773 int lineRangeStart
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.start
));
4774 int lineRangeEnd
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.end
));
4775 if (!IsOverlap(topLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
4776 //Platform::DebugPrintf("No overlap (%d-%d) with window(%d-%d)\n",
4777 // lineRangeStart, lineRangeEnd, topLine, bottomLine);
4781 // Assert rcPaint contained within or equal to rcText
4782 if (rcPaint
.top
> rcText
.top
) {
4783 // does range intersect rcText.top .. rcPaint.top
4784 int paintTopLine
= ((rcPaint
.top
- rcText
.top
- 1) / vs
.lineHeight
) + topLine
;
4785 // paintTopLine is the top line of the paint rectangle or the line just above if that line is completely inside the paint rectangle
4786 if (IsOverlap(topLine
, paintTopLine
, lineRangeStart
, lineRangeEnd
)) {
4787 //Platform::DebugPrintf("Change (%d-%d) in top npv(%d-%d)\n",
4788 // lineRangeStart, lineRangeEnd, topLine, paintTopLine);
4793 if (rcPaint
.bottom
< rcText
.bottom
) {
4794 // does range intersect rcPaint.bottom .. rcText.bottom
4795 int paintBottomLine
= ((rcPaint
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1) + topLine
;
4796 // paintTopLine is the bottom line of the paint rectangle or the line just below if that line is completely inside the paint rectangle
4797 if (IsOverlap(paintBottomLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
4798 //Platform::DebugPrintf("Change (%d-%d) in bottom npv(%d-%d)\n",
4799 // lineRangeStart, lineRangeEnd, paintBottomLine, bottomLine);
4807 char BraceOpposite(char ch
) {
4830 // TODO: should be able to extend styled region to find matching brace
4831 // TODO: may need to make DBCS safe
4832 // so should be moved into Document
4833 int Editor::BraceMatch(int position
, int /*maxReStyle*/) {
4834 char chBrace
= pdoc
->CharAt(position
);
4835 char chSeek
= BraceOpposite(chBrace
);
4838 char styBrace
= static_cast<char>(
4839 pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
4841 if (chBrace
== '(' || chBrace
== '[' || chBrace
== '{' || chBrace
== '<')
4844 position
= position
+ direction
;
4845 while ((position
>= 0) && (position
< pdoc
->Length())) {
4846 char chAtPos
= pdoc
->CharAt(position
);
4847 char styAtPos
= static_cast<char>(pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
4848 if ((position
> pdoc
->GetEndStyled()) || (styAtPos
== styBrace
)) {
4849 if (chAtPos
== chBrace
)
4851 if (chAtPos
== chSeek
)
4856 position
= position
+ direction
;
4861 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
4862 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
4863 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
4864 CheckForChangeOutsidePaint(Range(braces
[0]));
4865 CheckForChangeOutsidePaint(Range(pos0
));
4868 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
4869 CheckForChangeOutsidePaint(Range(braces
[1]));
4870 CheckForChangeOutsidePaint(Range(pos1
));
4873 bracesMatchStyle
= matchStyle
;
4874 if (paintState
== notPainting
) {
4880 void Editor::SetDocPointer(Document
*document
) {
4881 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
4882 pdoc
->RemoveWatcher(this, 0);
4884 if (document
== NULL
) {
4885 pdoc
= new Document();
4891 // Ensure all positions within document
4897 // Reset the contraction state to fully shown.
4899 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
4903 pdoc
->AddWatcher(this, 0);
4908 // Recursively expand a fold, making lines visible except where they have an unexpanded parent
4909 void Editor::Expand(int &line
, bool doExpand
) {
4910 int lineMaxSubord
= pdoc
->GetLastChild(line
);
4912 while (line
<= lineMaxSubord
) {
4914 cs
.SetVisible(line
, line
, true);
4915 int level
= pdoc
->GetLevel(line
);
4916 if (level
& SC_FOLDLEVELHEADERFLAG
) {
4917 if (doExpand
&& cs
.GetExpanded(line
)) {
4920 Expand(line
, false);
4928 void Editor::ToggleContraction(int line
) {
4929 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
4930 if (cs
.GetExpanded(line
)) {
4931 int lineMaxSubord
= pdoc
->GetLastChild(line
);
4932 cs
.SetExpanded(line
, 0);
4933 if (lineMaxSubord
> line
) {
4934 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
4939 cs
.SetExpanded(line
, 1);
4947 // Recurse up from this line to find any folds that prevent this line from being visible
4948 // and unfold them all->
4949 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
4951 // In case in need of wrapping to ensure DisplayFromDoc works.
4954 if (!cs
.GetVisible(lineDoc
)) {
4955 int lineParent
= pdoc
->GetFoldParent(lineDoc
);
4956 if (lineParent
>= 0) {
4957 if (lineDoc
!= lineParent
)
4958 EnsureLineVisible(lineParent
, enforcePolicy
);
4959 if (!cs
.GetExpanded(lineParent
)) {
4960 cs
.SetExpanded(lineParent
, 1);
4961 Expand(lineParent
, true);
4967 if (enforcePolicy
) {
4968 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
4969 if (visiblePolicy
& VISIBLE_SLOP
) {
4970 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
4971 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
4972 SetVerticalScrollPos();
4974 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
4975 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
4976 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
4977 SetVerticalScrollPos();
4981 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
4982 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
4983 SetVerticalScrollPos();
4990 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
4991 pdoc
->BeginUndoAction();
4993 length
= strlen(text
);
4994 if (replacePatterns
) {
4995 text
= pdoc
->SubstituteByPosition(text
, &length
);
4999 if (targetStart
!= targetEnd
)
5000 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
5001 targetEnd
= targetStart
;
5002 pdoc
->InsertString(targetStart
, text
, length
);
5003 targetEnd
= targetStart
+ length
;
5004 pdoc
->EndUndoAction();
5008 bool Editor::IsUnicodeMode() const {
5009 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
5012 int Editor::CodePage() const {
5014 return pdoc
->dbcsCodePage
;
5019 static bool ValidMargin(unsigned long wParam
) {
5020 return wParam
< ViewStyle::margins
;
5023 static char *CharPtrFromSPtr(sptr_t lParam
) {
5024 return reinterpret_cast<char *>(lParam
);
5027 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5028 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
5030 // Optional macro recording hook
5032 NotifyMacroRecord(iMessage
, wParam
, lParam
);
5041 char *ptr
= CharPtrFromSPtr(lParam
);
5042 unsigned int iChar
= 0;
5043 for (; iChar
< wParam
- 1; iChar
++)
5044 ptr
[iChar
] = pdoc
->CharAt(iChar
);
5052 pdoc
->DeleteChars(0, pdoc
->Length());
5053 SetEmptySelection(0);
5054 pdoc
->InsertString(0, CharPtrFromSPtr(lParam
));
5058 case SCI_GETTEXTLENGTH
:
5059 return pdoc
->Length();
5071 CopyRangeToClipboard(wParam
, lParam
);
5075 CopyText(wParam
, CharPtrFromSPtr(lParam
));
5081 EnsureCaretVisible();
5087 EnsureCaretVisible();
5096 return pdoc
->CanUndo() ? 1 : 0;
5098 case SCI_EMPTYUNDOBUFFER
:
5099 pdoc
->DeleteUndoHistory();
5102 case SCI_GETFIRSTVISIBLELINE
:
5105 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
5109 int lineStart
= pdoc
->LineStart(wParam
);
5110 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
5111 char *ptr
= CharPtrFromSPtr(lParam
);
5113 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
5114 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5119 case SCI_GETLINECOUNT
:
5120 if (pdoc
->LinesTotal() == 0)
5123 return pdoc
->LinesTotal();
5126 return !pdoc
->IsSavePoint();
5129 int nStart
= static_cast<int>(wParam
);
5130 int nEnd
= static_cast<int>(lParam
);
5132 nEnd
= pdoc
->Length();
5134 nStart
= nEnd
; // Remove selection
5135 selType
= selStream
;
5136 SetSelection(nEnd
, nStart
);
5137 EnsureCaretVisible();
5141 case SCI_GETSELTEXT
: {
5144 SelectionText selectedText
;
5145 CopySelectionRange(&selectedText
);
5146 char *ptr
= CharPtrFromSPtr(lParam
);
5148 if (selectedText
.len
) {
5149 for (; iChar
< selectedText
.len
; iChar
++)
5150 ptr
[iChar
] = selectedText
.s
[iChar
];
5158 case SCI_LINEFROMPOSITION
:
5159 if (static_cast<int>(wParam
) < 0)
5161 return pdoc
->LineFromPosition(wParam
);
5163 case SCI_POSITIONFROMLINE
:
5164 if (static_cast<int>(wParam
) < 0)
5165 wParam
= pdoc
->LineFromPosition(SelectionStart());
5167 return 0; // Even if there is no text, there is a first line that starts at 0
5168 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
5170 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
5172 return pdoc
->LineStart(wParam
);
5174 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
5175 case SCI_LINELENGTH
:
5176 if ((static_cast<int>(wParam
) < 0) ||
5177 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
5179 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
5181 case SCI_REPLACESEL
: {
5184 pdoc
->BeginUndoAction();
5186 char *replacement
= CharPtrFromSPtr(lParam
);
5187 pdoc
->InsertString(currentPos
, replacement
);
5188 pdoc
->EndUndoAction();
5189 SetEmptySelection(currentPos
+ strlen(replacement
));
5190 EnsureCaretVisible();
5194 case SCI_SETTARGETSTART
:
5195 targetStart
= wParam
;
5198 case SCI_GETTARGETSTART
:
5201 case SCI_SETTARGETEND
:
5205 case SCI_GETTARGETEND
:
5208 case SCI_TARGETFROMSELECTION
:
5209 if (currentPos
< anchor
) {
5210 targetStart
= currentPos
;
5213 targetStart
= anchor
;
5214 targetEnd
= currentPos
;
5218 case SCI_REPLACETARGET
:
5219 PLATFORM_ASSERT(lParam
);
5220 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), wParam
);
5222 case SCI_REPLACETARGETRE
:
5223 PLATFORM_ASSERT(lParam
);
5224 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), wParam
);
5226 case SCI_SEARCHINTARGET
:
5227 PLATFORM_ASSERT(lParam
);
5228 return SearchInTarget(CharPtrFromSPtr(lParam
), wParam
);
5230 case SCI_SETSEARCHFLAGS
:
5231 searchFlags
= wParam
;
5234 case SCI_GETSEARCHFLAGS
:
5237 case SCI_POSITIONBEFORE
:
5238 return pdoc
->MovePositionOutsideChar(wParam
-1, -1, true);
5240 case SCI_POSITIONAFTER
:
5241 return pdoc
->MovePositionOutsideChar(wParam
+1, 1, true);
5243 case SCI_LINESCROLL
:
5244 ScrollTo(topLine
+ lParam
);
5245 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
5248 case SCI_SETXOFFSET
:
5250 SetHorizontalScrollPos();
5254 case SCI_GETXOFFSET
:
5257 case SCI_CHOOSECARETX
:
5261 case SCI_SCROLLCARET
:
5262 EnsureCaretVisible();
5265 case SCI_SETREADONLY
:
5266 pdoc
->SetReadOnly(wParam
!= 0);
5269 case SCI_GETREADONLY
:
5270 return pdoc
->IsReadOnly();
5275 case SCI_POINTXFROMPOSITION
:
5279 Point pt
= LocationFromPosition(lParam
);
5283 case SCI_POINTYFROMPOSITION
:
5287 Point pt
= LocationFromPosition(lParam
);
5292 return FindText(wParam
, lParam
);
5294 case SCI_GETTEXTRANGE
: {
5297 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
5298 int cpMax
= tr
->chrg
.cpMax
;
5300 cpMax
= pdoc
->Length();
5301 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
5302 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
5303 // Spec says copied text is terminated with a NUL
5304 tr
->lpstrText
[len
] = '\0';
5305 return len
; // Not including NUL
5308 case SCI_HIDESELECTION
:
5309 hideSelection
= wParam
!= 0;
5313 case SCI_FORMATRANGE
:
5314 return FormatRange(wParam
!= 0, reinterpret_cast<RangeToFormat
*>(lParam
));
5316 case SCI_GETMARGINLEFT
:
5317 return vs
.leftMarginWidth
;
5319 case SCI_GETMARGINRIGHT
:
5320 return vs
.rightMarginWidth
;
5322 case SCI_SETMARGINLEFT
:
5323 vs
.leftMarginWidth
= lParam
;
5324 InvalidateStyleRedraw();
5327 case SCI_SETMARGINRIGHT
:
5328 vs
.rightMarginWidth
= lParam
;
5329 InvalidateStyleRedraw();
5332 // Control specific mesages
5337 pdoc
->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam
), wParam
);
5338 SetEmptySelection(currentPos
+ wParam
);
5342 case SCI_ADDSTYLEDTEXT
: {
5345 pdoc
->InsertStyledString(CurrentPosition() * 2, CharPtrFromSPtr(lParam
), wParam
);
5346 SetEmptySelection(currentPos
+ wParam
/ 2);
5350 case SCI_INSERTTEXT
: {
5353 int insertPos
= wParam
;
5354 if (static_cast<short>(wParam
) == -1)
5355 insertPos
= CurrentPosition();
5356 int newCurrent
= CurrentPosition();
5357 char *sz
= CharPtrFromSPtr(lParam
);
5358 pdoc
->InsertString(insertPos
, sz
);
5359 if (newCurrent
> insertPos
)
5360 newCurrent
+= strlen(sz
);
5361 SetEmptySelection(newCurrent
);
5365 case SCI_APPENDTEXT
:
5366 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), wParam
);
5373 case SCI_CLEARDOCUMENTSTYLE
:
5374 ClearDocumentStyle();
5377 case SCI_SETUNDOCOLLECTION
:
5378 pdoc
->SetUndoCollection(wParam
!= 0);
5381 case SCI_GETUNDOCOLLECTION
:
5382 return pdoc
->IsCollectingUndo();
5384 case SCI_BEGINUNDOACTION
:
5385 pdoc
->BeginUndoAction();
5388 case SCI_ENDUNDOACTION
:
5389 pdoc
->EndUndoAction();
5392 case SCI_GETCARETPERIOD
:
5393 return caret
.period
;
5395 case SCI_SETCARETPERIOD
:
5396 caret
.period
= wParam
;
5399 case SCI_SETWORDCHARS
: {
5402 pdoc
->SetWordChars(reinterpret_cast<unsigned char *>(lParam
));
5407 return pdoc
->Length();
5410 return pdoc
->CharAt(wParam
);
5412 case SCI_SETCURRENTPOS
:
5413 SetSelection(wParam
, anchor
);
5416 case SCI_GETCURRENTPOS
:
5420 SetSelection(currentPos
, wParam
);
5426 case SCI_SETSELECTIONSTART
:
5427 SetSelection(Platform::Maximum(currentPos
, wParam
), wParam
);
5430 case SCI_GETSELECTIONSTART
:
5431 return Platform::Minimum(anchor
, currentPos
);
5433 case SCI_SETSELECTIONEND
:
5434 SetSelection(wParam
, Platform::Minimum(anchor
, wParam
));
5437 case SCI_GETSELECTIONEND
:
5438 return Platform::Maximum(anchor
, currentPos
);
5440 case SCI_SETPRINTMAGNIFICATION
:
5441 printMagnification
= wParam
;
5444 case SCI_GETPRINTMAGNIFICATION
:
5445 return printMagnification
;
5447 case SCI_SETPRINTCOLOURMODE
:
5448 printColourMode
= wParam
;
5451 case SCI_GETPRINTCOLOURMODE
:
5452 return printColourMode
;
5454 case SCI_SETPRINTWRAPMODE
:
5455 printWrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
5458 case SCI_GETPRINTWRAPMODE
:
5459 return printWrapState
;
5461 case SCI_GETSTYLEAT
:
5462 if (static_cast<short>(wParam
) >= pdoc
->Length())
5465 return pdoc
->StyleAt(wParam
);
5475 case SCI_SETSAVEPOINT
:
5476 pdoc
->SetSavePoint();
5479 case SCI_GETSTYLEDTEXT
: {
5482 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
5484 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
5485 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
5486 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
5488 tr
->lpstrText
[iPlace
] = '\0';
5489 tr
->lpstrText
[iPlace
+ 1] = '\0';
5494 return pdoc
->CanRedo() ? 1 : 0;
5496 case SCI_MARKERLINEFROMHANDLE
:
5497 return pdoc
->LineFromHandle(wParam
);
5499 case SCI_MARKERDELETEHANDLE
:
5500 pdoc
->DeleteMarkFromHandle(wParam
);
5504 return vs
.viewWhitespace
;
5507 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
5511 case SCI_POSITIONFROMPOINT
:
5512 return PositionFromLocation(Point(wParam
, lParam
));
5514 case SCI_POSITIONFROMPOINTCLOSE
:
5515 return PositionFromLocationClose(Point(wParam
, lParam
));
5522 SetEmptySelection(wParam
);
5523 EnsureCaretVisible();
5527 case SCI_GETCURLINE
: {
5531 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
5532 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
5533 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
5534 char *ptr
= CharPtrFromSPtr(lParam
);
5535 unsigned int iPlace
= 0;
5536 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
5537 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5540 return currentPos
- lineStart
;
5543 case SCI_GETENDSTYLED
:
5544 return pdoc
->GetEndStyled();
5546 case SCI_GETEOLMODE
:
5547 return pdoc
->eolMode
;
5549 case SCI_SETEOLMODE
:
5550 pdoc
->eolMode
= wParam
;
5553 case SCI_STARTSTYLING
:
5554 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
5557 case SCI_SETSTYLING
:
5558 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
5561 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
5564 pdoc
->SetStyles(wParam
, CharPtrFromSPtr(lParam
));
5567 case SCI_SETBUFFEREDDRAW
:
5568 bufferedDraw
= wParam
!= 0;
5571 case SCI_GETBUFFEREDDRAW
:
5572 return bufferedDraw
;
5574 case SCI_GETTWOPHASEDRAW
:
5575 return twoPhaseDraw
;
5577 case SCI_SETTWOPHASEDRAW
:
5578 twoPhaseDraw
= wParam
!= 0;
5579 InvalidateStyleRedraw();
5582 case SCI_SETTABWIDTH
:
5584 pdoc
->tabInChars
= wParam
;
5585 InvalidateStyleRedraw();
5588 case SCI_GETTABWIDTH
:
5589 return pdoc
->tabInChars
;
5592 pdoc
->indentInChars
= wParam
;
5593 InvalidateStyleRedraw();
5597 return pdoc
->indentInChars
;
5599 case SCI_SETUSETABS
:
5600 pdoc
->useTabs
= wParam
!= 0;
5601 InvalidateStyleRedraw();
5604 case SCI_GETUSETABS
:
5605 return pdoc
->useTabs
;
5607 case SCI_SETLINEINDENTATION
:
5608 pdoc
->SetLineIndentation(wParam
, lParam
);
5611 case SCI_GETLINEINDENTATION
:
5612 return pdoc
->GetLineIndentation(wParam
);
5614 case SCI_GETLINEINDENTPOSITION
:
5615 return pdoc
->GetLineIndentPosition(wParam
);
5617 case SCI_SETTABINDENTS
:
5618 pdoc
->tabIndents
= wParam
!= 0;
5621 case SCI_GETTABINDENTS
:
5622 return pdoc
->tabIndents
;
5624 case SCI_SETBACKSPACEUNINDENTS
:
5625 pdoc
->backspaceUnindents
= wParam
!= 0;
5628 case SCI_GETBACKSPACEUNINDENTS
:
5629 return pdoc
->backspaceUnindents
;
5631 case SCI_SETMOUSEDWELLTIME
:
5632 dwellDelay
= wParam
;
5633 ticksToDwell
= dwellDelay
;
5636 case SCI_GETMOUSEDWELLTIME
:
5639 case SCI_WORDSTARTPOSITION
:
5640 return pdoc
->ExtendWordSelect(wParam
, -1, lParam
!= 0);
5642 case SCI_WORDENDPOSITION
:
5643 return pdoc
->ExtendWordSelect(wParam
, 1, lParam
!= 0);
5645 case SCI_SETWRAPMODE
:
5646 wrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
5648 InvalidateStyleRedraw();
5649 ReconfigureScrollBars();
5652 case SCI_GETWRAPMODE
:
5655 case SCI_SETLAYOUTCACHE
:
5656 llc
.SetLevel(wParam
);
5659 case SCI_GETLAYOUTCACHE
:
5660 return llc
.GetLevel();
5662 case SCI_SETSCROLLWIDTH
:
5663 PLATFORM_ASSERT(wParam
> 0);
5664 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
5665 scrollWidth
= wParam
;
5670 case SCI_GETSCROLLWIDTH
:
5677 case SCI_LINESSPLIT
:
5682 PLATFORM_ASSERT(wParam
<= STYLE_MAX
);
5683 PLATFORM_ASSERT(lParam
);
5684 return TextWidth(wParam
, CharPtrFromSPtr(lParam
));
5686 case SCI_TEXTHEIGHT
:
5687 return vs
.lineHeight
;
5689 case SCI_SETENDATLASTLINE
:
5690 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
5691 if (endAtLastLine
!= (wParam
!= 0)) {
5692 endAtLastLine
= wParam
!= 0;
5697 case SCI_GETENDATLASTLINE
:
5698 return endAtLastLine
;
5701 return pdoc
->GetColumn(wParam
);
5703 case SCI_SETHSCROLLBAR
:
5704 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
5705 horizontalScrollBarVisible
= wParam
!= 0;
5707 ReconfigureScrollBars();
5711 case SCI_GETHSCROLLBAR
:
5712 return horizontalScrollBarVisible
;
5714 case SCI_SETVSCROLLBAR
:
5715 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
5716 verticalScrollBarVisible
= wParam
!= 0;
5718 ReconfigureScrollBars();
5722 case SCI_GETVSCROLLBAR
:
5723 return verticalScrollBarVisible
;
5725 case SCI_SETINDENTATIONGUIDES
:
5726 vs
.viewIndentationGuides
= wParam
!= 0;
5730 case SCI_GETINDENTATIONGUIDES
:
5731 return vs
.viewIndentationGuides
;
5733 case SCI_SETHIGHLIGHTGUIDE
:
5734 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
5735 highlightGuideColumn
= wParam
;
5740 case SCI_GETHIGHLIGHTGUIDE
:
5741 return highlightGuideColumn
;
5743 case SCI_GETLINEENDPOSITION
:
5744 return pdoc
->LineEnd(wParam
);
5746 case SCI_SETCODEPAGE
:
5747 pdoc
->dbcsCodePage
= wParam
;
5748 InvalidateStyleRedraw();
5751 case SCI_GETCODEPAGE
:
5752 return pdoc
->dbcsCodePage
;
5754 case SCI_SETUSEPALETTE
:
5755 palette
.allowRealization
= wParam
!= 0;
5756 InvalidateStyleRedraw();
5759 case SCI_GETUSEPALETTE
:
5760 return palette
.allowRealization
;
5762 // Marker definition and setting
5763 case SCI_MARKERDEFINE
:
5764 if (wParam
<= MARKER_MAX
)
5765 vs
.markers
[wParam
].markType
= lParam
;
5766 InvalidateStyleData();
5769 case SCI_MARKERSETFORE
:
5770 if (wParam
<= MARKER_MAX
)
5771 vs
.markers
[wParam
].fore
.desired
= ColourDesired(lParam
);
5772 InvalidateStyleData();
5775 case SCI_MARKERSETBACK
:
5776 if (wParam
<= MARKER_MAX
)
5777 vs
.markers
[wParam
].back
.desired
= ColourDesired(lParam
);
5778 InvalidateStyleData();
5781 case SCI_MARKERADD
: {
5782 int markerID
= pdoc
->AddMark(wParam
, lParam
);
5786 case SCI_MARKERDELETE
:
5787 pdoc
->DeleteMark(wParam
, lParam
);
5790 case SCI_MARKERDELETEALL
:
5791 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
5795 return pdoc
->GetMark(wParam
);
5797 case SCI_MARKERNEXT
: {
5798 int lt
= pdoc
->LinesTotal();
5799 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
5800 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
5806 case SCI_MARKERPREVIOUS
: {
5807 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
5808 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
5814 case SCI_MARKERDEFINEPIXMAP
:
5815 if (wParam
<= MARKER_MAX
) {
5816 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
5818 InvalidateStyleData();
5822 case SCI_SETMARGINTYPEN
:
5823 if (ValidMargin(wParam
)) {
5824 vs
.ms
[wParam
].symbol
= (lParam
== SC_MARGIN_SYMBOL
);
5825 InvalidateStyleRedraw();
5829 case SCI_GETMARGINTYPEN
:
5830 if (ValidMargin(wParam
))
5831 return vs
.ms
[wParam
].symbol
? SC_MARGIN_SYMBOL
: SC_MARGIN_NUMBER
;
5835 case SCI_SETMARGINWIDTHN
:
5836 if (ValidMargin(wParam
)) {
5837 vs
.ms
[wParam
].width
= lParam
;
5838 InvalidateStyleRedraw();
5842 case SCI_GETMARGINWIDTHN
:
5843 if (ValidMargin(wParam
))
5844 return vs
.ms
[wParam
].width
;
5848 case SCI_SETMARGINMASKN
:
5849 if (ValidMargin(wParam
)) {
5850 vs
.ms
[wParam
].mask
= lParam
;
5851 InvalidateStyleRedraw();
5855 case SCI_GETMARGINMASKN
:
5856 if (ValidMargin(wParam
))
5857 return vs
.ms
[wParam
].mask
;
5861 case SCI_SETMARGINSENSITIVEN
:
5862 if (ValidMargin(wParam
)) {
5863 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
5864 InvalidateStyleRedraw();
5868 case SCI_GETMARGINSENSITIVEN
:
5869 if (ValidMargin(wParam
))
5870 return vs
.ms
[wParam
].sensitive
? 1 : 0;
5874 case SCI_STYLECLEARALL
:
5876 InvalidateStyleRedraw();
5879 case SCI_STYLESETFORE
:
5880 if (wParam
<= STYLE_MAX
) {
5881 vs
.styles
[wParam
].fore
.desired
= ColourDesired(lParam
);
5882 InvalidateStyleRedraw();
5885 case SCI_STYLESETBACK
:
5886 if (wParam
<= STYLE_MAX
) {
5887 vs
.styles
[wParam
].back
.desired
= ColourDesired(lParam
);
5888 InvalidateStyleRedraw();
5891 case SCI_STYLESETBOLD
:
5892 if (wParam
<= STYLE_MAX
) {
5893 vs
.styles
[wParam
].bold
= lParam
!= 0;
5894 InvalidateStyleRedraw();
5897 case SCI_STYLESETITALIC
:
5898 if (wParam
<= STYLE_MAX
) {
5899 vs
.styles
[wParam
].italic
= lParam
!= 0;
5900 InvalidateStyleRedraw();
5903 case SCI_STYLESETEOLFILLED
:
5904 if (wParam
<= STYLE_MAX
) {
5905 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
5906 InvalidateStyleRedraw();
5909 case SCI_STYLESETSIZE
:
5910 if (wParam
<= STYLE_MAX
) {
5911 vs
.styles
[wParam
].size
= lParam
;
5912 InvalidateStyleRedraw();
5915 case SCI_STYLESETFONT
:
5918 if (wParam
<= STYLE_MAX
) {
5919 vs
.SetStyleFontName(wParam
, CharPtrFromSPtr(lParam
));
5920 InvalidateStyleRedraw();
5923 case SCI_STYLESETUNDERLINE
:
5924 if (wParam
<= STYLE_MAX
) {
5925 vs
.styles
[wParam
].underline
= lParam
!= 0;
5926 InvalidateStyleRedraw();
5929 case SCI_STYLESETCASE
:
5930 if (wParam
<= STYLE_MAX
) {
5931 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
5932 InvalidateStyleRedraw();
5935 case SCI_STYLESETCHARACTERSET
:
5936 if (wParam
<= STYLE_MAX
) {
5937 vs
.styles
[wParam
].characterSet
= lParam
;
5938 InvalidateStyleRedraw();
5941 case SCI_STYLESETVISIBLE
:
5942 if (wParam
<= STYLE_MAX
) {
5943 vs
.styles
[wParam
].visible
= lParam
!= 0;
5944 InvalidateStyleRedraw();
5947 case SCI_STYLESETCHANGEABLE
:
5948 if (wParam
<= STYLE_MAX
) {
5949 vs
.styles
[wParam
].changeable
= lParam
!= 0;
5950 InvalidateStyleRedraw();
5953 case SCI_STYLESETHOTSPOT
:
5954 if (wParam
<= STYLE_MAX
) {
5955 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
5956 InvalidateStyleRedraw();
5960 case SCI_STYLERESETDEFAULT
:
5961 vs
.ResetDefaultStyle();
5962 InvalidateStyleRedraw();
5964 case SCI_SETSTYLEBITS
:
5965 pdoc
->SetStylingBits(wParam
);
5968 case SCI_GETSTYLEBITS
:
5969 return pdoc
->stylingBits
;
5971 case SCI_SETLINESTATE
:
5972 return pdoc
->SetLineState(wParam
, lParam
);
5974 case SCI_GETLINESTATE
:
5975 return pdoc
->GetLineState(wParam
);
5977 case SCI_GETMAXLINESTATE
:
5978 return pdoc
->GetMaxLineState();
5980 case SCI_GETCARETLINEVISIBLE
:
5981 return vs
.showCaretLineBackground
;
5982 case SCI_SETCARETLINEVISIBLE
:
5983 vs
.showCaretLineBackground
= wParam
!= 0;
5984 InvalidateStyleRedraw();
5986 case SCI_GETCARETLINEBACK
:
5987 return vs
.caretLineBackground
.desired
.AsLong();
5988 case SCI_SETCARETLINEBACK
:
5989 vs
.caretLineBackground
.desired
= wParam
;
5990 InvalidateStyleRedraw();
5995 case SCI_VISIBLEFROMDOCLINE
:
5996 return cs
.DisplayFromDoc(wParam
);
5998 case SCI_DOCLINEFROMVISIBLE
:
5999 return cs
.DocFromDisplay(wParam
);
6001 case SCI_SETFOLDLEVEL
: {
6002 int prev
= pdoc
->SetLevel(wParam
, lParam
);
6008 case SCI_GETFOLDLEVEL
:
6009 return pdoc
->GetLevel(wParam
);
6011 case SCI_GETLASTCHILD
:
6012 return pdoc
->GetLastChild(wParam
, lParam
);
6014 case SCI_GETFOLDPARENT
:
6015 return pdoc
->GetFoldParent(wParam
);
6018 cs
.SetVisible(wParam
, lParam
, true);
6024 cs
.SetVisible(wParam
, lParam
, false);
6029 case SCI_GETLINEVISIBLE
:
6030 return cs
.GetVisible(wParam
);
6032 case SCI_SETFOLDEXPANDED
:
6033 if (cs
.SetExpanded(wParam
, lParam
!= 0)) {
6038 case SCI_GETFOLDEXPANDED
:
6039 return cs
.GetExpanded(wParam
);
6041 case SCI_SETFOLDFLAGS
:
6046 case SCI_TOGGLEFOLD
:
6047 ToggleContraction(wParam
);
6050 case SCI_ENSUREVISIBLE
:
6051 EnsureLineVisible(wParam
, false);
6054 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
6055 EnsureLineVisible(wParam
, true);
6058 case SCI_SEARCHANCHOR
:
6062 case SCI_SEARCHNEXT
:
6063 case SCI_SEARCHPREV
:
6064 return SearchText(iMessage
, wParam
, lParam
);
6066 #ifdef INCLUDE_DEPRECATED_FEATURES
6067 case SCI_SETCARETPOLICY
: // Deprecated
6068 caretXPolicy
= caretYPolicy
= wParam
;
6069 caretXSlop
= caretYSlop
= lParam
;
6073 case SCI_SETXCARETPOLICY
:
6074 caretXPolicy
= wParam
;
6075 caretXSlop
= lParam
;
6078 case SCI_SETYCARETPOLICY
:
6079 caretYPolicy
= wParam
;
6080 caretYSlop
= lParam
;
6083 case SCI_SETVISIBLEPOLICY
:
6084 visiblePolicy
= wParam
;
6085 visibleSlop
= lParam
;
6088 case SCI_LINESONSCREEN
:
6089 return LinesOnScreen();
6091 case SCI_SETSELFORE
:
6092 vs
.selforeset
= wParam
!= 0;
6093 vs
.selforeground
.desired
= ColourDesired(lParam
);
6094 InvalidateStyleRedraw();
6097 case SCI_SETSELBACK
:
6098 vs
.selbackset
= wParam
!= 0;
6099 vs
.selbackground
.desired
= ColourDesired(lParam
);
6100 InvalidateStyleRedraw();
6103 case SCI_SETWHITESPACEFORE
:
6104 vs
.whitespaceForegroundSet
= wParam
!= 0;
6105 vs
.whitespaceForeground
.desired
= ColourDesired(lParam
);
6106 InvalidateStyleRedraw();
6109 case SCI_SETWHITESPACEBACK
:
6110 vs
.whitespaceBackgroundSet
= wParam
!= 0;
6111 vs
.whitespaceBackground
.desired
= ColourDesired(lParam
);
6112 InvalidateStyleRedraw();
6115 case SCI_SETCARETFORE
:
6116 vs
.caretcolour
.desired
= ColourDesired(wParam
);
6117 InvalidateStyleRedraw();
6120 case SCI_GETCARETFORE
:
6121 return vs
.caretcolour
.desired
.AsLong();
6123 case SCI_SETCARETWIDTH
:
6126 else if (wParam
>= 3)
6129 vs
.caretWidth
= wParam
;
6130 InvalidateStyleRedraw();
6133 case SCI_GETCARETWIDTH
:
6134 return vs
.caretWidth
;
6136 case SCI_ASSIGNCMDKEY
:
6137 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6138 Platform::HighShortFromLong(wParam
), lParam
);
6141 case SCI_CLEARCMDKEY
:
6142 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6143 Platform::HighShortFromLong(wParam
), SCI_NULL
);
6146 case SCI_CLEARALLCMDKEYS
:
6150 case SCI_INDICSETSTYLE
:
6151 if (wParam
<= INDIC_MAX
) {
6152 vs
.indicators
[wParam
].style
= lParam
;
6153 InvalidateStyleRedraw();
6157 case SCI_INDICGETSTYLE
:
6158 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
6160 case SCI_INDICSETFORE
:
6161 if (wParam
<= INDIC_MAX
) {
6162 vs
.indicators
[wParam
].fore
.desired
= ColourDesired(lParam
);
6163 InvalidateStyleRedraw();
6167 case SCI_INDICGETFORE
:
6168 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
6171 case SCI_LINEDOWNEXTEND
:
6173 case SCI_PARADOWNEXTEND
:
6175 case SCI_LINEUPEXTEND
:
6177 case SCI_PARAUPEXTEND
:
6179 case SCI_CHARLEFTEXTEND
:
6181 case SCI_CHARRIGHTEXTEND
:
6183 case SCI_WORDLEFTEXTEND
:
6185 case SCI_WORDRIGHTEXTEND
:
6187 case SCI_HOMEEXTEND
:
6189 case SCI_LINEENDEXTEND
:
6191 case SCI_HOMEWRAPEXTEND
:
6192 case SCI_LINEENDWRAP
:
6193 case SCI_LINEENDWRAPEXTEND
:
6194 case SCI_DOCUMENTSTART
:
6195 case SCI_DOCUMENTSTARTEXTEND
:
6196 case SCI_DOCUMENTEND
:
6197 case SCI_DOCUMENTENDEXTEND
:
6199 case SCI_PAGEUPEXTEND
:
6201 case SCI_PAGEDOWNEXTEND
:
6202 case SCI_EDITTOGGLEOVERTYPE
:
6204 case SCI_DELETEBACK
:
6210 case SCI_VCHOMEEXTEND
:
6211 case SCI_VCHOMEWRAP
:
6212 case SCI_VCHOMEWRAPEXTEND
:
6215 case SCI_DELWORDLEFT
:
6216 case SCI_DELWORDRIGHT
:
6217 case SCI_DELLINELEFT
:
6218 case SCI_DELLINERIGHT
:
6221 case SCI_LINEDELETE
:
6222 case SCI_LINETRANSPOSE
:
6223 case SCI_LINEDUPLICATE
:
6226 case SCI_LINESCROLLDOWN
:
6227 case SCI_LINESCROLLUP
:
6228 case SCI_WORDPARTLEFT
:
6229 case SCI_WORDPARTLEFTEXTEND
:
6230 case SCI_WORDPARTRIGHT
:
6231 case SCI_WORDPARTRIGHTEXTEND
:
6232 case SCI_DELETEBACKNOTLINE
:
6233 case SCI_HOMEDISPLAY
:
6234 case SCI_HOMEDISPLAYEXTEND
:
6235 case SCI_LINEENDDISPLAY
:
6236 case SCI_LINEENDDISPLAYEXTEND
:
6237 return KeyCommand(iMessage
);
6239 case SCI_BRACEHIGHLIGHT
:
6240 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
6243 case SCI_BRACEBADLIGHT
:
6244 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
6247 case SCI_BRACEMATCH
:
6248 // wParam is position of char to find brace for,
6249 // lParam is maximum amount of text to restyle to find it
6250 return BraceMatch(wParam
, lParam
);
6252 case SCI_GETVIEWEOL
:
6255 case SCI_SETVIEWEOL
:
6256 vs
.viewEOL
= wParam
!= 0;
6257 InvalidateStyleRedraw();
6261 vs
.zoomLevel
= wParam
;
6262 InvalidateStyleRedraw();
6267 return vs
.zoomLevel
;
6269 case SCI_GETEDGECOLUMN
:
6272 case SCI_SETEDGECOLUMN
:
6274 InvalidateStyleRedraw();
6277 case SCI_GETEDGEMODE
:
6278 return vs
.edgeState
;
6280 case SCI_SETEDGEMODE
:
6281 vs
.edgeState
= wParam
;
6282 InvalidateStyleRedraw();
6285 case SCI_GETEDGECOLOUR
:
6286 return vs
.edgecolour
.desired
.AsLong();
6288 case SCI_SETEDGECOLOUR
:
6289 vs
.edgecolour
.desired
= ColourDesired(wParam
);
6290 InvalidateStyleRedraw();
6293 case SCI_GETDOCPOINTER
:
6294 return reinterpret_cast<sptr_t
>(pdoc
);
6296 case SCI_SETDOCPOINTER
:
6298 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
6301 case SCI_CREATEDOCUMENT
: {
6302 Document
*doc
= new Document();
6306 return reinterpret_cast<sptr_t
>(doc
);
6309 case SCI_ADDREFDOCUMENT
:
6310 (reinterpret_cast<Document
*>(lParam
))->AddRef();
6313 case SCI_RELEASEDOCUMENT
:
6314 (reinterpret_cast<Document
*>(lParam
))->Release();
6317 case SCI_SETMODEVENTMASK
:
6318 modEventMask
= wParam
;
6321 case SCI_GETMODEVENTMASK
:
6322 return modEventMask
;
6324 case SCI_CONVERTEOLS
:
6325 pdoc
->ConvertLineEnds(wParam
);
6326 SetSelection(currentPos
, anchor
); // Ensure selection inside document
6329 case SCI_SELECTIONISRECTANGLE
:
6330 return (selType
== selRectangle
) ? 1 : 0;
6332 case SCI_SETOVERTYPE
:
6333 inOverstrike
= wParam
!= 0;
6336 case SCI_GETOVERTYPE
:
6337 return inOverstrike
? 1 : 0;
6340 SetFocusState(wParam
!= 0);
6347 errorStatus
= wParam
;
6353 case SCI_SETMOUSEDOWNCAPTURES
:
6354 mouseDownCaptures
= wParam
!= 0;
6357 case SCI_GETMOUSEDOWNCAPTURES
:
6358 return mouseDownCaptures
;
6361 cursorMode
= wParam
;
6362 DisplayCursor(Window::cursorText
);
6368 case SCI_SETCONTROLCHARSYMBOL
:
6369 controlCharSymbol
= wParam
;
6372 case SCI_GETCONTROLCHARSYMBOL
:
6373 return controlCharSymbol
;
6375 case SCI_STARTRECORD
:
6376 recordingMacro
= true;
6379 case SCI_STOPRECORD
:
6380 recordingMacro
= false;
6383 case SCI_MOVECARETINSIDEVIEW
:
6384 MoveCaretInsideView();
6387 case SCI_SETFOLDMARGINCOLOUR
:
6388 vs
.foldmarginColourSet
= wParam
!= 0;
6389 vs
.foldmarginColour
.desired
= ColourDesired(lParam
);
6390 InvalidateStyleRedraw();
6393 case SCI_SETFOLDMARGINHICOLOUR
:
6394 vs
.foldmarginHighlightColourSet
= wParam
!= 0;
6395 vs
.foldmarginHighlightColour
.desired
= ColourDesired(lParam
);
6396 InvalidateStyleRedraw();
6399 case SCI_SETHOTSPOTACTIVEFORE
:
6400 vs
.hotspotForegroundSet
= wParam
!= 0;
6401 vs
.hotspotForeground
.desired
= ColourDesired(lParam
);
6402 InvalidateStyleRedraw();
6405 case SCI_SETHOTSPOTACTIVEBACK
:
6406 vs
.hotspotBackgroundSet
= wParam
!= 0;
6407 vs
.hotspotBackground
.desired
= ColourDesired(lParam
);
6408 InvalidateStyleRedraw();
6411 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
6412 vs
.hotspotUnderline
= wParam
!= 0;
6413 InvalidateStyleRedraw();
6417 return DefWndProc(iMessage
, wParam
, lParam
);
6419 //Platform::DebugPrintf("end wnd proc\n");