1 // Scintilla source code edit control
3 ** Main code for the edit control.
4 Last change: JS 18 Jun 103 1:08 am
6 // Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
7 // The License.txt file describes the conditions under which this software may be distributed.
17 #define INCLUDE_DEPRECATED_FEATURES
19 #include "Scintilla.h"
21 #include "ContractionState.h"
23 #include "CellBuffer.h"
25 #include "Indicator.h"
27 #include "LineMarker.h"
29 #include "ViewStyle.h"
34 active(false), on(false), period(500) {}
37 ticking(false), ticksToWait(0), tickerID(0) {}
39 LineLayout::LineLayout(int maxLineLength_
) :
57 widthLine(wrapWidthInfinite
),
59 Resize(maxLineLength_
);
62 LineLayout::~LineLayout() {
66 void LineLayout::Resize(int maxLineLength_
) {
67 if (maxLineLength_
> maxLineLength
) {
69 chars
= new char[maxLineLength_
+ 1];
70 styles
= new char[maxLineLength_
+ 1];
71 indicators
= new char[maxLineLength_
+ 1];
72 // Extra position allocated as sometimes the Windows
73 // GetTextExtentExPoint API writes an extra element.
74 positions
= new int[maxLineLength_
+ 1 + 1];
75 maxLineLength
= maxLineLength_
;
79 void LineLayout::Free() {
92 void LineLayout::Invalidate(validLevel validity_
) {
93 if (validity
> validity_
)
97 void LineLayout::SetLineStart(int line
, int start
) {
98 if ((line
>= lenLineStarts
) && (line
!= 0)) {
99 int newMaxLines
= line
+ 20;
100 int *newLineStarts
= new int[newMaxLines
];
103 for (int i
= 0; i
< newMaxLines
; i
++) {
104 if (i
< lenLineStarts
)
105 newLineStarts
[i
] = lineStarts
[i
];
107 newLineStarts
[i
] = 0;
110 lineStarts
= newLineStarts
;
111 lenLineStarts
= newMaxLines
;
113 lineStarts
[line
] = start
;
116 void LineLayout::SetBracesHighlight(Range rangeLine
, Position braces
[],
117 char bracesMatchStyle
, int xHighlight
) {
118 if (rangeLine
.ContainsCharacter(braces
[0])) {
119 int braceOffset
= braces
[0] - rangeLine
.start
;
120 if (braceOffset
< numCharsInLine
) {
121 bracePreviousStyles
[0] = styles
[braceOffset
];
122 styles
[braceOffset
] = bracesMatchStyle
;
125 if (rangeLine
.ContainsCharacter(braces
[1])) {
126 int braceOffset
= braces
[1] - rangeLine
.start
;
127 if (braceOffset
< numCharsInLine
) {
128 bracePreviousStyles
[1] = styles
[braceOffset
];
129 styles
[braceOffset
] = bracesMatchStyle
;
132 if ((braces
[0] >= rangeLine
.start
&& braces
[1] <= rangeLine
.end
) ||
133 (braces
[1] >= rangeLine
.start
&& braces
[0] <= rangeLine
.end
)) {
134 xHighlightGuide
= xHighlight
;
138 void LineLayout::RestoreBracesHighlight(Range rangeLine
, Position braces
[]) {
139 if (rangeLine
.ContainsCharacter(braces
[0])) {
140 int braceOffset
= braces
[0] - rangeLine
.start
;
141 if (braceOffset
< numCharsInLine
) {
142 styles
[braceOffset
] = bracePreviousStyles
[0];
145 if (rangeLine
.ContainsCharacter(braces
[1])) {
146 int braceOffset
= braces
[1] - rangeLine
.start
;
147 if (braceOffset
< numCharsInLine
) {
148 styles
[braceOffset
] = bracePreviousStyles
[1];
154 LineLayoutCache::LineLayoutCache() :
155 level(0), length(0), size(0), cache(0),
156 allInvalidated(false), styleClock(-1) {
160 LineLayoutCache::~LineLayoutCache() {
164 void LineLayoutCache::Allocate(int length_
) {
165 allInvalidated
= false;
169 size
= (size
/ 16 + 1) * 16;
172 cache
= new LineLayout
* [size
];
174 for (int i
= 0; i
< size
; i
++)
178 void LineLayoutCache::AllocateForLevel(int linesOnScreen
, int linesInDoc
) {
179 int lengthForLevel
= 0;
180 if (level
== llcCaret
) {
182 } else if (level
== llcPage
) {
183 lengthForLevel
= linesOnScreen
+ 1;
184 } else if (level
== llcDocument
) {
185 lengthForLevel
= linesInDoc
;
187 if (lengthForLevel
> size
) {
189 } else if (lengthForLevel
< length
) {
190 for (int i
= lengthForLevel
; i
< length
; i
++) {
196 Allocate(lengthForLevel
);
200 void LineLayoutCache::Deallocate() {
201 for (int i
= 0; i
< length
; i
++)
208 void LineLayoutCache::Invalidate(LineLayout::validLevel validity_
) {
209 if (cache
&& !allInvalidated
) {
210 for (int i
= 0; i
< length
; i
++) {
212 cache
[i
]->Invalidate(validity_
);
215 if (validity_
== LineLayout::llInvalid
) {
216 allInvalidated
= true;
221 void LineLayoutCache::SetLevel(int level_
) {
222 allInvalidated
= false;
223 if ((level_
!= -1) && (level
!= level_
)) {
229 LineLayout
*LineLayoutCache::Retrieve(int lineNumber
, int lineCaret
, int maxChars
, int styleClock_
,
230 int linesOnScreen
, int linesInDoc
) {
231 AllocateForLevel(linesOnScreen
, linesInDoc
);
232 if (styleClock
!= styleClock_
) {
233 Invalidate(LineLayout::llCheckTextAndStyle
);
234 styleClock
= styleClock_
;
236 allInvalidated
= false;
239 if (((level
== llcCaret
) || (level
== llcPage
)) && (lineNumber
== lineCaret
)) {
241 } else if (level
== llcPage
) {
242 pos
= lineNumber
% length
;
243 } else if (level
== llcDocument
) {
247 if (cache
&& (pos
< length
)) {
249 if ((cache
[pos
]->lineNumber
!= lineNumber
) ||
250 (cache
[pos
]->maxLineLength
< maxChars
)) {
256 cache
[pos
] = new LineLayout(maxChars
);
259 cache
[pos
]->lineNumber
= lineNumber
;
260 cache
[pos
]->inCache
= true;
267 ret
= new LineLayout(maxChars
);
268 ret
->lineNumber
= lineNumber
;
274 void LineLayoutCache::Dispose(LineLayout
*ll
) {
275 allInvalidated
= false;
288 printMagnification
= 0;
289 printColourMode
= SC_PRINT_NORMAL
;
290 printWrapState
= eWrapWord
;
291 cursorMode
= SC_CURSORNORMAL
;
292 controlCharSymbol
= 0; /* Draw the control characters */
295 hideSelection
= false;
296 inOverstrike
= false;
298 mouseDownCaptures
= true;
304 dwellDelay
= SC_TIME_FOREVER
;
305 ticksToDwell
= SC_TIME_FOREVER
;
310 dropWentOutside
= false;
311 posDrag
= invalidPosition
;
312 posDrop
= invalidPosition
;
313 selectionType
= selChar
;
317 originalAnchorPos
= 0;
322 primarySelection
= true;
324 caretXPolicy
= CARET_SLOP
| CARET_EVEN
;
327 caretYPolicy
= CARET_EVEN
;
334 horizontalScrollBarVisible
= true;
336 verticalScrollBarVisible
= true;
337 endAtLastLine
= true;
339 pixmapLine
= Surface::Allocate();
340 pixmapSelMargin
= Surface::Allocate();
341 pixmapSelPattern
= Surface::Allocate();
342 pixmapIndentGuide
= Surface::Allocate();
343 pixmapIndentGuideHighlight
= Surface::Allocate();
356 braces
[0] = invalidPosition
;
357 braces
[1] = invalidPosition
;
358 bracesMatchStyle
= STYLE_BRACEBAD
;
359 highlightGuideColumn
= 0;
363 paintState
= notPainting
;
365 modEventMask
= SC_MODEVENTMASKALL
;
367 pdoc
= new Document();
369 pdoc
->AddWatcher(this, 0);
371 recordingMacro
= false;
374 wrapState
= eWrapNone
;
375 wrapWidth
= LineLayout::wrapWidthInfinite
;
376 docLineLastWrapped
= -1;
381 llc
.SetLevel(LineLayoutCache::llcCaret
);
385 pdoc
->RemoveWatcher(this, 0);
390 delete pixmapSelMargin
;
391 delete pixmapSelPattern
;
392 delete pixmapIndentGuide
;
393 delete pixmapIndentGuideHighlight
;
396 void Editor::Finalise() {
400 void Editor::DropGraphics() {
401 pixmapLine
->Release();
402 pixmapSelMargin
->Release();
403 pixmapSelPattern
->Release();
404 pixmapIndentGuide
->Release();
407 void Editor::InvalidateStyleData() {
411 llc
.Invalidate(LineLayout::llInvalid
);
414 void Editor::InvalidateStyleRedraw() {
416 InvalidateStyleData();
420 void Editor::RefreshColourPalette(Palette
&pal
, bool want
) {
421 vs
.RefreshColourPalette(pal
, want
);
424 void Editor::RefreshStyleData() {
427 AutoSurface
surface(this);
429 vs
.Refresh(*surface
);
430 RefreshColourPalette(palette
, true);
431 palette
.Allocate(wMain
);
432 RefreshColourPalette(palette
, false);
438 PRectangle
Editor::GetClientRectangle() {
439 return wMain
.GetClientPosition();
442 PRectangle
Editor::GetTextRectangle() {
443 PRectangle rc
= GetClientRectangle();
444 rc
.left
+= vs
.fixedColumnWidth
;
445 rc
.right
-= vs
.rightMarginWidth
;
449 int Editor::LinesOnScreen() {
450 PRectangle rcClient
= GetClientRectangle();
451 int htClient
= rcClient
.bottom
- rcClient
.top
;
452 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
453 return htClient
/ vs
.lineHeight
;
456 int Editor::LinesToScroll() {
457 int retVal
= LinesOnScreen() - 1;
464 int Editor::MaxScrollPos() {
465 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
466 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
467 int retVal
= cs
.LinesDisplayed();
469 retVal
-= LinesOnScreen();
480 static inline bool IsControlCharacter(char ch
) {
481 // iscntrl returns true for lots of chars > 127 which are displayable
482 return ch
>= 0 && ch
< ' ';
485 const char *ControlCharacterString(unsigned char ch
) {
486 const char *reps
[] = {
487 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
488 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
489 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
490 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
492 if (ch
< (sizeof(reps
) / sizeof(reps
[0]))) {
499 // Convenience class to ensure LineLayout objects are always disposed.
500 class AutoLineLayout
{
501 LineLayoutCache
&llc
;
503 AutoLineLayout
&operator=(const AutoLineLayout
&) { return * this; }
505 AutoLineLayout(LineLayoutCache
&llc_
, LineLayout
*ll_
) : llc(llc_
), ll(ll_
) {}
510 LineLayout
*operator->() const {
513 operator LineLayout
*() const {
516 void Set(LineLayout
*ll_
) {
522 Point
Editor::LocationFromPosition(int pos
) {
525 if (pos
== INVALID_POSITION
)
527 int line
= pdoc
->LineFromPosition(pos
);
528 int lineVisible
= cs
.DisplayFromDoc(line
);
529 //Platform::DebugPrintf("line=%d\n", line);
530 AutoSurface
surface(this);
531 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
533 // -1 because of adding in for visible lines in following loop.
534 pt
.y
= (lineVisible
- topLine
- 1) * vs
.lineHeight
;
536 unsigned int posLineStart
= pdoc
->LineStart(line
);
537 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
538 int posInLine
= pos
- posLineStart
;
539 // In case of very long line put x at arbitrary large position
540 if (posInLine
> ll
->maxLineLength
) {
541 pt
.x
= ll
->positions
[ll
->maxLineLength
] - ll
->positions
[ll
->LineStart(ll
->lines
)];
543 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
544 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
545 pt
.x
= ll
->positions
[posInLine
] - ll
->positions
[ll
->LineStart(subLine
)];
547 if (posInLine
>= ll
->LineStart(subLine
)) {
548 pt
.y
+= vs
.lineHeight
;
551 pt
.x
+= vs
.fixedColumnWidth
- xOffset
;
556 int Editor::XFromPosition(int pos
) {
557 Point pt
= LocationFromPosition(pos
);
558 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
561 int Editor::LineFromLocation(Point pt
) {
562 return cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
565 void Editor::SetTopLine(int topLineNew
) {
566 topLine
= topLineNew
;
567 posTopLine
= pdoc
->LineStart(topLine
);
570 static inline bool IsEOLChar(char ch
) {
571 return (ch
== '\r') || (ch
== '\n');
574 int Editor::PositionFromLocation(Point pt
) {
576 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
577 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
578 if (pt
.y
< 0) { // Division rounds towards 0
579 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
583 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
584 if (lineDoc
>= pdoc
->LinesTotal())
585 return pdoc
->Length();
586 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
587 int retVal
= posLineStart
;
588 AutoSurface
surface(this);
589 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
591 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
592 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
593 int subLine
= visibleLine
- lineStartSet
;
594 if (subLine
< ll
->lines
) {
595 int lineStart
= ll
->LineStart(subLine
);
596 int lineEnd
= ll
->LineStart(subLine
+ 1);
597 int subLineStart
= ll
->positions
[lineStart
];
598 for (int i
= lineStart
; i
< lineEnd
; i
++) {
599 if (pt
.x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
600 IsEOLChar(ll
->chars
[i
])) {
601 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
604 return lineEnd
+ posLineStart
;
606 retVal
= ll
->numCharsInLine
+ posLineStart
;
611 // Like PositionFromLocation but INVALID_POSITION returned when not near any text.
612 int Editor::PositionFromLocationClose(Point pt
) {
614 PRectangle rcClient
= GetTextRectangle();
615 if (!rcClient
.Contains(pt
))
616 return INVALID_POSITION
;
617 if (pt
.x
< vs
.fixedColumnWidth
)
618 return INVALID_POSITION
;
620 return INVALID_POSITION
;
621 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
622 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
623 if (pt
.y
< 0) { // Division rounds towards 0
624 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
626 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
628 return INVALID_POSITION
;
629 if (lineDoc
>= pdoc
->LinesTotal())
630 return INVALID_POSITION
;
631 AutoSurface
surface(this);
632 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
634 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
635 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
636 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
637 int subLine
= visibleLine
- lineStartSet
;
638 if (subLine
< ll
->lines
) {
639 int lineStart
= ll
->LineStart(subLine
);
640 int lineEnd
= ll
->LineStart(subLine
+ 1);
641 int subLineStart
= ll
->positions
[lineStart
];
642 for (int i
= lineStart
; i
< lineEnd
; i
++) {
643 if (pt
.x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
644 IsEOLChar(ll
->chars
[i
])) {
645 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
651 return INVALID_POSITION
;
655 * Find the document position corresponding to an x coordinate on a particular document line.
656 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
658 int Editor::PositionFromLineX(int lineDoc
, int x
) {
660 if (lineDoc
>= pdoc
->LinesTotal())
661 return pdoc
->Length();
662 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
663 AutoSurface
surface(this);
664 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
667 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
668 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
669 retVal
= ll
->numCharsInLine
+ posLineStart
;
671 int lineStart
= ll
->LineStart(subLine
);
672 int lineEnd
= ll
->LineStart(subLine
+ 1);
673 int subLineStart
= ll
->positions
[lineStart
];
674 for (int i
= lineStart
; i
< lineEnd
; i
++) {
675 if (x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
676 IsEOLChar(ll
->chars
[i
])) {
677 retVal
= pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
685 // If painting then abandon the painting because a wider redraw is needed.
686 // Return true if calling code should stop drawing
687 bool Editor::AbandonPaint() {
688 if ((paintState
== painting
) && !paintingAllText
) {
689 paintState
= paintAbandoned
;
691 return paintState
== paintAbandoned
;
694 void Editor::RedrawRect(PRectangle rc
) {
695 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
697 // Clip the redraw rectangle into the client area
698 PRectangle rcClient
= GetClientRectangle();
699 if (rc
.top
< rcClient
.top
)
700 rc
.top
= rcClient
.top
;
701 if (rc
.bottom
> rcClient
.bottom
)
702 rc
.bottom
= rcClient
.bottom
;
703 if (rc
.left
< rcClient
.left
)
704 rc
.left
= rcClient
.left
;
705 if (rc
.right
> rcClient
.right
)
706 rc
.right
= rcClient
.right
;
708 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
709 wMain
.InvalidateRectangle(rc
);
713 void Editor::Redraw() {
714 //Platform::DebugPrintf("Redraw all\n");
715 wMain
.InvalidateAll();
718 void Editor::RedrawSelMargin() {
719 if (!AbandonPaint()) {
723 PRectangle rcSelMargin
= GetClientRectangle();
724 rcSelMargin
.right
= vs
.fixedColumnWidth
;
725 wMain
.InvalidateRectangle(rcSelMargin
);
730 PRectangle
Editor::RectangleFromRange(int start
, int end
) {
737 int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(minPos
));
738 int lineDocMax
= pdoc
->LineFromPosition(maxPos
);
739 int maxLine
= cs
.DisplayFromDoc(lineDocMax
) + cs
.GetHeight(lineDocMax
) - 1;
740 PRectangle rcClient
= GetTextRectangle();
742 rc
.left
= vs
.fixedColumnWidth
;
743 rc
.top
= (minLine
- topLine
) * vs
.lineHeight
;
746 rc
.right
= rcClient
.right
;
747 rc
.bottom
= (maxLine
- topLine
+ 1) * vs
.lineHeight
;
748 // Ensure PRectangle is within 16 bit space
749 rc
.top
= Platform::Clamp(rc
.top
, -32000, 32000);
750 rc
.bottom
= Platform::Clamp(rc
.bottom
, -32000, 32000);
755 void Editor::InvalidateRange(int start
, int end
) {
756 RedrawRect(RectangleFromRange(start
, end
));
759 int Editor::CurrentPosition() {
763 bool Editor::SelectionEmpty() {
764 return anchor
== currentPos
;
767 int Editor::SelectionStart(int line
) {
768 if ((line
== -1) || (selType
== selStream
)) {
769 return Platform::Minimum(currentPos
, anchor
);
770 } else { // selType == selRectangle
771 int selStart
= SelectionStart();
772 int selEnd
= SelectionEnd();
773 int lineStart
= pdoc
->LineFromPosition(selStart
);
774 int lineEnd
= pdoc
->LineFromPosition(selEnd
);
775 if (line
< lineStart
|| line
> lineEnd
) {
778 int minX
= Platform::Minimum(xStartSelect
, xEndSelect
);
779 return PositionFromLineX(line
, minX
);
784 int Editor::SelectionEnd(int line
) {
785 if ((line
== -1) || (selType
== selStream
)) {
786 return Platform::Maximum(currentPos
, anchor
);
787 } else { // selType == selRectangle
788 int selStart
= SelectionStart();
789 int selEnd
= SelectionEnd();
790 int lineStart
= pdoc
->LineFromPosition(selStart
);
791 int lineEnd
= pdoc
->LineFromPosition(selEnd
);
792 if (line
< lineStart
|| line
> lineEnd
) {
795 int maxX
= Platform::Maximum(xStartSelect
, xEndSelect
);
796 // measure line and return character closest to minx
797 return PositionFromLineX(line
, maxX
);
802 void Editor::SetSelection(int currentPos_
, int anchor_
) {
803 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
804 anchor_
= pdoc
->ClampPositionIntoDocument(anchor_
);
805 if ((currentPos
!= currentPos_
) || (anchor
!= anchor_
)) {
806 int firstAffected
= anchor
;
807 if (firstAffected
> currentPos
)
808 firstAffected
= currentPos
;
809 if (firstAffected
> anchor_
)
810 firstAffected
= anchor_
;
811 if (firstAffected
> currentPos_
)
812 firstAffected
= currentPos_
;
813 int lastAffected
= anchor
;
814 if (lastAffected
< currentPos
)
815 lastAffected
= currentPos
;
816 if (lastAffected
< anchor_
)
817 lastAffected
= anchor_
;
818 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
819 lastAffected
= (currentPos_
+ 1);
820 currentPos
= currentPos_
;
823 InvalidateRange(firstAffected
, lastAffected
);
828 void Editor::SetSelection(int currentPos_
) {
829 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
830 if (currentPos
!= currentPos_
) {
831 int firstAffected
= anchor
;
832 if (firstAffected
> currentPos
)
833 firstAffected
= currentPos
;
834 if (firstAffected
> currentPos_
)
835 firstAffected
= currentPos_
;
836 int lastAffected
= anchor
;
837 if (lastAffected
< currentPos
)
838 lastAffected
= currentPos
;
839 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
840 lastAffected
= (currentPos_
+ 1);
841 currentPos
= currentPos_
;
843 InvalidateRange(firstAffected
, lastAffected
);
848 void Editor::SetEmptySelection(int currentPos_
) {
850 SetSelection(currentPos_
, currentPos_
);
853 bool Editor::RangeContainsProtected(int start
, int end
) const {
854 if (vs
.ProtectionActive()) {
860 int mask
= pdoc
->stylingBitsMask
;
861 for (int pos
= start
; pos
< end
; pos
++) {
862 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected())
869 bool Editor::SelectionContainsProtected() const {
870 // TODO: make support rectangular selection
871 return RangeContainsProtected(anchor
, currentPos
);
874 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) {
875 // Asks document to find a good position and then moves out of any invisible positions
876 pos
= pdoc
->MovePositionOutsideChar(pos
, moveDir
, checkLineEnd
);
877 if (vs
.ProtectionActive()) {
878 int mask
= pdoc
->stylingBitsMask
;
880 if ((pos
> 0) && vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()) {
881 while ((pos
< pdoc
->Length()) &&
882 (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected()))
885 } else if (moveDir
< 0) {
886 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected()) {
888 (vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()))
896 int Editor::MovePositionTo(int newPos
, bool extend
, bool ensureVisible
) {
897 int delta
= newPos
- currentPos
;
898 newPos
= pdoc
->ClampPositionIntoDocument(newPos
);
899 newPos
= MovePositionOutsideChar(newPos
, delta
);
901 SetSelection(newPos
);
903 SetEmptySelection(newPos
);
905 ShowCaretAtCurrentPosition();
907 EnsureCaretVisible();
912 int Editor::MovePositionSoVisible(int pos
, int moveDir
) {
913 pos
= pdoc
->ClampPositionIntoDocument(pos
);
914 pos
= MovePositionOutsideChar(pos
, moveDir
);
915 int lineDoc
= pdoc
->LineFromPosition(pos
);
916 if (cs
.GetVisible(lineDoc
)) {
919 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
921 // lineDisplay is already line before fold as lines in fold use display line of line after fold
922 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
923 return pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
));
925 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
926 return pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
));
931 // Choose the x position that the caret will try to stick to as it is moves up and down
932 void Editor::SetLastXChosen() {
933 Point pt
= LocationFromPosition(currentPos
);
937 void Editor::ScrollTo(int line
, bool moveThumb
) {
938 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
939 if (topLineNew
!= topLine
) {
940 // Try to optimise small scrolls
941 int linesToMove
= topLine
- topLineNew
;
942 SetTopLine(topLineNew
);
943 ShowCaretAtCurrentPosition();
944 // Perform redraw rather than scroll if many lines would be redrawn anyway.
945 if (abs(linesToMove
) <= 10) {
946 ScrollText(linesToMove
);
951 SetVerticalScrollPos();
956 void Editor::ScrollText(int /* linesToMove */) {
957 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
961 void Editor::HorizontalScrollTo(int xPos
) {
962 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
965 if ((wrapState
== eWrapNone
) && (xOffset
!= xPos
)) {
967 SetHorizontalScrollPos();
968 RedrawRect(GetClientRectangle());
972 void Editor::MoveCaretInsideView(bool ensureVisible
) {
973 PRectangle rcClient
= GetTextRectangle();
974 Point pt
= LocationFromPosition(currentPos
);
975 if (pt
.y
< rcClient
.top
) {
976 MovePositionTo(PositionFromLocation(
977 Point(lastXChosen
, rcClient
.top
)),
978 false, ensureVisible
);
979 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
980 int yOfLastLineFullyDisplayed
= rcClient
.top
+ (LinesOnScreen() - 1) * vs
.lineHeight
;
981 MovePositionTo(PositionFromLocation(
982 Point(lastXChosen
, rcClient
.top
+ yOfLastLineFullyDisplayed
)),
983 false, ensureVisible
);
987 int Editor::DisplayFromPosition(int pos
) {
988 int lineDoc
= pdoc
->LineFromPosition(pos
);
989 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
990 AutoSurface
surface(this);
991 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
993 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
994 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
995 int posInLine
= pos
- posLineStart
;
996 lineDisplay
--; // To make up for first increment ahead.
997 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
998 if (posInLine
>= ll
->LineStart(subLine
)) {
1007 * Ensure the caret is reasonably visible in context.
1009 Caret policy in SciTE
1011 If slop is set, we can define a slop value.
1012 This value defines an unwanted zone (UZ) where the caret is... unwanted.
1013 This zone is defined as a number of pixels near the vertical margins,
1014 and as a number of lines near the horizontal margins.
1015 By keeping the caret away from the edges, it is seen within its context,
1016 so it is likely that the identifier that the caret is on can be completely seen,
1017 and that the current line is seen with some of the lines following it which are
1018 often dependent on that line.
1020 If strict is set, the policy is enforced... strictly.
1021 The caret is centred on the display if slop is not set,
1022 and cannot go in the UZ if slop is set.
1024 If jumps is set, the display is moved more energetically
1025 so the caret can move in the same direction longer before the policy is applied again.
1026 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1028 If even is not set, instead of having symmetrical UZs,
1029 the left and bottom UZs are extended up to right and top UZs respectively.
1030 This way, we favour the displaying of useful information: the begining of lines,
1031 where most code reside, and the lines after the caret, eg. the body of a function.
1034 slop | strict | jumps | even | Caret can go to the margin | When reaching limit (caret going out of
1035 | | | | | visibility or going into the UZ) display is...
1036 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1037 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1038 0 | 0 | 0 | 1 | Yes | moved by one position
1039 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1040 0 | 0 | 1 | 1 | Yes | centred on the caret
1041 0 | 1 | - | 0 | Caret is always on top/on right of display | -
1042 0 | 1 | - | 1 | No, caret is always centred | -
1043 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1044 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1045 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1046 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1047 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1048 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1049 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1051 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
1052 //Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " ");
1053 PRectangle rcClient
= GetTextRectangle();
1054 //int rcClientFullWidth = rcClient.Width();
1055 int posCaret
= currentPos
;
1059 Point pt
= LocationFromPosition(posCaret
);
1060 Point ptBottomCaret
= pt
;
1061 ptBottomCaret
.y
+= vs
.lineHeight
- 1;
1062 int lineCaret
= DisplayFromPosition(posCaret
);
1063 bool bSlop
, bStrict
, bJump
, bEven
;
1065 // Vertical positioning
1066 if (vert
&& (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
> rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1067 int linesOnScreen
= LinesOnScreen();
1068 int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1069 int newTopLine
= topLine
;
1070 bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1071 bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1072 bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1073 bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1075 // It should be possible to scroll the window to show the caret,
1076 // but this fails to remove the caret on GTK+
1077 if (bSlop
) { // A margin is defined
1080 int yMarginT
, yMarginB
;
1082 // In drag mode, avoid moves
1083 // otherwise, a double click will select several lines.
1084 yMarginT
= yMarginB
= 0;
1086 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1087 // a maximum of slightly less than half the heigth of the text area.
1088 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1090 yMarginB
= yMarginT
;
1092 yMarginB
= linesOnScreen
- yMarginT
- 1;
1098 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1102 yMoveB
= linesOnScreen
- yMoveT
- 1;
1104 if (lineCaret
< topLine
+ yMarginT
) {
1105 // Caret goes too high
1106 newTopLine
= lineCaret
- yMoveT
;
1107 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1108 // Caret goes too low
1109 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1111 } else { // Not strict
1112 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1113 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1117 yMoveB
= linesOnScreen
- yMoveT
- 1;
1119 if (lineCaret
< topLine
) {
1120 // Caret goes too high
1121 newTopLine
= lineCaret
- yMoveT
;
1122 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1123 // Caret goes too low
1124 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1128 if (!bStrict
&& !bJump
) {
1130 if (lineCaret
< topLine
) {
1131 // Caret goes too high
1132 newTopLine
= lineCaret
;
1133 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1134 // Caret goes too low
1136 newTopLine
= lineCaret
- linesOnScreen
+ 1;
1138 newTopLine
= lineCaret
;
1141 } else { // Strict or going out of display
1143 // Always center caret
1144 newTopLine
= lineCaret
- halfScreen
;
1146 // Always put caret on top of display
1147 newTopLine
= lineCaret
;
1151 newTopLine
= Platform::Clamp(newTopLine
, 0, MaxScrollPos());
1152 if (newTopLine
!= topLine
) {
1154 SetTopLine(newTopLine
);
1155 SetVerticalScrollPos();
1159 // Horizontal positioning
1160 if (horiz
&& (wrapState
== eWrapNone
)) {
1161 int halfScreen
= Platform::Maximum(rcClient
.Width() - 4, 4) / 2;
1162 int xOffsetNew
= xOffset
;
1163 bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1164 bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1165 bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1166 bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1168 if (bSlop
) { // A margin is defined
1171 int xMarginL
, xMarginR
;
1173 // In drag mode, avoid moves unless very near of the margin
1174 // otherwise, a simple click will select text.
1175 xMarginL
= xMarginR
= 2;
1177 // xMargin must equal to caretXSlop, with a minimum of 2 and
1178 // a maximum of slightly less than half the width of the text area.
1179 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1181 xMarginL
= xMarginR
;
1183 xMarginL
= rcClient
.Width() - xMarginR
- 4;
1186 if (bJump
&& bEven
) {
1187 // Jump is used only in even mode
1188 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1190 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1192 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1193 // Caret is on the left of the display
1194 if (bJump
&& bEven
) {
1195 xOffsetNew
-= xMoveL
;
1197 // Move just enough to allow to display the caret
1198 xOffsetNew
-= (rcClient
.left
+ xMarginL
) - pt
.x
;
1200 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1201 // Caret is on the right of the display
1202 if (bJump
&& bEven
) {
1203 xOffsetNew
+= xMoveR
;
1205 // Move just enough to allow to display the caret
1206 xOffsetNew
+= pt
.x
- (rcClient
.right
- xMarginR
) + 1;
1209 } else { // Not strict
1210 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1211 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1215 xMoveL
= rcClient
.Width() - xMoveR
- 4;
1217 if (pt
.x
< rcClient
.left
) {
1218 // Caret is on the left of the display
1219 xOffsetNew
-= xMoveL
;
1220 } else if (pt
.x
>= rcClient
.right
) {
1221 // Caret is on the right of the display
1222 xOffsetNew
+= xMoveR
;
1227 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1228 // Strict or going out of display
1231 xOffsetNew
+= pt
.x
- rcClient
.left
- halfScreen
;
1233 // Put caret on right
1234 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1237 // Move just enough to allow to display the caret
1238 if (pt
.x
< rcClient
.left
) {
1239 // Caret is on the left of the display
1241 xOffsetNew
-= rcClient
.left
- pt
.x
;
1243 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1245 } else if (pt
.x
>= rcClient
.right
) {
1246 // Caret is on the right of the display
1247 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1251 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1252 if (pt
.x
+ xOffset
< rcClient
.left
+ xOffsetNew
) {
1253 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.left
;
1254 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ xOffsetNew
) {
1255 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.right
+ 1;
1257 if (xOffsetNew
< 0) {
1260 if (xOffset
!= xOffsetNew
) {
1261 xOffset
= xOffsetNew
;
1262 if (xOffsetNew
> 0) {
1263 PRectangle rcText
= GetTextRectangle();
1264 if (horizontalScrollBarVisible
== true &&
1265 rcText
.Width() + xOffset
> scrollWidth
) {
1266 scrollWidth
= xOffset
+ rcText
.Width();
1270 SetHorizontalScrollPos();
1276 void Editor::ShowCaretAtCurrentPosition() {
1278 caret
.active
= true;
1282 caret
.active
= false;
1288 void Editor::DropCaret() {
1289 caret
.active
= false;
1293 void Editor::InvalidateCaret() {
1295 InvalidateRange(posDrag
, posDrag
+ 1);
1297 InvalidateRange(currentPos
, currentPos
+ 1);
1300 void Editor::NeedWrapping(int docLineStartWrapping
) {
1301 if (docLineLastWrapped
> (docLineStartWrapping
- 1)) {
1302 docLineLastWrapped
= docLineStartWrapping
- 1;
1303 if (docLineLastWrapped
< -1)
1304 docLineLastWrapped
= -1;
1305 llc
.Invalidate(LineLayout::llPositions
);
1309 // Check if wrapping needed and perform any needed wrapping.
1310 // Return true if wrapping occurred.
1311 bool Editor::WrapLines() {
1312 int goodTopLine
= topLine
;
1313 bool wrapOccurred
= false;
1314 if (docLineLastWrapped
< pdoc
->LinesTotal()) {
1315 if (wrapState
== eWrapNone
) {
1316 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1317 wrapWidth
= LineLayout::wrapWidthInfinite
;
1318 for (int lineDoc
= 0; lineDoc
< pdoc
->LinesTotal(); lineDoc
++) {
1319 cs
.SetHeight(lineDoc
, 1);
1321 wrapOccurred
= true;
1323 docLineLastWrapped
= 0x7ffffff;
1326 int lineDocTop
= cs
.DocFromDisplay(topLine
);
1327 int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1328 PRectangle rcTextArea
= GetClientRectangle();
1329 rcTextArea
.left
= vs
.fixedColumnWidth
;
1330 rcTextArea
.right
-= vs
.rightMarginWidth
;
1331 wrapWidth
= rcTextArea
.Width();
1332 // Ensure all of the document is styled.
1333 pdoc
->EnsureStyledTo(pdoc
->Length());
1334 AutoSurface
surface(this);
1336 int lastLineToWrap
= pdoc
->LinesTotal();
1337 while (docLineLastWrapped
<= lastLineToWrap
) {
1338 docLineLastWrapped
++;
1339 AutoLineLayout
ll(llc
, RetrieveLineLayout(docLineLastWrapped
));
1340 int linesWrapped
= 1;
1342 LayoutLine(docLineLastWrapped
, surface
, vs
, ll
, wrapWidth
);
1343 linesWrapped
= ll
->lines
;
1345 if (cs
.SetHeight(docLineLastWrapped
, linesWrapped
)) {
1346 wrapOccurred
= true;
1350 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
);
1351 if (subLineTop
< cs
.GetHeight(lineDocTop
))
1352 goodTopLine
+= subLineTop
;
1354 goodTopLine
+= cs
.GetHeight(lineDocTop
);
1355 //double durWrap = et.Duration(true);
1356 //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap);
1361 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1362 SetVerticalScrollPos();
1364 return wrapOccurred
;
1367 void Editor::LinesJoin() {
1368 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1369 pdoc
->BeginUndoAction();
1370 bool prevNonWS
= true;
1371 for (int pos
= targetStart
; pos
< targetEnd
; pos
++) {
1372 if (IsEOLChar(pdoc
->CharAt(pos
))) {
1373 targetEnd
-= pdoc
->LenChar(pos
);
1376 // Ensure at least one space separating previous lines
1377 pdoc
->InsertChar(pos
, ' ');
1380 prevNonWS
= pdoc
->CharAt(pos
) != ' ';
1383 pdoc
->EndUndoAction();
1387 const char *StringFromEOLMode(int eolMode
) {
1388 if (eolMode
== SC_EOL_CRLF
) {
1390 } else if (eolMode
== SC_EOL_CR
) {
1397 void Editor::LinesSplit(int pixelWidth
) {
1398 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1399 if (pixelWidth
== 0) {
1400 PRectangle rcText
= GetTextRectangle();
1401 pixelWidth
= rcText
.Width();
1403 int lineStart
= pdoc
->LineFromPosition(targetStart
);
1404 int lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1405 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1406 pdoc
->BeginUndoAction();
1407 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
1408 AutoSurface
surface(this);
1409 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
1410 if (surface
&& ll
) {
1411 unsigned int posLineStart
= pdoc
->LineStart(line
);
1412 LayoutLine(line
, surface
, vs
, ll
, pixelWidth
);
1413 for (int subLine
= 1; subLine
< ll
->lines
; subLine
++) {
1414 pdoc
->InsertString(posLineStart
+ (subLine
- 1) * strlen(eol
) +
1415 ll
->LineStart(subLine
), eol
);
1416 targetEnd
+= strlen(eol
);
1420 pdoc
->EndUndoAction();
1424 int Editor::SubstituteMarkerIfEmpty(int markerCheck
, int markerDefault
) {
1425 if (vs
.markers
[markerCheck
].markType
== SC_MARK_EMPTY
)
1426 return markerDefault
;
1430 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1431 if (vs
.fixedColumnWidth
== 0)
1434 PRectangle rcMargin
= GetClientRectangle();
1435 rcMargin
.right
= vs
.fixedColumnWidth
;
1437 if (!rc
.Intersects(rcMargin
))
1442 surface
= pixmapSelMargin
;
1444 surface
= surfWindow
;
1447 PRectangle rcSelMargin
= rcMargin
;
1448 rcSelMargin
.right
= rcMargin
.left
;
1450 for (int margin
= 0; margin
< vs
.margins
; margin
++) {
1451 if (vs
.ms
[margin
].width
> 0) {
1453 rcSelMargin
.left
= rcSelMargin
.right
;
1454 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
1456 if (vs
.ms
[margin
].symbol
) {
1457 /* alternate scheme:
1458 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
1459 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1461 // Required because of special way brush is created for selection margin
1462 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
1464 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
1465 // Required because of special way brush is created for selection margin
1466 surface
->FillRectangle(rcSelMargin
, *pixmapSelPattern
);
1468 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1470 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1473 int visibleLine
= topLine
;
1476 // Work out whether the top line is whitespace located after a
1477 // lessening of fold level which implies a 'fold tail' but which should not
1478 // be displayed until the last of a sequence of whitespace.
1479 bool needWhiteClosure
= false;
1480 int level
= pdoc
->GetLevel(cs
.DocFromDisplay(topLine
));
1481 if (level
& SC_FOLDLEVELWHITEFLAG
) {
1482 int lineBack
= cs
.DocFromDisplay(topLine
);
1483 int levelPrev
= level
;
1484 while ((lineBack
> 0) && (levelPrev
& SC_FOLDLEVELWHITEFLAG
)) {
1486 levelPrev
= pdoc
->GetLevel(lineBack
);
1488 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
1489 if ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelPrev
& SC_FOLDLEVELNUMBERMASK
))
1490 needWhiteClosure
= true;
1494 // Old code does not know about new markers needed to distinguish all cases
1495 int folderOpenMid
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID
,
1496 SC_MARKNUM_FOLDEROPEN
);
1497 int folderEnd
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND
,
1500 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
1502 PLATFORM_ASSERT(visibleLine
< cs
.LinesDisplayed());
1504 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
1505 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
1506 bool firstSubLine
= visibleLine
== cs
.DisplayFromDoc(lineDoc
);
1508 // Decide which fold indicator should be displayed
1509 level
= pdoc
->GetLevel(lineDoc
);
1510 int levelNext
= pdoc
->GetLevel(lineDoc
+ 1);
1511 int marks
= pdoc
->GetMark(lineDoc
);
1514 int levelNum
= level
& SC_FOLDLEVELNUMBERMASK
;
1515 int levelNextNum
= levelNext
& SC_FOLDLEVELNUMBERMASK
;
1516 if (level
& SC_FOLDLEVELHEADERFLAG
) {
1518 if (cs
.GetExpanded(lineDoc
)) {
1519 if (levelNum
== SC_FOLDLEVELBASE
)
1520 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
1522 marks
|= 1 << folderOpenMid
;
1524 if (levelNum
== SC_FOLDLEVELBASE
)
1525 marks
|= 1 << SC_MARKNUM_FOLDER
;
1527 marks
|= 1 << folderEnd
;
1530 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1532 needWhiteClosure
= false;
1533 } else if (level
& SC_FOLDLEVELWHITEFLAG
) {
1534 if (needWhiteClosure
) {
1535 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1536 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1537 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1538 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1539 needWhiteClosure
= false;
1541 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1542 needWhiteClosure
= false;
1544 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1545 if (levelNextNum
< levelNum
) {
1546 if (levelNextNum
> SC_FOLDLEVELBASE
) {
1547 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1549 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1552 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1555 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1556 if (levelNextNum
< levelNum
) {
1557 needWhiteClosure
= false;
1558 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1559 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1560 needWhiteClosure
= true;
1561 } else if (levelNextNum
> SC_FOLDLEVELBASE
) {
1562 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1564 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1567 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1571 marks
&= vs
.ms
[margin
].mask
;
1572 PRectangle rcMarker
= rcSelMargin
;
1573 rcMarker
.top
= yposScreen
;
1574 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
1575 if (!vs
.ms
[margin
].symbol
) {
1579 sprintf(number
, "%d", lineDoc
+ 1);
1580 if (foldFlags
& SC_FOLDFLAG_LEVELNUMBERS
)
1581 sprintf(number
, "%X", pdoc
->GetLevel(lineDoc
));
1582 PRectangle rcNumber
= rcMarker
;
1584 int width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, strlen(number
));
1585 int xpos
= rcNumber
.right
- width
- 3;
1586 rcNumber
.left
= xpos
;
1587 surface
->DrawTextNoClip(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
1588 rcNumber
.top
+ vs
.maxAscent
, number
, strlen(number
),
1589 vs
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
1590 vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1594 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1596 vs
.markers
[markBit
].Draw(surface
, rcMarker
, vs
.styles
[STYLE_LINENUMBER
].font
);
1603 yposScreen
+= vs
.lineHeight
;
1608 PRectangle rcBlankMargin
= rcMargin
;
1609 rcBlankMargin
.left
= rcSelMargin
.right
;
1610 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1613 surfWindow
->Copy(rcMargin
, Point(), *pixmapSelMargin
);
1617 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
1618 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
1619 int xhead
= rcTab
.right
- 1 - ydiff
;
1620 if (xhead
<= rcTab
.left
) {
1621 ydiff
-= rcTab
.left
- xhead
- 1;
1622 xhead
= rcTab
.left
- 1;
1624 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
1625 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
1627 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1628 surface
->LineTo(rcTab
.right
- 1, ymid
);
1629 surface
->LineTo(xhead
, ymid
- ydiff
);
1630 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1631 surface
->LineTo(xhead
, ymid
+ ydiff
);
1634 static bool IsSpaceOrTab(char ch
) {
1635 return ch
== ' ' || ch
== '\t';
1638 LineLayout
*Editor::RetrieveLineLayout(int lineNumber
) {
1639 int posLineStart
= pdoc
->LineStart(lineNumber
);
1640 int posLineEnd
= pdoc
->LineStart(lineNumber
+ 1);
1641 int lineCaret
= pdoc
->LineFromPosition(currentPos
);
1642 return llc
.Retrieve(lineNumber
, lineCaret
,
1643 posLineEnd
- posLineStart
, pdoc
->GetStyleClock(),
1644 LinesOnScreen() + 1, pdoc
->LinesTotal());
1648 * Fill in the LineLayout data for the given line.
1649 * Copy the given @a line and its styles from the document into local arrays.
1650 * Also determine the x position at which each character starts.
1652 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
*ll
, int width
) {
1655 int posLineStart
= pdoc
->LineStart(line
);
1656 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1657 // If the line is very long, limit the treatment to a length that should fit in the viewport
1658 if (posLineEnd
> (posLineStart
+ ll
->maxLineLength
)) {
1659 posLineEnd
= posLineStart
+ ll
->maxLineLength
;
1661 if (ll
->validity
== LineLayout::llCheckTextAndStyle
) {
1663 for (int cid
= posLineStart
; cid
< posLineEnd
; cid
++) {
1664 char chDoc
= pdoc
->CharAt(cid
);
1665 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
1669 if (lineLength
== ll
->numCharsInLine
) {
1670 int numCharsInLine
= 0;
1671 // See if chars, styles, indicators, are all the same
1672 bool allSame
= true;
1674 int styleMask
= pdoc
->stylingBitsMask
;
1675 // Check base line layout
1676 for (int charInDoc
= posLineStart
; allSame
&& (charInDoc
< posLineEnd
); charInDoc
++) {
1677 char chDoc
= pdoc
->CharAt(charInDoc
);
1678 styleByte
= pdoc
->StyleAt(charInDoc
);
1679 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
!= '\r'))) {
1680 allSame
= allSame
&&
1681 (ll
->styles
[numCharsInLine
] == static_cast<char>(styleByte
& styleMask
));
1682 allSame
= allSame
&&
1683 (ll
->indicators
[numCharsInLine
] == static_cast<char>(styleByte
& ~styleMask
));
1684 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
1685 allSame
= allSame
&&
1686 (ll
->chars
[numCharsInLine
] == static_cast<char>(toupper(chDoc
)));
1687 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1688 allSame
= allSame
&&
1689 (ll
->chars
[numCharsInLine
] == static_cast<char>(tolower(chDoc
)));
1691 allSame
= allSame
&&
1692 (ll
->chars
[numCharsInLine
] == chDoc
);
1697 ll
->validity
= LineLayout::llPositions
;
1699 ll
->validity
= LineLayout::llInvalid
;
1702 ll
->validity
= LineLayout::llInvalid
;
1705 if (ll
->validity
== LineLayout::llInvalid
) {
1706 ll
->widthLine
= LineLayout::wrapWidthInfinite
;
1708 int numCharsInLine
= 0;
1709 if (vstyle
.edgeState
== EDGE_BACKGROUND
) {
1710 ll
->edgeColumn
= pdoc
->FindColumn(line
, theEdge
);
1711 if (ll
->edgeColumn
>= posLineStart
) {
1712 ll
->edgeColumn
-= posLineStart
;
1715 ll
->edgeColumn
= -1;
1719 int styleMask
= pdoc
->stylingBitsMask
;
1720 // Fill base line layout
1721 for (int charInDoc
= posLineStart
; charInDoc
< posLineEnd
; charInDoc
++) {
1722 char chDoc
= pdoc
->CharAt(charInDoc
);
1723 styleByte
= pdoc
->StyleAt(charInDoc
);
1724 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
1725 ll
->chars
[numCharsInLine
] = chDoc
;
1726 ll
->styles
[numCharsInLine
] = static_cast<char>(styleByte
& styleMask
);
1727 ll
->indicators
[numCharsInLine
] = static_cast<char>(styleByte
& ~styleMask
);
1728 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
1729 ll
->chars
[numCharsInLine
] = static_cast<char>(toupper(chDoc
));
1730 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1731 ll
->chars
[numCharsInLine
] = static_cast<char>(tolower(chDoc
));
1735 ll
->xHighlightGuide
= 0;
1736 // Extra element at the end of the line to hold end x position and act as
1737 ll
->chars
[numCharsInLine
] = 0; // Also triggers processing in the loops as this is a control character
1738 ll
->styles
[numCharsInLine
] = styleByte
; // For eolFilled
1739 ll
->indicators
[numCharsInLine
] = 0;
1741 // Layout the line, determining the position of each character,
1742 // with an extra element at the end for the end of the line.
1743 int startseg
= 0; // Start of the current segment, in char. number
1744 int startsegx
= 0; // Start of the current segment, in pixels
1745 ll
->positions
[0] = 0;
1746 unsigned int tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
1747 bool lastSegItalics
= false;
1748 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
1750 bool isControlNext
= IsControlCharacter(ll
->chars
[0]);
1751 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
1752 bool isControl
= isControlNext
;
1753 isControlNext
= IsControlCharacter(ll
->chars
[charInLine
+ 1]);
1754 if ((ll
->styles
[charInLine
] != ll
->styles
[charInLine
+ 1]) ||
1755 isControl
|| isControlNext
) {
1756 ll
->positions
[startseg
] = 0;
1757 if (vstyle
.styles
[ll
->styles
[charInLine
]].visible
) {
1759 if (ll
->chars
[charInLine
] == '\t') {
1760 ll
->positions
[charInLine
+ 1] = ((((startsegx
+ 2) /
1761 tabWidth
) + 1) * tabWidth
) - startsegx
;
1762 } else if (controlCharSymbol
< 32) {
1763 const char *ctrlChar
= ControlCharacterString(ll
->chars
[charInLine
]);
1764 // +3 For a blank on front and rounded edge each side:
1765 ll
->positions
[charInLine
+ 1] = surface
->WidthText(ctrlCharsFont
, ctrlChar
, strlen(ctrlChar
)) + 3;
1767 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
1768 surface
->MeasureWidths(ctrlCharsFont
, cc
, 1,
1769 ll
->positions
+ startseg
+ 1);
1771 lastSegItalics
= false;
1772 } else { // Regular character
1773 int lenSeg
= charInLine
- startseg
+ 1;
1774 if ((lenSeg
== 1) && (' ' == ll
->chars
[startseg
])) {
1775 lastSegItalics
= false;
1776 // Over half the segments are single characters and of these about half are space characters.
1777 ll
->positions
[charInLine
+ 1] = vstyle
.styles
[ll
->styles
[charInLine
]].spaceWidth
;
1779 lastSegItalics
= vstyle
.styles
[ll
->styles
[charInLine
]].italic
;
1780 surface
->MeasureWidths(vstyle
.styles
[ll
->styles
[charInLine
]].font
, ll
->chars
+ startseg
,
1781 lenSeg
, ll
->positions
+ startseg
+ 1);
1784 } else { // invisible
1785 for (int posToZero
= startseg
; posToZero
<= (charInLine
+ 1); posToZero
++) {
1786 ll
->positions
[posToZero
] = 0;
1789 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
1790 ll
->positions
[posToIncrease
] += startsegx
;
1792 startsegx
= ll
->positions
[charInLine
+ 1];
1793 startseg
= charInLine
+ 1;
1796 // Small hack to make lines that end with italics not cut off the edge of the last character
1797 if ((startseg
> 0) && lastSegItalics
) {
1798 ll
->positions
[startseg
] += 2;
1800 ll
->numCharsInLine
= numCharsInLine
;
1801 ll
->validity
= LineLayout::llPositions
;
1803 // Hard to cope when too narrow, so just assume there is space
1807 if ((ll
->validity
== LineLayout::llPositions
) || (ll
->widthLine
!= width
)) {
1808 ll
->widthLine
= width
;
1809 if (width
== LineLayout::wrapWidthInfinite
) {
1811 } else if (width
> ll
->positions
[ll
->numCharsInLine
]) {
1812 // Simple common case where line does not need wrapping.
1816 // Calculate line start positions based upon width.
1817 // For now this is simplistic - wraps on byte rather than character and
1818 // in the middle of words. Should search for spaces or style changes.
1819 int lastGoodBreak
= 0;
1820 int lastLineStart
= 0;
1821 int startOffset
= 0;
1823 while (p
< ll
->numCharsInLine
) {
1824 if ((ll
->positions
[p
+ 1] - startOffset
) >= width
) {
1825 if (lastGoodBreak
== lastLineStart
) {
1826 // Try moving to start of last character
1828 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
1831 if (lastGoodBreak
== lastLineStart
) {
1832 // Ensure at least one character on line.
1833 lastGoodBreak
= pdoc
->MovePositionOutsideChar(lastGoodBreak
+ posLineStart
+ 1, 1)
1837 lastLineStart
= lastGoodBreak
;
1839 ll
->SetLineStart(ll
->lines
, lastGoodBreak
);
1840 startOffset
= ll
->positions
[lastGoodBreak
];
1841 p
= lastGoodBreak
+ 1;
1845 if (ll
->styles
[p
] != ll
->styles
[p
- 1]) {
1847 } else if (IsSpaceOrTab(ll
->chars
[p
- 1]) && !IsSpaceOrTab(ll
->chars
[p
])) {
1855 ll
->validity
= LineLayout::llLines
;
1859 ColourAllocated
Editor::TextBackground(ViewStyle
&vsDraw
, bool overrideBackground
,
1860 ColourAllocated background
, bool inSelection
, bool inHotspot
, int styleMain
, int i
, LineLayout
*ll
) {
1862 if (vsDraw
.selbackset
) {
1863 if (primarySelection
)
1864 return vsDraw
.selbackground
.allocated
;
1866 return vsDraw
.selbackground2
.allocated
;
1869 if ((vsDraw
.edgeState
== EDGE_BACKGROUND
) &&
1870 (i
>= ll
->edgeColumn
) &&
1871 !IsEOLChar(ll
->chars
[i
]))
1872 return vsDraw
.edgecolour
.allocated
;
1874 return vsDraw
.hotspotBackground
.allocated
;
1875 if (overrideBackground
)
1878 return vsDraw
.styles
[styleMain
].back
.allocated
;
1881 void Editor::DrawIndentGuide(Surface
*surface
, int lineVisible
, int lineHeight
, int start
, PRectangle rcSegment
, bool highlight
) {
1882 Point
from(0, ((lineVisible
& 1) && (lineHeight
& 1)) ? 1 : 0);
1883 PRectangle
rcCopyArea(start
+ 1, rcSegment
.top
, start
+ 2, rcSegment
.bottom
);
1884 surface
->Copy(rcCopyArea
, from
,
1885 highlight
? *pixmapIndentGuideHighlight
: *pixmapIndentGuide
);
1888 void Editor::DrawEOL(Surface
*surface
, ViewStyle
&vsDraw
, PRectangle rcLine
, LineLayout
*ll
,
1889 int line
, int lineEnd
, int xStart
, int subLine
, int subLineStart
,
1890 bool overrideBackground
, ColourAllocated background
) {
1892 int styleMask
= pdoc
->stylingBitsMask
;
1893 PRectangle rcSegment
= rcLine
;
1895 // Fill in a PRectangle representing the end of line characters
1896 int xEol
= ll
->positions
[lineEnd
] - subLineStart
;
1897 rcSegment
.left
= xEol
+ xStart
;
1898 rcSegment
.right
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
1899 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1900 bool eolInSelection
= (subLine
== (ll
->lines
- 1)) &&
1901 (posLineEnd
> ll
->selStart
) && (posLineEnd
<= ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
1902 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1)) {
1903 if (primarySelection
)
1904 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground
.allocated
);
1906 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground2
.allocated
);
1907 } else if (overrideBackground
) {
1908 surface
->FillRectangle(rcSegment
, background
);
1910 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
1913 rcSegment
.left
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
1914 rcSegment
.right
= rcLine
.right
;
1915 if (overrideBackground
) {
1916 surface
->FillRectangle(rcSegment
, background
);
1917 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
1918 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
1920 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
1924 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int lineVisible
, int xStart
,
1925 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
1927 PRectangle rcSegment
= rcLine
;
1929 // Using one font for all control characters so it can be controlled independently to ensure
1930 // the box goes around the characters tightly. Seems to be no way to work out what height
1931 // is taken by an individual character - internal leading gives varying results.
1932 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
1934 // See if something overrides the line background color: Either if caret is on the line
1935 // and background color is set for that, or if a marker is defined that forces its background
1936 // color onto the line, or if a marker is defined but has no selection margin in which to
1937 // display itself. These are checked in order with the earlier taking precedence. When
1938 // multiple markers cause background override, the color for the highest numbered one is used.
1939 bool overrideBackground
= false;
1940 ColourAllocated background
;
1941 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& ll
->containsCaret
) {
1942 overrideBackground
= true;
1943 background
= vsDraw
.caretLineBackground
.allocated
;
1945 if (!overrideBackground
) {
1946 int marks
= pdoc
->GetMark(line
);
1947 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1948 if ((marks
& 1) && vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
) {
1949 background
= vsDraw
.markers
[markBit
].back
.allocated
;
1950 overrideBackground
= true;
1955 if (!overrideBackground
) {
1956 if (vsDraw
.maskInLine
) {
1957 int marks
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
1959 overrideBackground
= true;
1960 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1962 background
= vsDraw
.markers
[markBit
].back
.allocated
;
1970 bool drawWhitespaceBackground
= (vsDraw
.viewWhitespace
!= wsInvisible
) &&
1971 (!overrideBackground
) && (vsDraw
.whitespaceBackgroundSet
);
1973 bool inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
1974 int indentWidth
= pdoc
->indentInChars
* vsDraw
.spaceWidth
;
1975 if (indentWidth
== 0)
1976 indentWidth
= pdoc
->tabInChars
* vsDraw
.spaceWidth
;
1978 int posLineStart
= pdoc
->LineStart(line
);
1980 int startseg
= ll
->LineStart(subLine
);
1981 int subLineStart
= ll
->positions
[startseg
];
1984 if (subLine
< ll
->lines
) {
1985 lineStart
= ll
->LineStart(subLine
);
1986 lineEnd
= ll
->LineStart(subLine
+ 1);
1990 // Background drawing loop
1991 for (i
= lineStart
; twoPhaseDraw
&& (i
< lineEnd
); i
++) {
1993 int iDoc
= i
+ posLineStart
;
1994 // If there is the end of a style run for any reason
1995 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
1996 i
== (lineEnd
- 1) ||
1997 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
1998 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
1999 (i
== (ll
->edgeColumn
- 1))) {
2000 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2001 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2002 // Only try to draw if really visible - enhances performance by not calling environment to
2003 // draw strings that are completely past the right side of the window.
2004 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2005 int styleMain
= ll
->styles
[i
];
2006 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2007 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2008 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2009 if (ll
->chars
[i
] == '\t') {
2011 if (drawWhitespaceBackground
&&
2012 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2013 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2014 surface
->FillRectangle(rcSegment
, textBack
);
2015 } else if (IsControlCharacter(ll
->chars
[i
])) {
2016 // Control character display
2017 inIndentation
= false;
2018 surface
->FillRectangle(rcSegment
, textBack
);
2020 // Normal text display
2021 surface
->FillRectangle(rcSegment
, textBack
);
2022 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2023 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
2024 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2025 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2026 if (drawWhitespaceBackground
&&
2027 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2028 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
,
2029 ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2030 surface
->FillRectangle(rcSpace
, vsDraw
.whitespaceBackground
.allocated
);
2033 inIndentation
= false;
2044 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2045 xStart
, subLine
, subLineStart
, overrideBackground
, background
);
2048 inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2049 startseg
= ll
->LineStart(subLine
);
2050 // Foreground drawing loop
2051 for (i
= lineStart
; i
< lineEnd
; i
++) {
2053 int iDoc
= i
+ posLineStart
;
2054 // If there is the end of a style run for any reason
2055 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
2056 i
== (lineEnd
- 1) ||
2057 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
2058 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
2059 (i
== (ll
->edgeColumn
- 1))) {
2060 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2061 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2062 // Only try to draw if really visible - enhances performance by not calling environment to
2063 // draw strings that are completely past the right side of the window.
2064 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2065 int styleMain
= ll
->styles
[i
];
2066 ColourAllocated textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
2067 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
2068 //hotspot foreground
2069 if (ll
->hsStart
!= -1 && iDoc
>= ll
->hsStart
&& iDoc
< hsEnd
) {
2070 if (vsDraw
.hotspotForegroundSet
)
2071 textFore
= vsDraw
.hotspotForeground
.allocated
;
2073 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2074 if (inSelection
&& (vsDraw
.selforeset
)) {
2075 textFore
= vsDraw
.selforeground
.allocated
;
2077 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2078 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2079 if (ll
->chars
[i
] == '\t') {
2081 if (!twoPhaseDraw
) {
2082 if (drawWhitespaceBackground
&&
2083 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2084 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2085 surface
->FillRectangle(rcSegment
, textBack
);
2087 if ((vsDraw
.viewWhitespace
!= wsInvisible
) || ((inIndentation
&& vsDraw
.viewIndentationGuides
))) {
2088 if (vsDraw
.whitespaceForegroundSet
)
2089 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2090 surface
->PenColour(textFore
);
2092 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
2093 for (int xIG
= ll
->positions
[i
] / indentWidth
* indentWidth
; xIG
< ll
->positions
[i
+ 1]; xIG
+= indentWidth
) {
2094 if (xIG
>= ll
->positions
[i
] && xIG
> 0) {
2095 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIG
+ xStart
, rcSegment
,
2096 (ll
->xHighlightGuide
== xIG
));
2100 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2101 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2102 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
2103 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
2104 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
2107 } else if (IsControlCharacter(ll
->chars
[i
])) {
2108 // Control character display
2109 inIndentation
= false;
2110 if (controlCharSymbol
< 32) {
2111 // Draw the character
2112 const char *ctrlChar
= ControlCharacterString(ll
->chars
[i
]);
2113 if (!twoPhaseDraw
) {
2114 surface
->FillRectangle(rcSegment
, textBack
);
2116 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
2117 surface
->InternalLeading(ctrlCharsFont
);
2118 PRectangle rcCChar
= rcSegment
;
2119 rcCChar
.left
= rcCChar
.left
+ 1;
2120 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
2121 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
2122 PRectangle rcCentral
= rcCChar
;
2125 surface
->FillRectangle(rcCentral
, textFore
);
2126 PRectangle rcChar
= rcCChar
;
2129 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
2130 rcSegment
.top
+ vsDraw
.maxAscent
, ctrlChar
, strlen(ctrlChar
),
2131 textBack
, textFore
);
2133 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
2134 surface
->DrawTextNoClip(rcSegment
, ctrlCharsFont
,
2135 rcSegment
.top
+ vsDraw
.maxAscent
,
2136 cc
, 1, textBack
, textFore
);
2139 // Normal text display
2140 if (vsDraw
.styles
[styleMain
].visible
) {
2142 surface
->DrawTextTransparent(rcSegment
, textFont
,
2143 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2144 i
- startseg
+ 1, textFore
);
2146 surface
->DrawTextNoClip(rcSegment
, textFont
,
2147 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2148 i
- startseg
+ 1, textFore
, textBack
);
2151 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2152 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
2153 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2154 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2155 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2156 if (vsDraw
.whitespaceForegroundSet
)
2157 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2158 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2159 int xmid
= (ll
->positions
[cpos
+ startseg
] + ll
->positions
[cpos
+ startseg
+ 1]) / 2;
2160 if (!twoPhaseDraw
&& drawWhitespaceBackground
&&
2161 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2162 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2163 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
, ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2164 surface
->FillRectangle(rcSpace
, textBack
);
2166 PRectangle
rcDot(xmid
+ xStart
- subLineStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
2167 rcDot
.right
= rcDot
.left
+ 1;
2168 rcDot
.bottom
= rcDot
.top
+ 1;
2169 surface
->FillRectangle(rcDot
, textFore
);
2172 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
2173 int startSpace
= ll
->positions
[cpos
+ startseg
];
2174 if (startSpace
> 0 && (startSpace
% indentWidth
== 0)) {
2175 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, startSpace
+ xStart
, rcSegment
,
2176 (ll
->xHighlightGuide
== ll
->positions
[cpos
+ startseg
]));
2180 inIndentation
= false;
2185 if (ll
->hsStart
!= -1 && vsDraw
.hotspotUnderline
&& iDoc
>= ll
->hsStart
&& iDoc
< ll
->hsEnd
) {
2186 PRectangle rcUL
= rcSegment
;
2187 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2188 rcUL
.bottom
= rcUL
.top
+ 1;
2189 if (vsDraw
.hotspotForegroundSet
)
2190 surface
->FillRectangle(rcUL
, vsDraw
.hotspotForeground
.allocated
);
2192 surface
->FillRectangle(rcUL
, textFore
);
2193 } else if (vsDraw
.styles
[styleMain
].underline
) {
2194 PRectangle rcUL
= rcSegment
;
2195 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2196 rcUL
.bottom
= rcUL
.top
+ 1;
2197 surface
->FillRectangle(rcUL
, textFore
);
2205 int indStart
[INDIC_MAX
+ 1] = {0};
2206 for (int indica
= 0; indica
<= INDIC_MAX
; indica
++)
2207 indStart
[indica
] = 0;
2209 for (int indicPos
= 0; indicPos
< ll
->numCharsInLine
; indicPos
++) {
2210 if (ll
->indicators
[indicPos
] != ll
->indicators
[indicPos
+ 1]) {
2211 int mask
= 1 << pdoc
->stylingBits
;
2212 for (int indicnum
= 0; mask
< 0x100; indicnum
++) {
2213 if ((ll
->indicators
[indicPos
+ 1] & mask
) && !(ll
->indicators
[indicPos
] & mask
)) {
2214 indStart
[indicnum
] = ll
->positions
[indicPos
+ 1];
2216 if (!(ll
->indicators
[indicPos
+ 1] & mask
) && (ll
->indicators
[indicPos
] & mask
)) {
2218 indStart
[indicnum
] + xStart
,
2219 rcLine
.top
+ vsDraw
.maxAscent
,
2220 ll
->positions
[indicPos
+ 1] + xStart
,
2221 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
2222 vsDraw
.indicators
[indicnum
].Draw(surface
, rcIndic
);
2228 // End of the drawing of the current line
2230 if (!twoPhaseDraw
) {
2231 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2232 xStart
, subLine
, subLineStart
, overrideBackground
, background
);
2235 if (vsDraw
.edgeState
== EDGE_LINE
) {
2236 int edgeX
= theEdge
* vsDraw
.spaceWidth
;
2237 rcSegment
.left
= edgeX
+ xStart
;
2238 rcSegment
.right
= rcSegment
.left
+ 1;
2239 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
.allocated
);
2243 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
2244 if (!pixmapSelPattern
->Initialised()) {
2245 const int patternSize
= 8;
2246 pixmapSelPattern
->InitPixMap(patternSize
, patternSize
, surfaceWindow
, wMain
.GetID());
2247 // This complex procedure is to reproduce the checkerboard dithered pattern used by windows
2248 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
2249 // way between the chrome colour and the chrome highlight colour making a nice transition
2250 // between the window chrome and the content area. And it works in low colour depths.
2251 PRectangle
rcPattern(0, 0, patternSize
, patternSize
);
2253 // Initialize default colours based on the chrome colour scheme. Typically the highlight is white.
2254 ColourAllocated colourFMFill
= vs
.selbar
.allocated
;
2255 ColourAllocated colourFMStripes
= vs
.selbarlight
.allocated
;
2257 if (!(vs
.selbarlight
.desired
== ColourDesired(0xff, 0xff, 0xff))) {
2258 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
2259 // (Typically, the highlight colour is white.)
2260 colourFMFill
= vs
.selbarlight
.allocated
;
2263 if (vs
.foldmarginColourSet
) {
2264 // override default fold margin colour
2265 colourFMFill
= vs
.foldmarginColour
.allocated
;
2267 if (vs
.foldmarginHighlightColourSet
) {
2268 // override default fold margin highlight colour
2269 colourFMStripes
= vs
.foldmarginHighlightColour
.allocated
;
2272 pixmapSelPattern
->FillRectangle(rcPattern
, colourFMFill
);
2273 pixmapSelPattern
->PenColour(colourFMStripes
);
2274 for (int stripe
= 0; stripe
< patternSize
; stripe
++) {
2275 // Alternating 1 pixel stripes is same as checkerboard.
2276 pixmapSelPattern
->MoveTo(0, stripe
* 2);
2277 pixmapSelPattern
->LineTo(patternSize
, stripe
* 2 - patternSize
);
2281 if (!pixmapIndentGuide
->Initialised()) {
2282 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
2283 pixmapIndentGuide
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2284 pixmapIndentGuideHighlight
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2285 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
2286 pixmapIndentGuide
->FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
.allocated
);
2287 pixmapIndentGuide
->PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
2288 pixmapIndentGuideHighlight
->FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
.allocated
);
2289 pixmapIndentGuideHighlight
->PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
2290 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
2291 pixmapIndentGuide
->MoveTo(0, stripe
);
2292 pixmapIndentGuide
->LineTo(2, stripe
);
2293 pixmapIndentGuideHighlight
->MoveTo(0, stripe
);
2294 pixmapIndentGuideHighlight
->LineTo(2, stripe
);
2299 if (!pixmapLine
->Initialised()) {
2300 PRectangle rcClient
= GetClientRectangle();
2301 pixmapLine
->InitPixMap(rcClient
.Width(), rcClient
.Height(),
2302 surfaceWindow
, wMain
.GetID());
2303 pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
2304 rcClient
.Height(), surfaceWindow
, wMain
.GetID());
2309 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
2310 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
2311 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
2315 RefreshPixMaps(surfaceWindow
);
2317 PRectangle rcClient
= GetClientRectangle();
2318 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
2319 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
2321 surfaceWindow
->SetPalette(&palette
, true);
2322 pixmapLine
->SetPalette(&palette
, !hasFocus
);
2324 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
2325 // The area to be painted plus one extra line is styled.
2326 // The extra line is to determine when a style change, such as starting a comment flows on to other lines.
2327 int lineStyleLast
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
2328 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
2329 int endPosPaint
= pdoc
->Length();
2330 if (lineStyleLast
< cs
.LinesDisplayed())
2331 endPosPaint
= pdoc
->LineStart(cs
.DocFromDisplay(lineStyleLast
+ 1));
2333 int xStart
= vs
.fixedColumnWidth
- xOffset
;
2336 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
2337 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
2339 // Ensure we are styled as far as we are painting.
2340 pdoc
->EnsureStyledTo(endPosPaint
);
2341 bool paintAbandonedByStyling
= paintState
== paintAbandoned
;
2344 needUpdateUI
= false;
2347 PaintSelMargin(surfaceWindow
, rcArea
);
2350 // The wrapping process has changed the height of some lines so abandon this
2351 // paint for a complete repaint.
2352 if (AbandonPaint()) {
2357 // Workaround by JACS: sometimes due to a re-entry condition,
2358 // pixmapLine becomes uninitialised, followed by a crash.
2359 if (!pixmapLine
->Initialised())
2362 PRectangle rcRightMargin
= rcClient
;
2363 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
2364 if (rcArea
.Intersects(rcRightMargin
)) {
2365 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2368 if (paintState
== paintAbandoned
) {
2369 // Either styling or NotifyUpdateUI noticed that painting is needed
2370 // outside the current painting rectangle
2371 //Platform::DebugPrintf("Abandoning paint\n");
2372 if (wrapState
!= eWrapNone
) {
2373 if (paintAbandonedByStyling
) {
2374 // Styling has spilled over a line end, such as occurs by starting a multiline
2375 // comment. The width of subsequent text may have changed, so rewrap.
2376 NeedWrapping(cs
.DocFromDisplay(topLine
));
2381 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
2384 if (rcArea
.right
> vs
.fixedColumnWidth
) {
2386 Surface
*surface
= surfaceWindow
;
2388 surface
= pixmapLine
;
2390 surface
->SetUnicodeMode(IsUnicodeMode());
2391 surface
->SetDBCSMode(CodePage());
2393 int visibleLine
= topLine
+ screenLinePaintFirst
;
2395 int posCaret
= currentPos
;
2398 int lineCaret
= pdoc
->LineFromPosition(posCaret
);
2400 // Remove selection margin from drawing area so text will not be drawn
2401 // on it in unbuffered mode.
2402 PRectangle rcTextArea
= rcClient
;
2403 rcTextArea
.left
= vs
.fixedColumnWidth
;
2404 rcTextArea
.right
-= vs
.rightMarginWidth
;
2405 surfaceWindow
->SetClip(rcTextArea
);
2407 // Loop on visible lines
2408 //double durLayout = 0.0;
2409 //double durPaint = 0.0;
2410 //double durCopy = 0.0;
2411 //ElapsedTime etWhole;
2412 int lineDocPrevious
= -1; // Used to avoid laying out one document line multiple times
2413 AutoLineLayout
ll(llc
, 0);
2414 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
2416 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
2417 // Only visible lines should be handled by the code within the loop
2418 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
2419 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
2420 int subLine
= visibleLine
- lineStartSet
;
2422 // Copy this line and its styles from the document into local arrays
2423 // and determine the x position at which each character starts.
2425 if (lineDoc
!= lineDocPrevious
) {
2426 ll
.Set(RetrieveLineLayout(lineDoc
));
2427 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
2428 lineDocPrevious
= lineDoc
;
2430 //durLayout += et.Duration(true);
2433 ll
->selStart
= SelectionStart(lineDoc
);
2434 ll
->selEnd
= SelectionEnd(lineDoc
);
2435 ll
->containsCaret
= lineDoc
== lineCaret
;
2436 if (hideSelection
) {
2439 ll
->containsCaret
= false;
2442 GetHotSpotRange(ll
->hsStart
, ll
->hsEnd
);
2444 PRectangle rcLine
= rcClient
;
2446 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
2448 Range
rangeLine(pdoc
->LineStart(lineDoc
), pdoc
->LineStart(lineDoc
+ 1));
2449 // Highlight the current braces if any
2450 ll
->SetBracesHighlight(rangeLine
, braces
, static_cast<char>(bracesMatchStyle
),
2451 highlightGuideColumn
* vs
.spaceWidth
);
2454 DrawLine(surface
, vs
, lineDoc
, visibleLine
, xStart
, rcLine
, ll
, subLine
);
2455 //durPaint += et.Duration(true);
2457 // Restore the precvious styles for the brace highlights in case layout is in cache.
2458 ll
->RestoreBracesHighlight(rangeLine
, braces
);
2460 bool expanded
= cs
.GetExpanded(lineDoc
);
2461 if ((foldFlags
& SC_FOLDFLAG_BOX
) == 0) {
2462 // Paint the line above the fold
2463 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_EXPANDED
))
2465 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_CONTRACTED
))) {
2466 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2467 PRectangle rcFoldLine
= rcLine
;
2468 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2469 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2472 // Paint the line below the fold
2473 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_EXPANDED
))
2475 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2476 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2477 PRectangle rcFoldLine
= rcLine
;
2478 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2479 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2483 int FoldLevelCurr
= (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2484 int FoldLevelPrev
= (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2485 int FoldLevelFlags
= (pdoc
->GetLevel(lineDoc
) & ~SC_FOLDLEVELNUMBERMASK
);
2486 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
2487 // Draw line above fold
2488 if ((FoldLevelPrev
< FoldLevelCurr
)
2490 (FoldLevelFlags
& SC_FOLDLEVELBOXHEADERFLAG
2492 (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELBOXFOOTERFLAG
) == 0)) {
2493 PRectangle rcFoldLine
= rcLine
;
2494 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2495 rcFoldLine
.left
+= xStart
+ FoldLevelCurr
* vs
.spaceWidth
* indentationStep
- 1;
2496 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2499 // Line below the fold (or below a contracted fold)
2500 if (FoldLevelFlags
& SC_FOLDLEVELBOXFOOTERFLAG
2502 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2503 PRectangle rcFoldLine
= rcLine
;
2504 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2505 rcFoldLine
.left
+= xStart
+ (FoldLevelCurr
) * vs
.spaceWidth
* indentationStep
- 1;
2506 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2509 PRectangle rcBoxLine
= rcLine
;
2510 // Draw vertical line for every fold level
2511 for (int i
= 0; i
<= FoldLevelCurr
; i
++) {
2512 rcBoxLine
.left
= xStart
+ i
* vs
.spaceWidth
* indentationStep
- 1;
2513 rcBoxLine
.right
= rcBoxLine
.left
+ 1;
2514 surface
->FillRectangle(rcBoxLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2519 if (lineDoc
== lineCaret
) {
2520 int offset
= Platform::Minimum(posCaret
- rangeLine
.start
, ll
->maxLineLength
);
2521 if ((offset
>= ll
->LineStart(subLine
)) &&
2522 ((offset
< ll
->LineStart(subLine
+ 1)) || offset
== ll
->numCharsInLine
)) {
2523 int xposCaret
= ll
->positions
[offset
] - ll
->positions
[ll
->LineStart(subLine
)] + xStart
;
2524 int widthOverstrikeCaret
;
2525 if (posCaret
== pdoc
->Length()) { // At end of document
2526 widthOverstrikeCaret
= vs
.aveCharWidth
;
2527 } else if ((posCaret
- rangeLine
.start
) >= ll
->numCharsInLine
) { // At end of line
2528 widthOverstrikeCaret
= vs
.aveCharWidth
;
2530 widthOverstrikeCaret
= ll
->positions
[offset
+ 1] - ll
->positions
[offset
];
2532 if (widthOverstrikeCaret
< 3) // Make sure its visible
2533 widthOverstrikeCaret
= 3;
2534 if (((caret
.active
&& caret
.on
) || (posDrag
>= 0)) && xposCaret
>= 0) {
2535 PRectangle rcCaret
= rcLine
;
2536 int caretWidthOffset
= 0;
2537 if ((offset
> 0) && (vs
.caretWidth
> 1))
2538 caretWidthOffset
= 1; // Move back so overlaps both character cells.
2540 rcCaret
.left
= xposCaret
- caretWidthOffset
;
2541 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
2544 rcCaret
.top
= rcCaret
.bottom
- 2;
2545 rcCaret
.left
= xposCaret
+ 1;
2546 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
2548 rcCaret
.left
= xposCaret
- caretWidthOffset
;
2549 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
2552 surface
->FillRectangle(rcCaret
, vs
.caretcolour
.allocated
);
2558 Point
from(vs
.fixedColumnWidth
, 0);
2559 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
2560 rcClient
.right
, yposScreen
+ vs
.lineHeight
);
2561 surfaceWindow
->Copy(rcCopyArea
, from
, *pixmapLine
);
2563 //durCopy += et.Duration(true);
2566 if (!bufferedDraw
) {
2567 ypos
+= vs
.lineHeight
;
2570 yposScreen
+= vs
.lineHeight
;
2574 //if (durPaint < 0.00000001)
2575 // durPaint = 0.00000001;
2577 // Right column limit indicator
2578 PRectangle rcBeyondEOF
= rcClient
;
2579 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
2580 rcBeyondEOF
.right
= rcBeyondEOF
.right
;
2581 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
2582 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
2583 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2584 if (vs
.edgeState
== EDGE_LINE
) {
2585 int edgeX
= theEdge
* vs
.spaceWidth
;
2586 rcBeyondEOF
.left
= edgeX
+ xStart
;
2587 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
2588 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
.allocated
);
2591 //Platform::DebugPrintf(
2592 //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
2593 //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
2598 // Space (3 space characters) between line numbers and text when printing.
2599 #define lineNumberPrintSpace " "
2601 ColourDesired
InvertedLight(ColourDesired orig
) {
2602 unsigned int r
= orig
.GetRed();
2603 unsigned int g
= orig
.GetGreen();
2604 unsigned int b
= orig
.GetBlue();
2605 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
2606 unsigned int il
= 0xff - l
;
2608 return ColourDesired(0xff, 0xff, 0xff);
2612 return ColourDesired(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
2615 // This is mostly copied from the Paint method but with some things omitted
2616 // such as the margin markers, line numbers, selection and caret
2617 // Should be merged back into a combined Draw method.
2618 long Editor::FormatRange(bool draw
, RangeToFormat
*pfr
) {
2622 AutoSurface
surface(pfr
->hdc
, this);
2625 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this);
2626 if (!surfaceMeasure
) {
2630 ViewStyle
vsPrint(vs
);
2632 // Modify the view style for printing as do not normally want any of the transient features to be printed
2633 // Printing supports only the line number margin.
2634 int lineNumberIndex
= -1;
2635 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
2636 if ((!vsPrint
.ms
[margin
].symbol
) && (vsPrint
.ms
[margin
].width
> 0)) {
2637 lineNumberIndex
= margin
;
2639 vsPrint
.ms
[margin
].width
= 0;
2642 vsPrint
.showMarkedLines
= false;
2643 vsPrint
.fixedColumnWidth
= 0;
2644 vsPrint
.zoomLevel
= printMagnification
;
2645 vsPrint
.viewIndentationGuides
= false;
2646 // Don't show the selection when printing
2647 vsPrint
.selbackset
= false;
2648 vsPrint
.selforeset
= false;
2649 vsPrint
.whitespaceBackgroundSet
= false;
2650 vsPrint
.whitespaceForegroundSet
= false;
2651 vsPrint
.showCaretLineBackground
= false;
2653 // Set colours for printing according to users settings
2654 for (int sty
= 0;sty
<= STYLE_MAX
;sty
++) {
2655 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
2656 vsPrint
.styles
[sty
].fore
.desired
= InvertedLight(vsPrint
.styles
[sty
].fore
.desired
);
2657 vsPrint
.styles
[sty
].back
.desired
= InvertedLight(vsPrint
.styles
[sty
].back
.desired
);
2658 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
2659 vsPrint
.styles
[sty
].fore
.desired
= ColourDesired(0, 0, 0);
2660 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2661 } else if (printColourMode
== SC_PRINT_COLOURONWHITE
) {
2662 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2663 } else if (printColourMode
== SC_PRINT_COLOURONWHITEDEFAULTBG
) {
2664 if (sty
<= STYLE_DEFAULT
) {
2665 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2669 // White background for the line numbers
2670 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2672 vsPrint
.Refresh(*surfaceMeasure
);
2673 // Ensure colours are set up
2674 vsPrint
.RefreshColourPalette(palette
, true);
2675 vsPrint
.RefreshColourPalette(palette
, false);
2676 // Determining width must hapen after fonts have been realised in Refresh
2677 int lineNumberWidth
= 0;
2678 if (lineNumberIndex
>= 0) {
2679 lineNumberWidth
= surfaceMeasure
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
2680 "99999" lineNumberPrintSpace
, 5 + strlen(lineNumberPrintSpace
));
2681 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
2684 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
2685 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
2686 if (linePrintLast
< linePrintStart
)
2687 linePrintLast
= linePrintStart
;
2688 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
);
2689 if (linePrintLast
> linePrintMax
)
2690 linePrintLast
= linePrintMax
;
2691 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
2692 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
2693 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
2694 int endPosPrint
= pdoc
->Length();
2695 if (linePrintLast
< pdoc
->LinesTotal())
2696 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
2698 // Ensure we are styled to where we are formatting.
2699 pdoc
->EnsureStyledTo(endPosPrint
);
2701 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
+ lineNumberWidth
;
2702 int ypos
= pfr
->rc
.top
;
2704 int lineDoc
= linePrintStart
;
2706 int nPrintPos
= pfr
->chrg
.cpMin
;
2707 int visibleLine
= 0;
2708 int widthPrint
= pfr
->rc
.Width() - lineNumberWidth
;
2709 if (printWrapState
== eWrapNone
)
2710 widthPrint
= LineLayout::wrapWidthInfinite
;
2712 while (lineDoc
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
2714 // When printing, the hdc and hdcTarget may be the same, so
2715 // changing the state of surfaceMeasure may change the underlying
2716 // state of surface. Therefore, any cached state is discarded before
2717 // using each surface.
2718 surfaceMeasure
->FlushCachedState();
2720 // Copy this line and its styles from the document into local arrays
2721 // and determine the x position at which each character starts.
2722 LineLayout
ll(8000);
2723 LayoutLine(lineDoc
, surfaceMeasure
, vsPrint
, &ll
, widthPrint
);
2727 ll
.containsCaret
= false;
2730 rcLine
.left
= pfr
->rc
.left
+ lineNumberWidth
;
2732 rcLine
.right
= pfr
->rc
.right
- 1;
2733 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
2735 // When document line is wrapped over multiple display lines, find where
2736 // to start printing from to ensure a particular position is on the first
2737 // line of the page.
2738 if (visibleLine
== 0) {
2739 int startWithinLine
= nPrintPos
- pdoc
->LineStart(lineDoc
);
2740 for (int iwl
= 0; iwl
< ll
.lines
- 1; iwl
++) {
2741 if (ll
.LineStart(iwl
) <= startWithinLine
&& ll
.LineStart(iwl
+ 1) >= startWithinLine
) {
2746 if (ll
.lines
> 1 && startWithinLine
>= ll
.LineStart(ll
.lines
- 1)) {
2747 visibleLine
= -(ll
.lines
- 1);
2751 if (draw
&& lineNumberWidth
&&
2752 (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) &&
2753 (visibleLine
>= 0)) {
2755 sprintf(number
, "%d" lineNumberPrintSpace
, lineDoc
+ 1);
2756 PRectangle rcNumber
= rcLine
;
2757 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
2759 rcNumber
.left
-= surfaceMeasure
->WidthText(
2760 vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, strlen(number
));
2761 surface
->FlushCachedState();
2762 surface
->DrawTextNoClip(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
2763 ypos
+ vsPrint
.maxAscent
, number
, strlen(number
),
2764 vsPrint
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
2765 vsPrint
.styles
[STYLE_LINENUMBER
].back
.allocated
);
2769 surface
->FlushCachedState();
2771 for (int iwl
= 0; iwl
< ll
.lines
; iwl
++) {
2772 if (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) {
2773 if (visibleLine
>= 0) {
2776 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
2777 DrawLine(surface
, vsPrint
, lineDoc
, visibleLine
, xStart
, rcLine
, &ll
, iwl
);
2779 ypos
+= vsPrint
.lineHeight
;
2782 if (iwl
== ll
.lines
- 1)
2783 nPrintPos
= pdoc
->LineStart(lineDoc
+ 1);
2785 nPrintPos
+= ll
.LineStart(iwl
+ 1) - ll
.LineStart(iwl
);
2795 int Editor::TextWidth(int style
, const char *text
) {
2797 AutoSurface
surface(this);
2799 return surface
->WidthText(vs
.styles
[style
].font
, text
, strlen(text
));
2805 // Empty method is overridden on GTK+ to show / hide scrollbars
2806 void Editor::ReconfigureScrollBars() {}
2808 void Editor::SetScrollBars() {
2811 int nMax
= MaxScrollPos();
2812 int nPage
= LinesOnScreen();
2813 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
2815 // TODO: ensure always showing as many lines as possible
2816 // May not be, if, for example, window made larger
2817 if (topLine
> MaxScrollPos()) {
2818 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
2819 SetVerticalScrollPos();
2823 if (!AbandonPaint())
2826 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
2829 void Editor::ChangeSize() {
2832 if (wrapState
!= eWrapNone
) {
2833 PRectangle rcTextArea
= GetClientRectangle();
2834 rcTextArea
.left
= vs
.fixedColumnWidth
;
2835 rcTextArea
.right
-= vs
.rightMarginWidth
;
2836 if (wrapWidth
!= rcTextArea
.Width()) {
2843 void Editor::AddChar(char ch
) {
2850 void Editor::AddCharUTF(char *s
, unsigned int len
, bool treatAsDBCS
) {
2851 bool wasSelection
= currentPos
!= anchor
;
2853 if (inOverstrike
&& !wasSelection
&& !RangeContainsProtected(currentPos
, currentPos
+ 1)) {
2854 if (currentPos
< (pdoc
->Length())) {
2855 if (!IsEOLChar(pdoc
->CharAt(currentPos
))) {
2856 pdoc
->DelChar(currentPos
);
2860 if (pdoc
->InsertString(currentPos
, s
, len
)) {
2861 SetEmptySelection(currentPos
+ len
);
2863 EnsureCaretVisible();
2864 // Avoid blinking during rapid typing:
2865 ShowCaretAtCurrentPosition();
2869 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
2870 static_cast<unsigned char>(s
[1]));
2872 int byte
= static_cast<unsigned char>(s
[0]);
2873 if ((byte
< 0xC0) || (1 == len
)) {
2874 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
2875 // characters when not in UTF-8 mode.
2876 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
2877 // characters representing themselves.
2879 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
2880 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
2881 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
2883 int byte2
= static_cast<unsigned char>(s
[1]);
2884 if ((byte2
& 0xC0) == 0x80) {
2885 // Two-byte-character lead-byte followed by a trail-byte.
2886 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
2888 // A two-byte-character lead-byte not followed by trail-byte
2889 // represents itself.
2890 } else if (byte
< 0xF0) {
2891 int byte2
= static_cast<unsigned char>(s
[1]);
2892 int byte3
= static_cast<unsigned char>(s
[2]);
2893 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
2894 // Three-byte-character lead byte followed by two trail bytes.
2895 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
2898 // A three-byte-character lead-byte not followed by two trail-bytes
2899 // represents itself.
2906 void Editor::ClearSelection() {
2907 if (!SelectionContainsProtected()) {
2908 if (selType
== selRectangle
) {
2909 pdoc
->BeginUndoAction();
2910 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2911 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2912 int startPos
= SelectionStart();
2913 for (int line
= lineEnd
; line
>= lineStart
; line
--) {
2914 startPos
= SelectionStart(line
);
2915 unsigned int chars
= SelectionEnd(line
) - startPos
;
2917 pdoc
->DeleteChars(startPos
, chars
);
2920 SetEmptySelection(startPos
);
2921 pdoc
->EndUndoAction();
2922 selType
= selStream
;
2924 int startPos
= SelectionStart();
2925 unsigned int chars
= SelectionEnd() - startPos
;
2926 SetEmptySelection(startPos
);
2928 pdoc
->BeginUndoAction();
2929 pdoc
->DeleteChars(startPos
, chars
);
2930 pdoc
->EndUndoAction();
2936 void Editor::ClearAll() {
2937 pdoc
->BeginUndoAction();
2938 if (0 != pdoc
->Length()) {
2939 pdoc
->DeleteChars(0, pdoc
->Length());
2941 if (!pdoc
->IsReadOnly()) {
2944 pdoc
->EndUndoAction();
2948 SetVerticalScrollPos();
2951 void Editor::ClearDocumentStyle() {
2952 pdoc
->StartStyling(0, '\377');
2953 pdoc
->SetStyleFor(pdoc
->Length(), 0);
2955 pdoc
->ClearLevels();
2958 void Editor::Cut() {
2959 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
2965 void Editor::PasteRectangular(int pos
, const char *ptr
, int len
) {
2966 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
2970 int xInsert
= XFromPosition(currentPos
);
2971 int line
= pdoc
->LineFromPosition(currentPos
);
2972 bool prevCr
= false;
2973 pdoc
->BeginUndoAction();
2974 for (int i
= 0; i
< len
; i
++) {
2975 if (IsEOLChar(ptr
[i
])) {
2976 if ((ptr
[i
] == '\r') || (!prevCr
))
2978 if (line
>= pdoc
->LinesTotal()) {
2979 if (pdoc
->eolMode
!= SC_EOL_LF
)
2980 pdoc
->InsertChar(pdoc
->Length(), '\r');
2981 if (pdoc
->eolMode
!= SC_EOL_CR
)
2982 pdoc
->InsertChar(pdoc
->Length(), '\n');
2984 // Pad the end of lines with spaces if required
2985 currentPos
= PositionFromLineX(line
, xInsert
);
2986 if ((XFromPosition(currentPos
) < xInsert
) && (i
+ 1 < len
)) {
2987 for (int i
= 0; i
< xInsert
- XFromPosition(currentPos
); i
++) {
2988 pdoc
->InsertChar(currentPos
, ' ');
2992 prevCr
= ptr
[i
] == '\r';
2994 pdoc
->InsertString(currentPos
, ptr
+ i
, 1);
2999 pdoc
->EndUndoAction();
3000 SetEmptySelection(pos
);
3003 bool Editor::CanPaste() {
3004 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
3007 void Editor::Clear() {
3008 if (currentPos
== anchor
) {
3009 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3015 SetEmptySelection(currentPos
);
3018 void Editor::SelectAll() {
3019 SetSelection(0, pdoc
->Length());
3023 void Editor::Undo() {
3024 if (pdoc
->CanUndo()) {
3026 int newPos
= pdoc
->Undo();
3027 SetEmptySelection(newPos
);
3028 EnsureCaretVisible();
3032 void Editor::Redo() {
3033 if (pdoc
->CanRedo()) {
3034 int newPos
= pdoc
->Redo();
3035 SetEmptySelection(newPos
);
3036 EnsureCaretVisible();
3040 void Editor::DelChar() {
3041 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3042 pdoc
->DelChar(currentPos
);
3044 // Avoid blinking during rapid typing:
3045 ShowCaretAtCurrentPosition();
3048 void Editor::DelCharBack(bool allowLineStartDeletion
) {
3049 if (currentPos
== anchor
) {
3050 if (!RangeContainsProtected(currentPos
- 1, currentPos
)) {
3051 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
3052 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != currentPos
)) {
3053 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3054 pdoc
->GetColumn(currentPos
) > 0 && pdoc
->backspaceUnindents
) {
3055 pdoc
->BeginUndoAction();
3056 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3057 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
3058 if (indentation
% indentationStep
== 0) {
3059 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3061 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- (indentation
% indentationStep
));
3063 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
3064 pdoc
->EndUndoAction();
3066 pdoc
->DelCharBack(currentPos
);
3072 SetEmptySelection(currentPos
);
3074 // Avoid blinking during rapid typing:
3075 ShowCaretAtCurrentPosition();
3078 void Editor::NotifyFocus(bool) {}
3080 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
3082 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
3083 scn
.position
= endStyleNeeded
;
3087 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
3088 NotifyStyleToNeeded(endStyleNeeded
);
3091 void Editor::NotifyChar(int ch
) {
3093 scn
.nmhdr
.code
= SCN_CHARADDED
;
3096 if (recordingMacro
) {
3098 txt
[0] = static_cast<char>(ch
);
3100 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
3104 void Editor::NotifySavePoint(bool isSavePoint
) {
3107 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
3109 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
3114 void Editor::NotifyModifyAttempt() {
3116 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
3120 void Editor::NotifyDoubleClick(Point
, bool) {
3122 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
3126 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3128 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
3129 scn
.position
= position
;
3130 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3131 (alt
? SCI_ALT
: 0);
3135 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3137 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
3138 scn
.position
= position
;
3139 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3140 (alt
? SCI_ALT
: 0);
3144 void Editor::NotifyUpdateUI() {
3146 scn
.nmhdr
.code
= SCN_UPDATEUI
;
3150 void Editor::NotifyPainted() {
3152 scn
.nmhdr
.code
= SCN_PAINTED
;
3156 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
3157 int marginClicked
= -1;
3159 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
3160 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
3161 marginClicked
= margin
;
3162 x
+= vs
.ms
[margin
].width
;
3164 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
3166 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
3167 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3168 (alt
? SCI_ALT
: 0);
3169 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
3170 scn
.margin
= marginClicked
;
3178 void Editor::NotifyNeedShown(int pos
, int len
) {
3180 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
3186 void Editor::NotifyDwelling(Point pt
, bool state
) {
3188 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
3189 scn
.position
= PositionFromLocationClose(pt
);
3195 void Editor::NotifyZoom() {
3197 scn
.nmhdr
.code
= SCN_ZOOM
;
3201 // Notifications from document
3202 void Editor::NotifyModifyAttempt(Document
*, void *) {
3203 //Platform::DebugPrintf("** Modify Attempt\n");
3204 NotifyModifyAttempt();
3207 void Editor::NotifyMove(int position
) {
3209 scn
.nmhdr
.code
= SCN_POSCHANGED
;
3210 scn
.position
= position
;
3214 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
3215 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
3216 NotifySavePoint(atSavePoint
);
3219 void Editor::CheckModificationForWrap(DocModification mh
) {
3220 if ((mh
.modificationType
& SC_MOD_INSERTTEXT
) ||
3221 (mh
.modificationType
& SC_MOD_DELETETEXT
)) {
3222 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
3223 if (wrapState
!= eWrapNone
) {
3224 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
3225 if (mh
.linesAdded
== 0) {
3226 AutoSurface
surface(this);
3227 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
3228 if (surface
&& ll
) {
3229 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
3230 if (cs
.GetHeight(lineDoc
) != ll
->lines
) {
3231 NeedWrapping(lineDoc
- 1);
3235 NeedWrapping(lineDoc
);
3238 NeedWrapping(lineDoc
);
3244 // Move a position so it is still after the same character as before the insertion.
3245 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
3246 if (position
> startInsertion
) {
3247 return position
+ length
;
3252 // Move a position so it is still after the same character as before the deletion if that
3253 // character is still present else after the previous surviving character.
3254 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
3255 if (position
> startDeletion
) {
3256 int endDeletion
= startDeletion
+ length
;
3257 if (position
> endDeletion
) {
3258 return position
- length
;
3260 return startDeletion
;
3267 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
3268 needUpdateUI
= true;
3269 if (paintState
== painting
) {
3270 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
3272 CheckModificationForWrap(mh
);
3273 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
3274 if (paintState
== notPainting
) {
3275 if (mh
.position
< pdoc
->LineStart(topLine
)) {
3276 // Styling performed before this view
3279 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3283 // Move selection and brace highlights
3284 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
3285 currentPos
= MovePositionForInsertion(currentPos
, mh
.position
, mh
.length
);
3286 anchor
= MovePositionForInsertion(anchor
, mh
.position
, mh
.length
);
3287 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
3288 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
3289 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
3290 currentPos
= MovePositionForDeletion(currentPos
, mh
.position
, mh
.length
);
3291 anchor
= MovePositionForDeletion(anchor
, mh
.position
, mh
.length
);
3292 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
3293 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
3295 if (cs
.LinesDisplayed() < cs
.LinesInDoc()) {
3296 // Some lines are hidden so may need shown.
3297 // TODO: check if the modified area is hidden.
3298 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
3299 NotifyNeedShown(mh
.position
, mh
.length
);
3300 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
3301 NotifyNeedShown(mh
.position
, mh
.length
);
3304 if (mh
.linesAdded
!= 0) {
3305 // Update contraction state for inserted and removed lines
3306 // lineOfPos should be calculated in context of state before modification, shouldn't it
3307 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
3308 if (mh
.linesAdded
> 0) {
3309 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
3311 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
3313 // Avoid scrolling of display if change before current display
3314 if (mh
.position
< posTopLine
) {
3315 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
3316 if (newTop
!= topLine
) {
3318 SetVerticalScrollPos();
3322 //Platform::DebugPrintf("** %x Doc Changed\n", this);
3323 // TODO: could invalidate from mh.startModification to end of screen
3324 //InvalidateRange(mh.position, mh.position + mh.length);
3325 if (paintState
== notPainting
) {
3329 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
3330 // mh.position, mh.position + mh.length);
3331 if (paintState
== notPainting
) {
3332 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3337 if (mh
.linesAdded
!= 0) {
3341 if (mh
.modificationType
& SC_MOD_CHANGEMARKER
) {
3342 if (paintState
== notPainting
) {
3347 // If client wants to see this modification
3348 if (mh
.modificationType
& modEventMask
) {
3349 if ((mh
.modificationType
& SC_MOD_CHANGESTYLE
) == 0) {
3350 // Real modification made to text of document.
3351 NotifyChange(); // Send EN_CHANGE
3355 scn
.nmhdr
.code
= SCN_MODIFIED
;
3356 scn
.position
= mh
.position
;
3357 scn
.modificationType
= mh
.modificationType
;
3359 scn
.length
= mh
.length
;
3360 scn
.linesAdded
= mh
.linesAdded
;
3362 scn
.foldLevelNow
= mh
.foldLevelNow
;
3363 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
3368 void Editor::NotifyDeleted(Document
*, void *) {
3372 void Editor::NotifyMacroRecord(unsigned int iMessage
, unsigned long wParam
, long lParam
) {
3374 // Enumerates all macroable messages
3380 case SCI_REPLACESEL
:
3382 case SCI_INSERTTEXT
:
3383 case SCI_APPENDTEXT
:
3388 case SCI_SEARCHANCHOR
:
3389 case SCI_SEARCHNEXT
:
3390 case SCI_SEARCHPREV
:
3392 case SCI_LINEDOWNEXTEND
:
3394 case SCI_PARADOWNEXTEND
:
3396 case SCI_LINEUPEXTEND
:
3398 case SCI_PARAUPEXTEND
:
3400 case SCI_CHARLEFTEXTEND
:
3402 case SCI_CHARRIGHTEXTEND
:
3404 case SCI_WORDLEFTEXTEND
:
3406 case SCI_WORDRIGHTEXTEND
:
3407 case SCI_WORDPARTLEFT
:
3408 case SCI_WORDPARTLEFTEXTEND
:
3409 case SCI_WORDPARTRIGHT
:
3410 case SCI_WORDPARTRIGHTEXTEND
:
3412 case SCI_HOMEEXTEND
:
3414 case SCI_LINEENDEXTEND
:
3416 case SCI_HOMEWRAPEXTEND
:
3417 case SCI_LINEENDWRAP
:
3418 case SCI_LINEENDWRAPEXTEND
:
3419 case SCI_DOCUMENTSTART
:
3420 case SCI_DOCUMENTSTARTEXTEND
:
3421 case SCI_DOCUMENTEND
:
3422 case SCI_DOCUMENTENDEXTEND
:
3424 case SCI_PAGEUPEXTEND
:
3426 case SCI_PAGEDOWNEXTEND
:
3427 case SCI_EDITTOGGLEOVERTYPE
:
3429 case SCI_DELETEBACK
:
3434 case SCI_VCHOMEEXTEND
:
3435 case SCI_VCHOMEWRAP
:
3436 case SCI_VCHOMEWRAPEXTEND
:
3437 case SCI_DELWORDLEFT
:
3438 case SCI_DELWORDRIGHT
:
3439 case SCI_DELLINELEFT
:
3440 case SCI_DELLINERIGHT
:
3442 case SCI_LINEDELETE
:
3443 case SCI_LINETRANSPOSE
:
3444 case SCI_LINEDUPLICATE
:
3447 case SCI_LINESCROLLDOWN
:
3448 case SCI_LINESCROLLUP
:
3449 case SCI_DELETEBACKNOTLINE
:
3450 case SCI_HOMEDISPLAY
:
3451 case SCI_HOMEDISPLAYEXTEND
:
3452 case SCI_LINEENDDISPLAY
:
3453 case SCI_LINEENDDISPLAYEXTEND
:
3456 // Filter out all others like display changes. Also, newlines are redundant
3457 // with char insert messages.
3460 // printf("Filtered out %ld of macro recording\n", iMessage);
3464 // Send notification
3466 scn
.nmhdr
.code
= SCN_MACRORECORD
;
3467 scn
.message
= iMessage
;
3468 scn
.wParam
= wParam
;
3469 scn
.lParam
= lParam
;
3473 // Force scroll and keep position relative to top of window
3474 void Editor::PageMove(int direction
, bool extend
) {
3475 Point pt
= LocationFromPosition(currentPos
);
3476 int topLineNew
= Platform::Clamp(
3477 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
3478 int newPos
= PositionFromLocation(
3479 Point(lastXChosen
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())));
3480 if (topLineNew
!= topLine
) {
3481 SetTopLine(topLineNew
);
3482 MovePositionTo(newPos
, extend
);
3484 SetVerticalScrollPos();
3486 MovePositionTo(newPos
, extend
);
3490 void Editor::ChangeCaseOfSelection(bool makeUpperCase
) {
3491 pdoc
->BeginUndoAction();
3492 int startCurrent
= currentPos
;
3493 int startAnchor
= anchor
;
3494 if (selType
== selRectangle
) {
3495 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
3496 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
3497 for (int line
= lineEnd
; line
>= lineStart
; line
--) {
3499 Range(SelectionStart(line
), SelectionEnd(line
)),
3502 // Would be nicer to keep the rectangular selection but this is complex
3503 selType
= selStream
;
3504 SetSelection(startCurrent
, startCurrent
);
3506 pdoc
->ChangeCase(Range(SelectionStart(), SelectionEnd()),
3508 SetSelection(startCurrent
, startAnchor
);
3510 pdoc
->EndUndoAction();
3513 void Editor::LineTranspose() {
3514 int line
= pdoc
->LineFromPosition(currentPos
);
3516 int startPrev
= pdoc
->LineStart(line
- 1);
3517 int endPrev
= pdoc
->LineEnd(line
- 1);
3518 int start
= pdoc
->LineStart(line
);
3519 int end
= pdoc
->LineEnd(line
);
3520 int startNext
= pdoc
->LineStart(line
+ 1);
3521 if (end
< pdoc
->Length()) {
3523 char *thisLine
= CopyRange(start
, end
);
3524 pdoc
->DeleteChars(start
, end
- start
);
3525 if (pdoc
->InsertString(startPrev
, thisLine
, end
- start
)) {
3526 MovePositionTo(startPrev
+ end
- start
);
3530 // Last line so line has no line end
3531 char *thisLine
= CopyRange(start
, end
);
3532 char *prevEnd
= CopyRange(endPrev
, start
);
3533 pdoc
->DeleteChars(endPrev
, end
- endPrev
);
3534 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
3535 if (pdoc
->InsertString(startPrev
+ end
- start
, prevEnd
, start
- endPrev
)) {
3536 MovePositionTo(startPrev
+ end
- endPrev
);
3545 void Editor::LineDuplicate() {
3546 int line
= pdoc
->LineFromPosition(currentPos
);
3547 int start
= pdoc
->LineStart(line
);
3548 int end
= pdoc
->LineEnd(line
);
3549 char *thisLine
= CopyRange(start
, end
);
3550 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
3551 pdoc
->InsertString(end
, eol
);
3552 pdoc
->InsertString(end
+ strlen(eol
), thisLine
, end
- start
);
3556 void Editor::CancelModes() {}
3558 void Editor::NewLine() {
3560 const char *eol
= "\n";
3561 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
3563 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
3565 } // else SC_EOL_LF -> "\n" already set
3566 if (pdoc
->InsertString(currentPos
, eol
)) {
3567 SetEmptySelection(currentPos
+ strlen(eol
));
3574 EnsureCaretVisible();
3577 void Editor::CursorUpOrDown(int direction
, bool extend
) {
3578 Point pt
= LocationFromPosition(currentPos
);
3579 int posNew
= PositionFromLocation(
3580 Point(lastXChosen
, pt
.y
+ direction
* vs
.lineHeight
));
3581 if (direction
< 0) {
3582 // Line wrapping may lead to a location on the same line, so
3583 // seek back if that is the case.
3584 // There is an equivalent case when moving down which skips
3585 // over a line but as that does not trap the user it is fine.
3586 Point ptNew
= LocationFromPosition(posNew
);
3587 while ((posNew
> 0) && (pt
.y
== ptNew
.y
)) {
3589 ptNew
= LocationFromPosition(posNew
);
3592 MovePositionTo(posNew
, extend
);
3595 int Editor::StartEndDisplayLine(int pos
, bool start
) {
3597 int line
= pdoc
->LineFromPosition(pos
);
3598 AutoSurface
surface(this);
3599 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
3600 int posRet
= INVALID_POSITION
;
3601 if (surface
&& ll
) {
3602 unsigned int posLineStart
= pdoc
->LineStart(line
);
3603 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
3604 int posInLine
= pos
- posLineStart
;
3605 if (posInLine
<= ll
->maxLineLength
) {
3606 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
3607 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
3609 posRet
= ll
->LineStart(subLine
) + posLineStart
;
3611 if (subLine
== ll
->lines
- 1)
3612 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
;
3614 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
- 1;
3620 if (posRet
== INVALID_POSITION
) {
3627 int Editor::KeyCommand(unsigned int iMessage
) {
3632 case SCI_LINEDOWNEXTEND
:
3633 CursorUpOrDown(1, true);
3636 MovePositionTo(pdoc
->ParaDown(currentPos
));
3638 case SCI_PARADOWNEXTEND
:
3639 MovePositionTo(pdoc
->ParaDown(currentPos
), true);
3641 case SCI_LINESCROLLDOWN
:
3642 ScrollTo(topLine
+ 1);
3643 MoveCaretInsideView(false);
3648 case SCI_LINEUPEXTEND
:
3649 CursorUpOrDown(-1, true);
3652 MovePositionTo(pdoc
->ParaUp(currentPos
));
3654 case SCI_PARAUPEXTEND
:
3655 MovePositionTo(pdoc
->ParaUp(currentPos
), true);
3657 case SCI_LINESCROLLUP
:
3658 ScrollTo(topLine
- 1);
3659 MoveCaretInsideView(false);
3662 if (SelectionEmpty()) {
3663 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1));
3665 MovePositionTo(SelectionStart());
3669 case SCI_CHARLEFTEXTEND
:
3670 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), true);
3674 if (SelectionEmpty()) {
3675 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1));
3677 MovePositionTo(SelectionEnd());
3681 case SCI_CHARRIGHTEXTEND
:
3682 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), true);
3686 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1));
3689 case SCI_WORDLEFTEXTEND
:
3690 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1), true);
3694 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1));
3697 case SCI_WORDRIGHTEXTEND
:
3698 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1), true);
3702 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)));
3705 case SCI_HOMEEXTEND
:
3706 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), true);
3710 MovePositionTo(pdoc
->LineEndPosition(currentPos
));
3713 case SCI_LINEENDEXTEND
:
3714 MovePositionTo(pdoc
->LineEndPosition(currentPos
), true);
3717 case SCI_HOMEWRAP
: {
3718 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
3719 if (currentPos
<= homePos
)
3720 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
3721 MovePositionTo(homePos
);
3725 case SCI_HOMEWRAPEXTEND
: {
3726 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
3727 if (currentPos
<= homePos
)
3728 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
3729 MovePositionTo(homePos
, true);
3733 case SCI_LINEENDWRAP
: {
3734 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
3735 if (currentPos
>= endPos
)
3736 endPos
= pdoc
->LineEndPosition(currentPos
);
3737 MovePositionTo(endPos
);
3741 case SCI_LINEENDWRAPEXTEND
: {
3742 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
3743 if (currentPos
>= endPos
)
3744 endPos
= pdoc
->LineEndPosition(currentPos
);
3745 MovePositionTo(endPos
, true);
3749 case SCI_DOCUMENTSTART
:
3753 case SCI_DOCUMENTSTARTEXTEND
:
3754 MovePositionTo(0, true);
3757 case SCI_DOCUMENTEND
:
3758 MovePositionTo(pdoc
->Length());
3761 case SCI_DOCUMENTENDEXTEND
:
3762 MovePositionTo(pdoc
->Length(), true);
3768 case SCI_PAGEUPEXTEND
:
3774 case SCI_PAGEDOWNEXTEND
:
3777 case SCI_EDITTOGGLEOVERTYPE
:
3778 inOverstrike
= !inOverstrike
;
3780 ShowCaretAtCurrentPosition();
3783 case SCI_CANCEL
: // Cancel any modes - handled in subclass
3784 // Also unselect text
3787 case SCI_DELETEBACK
:
3790 EnsureCaretVisible();
3792 case SCI_DELETEBACKNOTLINE
:
3795 EnsureCaretVisible();
3800 EnsureCaretVisible();
3805 EnsureCaretVisible();
3814 MovePositionTo(pdoc
->VCHomePosition(currentPos
));
3817 case SCI_VCHOMEEXTEND
:
3818 MovePositionTo(pdoc
->VCHomePosition(currentPos
), true);
3821 case SCI_VCHOMEWRAP
: {
3822 int homePos
= pdoc
->VCHomePosition(currentPos
);
3823 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
3824 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
3825 homePos
= viewLineStart
;
3827 MovePositionTo(homePos
);
3831 case SCI_VCHOMEWRAPEXTEND
: {
3832 int homePos
= pdoc
->VCHomePosition(currentPos
);
3833 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
3834 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
3835 homePos
= viewLineStart
;
3837 MovePositionTo(homePos
, true);
3842 if (vs
.zoomLevel
< 20) {
3844 InvalidateStyleRedraw();
3849 if (vs
.zoomLevel
> -10) {
3851 InvalidateStyleRedraw();
3855 case SCI_DELWORDLEFT
: {
3856 int startWord
= pdoc
->NextWordStart(currentPos
, -1);
3857 pdoc
->DeleteChars(startWord
, currentPos
- startWord
);
3861 case SCI_DELWORDRIGHT
: {
3862 int endWord
= pdoc
->NextWordStart(currentPos
, 1);
3863 pdoc
->DeleteChars(currentPos
, endWord
- currentPos
);
3866 case SCI_DELLINELEFT
: {
3867 int line
= pdoc
->LineFromPosition(currentPos
);
3868 int start
= pdoc
->LineStart(line
);
3869 pdoc
->DeleteChars(start
, currentPos
- start
);
3873 case SCI_DELLINERIGHT
: {
3874 int line
= pdoc
->LineFromPosition(currentPos
);
3875 int end
= pdoc
->LineEnd(line
);
3876 pdoc
->DeleteChars(currentPos
, end
- currentPos
);
3880 int lineStart
= pdoc
->LineFromPosition(currentPos
);
3881 int lineEnd
= pdoc
->LineFromPosition(anchor
);
3882 if (lineStart
> lineEnd
) {
3884 lineEnd
= lineStart
;
3887 int start
= pdoc
->LineStart(lineStart
);
3888 int end
= pdoc
->LineStart(lineEnd
+ 1);
3889 SetSelection(start
, end
);
3893 case SCI_LINEDELETE
: {
3894 int line
= pdoc
->LineFromPosition(currentPos
);
3895 int start
= pdoc
->LineStart(line
);
3896 int end
= pdoc
->LineStart(line
+ 1);
3897 pdoc
->DeleteChars(start
, end
- start
);
3900 case SCI_LINETRANSPOSE
:
3903 case SCI_LINEDUPLICATE
:
3907 ChangeCaseOfSelection(false);
3910 ChangeCaseOfSelection(true);
3912 case SCI_WORDPARTLEFT
:
3913 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1));
3916 case SCI_WORDPARTLEFTEXTEND
:
3917 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1), true);
3920 case SCI_WORDPARTRIGHT
:
3921 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1));
3924 case SCI_WORDPARTRIGHTEXTEND
:
3925 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1), true);
3928 case SCI_HOMEDISPLAY
:
3929 MovePositionTo(MovePositionSoVisible(
3930 StartEndDisplayLine(currentPos
, true), -1));
3933 case SCI_HOMEDISPLAYEXTEND
:
3934 MovePositionTo(MovePositionSoVisible(
3935 StartEndDisplayLine(currentPos
, true), -1), true);
3938 case SCI_LINEENDDISPLAY
:
3939 MovePositionTo(MovePositionSoVisible(
3940 StartEndDisplayLine(currentPos
, false), 1));
3943 case SCI_LINEENDDISPLAYEXTEND
:
3944 MovePositionTo(MovePositionSoVisible(
3945 StartEndDisplayLine(currentPos
, false), 1), true);
3952 int Editor::KeyDefault(int, int) {
3956 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
3958 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3959 (alt
? SCI_ALT
: 0);
3960 int msg
= kmap
.Find(key
, modifiers
);
3964 return WndProc(msg
, 0, 0);
3968 return KeyDefault(key
, modifiers
);
3972 void Editor::SetWhitespaceVisible(int view
) {
3973 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(view
);
3976 int Editor::GetWhitespaceVisible() {
3977 return vs
.viewWhitespace
;
3980 void Editor::Indent(bool forwards
) {
3981 //Platform::DebugPrintf("INdent %d\n", forwards);
3982 int lineOfAnchor
= pdoc
->LineFromPosition(anchor
);
3983 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
3984 if (lineOfAnchor
== lineCurrentPos
) {
3986 pdoc
->BeginUndoAction();
3988 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
3990 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3991 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
3992 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
+ indentationStep
);
3993 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
3995 if (pdoc
->useTabs
) {
3996 pdoc
->InsertChar(currentPos
, '\t');
3997 SetEmptySelection(currentPos
+ 1);
3999 int numSpaces
= (pdoc
->tabInChars
) -
4000 (pdoc
->GetColumn(currentPos
) % (pdoc
->tabInChars
));
4002 numSpaces
= pdoc
->tabInChars
;
4003 for (int i
= 0; i
< numSpaces
; i
++) {
4004 pdoc
->InsertChar(currentPos
+ i
, ' ');
4006 SetEmptySelection(currentPos
+ numSpaces
);
4009 pdoc
->EndUndoAction();
4011 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
4013 pdoc
->BeginUndoAction();
4014 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4015 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
4016 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
4017 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4018 pdoc
->EndUndoAction();
4020 int newColumn
= ((pdoc
->GetColumn(currentPos
) - 1) / pdoc
->tabInChars
) *
4024 int newPos
= currentPos
;
4025 while (pdoc
->GetColumn(newPos
) > newColumn
)
4027 SetEmptySelection(newPos
);
4031 int anchorPosOnLine
= anchor
- pdoc
->LineStart(lineOfAnchor
);
4032 int currentPosPosOnLine
= currentPos
- pdoc
->LineStart(lineCurrentPos
);
4033 // Multiple lines selected so indent / dedent
4034 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
4035 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
4036 if (pdoc
->LineStart(lineBottomSel
) == anchor
|| pdoc
->LineStart(lineBottomSel
) == currentPos
)
4037 lineBottomSel
--; // If not selecting any characters on a line, do not indent
4038 pdoc
->BeginUndoAction();
4039 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
4040 pdoc
->EndUndoAction();
4041 if (lineOfAnchor
< lineCurrentPos
) {
4042 if (currentPosPosOnLine
== 0)
4043 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4045 SetSelection(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
4047 if (anchorPosOnLine
== 0)
4048 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4050 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
4056 * Search of a text in the document, in the given range.
4057 * @return The position of the found text, -1 if not found.
4059 long Editor::FindText(
4060 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4061 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4062 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
4064 TextToFind
*ft
= reinterpret_cast<TextToFind
*>(lParam
);
4065 int lengthFound
= strlen(ft
->lpstrText
);
4066 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
4067 (wParam
& SCFIND_MATCHCASE
) != 0,
4068 (wParam
& SCFIND_WHOLEWORD
) != 0,
4069 (wParam
& SCFIND_WORDSTART
) != 0,
4070 (wParam
& SCFIND_REGEXP
) != 0,
4071 (wParam
& SCFIND_POSIX
) != 0,
4074 ft
->chrgText
.cpMin
= pos
;
4075 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
4081 * Relocatable search support : Searches relative to current selection
4082 * point and sets the selection to the found text range with
4086 * Anchor following searches at current selection start: This allows
4087 * multiple incremental interactive searches to be macro recorded
4088 * while still setting the selection to found text so the find/select
4089 * operation is self-contained.
4091 void Editor::SearchAnchor() {
4092 searchAnchor
= SelectionStart();
4096 * Find text from current search anchor: Must call @c SearchAnchor first.
4097 * Used for next text and previous text requests.
4098 * @return The position of the found text, -1 if not found.
4100 long Editor::SearchText(
4101 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
4102 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4103 ///< @c SCFIND_WORDSTART or @c SCFIND_REGEXP.
4104 sptr_t lParam
) { ///< The text to search for.
4106 const char *txt
= reinterpret_cast<char *>(lParam
);
4108 int lengthFound
= strlen(txt
);
4109 if (iMessage
== SCI_SEARCHNEXT
) {
4110 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
4111 (wParam
& SCFIND_MATCHCASE
) != 0,
4112 (wParam
& SCFIND_WHOLEWORD
) != 0,
4113 (wParam
& SCFIND_WORDSTART
) != 0,
4114 (wParam
& SCFIND_REGEXP
) != 0,
4115 (wParam
& SCFIND_POSIX
) != 0,
4118 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
4119 (wParam
& SCFIND_MATCHCASE
) != 0,
4120 (wParam
& SCFIND_WHOLEWORD
) != 0,
4121 (wParam
& SCFIND_WORDSTART
) != 0,
4122 (wParam
& SCFIND_REGEXP
) != 0,
4123 (wParam
& SCFIND_POSIX
) != 0,
4128 SetSelection(pos
, pos
+ lengthFound
);
4135 * Search for text in the target range of the document.
4136 * @return The position of the found text, -1 if not found.
4138 long Editor::SearchInTarget(const char *text
, int length
) {
4139 int lengthFound
= length
;
4140 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
4141 (searchFlags
& SCFIND_MATCHCASE
) != 0,
4142 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
4143 (searchFlags
& SCFIND_WORDSTART
) != 0,
4144 (searchFlags
& SCFIND_REGEXP
) != 0,
4145 (searchFlags
& SCFIND_POSIX
) != 0,
4149 targetEnd
= pos
+ lengthFound
;
4154 void Editor::GoToLine(int lineNo
) {
4155 if (lineNo
> pdoc
->LinesTotal())
4156 lineNo
= pdoc
->LinesTotal();
4159 SetEmptySelection(pdoc
->LineStart(lineNo
));
4160 ShowCaretAtCurrentPosition();
4161 EnsureCaretVisible();
4164 static bool Close(Point pt1
, Point pt2
) {
4165 if (abs(pt1
.x
- pt2
.x
) > 3)
4167 if (abs(pt1
.y
- pt2
.y
) > 3)
4172 char *Editor::CopyRange(int start
, int end
) {
4175 int len
= end
- start
;
4176 text
= new char[len
+ 1];
4178 for (int i
= 0; i
< len
; i
++) {
4179 text
[i
] = pdoc
->CharAt(start
+ i
);
4187 void Editor::CopySelectionRange(SelectionText
*ss
) {
4190 if (selType
== selRectangle
) {
4191 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4192 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4194 for (line
= lineStart
; line
<= lineEnd
; line
++) {
4195 size
+= SelectionEnd(line
) - SelectionStart(line
) + 1;
4196 if (pdoc
->eolMode
== SC_EOL_CRLF
)
4200 text
= new char[size
+ 1];
4203 for (line
= lineStart
; line
<= lineEnd
; line
++) {
4204 for (int i
= SelectionStart(line
);i
< SelectionEnd(line
);i
++) {
4205 text
[j
++] = pdoc
->CharAt(i
);
4207 if (pdoc
->eolMode
!= SC_EOL_LF
)
4209 if (pdoc
->eolMode
!= SC_EOL_CR
)
4216 size
= SelectionEnd() - SelectionStart();
4217 text
= CopyRange(SelectionStart(), SelectionEnd());
4219 ss
->Set(text
, size
, selType
== selRectangle
);
4222 void Editor::SetDragPosition(int newPos
) {
4224 newPos
= MovePositionOutsideChar(newPos
, 1);
4227 if (posDrag
!= newPos
) {
4236 void Editor::DisplayCursor(Window::Cursor c
) {
4237 if (cursorMode
== SC_CURSORNORMAL
)
4240 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
4243 void Editor::StartDrag() {
4244 // Always handled by subclasses
4245 //SetMouseCapture(true);
4246 //DisplayCursor(Window::cursorArrow);
4249 void Editor::DropAt(int position
, const char *value
, bool moving
, bool rectangular
) {
4250 //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
4252 dropWentOutside
= false;
4254 int positionWasInSelection
= PositionInSelection(position
);
4256 bool positionOnEdgeOfSelection
=
4257 (position
== SelectionStart()) || (position
== SelectionEnd());
4259 if ((!inDragDrop
) || !(0 == positionWasInSelection
) ||
4260 (positionOnEdgeOfSelection
&& !moving
)) {
4262 int selStart
= SelectionStart();
4263 int selEnd
= SelectionEnd();
4265 pdoc
->BeginUndoAction();
4267 int positionAfterDeletion
= position
;
4268 if (inDragDrop
&& moving
) {
4269 // Remove dragged out text
4271 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4272 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4273 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
4274 int startPos
= SelectionStart(line
);
4275 int endPos
= SelectionEnd(line
);
4276 if (position
>= startPos
) {
4277 if (position
> endPos
) {
4278 positionAfterDeletion
-= endPos
- startPos
;
4280 positionAfterDeletion
-= position
- startPos
;
4285 if (position
> selStart
) {
4286 positionAfterDeletion
-= selEnd
- selStart
;
4291 position
= positionAfterDeletion
;
4294 PasteRectangular(position
, value
, strlen(value
));
4295 pdoc
->EndUndoAction();
4296 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
4297 SetSelection(position
, position
);
4299 position
= MovePositionOutsideChar(position
, currentPos
- position
);
4300 if (pdoc
->InsertString(position
, value
)) {
4301 SetSelection(position
+ strlen(value
), position
);
4303 pdoc
->EndUndoAction();
4305 } else if (inDragDrop
) {
4306 SetSelection(position
, position
);
4310 static int BeforeInOrAfter(int val
, int minim
, int maxim
) {
4313 else if (val
> maxim
)
4319 int Editor::PositionInSelection(int pos
) {
4320 pos
= MovePositionOutsideChar(pos
, currentPos
- pos
);
4321 if (selType
== selRectangle
) {
4322 if (pos
< SelectionStart())
4324 if (pos
> SelectionEnd())
4326 int linePos
= pdoc
->LineFromPosition(pos
);
4327 return BeforeInOrAfter(pos
, SelectionStart(linePos
), SelectionEnd(linePos
));
4329 if (currentPos
> anchor
) {
4330 return BeforeInOrAfter(pos
, anchor
, currentPos
);
4331 } else if (currentPos
< anchor
) {
4332 return BeforeInOrAfter(pos
, currentPos
, anchor
);
4338 bool Editor::PointInSelection(Point pt
) {
4339 // TODO: fix up for rectangular selection
4340 int pos
= PositionFromLocation(pt
);
4341 if (0 == PositionInSelection(pos
)) {
4342 if (pos
== SelectionStart()) {
4343 // see if just before selection
4344 Point locStart
= LocationFromPosition(pos
);
4345 if (pt
.x
< locStart
.x
)
4348 if (pos
== SelectionEnd()) {
4349 // see if just after selection
4350 Point locEnd
= LocationFromPosition(pos
);
4351 if (pt
.x
> locEnd
.x
)
4359 bool Editor::PointInSelMargin(Point pt
) {
4360 // Really means: "Point in a margin"
4361 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4362 PRectangle rcSelMargin
= GetClientRectangle();
4363 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
4364 return rcSelMargin
.Contains(pt
);
4370 void Editor::LineSelection(int lineCurrent_
, int lineAnchor_
) {
4371 if (lineAnchor_
< lineCurrent_
) {
4372 SetSelection(pdoc
->LineStart(lineCurrent_
+ 1),
4373 pdoc
->LineStart(lineAnchor_
));
4374 } else if (lineAnchor_
> lineCurrent_
) {
4375 SetSelection(pdoc
->LineStart(lineCurrent_
),
4376 pdoc
->LineStart(lineAnchor_
+ 1));
4377 } else { // Same line, select it
4378 SetSelection(pdoc
->LineStart(lineAnchor_
+ 1),
4379 pdoc
->LineStart(lineAnchor_
));
4383 void Editor::DwellEnd(bool mouseMoved
) {
4385 ticksToDwell
= dwellDelay
;
4387 ticksToDwell
= SC_TIME_FOREVER
;
4388 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4390 NotifyDwelling(ptMouseLast
, dwelling
);
4394 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
4395 //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
4397 int newPos
= PositionFromLocation(pt
);
4398 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
4401 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
4405 bool inSelMargin
= PointInSelMargin(pt
);
4406 if (shift
& !inSelMargin
) {
4407 SetSelection(newPos
);
4409 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
4410 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
4411 SetMouseCapture(true);
4412 SetEmptySelection(newPos
);
4413 bool doubleClick
= false;
4414 // Stop mouse button bounce changing selection type
4415 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
4416 if (selectionType
== selChar
) {
4417 selectionType
= selWord
;
4419 } else if (selectionType
== selWord
) {
4420 selectionType
= selLine
;
4422 selectionType
= selChar
;
4423 originalAnchorPos
= currentPos
;
4427 if (selectionType
== selWord
) {
4428 if (currentPos
>= originalAnchorPos
) { // Moved forward
4429 SetSelection(pdoc
->ExtendWordSelect(currentPos
, 1),
4430 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
4431 } else { // Moved backward
4432 SetSelection(pdoc
->ExtendWordSelect(currentPos
, -1),
4433 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
4435 } else if (selectionType
== selLine
) {
4436 lineAnchor
= LineFromLocation(pt
);
4437 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
4438 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
4440 SetEmptySelection(currentPos
);
4442 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
4444 NotifyDoubleClick(pt
, shift
);
4445 if (PositionIsHotspot(newPos
))
4446 NotifyHotSpotDoubleClicked(newPos
, shift
, ctrl
, alt
);
4448 } else { // Single click
4450 selType
= selStream
;
4453 lastClickTime
= curTime
;
4457 lineAnchor
= LineFromLocation(pt
);
4458 // Single click in margin: select whole line
4459 LineSelection(lineAnchor
, lineAnchor
);
4460 SetSelection(pdoc
->LineStart(lineAnchor
+ 1),
4461 pdoc
->LineStart(lineAnchor
));
4463 // Single shift+click in margin: select from line anchor to clicked line
4464 if (anchor
> currentPos
)
4465 lineAnchor
= pdoc
->LineFromPosition(anchor
- 1);
4467 lineAnchor
= pdoc
->LineFromPosition(anchor
);
4468 int lineStart
= LineFromLocation(pt
);
4469 LineSelection(lineStart
, lineAnchor
);
4470 //lineAnchor = lineStart; // Keep the same anchor for ButtonMove
4473 SetDragPosition(invalidPosition
);
4474 SetMouseCapture(true);
4475 selectionType
= selLine
;
4477 if (PositionIsHotspot(newPos
)) {
4478 NotifyHotSpotClicked(newPos
, shift
, ctrl
, alt
);
4481 inDragDrop
= PointInSelection(pt
);
4484 SetMouseCapture(false);
4485 SetDragPosition(newPos
);
4486 CopySelectionRange(&drag
);
4489 xStartSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4490 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4491 SetDragPosition(invalidPosition
);
4492 SetMouseCapture(true);
4494 SetEmptySelection(newPos
);
4495 selType
= alt
? selRectangle
: selStream
;
4496 selectionType
= selChar
;
4497 originalAnchorPos
= currentPos
;
4501 lastClickTime
= curTime
;
4503 ShowCaretAtCurrentPosition();
4506 bool Editor::PositionIsHotspot(int position
) {
4507 return vs
.styles
[pdoc
->StyleAt(position
)].hotspot
;
4510 bool Editor::PointIsHotspot(Point pt
) {
4511 int pos
= PositionFromLocation(pt
);
4512 return PositionIsHotspot(pos
);
4515 void Editor::SetHotSpotRange(Point
*pt
) {
4517 int pos
= PositionFromLocation(*pt
);
4519 // If we don't limit this to word characters then the
4520 // range can encompass more than the run range and then
4521 // the underline will not be drawn properly.
4522 int hsStart_
= pdoc
->ExtendStyleRange(pos
, -1);
4523 int hsEnd_
= pdoc
->ExtendStyleRange(pos
, 1);
4525 // Only invalidate the range if the hotspot range has changed...
4526 if (hsStart_
!= hsStart
|| hsEnd_
!= hsEnd
) {
4527 if (hsStart
!= -1) {
4528 InvalidateRange(hsStart
, hsEnd
);
4532 InvalidateRange(hsStart
, hsEnd
);
4535 if (hsStart
!= -1) {
4536 int hsStart_
= hsStart
;
4540 InvalidateRange(hsStart_
, hsEnd_
);
4548 void Editor::GetHotSpotRange(int& hsStart_
, int& hsEnd_
) {
4553 void Editor::ButtonMove(Point pt
) {
4554 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
4558 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
4559 if (HaveMouseCapture()) {
4561 // Slow down autoscrolling/selection
4562 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
4563 if (autoScrollTimer
.ticksToWait
> 0)
4565 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
4568 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4569 int movePos
= PositionFromLocation(pt
);
4570 movePos
= MovePositionOutsideChar(movePos
, currentPos
- movePos
);
4572 SetDragPosition(movePos
);
4574 if (selectionType
== selChar
) {
4575 SetSelection(movePos
);
4576 } else if (selectionType
== selWord
) {
4577 // Continue selecting by word
4578 if (movePos
>= originalAnchorPos
) { // Moved forward
4579 SetSelection(pdoc
->ExtendWordSelect(movePos
, 1),
4580 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
4581 } else { // Moved backward
4582 SetSelection(pdoc
->ExtendWordSelect(movePos
, -1),
4583 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
4586 // Continue selecting by line
4587 int lineMove
= LineFromLocation(pt
);
4588 LineSelection(lineMove
, lineAnchor
);
4593 PRectangle rcClient
= GetClientRectangle();
4594 if (pt
.y
> rcClient
.bottom
) {
4595 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
4597 lineMove
= cs
.DisplayFromDoc(pdoc
->LinesTotal() - 1);
4599 ScrollTo(lineMove
- LinesOnScreen() + 5);
4601 } else if (pt
.y
< rcClient
.top
) {
4602 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
4603 ScrollTo(lineMove
- 5);
4606 EnsureCaretVisible(false, false, true);
4608 if (hsStart
!= -1 && !PositionIsHotspot(movePos
))
4609 SetHotSpotRange(NULL
);
4612 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4613 if (PointInSelMargin(pt
)) {
4614 DisplayCursor(Window::cursorReverseArrow
);
4615 return; // No need to test for selection
4618 // Display regular (drag) cursor over selection
4619 if (PointInSelection(pt
)) {
4620 DisplayCursor(Window::cursorArrow
);
4621 } else if (PointIsHotspot(pt
)) {
4622 DisplayCursor(Window::cursorHand
);
4623 SetHotSpotRange(&pt
);
4625 DisplayCursor(Window::cursorText
);
4626 SetHotSpotRange(NULL
);
4632 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
4633 //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
4634 if (HaveMouseCapture()) {
4635 if (PointInSelMargin(pt
)) {
4636 DisplayCursor(Window::cursorReverseArrow
);
4638 DisplayCursor(Window::cursorText
);
4639 SetHotSpotRange(NULL
);
4641 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4643 SetMouseCapture(false);
4644 int newPos
= PositionFromLocation(pt
);
4645 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
4647 int selStart
= SelectionStart();
4648 int selEnd
= SelectionEnd();
4649 if (selStart
< selEnd
) {
4652 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
4653 SetSelection(newPos
, newPos
+ drag
.len
);
4655 } else if (newPos
< selStart
) {
4656 pdoc
->DeleteChars(selStart
, drag
.len
);
4657 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
4658 SetSelection(newPos
, newPos
+ drag
.len
);
4660 } else if (newPos
> selEnd
) {
4661 pdoc
->DeleteChars(selStart
, drag
.len
);
4663 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
4664 SetSelection(newPos
, newPos
+ drag
.len
);
4667 SetEmptySelection(newPos
);
4671 selectionType
= selChar
;
4674 if (selectionType
== selChar
) {
4675 SetSelection(newPos
);
4678 lastClickTime
= curTime
;
4681 if (selType
== selStream
) {
4685 EnsureCaretVisible(false);
4689 // Called frequently to perform background UI including
4690 // caret blinking and automatic scrolling.
4691 void Editor::Tick() {
4692 if (HaveMouseCapture()) {
4694 ButtonMove(ptMouseLast
);
4696 if (caret
.period
> 0) {
4697 timer
.ticksToWait
-= timer
.tickSize
;
4698 if (timer
.ticksToWait
<= 0) {
4699 caret
.on
= !caret
.on
;
4700 timer
.ticksToWait
= caret
.period
;
4704 if ((dwellDelay
< SC_TIME_FOREVER
) &&
4705 (ticksToDwell
> 0) &&
4706 (!HaveMouseCapture())) {
4707 ticksToDwell
-= timer
.tickSize
;
4708 if (ticksToDwell
<= 0) {
4710 NotifyDwelling(ptMouseLast
, dwelling
);
4715 void Editor::SetFocusState(bool focusState
) {
4716 hasFocus
= focusState
;
4717 NotifyFocus(hasFocus
);
4719 ShowCaretAtCurrentPosition();
4726 static bool IsIn(int a
, int minimum
, int maximum
) {
4727 return (a
>= minimum
) && (a
<= maximum
);
4730 static bool IsOverlap(int mina
, int maxa
, int minb
, int maxb
) {
4732 IsIn(mina
, minb
, maxb
) ||
4733 IsIn(maxa
, minb
, maxb
) ||
4734 IsIn(minb
, mina
, maxa
) ||
4735 IsIn(maxb
, mina
, maxa
);
4738 void Editor::CheckForChangeOutsidePaint(Range r
) {
4739 if (paintState
== painting
&& !paintingAllText
) {
4740 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
4744 PRectangle rcText
= GetTextRectangle();
4745 // Determine number of lines displayed including a possible partially displayed last line
4746 int linesDisplayed
= (rcText
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1;
4747 int bottomLine
= topLine
+ linesDisplayed
- 1;
4749 int lineRangeStart
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.start
));
4750 int lineRangeEnd
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.end
));
4751 if (!IsOverlap(topLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
4752 //Platform::DebugPrintf("No overlap (%d-%d) with window(%d-%d)\n",
4753 // lineRangeStart, lineRangeEnd, topLine, bottomLine);
4757 // Assert rcPaint contained within or equal to rcText
4758 if (rcPaint
.top
> rcText
.top
) {
4759 // does range intersect rcText.top .. rcPaint.top
4760 int paintTopLine
= ((rcPaint
.top
- rcText
.top
- 1) / vs
.lineHeight
) + topLine
;
4761 // paintTopLine is the top line of the paint rectangle or the line just above if that line is completely inside the paint rectangle
4762 if (IsOverlap(topLine
, paintTopLine
, lineRangeStart
, lineRangeEnd
)) {
4763 //Platform::DebugPrintf("Change (%d-%d) in top npv(%d-%d)\n",
4764 // lineRangeStart, lineRangeEnd, topLine, paintTopLine);
4769 if (rcPaint
.bottom
< rcText
.bottom
) {
4770 // does range intersect rcPaint.bottom .. rcText.bottom
4771 int paintBottomLine
= ((rcPaint
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1) + topLine
;
4772 // paintTopLine is the bottom line of the paint rectangle or the line just below if that line is completely inside the paint rectangle
4773 if (IsOverlap(paintBottomLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
4774 //Platform::DebugPrintf("Change (%d-%d) in bottom npv(%d-%d)\n",
4775 // lineRangeStart, lineRangeEnd, paintBottomLine, bottomLine);
4783 char BraceOpposite(char ch
) {
4806 // TODO: should be able to extend styled region to find matching brace
4807 // TODO: may need to make DBCS safe
4808 // so should be moved into Document
4809 int Editor::BraceMatch(int position
, int /*maxReStyle*/) {
4810 char chBrace
= pdoc
->CharAt(position
);
4811 char chSeek
= BraceOpposite(chBrace
);
4814 char styBrace
= static_cast<char>(
4815 pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
4817 if (chBrace
== '(' || chBrace
== '[' || chBrace
== '{' || chBrace
== '<')
4820 position
= position
+ direction
;
4821 while ((position
>= 0) && (position
< pdoc
->Length())) {
4822 char chAtPos
= pdoc
->CharAt(position
);
4823 char styAtPos
= static_cast<char>(pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
4824 if ((position
> pdoc
->GetEndStyled()) || (styAtPos
== styBrace
)) {
4825 if (chAtPos
== chBrace
)
4827 if (chAtPos
== chSeek
)
4832 position
= position
+ direction
;
4837 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
4838 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
4839 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
4840 CheckForChangeOutsidePaint(Range(braces
[0]));
4841 CheckForChangeOutsidePaint(Range(pos0
));
4844 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
4845 CheckForChangeOutsidePaint(Range(braces
[1]));
4846 CheckForChangeOutsidePaint(Range(pos1
));
4849 bracesMatchStyle
= matchStyle
;
4850 if (paintState
== notPainting
) {
4856 void Editor::SetDocPointer(Document
*document
) {
4857 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
4858 pdoc
->RemoveWatcher(this, 0);
4860 if (document
== NULL
) {
4861 pdoc
= new Document();
4867 // Ensure all positions within document
4873 // Reset the contraction state to fully shown.
4875 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
4879 pdoc
->AddWatcher(this, 0);
4881 // Removed because of reentrance problems of GTK+ 2.x
4882 // where changing a scroll bar position causes synchronous
4883 // painting before lexer and styling state is set up.
4887 // Recursively expand a fold, making lines visible except where they have an unexpanded parent
4888 void Editor::Expand(int &line
, bool doExpand
) {
4889 int lineMaxSubord
= pdoc
->GetLastChild(line
);
4891 while (line
<= lineMaxSubord
) {
4893 cs
.SetVisible(line
, line
, true);
4894 int level
= pdoc
->GetLevel(line
);
4895 if (level
& SC_FOLDLEVELHEADERFLAG
) {
4896 if (doExpand
&& cs
.GetExpanded(line
)) {
4899 Expand(line
, false);
4907 void Editor::ToggleContraction(int line
) {
4908 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
4909 if (cs
.GetExpanded(line
)) {
4910 int lineMaxSubord
= pdoc
->GetLastChild(line
);
4911 cs
.SetExpanded(line
, 0);
4912 if (lineMaxSubord
> line
) {
4913 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
4918 cs
.SetExpanded(line
, 1);
4926 // Recurse up from this line to find any folds that prevent this line from being visible
4927 // and unfold them all->
4928 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
4930 // In case in need of wrapping to ensure DisplayFromDoc works.
4933 if (!cs
.GetVisible(lineDoc
)) {
4934 int lineParent
= pdoc
->GetFoldParent(lineDoc
);
4935 if (lineParent
>= 0) {
4936 if (lineDoc
!= lineParent
)
4937 EnsureLineVisible(lineParent
, enforcePolicy
);
4938 if (!cs
.GetExpanded(lineParent
)) {
4939 cs
.SetExpanded(lineParent
, 1);
4940 Expand(lineParent
, true);
4946 if (enforcePolicy
) {
4947 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
4948 if (visiblePolicy
& VISIBLE_SLOP
) {
4949 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
4950 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
4951 SetVerticalScrollPos();
4953 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
4954 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
4955 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
4956 SetVerticalScrollPos();
4960 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
4961 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
4962 SetVerticalScrollPos();
4969 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
4970 pdoc
->BeginUndoAction();
4972 length
= strlen(text
);
4973 if (replacePatterns
) {
4974 text
= pdoc
->SubstituteByPosition(text
, &length
);
4978 if (targetStart
!= targetEnd
)
4979 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
4980 targetEnd
= targetStart
;
4981 pdoc
->InsertString(targetStart
, text
, length
);
4982 targetEnd
= targetStart
+ length
;
4983 pdoc
->EndUndoAction();
4987 bool Editor::IsUnicodeMode() const {
4988 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
4991 int Editor::CodePage() const {
4993 return pdoc
->dbcsCodePage
;
4998 static bool ValidMargin(unsigned long wParam
) {
4999 return wParam
< ViewStyle::margins
;
5002 static char *CharPtrFromSPtr(sptr_t lParam
) {
5003 return reinterpret_cast<char *>(lParam
);
5006 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5007 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
5009 // Optional macro recording hook
5011 NotifyMacroRecord(iMessage
, wParam
, lParam
);
5020 char *ptr
= CharPtrFromSPtr(lParam
);
5021 unsigned int iChar
= 0;
5022 for (; iChar
< wParam
- 1; iChar
++)
5023 ptr
[iChar
] = pdoc
->CharAt(iChar
);
5031 pdoc
->DeleteChars(0, pdoc
->Length());
5032 SetEmptySelection(0);
5033 pdoc
->InsertString(0, CharPtrFromSPtr(lParam
));
5037 case SCI_GETTEXTLENGTH
:
5038 return pdoc
->Length();
5052 EnsureCaretVisible();
5058 EnsureCaretVisible();
5067 return pdoc
->CanUndo() ? 1 : 0;
5069 case SCI_EMPTYUNDOBUFFER
:
5070 pdoc
->DeleteUndoHistory();
5073 case SCI_GETFIRSTVISIBLELINE
:
5076 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
5080 int lineStart
= pdoc
->LineStart(wParam
);
5081 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
5082 char *ptr
= CharPtrFromSPtr(lParam
);
5084 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
5085 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5090 case SCI_GETLINECOUNT
:
5091 if (pdoc
->LinesTotal() == 0)
5094 return pdoc
->LinesTotal();
5097 return !pdoc
->IsSavePoint();
5100 int nStart
= static_cast<int>(wParam
);
5101 int nEnd
= static_cast<int>(lParam
);
5103 nEnd
= pdoc
->Length();
5105 nStart
= nEnd
; // Remove selection
5106 selType
= selStream
;
5107 SetSelection(nEnd
, nStart
);
5108 EnsureCaretVisible();
5112 case SCI_GETSELTEXT
: {
5115 SelectionText selectedText
;
5116 CopySelectionRange(&selectedText
);
5117 char *ptr
= CharPtrFromSPtr(lParam
);
5119 if (selectedText
.len
) {
5120 for (; iChar
< selectedText
.len
; iChar
++)
5121 ptr
[iChar
] = selectedText
.s
[iChar
];
5129 case SCI_LINEFROMPOSITION
:
5130 if (static_cast<int>(wParam
) < 0)
5132 return pdoc
->LineFromPosition(wParam
);
5134 case SCI_POSITIONFROMLINE
:
5135 if (static_cast<int>(wParam
) < 0)
5136 wParam
= pdoc
->LineFromPosition(SelectionStart());
5138 return 0; // Even if there is no text, there is a first line that starts at 0
5139 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
5141 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
5143 return pdoc
->LineStart(wParam
);
5145 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
5146 case SCI_LINELENGTH
:
5147 if ((static_cast<int>(wParam
) < 0) ||
5148 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
5150 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
5152 case SCI_REPLACESEL
: {
5155 pdoc
->BeginUndoAction();
5157 char *replacement
= CharPtrFromSPtr(lParam
);
5158 pdoc
->InsertString(currentPos
, replacement
);
5159 pdoc
->EndUndoAction();
5160 SetEmptySelection(currentPos
+ strlen(replacement
));
5161 EnsureCaretVisible();
5165 case SCI_SETTARGETSTART
:
5166 targetStart
= wParam
;
5169 case SCI_GETTARGETSTART
:
5172 case SCI_SETTARGETEND
:
5176 case SCI_GETTARGETEND
:
5179 case SCI_TARGETFROMSELECTION
:
5180 if (currentPos
< anchor
) {
5181 targetStart
= currentPos
;
5184 targetStart
= anchor
;
5185 targetEnd
= currentPos
;
5189 case SCI_REPLACETARGET
:
5190 PLATFORM_ASSERT(lParam
);
5191 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), wParam
);
5193 case SCI_REPLACETARGETRE
:
5194 PLATFORM_ASSERT(lParam
);
5195 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), wParam
);
5197 case SCI_SEARCHINTARGET
:
5198 PLATFORM_ASSERT(lParam
);
5199 return SearchInTarget(CharPtrFromSPtr(lParam
), wParam
);
5201 case SCI_SETSEARCHFLAGS
:
5202 searchFlags
= wParam
;
5205 case SCI_GETSEARCHFLAGS
:
5208 case SCI_LINESCROLL
:
5209 ScrollTo(topLine
+ lParam
);
5210 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
5213 case SCI_SETXOFFSET
:
5215 SetHorizontalScrollPos();
5219 case SCI_GETXOFFSET
:
5222 case SCI_CHOOSECARETX
:
5226 case SCI_SCROLLCARET
:
5227 EnsureCaretVisible();
5230 case SCI_SETREADONLY
:
5231 pdoc
->SetReadOnly(wParam
!= 0);
5234 case SCI_GETREADONLY
:
5235 return pdoc
->IsReadOnly();
5240 case SCI_POINTXFROMPOSITION
:
5244 Point pt
= LocationFromPosition(lParam
);
5248 case SCI_POINTYFROMPOSITION
:
5252 Point pt
= LocationFromPosition(lParam
);
5257 return FindText(wParam
, lParam
);
5259 case SCI_GETTEXTRANGE
: {
5262 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
5263 int cpMax
= tr
->chrg
.cpMax
;
5265 cpMax
= pdoc
->Length();
5266 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
5267 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
5268 // Spec says copied text is terminated with a NUL
5269 tr
->lpstrText
[len
] = '\0';
5270 return len
; // Not including NUL
5273 case SCI_HIDESELECTION
:
5274 hideSelection
= wParam
!= 0;
5278 case SCI_FORMATRANGE
:
5279 return FormatRange(wParam
!= 0, reinterpret_cast<RangeToFormat
*>(lParam
));
5281 case SCI_GETMARGINLEFT
:
5282 return vs
.leftMarginWidth
;
5284 case SCI_GETMARGINRIGHT
:
5285 return vs
.rightMarginWidth
;
5287 case SCI_SETMARGINLEFT
:
5288 vs
.leftMarginWidth
= lParam
;
5289 InvalidateStyleRedraw();
5292 case SCI_SETMARGINRIGHT
:
5293 vs
.rightMarginWidth
= lParam
;
5294 InvalidateStyleRedraw();
5297 // Control specific mesages
5302 pdoc
->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam
), wParam
);
5303 SetEmptySelection(currentPos
+ wParam
);
5307 case SCI_ADDSTYLEDTEXT
: {
5310 pdoc
->InsertStyledString(CurrentPosition() * 2, CharPtrFromSPtr(lParam
), wParam
);
5311 SetEmptySelection(currentPos
+ wParam
/ 2);
5315 case SCI_INSERTTEXT
: {
5318 int insertPos
= wParam
;
5319 if (static_cast<short>(wParam
) == -1)
5320 insertPos
= CurrentPosition();
5321 int newCurrent
= CurrentPosition();
5322 char *sz
= CharPtrFromSPtr(lParam
);
5323 pdoc
->InsertString(insertPos
, sz
);
5324 if (newCurrent
> insertPos
)
5325 newCurrent
+= strlen(sz
);
5326 SetEmptySelection(newCurrent
);
5330 case SCI_APPENDTEXT
:
5331 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), wParam
);
5338 case SCI_CLEARDOCUMENTSTYLE
:
5339 ClearDocumentStyle();
5342 case SCI_SETUNDOCOLLECTION
:
5343 pdoc
->SetUndoCollection(wParam
!= 0);
5346 case SCI_GETUNDOCOLLECTION
:
5347 return pdoc
->IsCollectingUndo();
5349 case SCI_BEGINUNDOACTION
:
5350 pdoc
->BeginUndoAction();
5353 case SCI_ENDUNDOACTION
:
5354 pdoc
->EndUndoAction();
5357 case SCI_GETCARETPERIOD
:
5358 return caret
.period
;
5360 case SCI_SETCARETPERIOD
:
5361 caret
.period
= wParam
;
5364 case SCI_SETWORDCHARS
: {
5367 pdoc
->SetWordChars(reinterpret_cast<unsigned char *>(lParam
));
5372 return pdoc
->Length();
5375 return pdoc
->CharAt(wParam
);
5377 case SCI_SETCURRENTPOS
:
5378 SetSelection(wParam
, anchor
);
5381 case SCI_GETCURRENTPOS
:
5385 SetSelection(currentPos
, wParam
);
5391 case SCI_SETSELECTIONSTART
:
5392 SetSelection(Platform::Maximum(currentPos
, wParam
), wParam
);
5395 case SCI_GETSELECTIONSTART
:
5396 return Platform::Minimum(anchor
, currentPos
);
5398 case SCI_SETSELECTIONEND
:
5399 SetSelection(wParam
, Platform::Minimum(anchor
, wParam
));
5402 case SCI_GETSELECTIONEND
:
5403 return Platform::Maximum(anchor
, currentPos
);
5405 case SCI_SETPRINTMAGNIFICATION
:
5406 printMagnification
= wParam
;
5409 case SCI_GETPRINTMAGNIFICATION
:
5410 return printMagnification
;
5412 case SCI_SETPRINTCOLOURMODE
:
5413 printColourMode
= wParam
;
5416 case SCI_GETPRINTCOLOURMODE
:
5417 return printColourMode
;
5419 case SCI_SETPRINTWRAPMODE
:
5420 printWrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
5423 case SCI_GETPRINTWRAPMODE
:
5424 return printWrapState
;
5426 case SCI_GETSTYLEAT
:
5427 if (static_cast<short>(wParam
) >= pdoc
->Length())
5430 return pdoc
->StyleAt(wParam
);
5440 case SCI_SETSAVEPOINT
:
5441 pdoc
->SetSavePoint();
5444 case SCI_GETSTYLEDTEXT
: {
5447 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
5449 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
5450 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
5451 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
5453 tr
->lpstrText
[iPlace
] = '\0';
5454 tr
->lpstrText
[iPlace
+ 1] = '\0';
5459 return pdoc
->CanRedo() ? 1 : 0;
5461 case SCI_MARKERLINEFROMHANDLE
:
5462 return pdoc
->LineFromHandle(wParam
);
5464 case SCI_MARKERDELETEHANDLE
:
5465 pdoc
->DeleteMarkFromHandle(wParam
);
5469 return vs
.viewWhitespace
;
5472 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
5476 case SCI_POSITIONFROMPOINT
:
5477 return PositionFromLocation(Point(wParam
, lParam
));
5479 case SCI_POSITIONFROMPOINTCLOSE
:
5480 return PositionFromLocationClose(Point(wParam
, lParam
));
5487 SetEmptySelection(wParam
);
5488 EnsureCaretVisible();
5492 case SCI_GETCURLINE
: {
5496 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
5497 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
5498 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
5499 char *ptr
= CharPtrFromSPtr(lParam
);
5500 unsigned int iPlace
= 0;
5501 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
5502 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5505 return currentPos
- lineStart
;
5508 case SCI_GETENDSTYLED
:
5509 return pdoc
->GetEndStyled();
5511 case SCI_GETEOLMODE
:
5512 return pdoc
->eolMode
;
5514 case SCI_SETEOLMODE
:
5515 pdoc
->eolMode
= wParam
;
5518 case SCI_STARTSTYLING
:
5519 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
5522 case SCI_SETSTYLING
:
5523 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
5526 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
5529 pdoc
->SetStyles(wParam
, CharPtrFromSPtr(lParam
));
5532 case SCI_SETBUFFEREDDRAW
:
5533 bufferedDraw
= wParam
!= 0;
5536 case SCI_GETBUFFEREDDRAW
:
5537 return bufferedDraw
;
5539 case SCI_GETTWOPHASEDRAW
:
5540 return twoPhaseDraw
;
5542 case SCI_SETTWOPHASEDRAW
:
5543 twoPhaseDraw
= wParam
!= 0;
5544 InvalidateStyleRedraw();
5547 case SCI_SETTABWIDTH
:
5549 pdoc
->tabInChars
= wParam
;
5550 InvalidateStyleRedraw();
5553 case SCI_GETTABWIDTH
:
5554 return pdoc
->tabInChars
;
5557 pdoc
->indentInChars
= wParam
;
5558 InvalidateStyleRedraw();
5562 return pdoc
->indentInChars
;
5564 case SCI_SETUSETABS
:
5565 pdoc
->useTabs
= wParam
!= 0;
5566 InvalidateStyleRedraw();
5569 case SCI_GETUSETABS
:
5570 return pdoc
->useTabs
;
5572 case SCI_SETLINEINDENTATION
:
5573 pdoc
->SetLineIndentation(wParam
, lParam
);
5576 case SCI_GETLINEINDENTATION
:
5577 return pdoc
->GetLineIndentation(wParam
);
5579 case SCI_GETLINEINDENTPOSITION
:
5580 return pdoc
->GetLineIndentPosition(wParam
);
5582 case SCI_SETTABINDENTS
:
5583 pdoc
->tabIndents
= wParam
!= 0;
5586 case SCI_GETTABINDENTS
:
5587 return pdoc
->tabIndents
;
5589 case SCI_SETBACKSPACEUNINDENTS
:
5590 pdoc
->backspaceUnindents
= wParam
!= 0;
5593 case SCI_GETBACKSPACEUNINDENTS
:
5594 return pdoc
->backspaceUnindents
;
5596 case SCI_SETMOUSEDWELLTIME
:
5597 dwellDelay
= wParam
;
5598 ticksToDwell
= dwellDelay
;
5601 case SCI_GETMOUSEDWELLTIME
:
5604 case SCI_WORDSTARTPOSITION
:
5605 return pdoc
->ExtendWordSelect(wParam
, -1, lParam
!= 0);
5607 case SCI_WORDENDPOSITION
:
5608 return pdoc
->ExtendWordSelect(wParam
, 1, lParam
!= 0);
5610 case SCI_SETWRAPMODE
:
5611 wrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
5613 InvalidateStyleRedraw();
5614 ReconfigureScrollBars();
5617 case SCI_GETWRAPMODE
:
5620 case SCI_SETLAYOUTCACHE
:
5621 llc
.SetLevel(wParam
);
5624 case SCI_GETLAYOUTCACHE
:
5625 return llc
.GetLevel();
5627 case SCI_SETSCROLLWIDTH
:
5628 PLATFORM_ASSERT(wParam
> 0);
5629 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
5630 scrollWidth
= wParam
;
5635 case SCI_GETSCROLLWIDTH
:
5642 case SCI_LINESSPLIT
:
5647 PLATFORM_ASSERT(wParam
<= STYLE_MAX
);
5648 PLATFORM_ASSERT(lParam
);
5649 return TextWidth(wParam
, CharPtrFromSPtr(lParam
));
5651 case SCI_TEXTHEIGHT
:
5652 return vs
.lineHeight
;
5654 case SCI_SETENDATLASTLINE
:
5655 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
5656 if (endAtLastLine
!= (wParam
!= 0)) {
5657 endAtLastLine
= wParam
!= 0;
5662 case SCI_GETENDATLASTLINE
:
5663 return endAtLastLine
;
5666 return pdoc
->GetColumn(wParam
);
5668 case SCI_SETHSCROLLBAR
:
5669 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
5670 horizontalScrollBarVisible
= wParam
!= 0;
5672 ReconfigureScrollBars();
5676 case SCI_GETHSCROLLBAR
:
5677 return horizontalScrollBarVisible
;
5679 case SCI_SETVSCROLLBAR
:
5680 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
5681 verticalScrollBarVisible
= wParam
!= 0;
5683 ReconfigureScrollBars();
5687 case SCI_GETVSCROLLBAR
:
5688 return verticalScrollBarVisible
;
5690 case SCI_SETINDENTATIONGUIDES
:
5691 vs
.viewIndentationGuides
= wParam
!= 0;
5695 case SCI_GETINDENTATIONGUIDES
:
5696 return vs
.viewIndentationGuides
;
5698 case SCI_SETHIGHLIGHTGUIDE
:
5699 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
5700 highlightGuideColumn
= wParam
;
5705 case SCI_GETHIGHLIGHTGUIDE
:
5706 return highlightGuideColumn
;
5708 case SCI_GETLINEENDPOSITION
:
5709 return pdoc
->LineEnd(wParam
);
5711 case SCI_SETCODEPAGE
:
5712 pdoc
->dbcsCodePage
= wParam
;
5713 InvalidateStyleRedraw();
5716 case SCI_GETCODEPAGE
:
5717 return pdoc
->dbcsCodePage
;
5719 case SCI_SETUSEPALETTE
:
5720 palette
.allowRealization
= wParam
!= 0;
5721 InvalidateStyleRedraw();
5724 case SCI_GETUSEPALETTE
:
5725 return palette
.allowRealization
;
5727 // Marker definition and setting
5728 case SCI_MARKERDEFINE
:
5729 if (wParam
<= MARKER_MAX
)
5730 vs
.markers
[wParam
].markType
= lParam
;
5731 InvalidateStyleData();
5734 case SCI_MARKERSETFORE
:
5735 if (wParam
<= MARKER_MAX
)
5736 vs
.markers
[wParam
].fore
.desired
= ColourDesired(lParam
);
5737 InvalidateStyleData();
5740 case SCI_MARKERSETBACK
:
5741 if (wParam
<= MARKER_MAX
)
5742 vs
.markers
[wParam
].back
.desired
= ColourDesired(lParam
);
5743 InvalidateStyleData();
5746 case SCI_MARKERADD
: {
5747 int markerID
= pdoc
->AddMark(wParam
, lParam
);
5751 case SCI_MARKERDELETE
:
5752 pdoc
->DeleteMark(wParam
, lParam
);
5755 case SCI_MARKERDELETEALL
:
5756 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
5760 return pdoc
->GetMark(wParam
);
5762 case SCI_MARKERNEXT
: {
5763 int lt
= pdoc
->LinesTotal();
5764 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
5765 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
5771 case SCI_MARKERPREVIOUS
: {
5772 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
5773 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
5779 case SCI_MARKERDEFINEPIXMAP
:
5780 if (wParam
<= MARKER_MAX
) {
5781 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
5783 InvalidateStyleData();
5787 case SCI_SETMARGINTYPEN
:
5788 if (ValidMargin(wParam
)) {
5789 vs
.ms
[wParam
].symbol
= (lParam
== SC_MARGIN_SYMBOL
);
5790 InvalidateStyleRedraw();
5794 case SCI_GETMARGINTYPEN
:
5795 if (ValidMargin(wParam
))
5796 return vs
.ms
[wParam
].symbol
? SC_MARGIN_SYMBOL
: SC_MARGIN_NUMBER
;
5800 case SCI_SETMARGINWIDTHN
:
5801 if (ValidMargin(wParam
)) {
5802 vs
.ms
[wParam
].width
= lParam
;
5803 InvalidateStyleRedraw();
5807 case SCI_GETMARGINWIDTHN
:
5808 if (ValidMargin(wParam
))
5809 return vs
.ms
[wParam
].width
;
5813 case SCI_SETMARGINMASKN
:
5814 if (ValidMargin(wParam
)) {
5815 vs
.ms
[wParam
].mask
= lParam
;
5816 InvalidateStyleRedraw();
5820 case SCI_GETMARGINMASKN
:
5821 if (ValidMargin(wParam
))
5822 return vs
.ms
[wParam
].mask
;
5826 case SCI_SETMARGINSENSITIVEN
:
5827 if (ValidMargin(wParam
)) {
5828 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
5829 InvalidateStyleRedraw();
5833 case SCI_GETMARGINSENSITIVEN
:
5834 if (ValidMargin(wParam
))
5835 return vs
.ms
[wParam
].sensitive
? 1 : 0;
5839 case SCI_STYLECLEARALL
:
5841 InvalidateStyleRedraw();
5844 case SCI_STYLESETFORE
:
5845 if (wParam
<= STYLE_MAX
) {
5846 vs
.styles
[wParam
].fore
.desired
= ColourDesired(lParam
);
5847 InvalidateStyleRedraw();
5850 case SCI_STYLESETBACK
:
5851 if (wParam
<= STYLE_MAX
) {
5852 vs
.styles
[wParam
].back
.desired
= ColourDesired(lParam
);
5853 InvalidateStyleRedraw();
5856 case SCI_STYLESETBOLD
:
5857 if (wParam
<= STYLE_MAX
) {
5858 vs
.styles
[wParam
].bold
= lParam
!= 0;
5859 InvalidateStyleRedraw();
5862 case SCI_STYLESETITALIC
:
5863 if (wParam
<= STYLE_MAX
) {
5864 vs
.styles
[wParam
].italic
= lParam
!= 0;
5865 InvalidateStyleRedraw();
5868 case SCI_STYLESETEOLFILLED
:
5869 if (wParam
<= STYLE_MAX
) {
5870 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
5871 InvalidateStyleRedraw();
5874 case SCI_STYLESETSIZE
:
5875 if (wParam
<= STYLE_MAX
) {
5876 vs
.styles
[wParam
].size
= lParam
;
5877 InvalidateStyleRedraw();
5880 case SCI_STYLESETFONT
:
5883 if (wParam
<= STYLE_MAX
) {
5884 vs
.SetStyleFontName(wParam
, CharPtrFromSPtr(lParam
));
5885 InvalidateStyleRedraw();
5888 case SCI_STYLESETUNDERLINE
:
5889 if (wParam
<= STYLE_MAX
) {
5890 vs
.styles
[wParam
].underline
= lParam
!= 0;
5891 InvalidateStyleRedraw();
5894 case SCI_STYLESETCASE
:
5895 if (wParam
<= STYLE_MAX
) {
5896 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
5897 InvalidateStyleRedraw();
5900 case SCI_STYLESETCHARACTERSET
:
5901 if (wParam
<= STYLE_MAX
) {
5902 vs
.styles
[wParam
].characterSet
= lParam
;
5903 InvalidateStyleRedraw();
5906 case SCI_STYLESETVISIBLE
:
5907 if (wParam
<= STYLE_MAX
) {
5908 vs
.styles
[wParam
].visible
= lParam
!= 0;
5909 InvalidateStyleRedraw();
5912 case SCI_STYLESETCHANGEABLE
:
5913 if (wParam
<= STYLE_MAX
) {
5914 vs
.styles
[wParam
].changeable
= lParam
!= 0;
5915 InvalidateStyleRedraw();
5918 case SCI_STYLESETHOTSPOT
:
5919 if (wParam
<= STYLE_MAX
) {
5920 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
5921 InvalidateStyleRedraw();
5925 case SCI_STYLERESETDEFAULT
:
5926 vs
.ResetDefaultStyle();
5927 InvalidateStyleRedraw();
5929 case SCI_SETSTYLEBITS
:
5930 pdoc
->SetStylingBits(wParam
);
5933 case SCI_GETSTYLEBITS
:
5934 return pdoc
->stylingBits
;
5936 case SCI_SETLINESTATE
:
5937 return pdoc
->SetLineState(wParam
, lParam
);
5939 case SCI_GETLINESTATE
:
5940 return pdoc
->GetLineState(wParam
);
5942 case SCI_GETMAXLINESTATE
:
5943 return pdoc
->GetMaxLineState();
5945 case SCI_GETCARETLINEVISIBLE
:
5946 return vs
.showCaretLineBackground
;
5947 case SCI_SETCARETLINEVISIBLE
:
5948 vs
.showCaretLineBackground
= wParam
!= 0;
5949 InvalidateStyleRedraw();
5951 case SCI_GETCARETLINEBACK
:
5952 return vs
.caretLineBackground
.desired
.AsLong();
5953 case SCI_SETCARETLINEBACK
:
5954 vs
.caretLineBackground
.desired
= wParam
;
5955 InvalidateStyleRedraw();
5960 case SCI_VISIBLEFROMDOCLINE
:
5961 return cs
.DisplayFromDoc(wParam
);
5963 case SCI_DOCLINEFROMVISIBLE
:
5964 return cs
.DocFromDisplay(wParam
);
5966 case SCI_SETFOLDLEVEL
: {
5967 int prev
= pdoc
->SetLevel(wParam
, lParam
);
5973 case SCI_GETFOLDLEVEL
:
5974 return pdoc
->GetLevel(wParam
);
5976 case SCI_GETLASTCHILD
:
5977 return pdoc
->GetLastChild(wParam
, lParam
);
5979 case SCI_GETFOLDPARENT
:
5980 return pdoc
->GetFoldParent(wParam
);
5983 cs
.SetVisible(wParam
, lParam
, true);
5989 cs
.SetVisible(wParam
, lParam
, false);
5994 case SCI_GETLINEVISIBLE
:
5995 return cs
.GetVisible(wParam
);
5997 case SCI_SETFOLDEXPANDED
:
5998 if (cs
.SetExpanded(wParam
, lParam
!= 0)) {
6003 case SCI_GETFOLDEXPANDED
:
6004 return cs
.GetExpanded(wParam
);
6006 case SCI_SETFOLDFLAGS
:
6011 case SCI_TOGGLEFOLD
:
6012 ToggleContraction(wParam
);
6015 case SCI_ENSUREVISIBLE
:
6016 EnsureLineVisible(wParam
, false);
6019 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
6020 EnsureLineVisible(wParam
, true);
6023 case SCI_SEARCHANCHOR
:
6027 case SCI_SEARCHNEXT
:
6028 case SCI_SEARCHPREV
:
6029 return SearchText(iMessage
, wParam
, lParam
);
6031 #ifdef INCLUDE_DEPRECATED_FEATURES
6032 case SCI_SETCARETPOLICY
: // Deprecated
6033 caretXPolicy
= caretYPolicy
= wParam
;
6034 caretXSlop
= caretYSlop
= lParam
;
6038 case SCI_SETXCARETPOLICY
:
6039 caretXPolicy
= wParam
;
6040 caretXSlop
= lParam
;
6043 case SCI_SETYCARETPOLICY
:
6044 caretYPolicy
= wParam
;
6045 caretYSlop
= lParam
;
6048 case SCI_SETVISIBLEPOLICY
:
6049 visiblePolicy
= wParam
;
6050 visibleSlop
= lParam
;
6053 case SCI_LINESONSCREEN
:
6054 return LinesOnScreen();
6056 case SCI_SETSELFORE
:
6057 vs
.selforeset
= wParam
!= 0;
6058 vs
.selforeground
.desired
= ColourDesired(lParam
);
6059 InvalidateStyleRedraw();
6062 case SCI_SETSELBACK
:
6063 vs
.selbackset
= wParam
!= 0;
6064 vs
.selbackground
.desired
= ColourDesired(lParam
);
6065 InvalidateStyleRedraw();
6068 case SCI_SETWHITESPACEFORE
:
6069 vs
.whitespaceForegroundSet
= wParam
!= 0;
6070 vs
.whitespaceForeground
.desired
= ColourDesired(lParam
);
6071 InvalidateStyleRedraw();
6074 case SCI_SETWHITESPACEBACK
:
6075 vs
.whitespaceBackgroundSet
= wParam
!= 0;
6076 vs
.whitespaceBackground
.desired
= ColourDesired(lParam
);
6077 InvalidateStyleRedraw();
6080 case SCI_SETCARETFORE
:
6081 vs
.caretcolour
.desired
= ColourDesired(wParam
);
6082 InvalidateStyleRedraw();
6085 case SCI_GETCARETFORE
:
6086 return vs
.caretcolour
.desired
.AsLong();
6088 case SCI_SETCARETWIDTH
:
6091 else if (wParam
>= 3)
6094 vs
.caretWidth
= wParam
;
6095 InvalidateStyleRedraw();
6098 case SCI_GETCARETWIDTH
:
6099 return vs
.caretWidth
;
6101 case SCI_ASSIGNCMDKEY
:
6102 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6103 Platform::HighShortFromLong(wParam
), lParam
);
6106 case SCI_CLEARCMDKEY
:
6107 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6108 Platform::HighShortFromLong(wParam
), SCI_NULL
);
6111 case SCI_CLEARALLCMDKEYS
:
6115 case SCI_INDICSETSTYLE
:
6116 if (wParam
<= INDIC_MAX
) {
6117 vs
.indicators
[wParam
].style
= lParam
;
6118 InvalidateStyleRedraw();
6122 case SCI_INDICGETSTYLE
:
6123 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
6125 case SCI_INDICSETFORE
:
6126 if (wParam
<= INDIC_MAX
) {
6127 vs
.indicators
[wParam
].fore
.desired
= ColourDesired(lParam
);
6128 InvalidateStyleRedraw();
6132 case SCI_INDICGETFORE
:
6133 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
6136 case SCI_LINEDOWNEXTEND
:
6138 case SCI_PARADOWNEXTEND
:
6140 case SCI_LINEUPEXTEND
:
6142 case SCI_PARAUPEXTEND
:
6144 case SCI_CHARLEFTEXTEND
:
6146 case SCI_CHARRIGHTEXTEND
:
6148 case SCI_WORDLEFTEXTEND
:
6150 case SCI_WORDRIGHTEXTEND
:
6152 case SCI_HOMEEXTEND
:
6154 case SCI_LINEENDEXTEND
:
6156 case SCI_HOMEWRAPEXTEND
:
6157 case SCI_LINEENDWRAP
:
6158 case SCI_LINEENDWRAPEXTEND
:
6159 case SCI_DOCUMENTSTART
:
6160 case SCI_DOCUMENTSTARTEXTEND
:
6161 case SCI_DOCUMENTEND
:
6162 case SCI_DOCUMENTENDEXTEND
:
6164 case SCI_PAGEUPEXTEND
:
6166 case SCI_PAGEDOWNEXTEND
:
6167 case SCI_EDITTOGGLEOVERTYPE
:
6169 case SCI_DELETEBACK
:
6175 case SCI_VCHOMEEXTEND
:
6176 case SCI_VCHOMEWRAP
:
6177 case SCI_VCHOMEWRAPEXTEND
:
6180 case SCI_DELWORDLEFT
:
6181 case SCI_DELWORDRIGHT
:
6182 case SCI_DELLINELEFT
:
6183 case SCI_DELLINERIGHT
:
6185 case SCI_LINEDELETE
:
6186 case SCI_LINETRANSPOSE
:
6187 case SCI_LINEDUPLICATE
:
6190 case SCI_LINESCROLLDOWN
:
6191 case SCI_LINESCROLLUP
:
6192 case SCI_WORDPARTLEFT
:
6193 case SCI_WORDPARTLEFTEXTEND
:
6194 case SCI_WORDPARTRIGHT
:
6195 case SCI_WORDPARTRIGHTEXTEND
:
6196 case SCI_DELETEBACKNOTLINE
:
6197 case SCI_HOMEDISPLAY
:
6198 case SCI_HOMEDISPLAYEXTEND
:
6199 case SCI_LINEENDDISPLAY
:
6200 case SCI_LINEENDDISPLAYEXTEND
:
6201 return KeyCommand(iMessage
);
6203 case SCI_BRACEHIGHLIGHT
:
6204 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
6207 case SCI_BRACEBADLIGHT
:
6208 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
6211 case SCI_BRACEMATCH
:
6212 // wParam is position of char to find brace for,
6213 // lParam is maximum amount of text to restyle to find it
6214 return BraceMatch(wParam
, lParam
);
6216 case SCI_GETVIEWEOL
:
6219 case SCI_SETVIEWEOL
:
6220 vs
.viewEOL
= wParam
!= 0;
6221 InvalidateStyleRedraw();
6225 vs
.zoomLevel
= wParam
;
6226 InvalidateStyleRedraw();
6231 return vs
.zoomLevel
;
6233 case SCI_GETEDGECOLUMN
:
6236 case SCI_SETEDGECOLUMN
:
6238 InvalidateStyleRedraw();
6241 case SCI_GETEDGEMODE
:
6242 return vs
.edgeState
;
6244 case SCI_SETEDGEMODE
:
6245 vs
.edgeState
= wParam
;
6246 InvalidateStyleRedraw();
6249 case SCI_GETEDGECOLOUR
:
6250 return vs
.edgecolour
.desired
.AsLong();
6252 case SCI_SETEDGECOLOUR
:
6253 vs
.edgecolour
.desired
= ColourDesired(wParam
);
6254 InvalidateStyleRedraw();
6257 case SCI_GETDOCPOINTER
:
6258 return reinterpret_cast<sptr_t
>(pdoc
);
6260 case SCI_SETDOCPOINTER
:
6262 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
6265 case SCI_CREATEDOCUMENT
: {
6266 Document
*doc
= new Document();
6270 return reinterpret_cast<sptr_t
>(doc
);
6273 case SCI_ADDREFDOCUMENT
:
6274 (reinterpret_cast<Document
*>(lParam
))->AddRef();
6277 case SCI_RELEASEDOCUMENT
:
6278 (reinterpret_cast<Document
*>(lParam
))->Release();
6281 case SCI_SETMODEVENTMASK
:
6282 modEventMask
= wParam
;
6285 case SCI_GETMODEVENTMASK
:
6286 return modEventMask
;
6288 case SCI_CONVERTEOLS
:
6289 pdoc
->ConvertLineEnds(wParam
);
6290 SetSelection(currentPos
, anchor
); // Ensure selection inside document
6293 case SCI_SELECTIONISRECTANGLE
:
6294 return (selType
== selRectangle
) ? 1 : 0;
6296 case SCI_SETOVERTYPE
:
6297 inOverstrike
= wParam
!= 0;
6300 case SCI_GETOVERTYPE
:
6301 return inOverstrike
? 1 : 0;
6304 SetFocusState(wParam
!= 0);
6311 errorStatus
= wParam
;
6317 case SCI_SETMOUSEDOWNCAPTURES
:
6318 mouseDownCaptures
= wParam
!= 0;
6321 case SCI_GETMOUSEDOWNCAPTURES
:
6322 return mouseDownCaptures
;
6325 cursorMode
= wParam
;
6326 DisplayCursor(Window::cursorText
);
6332 case SCI_SETCONTROLCHARSYMBOL
:
6333 controlCharSymbol
= wParam
;
6336 case SCI_GETCONTROLCHARSYMBOL
:
6337 return controlCharSymbol
;
6339 case SCI_STARTRECORD
:
6340 recordingMacro
= true;
6343 case SCI_STOPRECORD
:
6344 recordingMacro
= false;
6347 case SCI_MOVECARETINSIDEVIEW
:
6348 MoveCaretInsideView();
6351 case SCI_SETFOLDMARGINCOLOUR
:
6352 vs
.foldmarginColourSet
= wParam
!= 0;
6353 vs
.foldmarginColour
.desired
= ColourDesired(lParam
);
6354 InvalidateStyleRedraw();
6357 case SCI_SETFOLDMARGINHICOLOUR
:
6358 vs
.foldmarginHighlightColourSet
= wParam
!= 0;
6359 vs
.foldmarginHighlightColour
.desired
= ColourDesired(lParam
);
6360 InvalidateStyleRedraw();
6363 case SCI_SETHOTSPOTACTIVEFORE
:
6364 vs
.hotspotForegroundSet
= wParam
!= 0;
6365 vs
.hotspotForeground
.desired
= ColourDesired(lParam
);
6366 InvalidateStyleRedraw();
6369 case SCI_SETHOTSPOTACTIVEBACK
:
6370 vs
.hotspotBackgroundSet
= wParam
!= 0;
6371 vs
.hotspotBackground
.desired
= ColourDesired(lParam
);
6372 InvalidateStyleRedraw();
6375 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
6376 vs
.hotspotUnderline
= wParam
!= 0;
6377 InvalidateStyleRedraw();
6381 return DefWndProc(iMessage
, wParam
, lParam
);
6383 //Platform::DebugPrintf("end wnd proc\n");