1 // Scintilla source code edit control
3 ** Main code for the edit control.
5 // Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
16 #define INCLUDE_DEPRECATED_FEATURES
18 #include "Scintilla.h"
20 #include "ContractionState.h"
22 #include "CellBuffer.h"
24 #include "Indicator.h"
26 #include "LineMarker.h"
28 #include "ViewStyle.h"
33 active(false), on(false), period(500) {}
36 ticking(false), ticksToWait(0), tickerID(0) {}
38 LineLayout::LineLayout(int maxLineLength_
) :
56 widthLine(wrapWidthInfinite
),
58 Resize(maxLineLength_
);
61 LineLayout::~LineLayout() {
65 void LineLayout::Resize(int maxLineLength_
) {
66 if (maxLineLength_
> maxLineLength
) {
68 chars
= new char[maxLineLength_
+ 1];
69 styles
= new char[maxLineLength_
+ 1];
70 indicators
= new char[maxLineLength_
+ 1];
71 // Extra position allocated as sometimes the Windows
72 // GetTextExtentExPoint API writes an extra element.
73 positions
= new int[maxLineLength_
+ 1 + 1];
74 maxLineLength
= maxLineLength_
;
78 void LineLayout::Free() {
91 void LineLayout::Invalidate(validLevel validity_
) {
92 if (validity
> validity_
)
96 void LineLayout::SetLineStart(int line
, int start
) {
97 if ((line
>= lenLineStarts
) && (line
!= 0)) {
98 int newMaxLines
= line
+ 20;
99 int *newLineStarts
= new int[newMaxLines
];
102 for (int i
= 0; i
< newMaxLines
; i
++) {
103 if (i
< lenLineStarts
)
104 newLineStarts
[i
] = lineStarts
[i
];
106 newLineStarts
[i
] = 0;
109 lineStarts
= newLineStarts
;
110 lenLineStarts
= newMaxLines
;
112 lineStarts
[line
] = start
;
115 void LineLayout::SetBracesHighlight(Range rangeLine
, Position braces
[],
116 char bracesMatchStyle
, int xHighlight
) {
117 if (rangeLine
.ContainsCharacter(braces
[0])) {
118 int braceOffset
= braces
[0] - rangeLine
.start
;
119 if (braceOffset
< numCharsInLine
) {
120 bracePreviousStyles
[0] = styles
[braceOffset
];
121 styles
[braceOffset
] = bracesMatchStyle
;
124 if (rangeLine
.ContainsCharacter(braces
[1])) {
125 int braceOffset
= braces
[1] - rangeLine
.start
;
126 if (braceOffset
< numCharsInLine
) {
127 bracePreviousStyles
[1] = styles
[braceOffset
];
128 styles
[braceOffset
] = bracesMatchStyle
;
131 if ((braces
[0] >= rangeLine
.start
&& braces
[1] <= rangeLine
.end
) ||
132 (braces
[1] >= rangeLine
.start
&& braces
[0] <= rangeLine
.end
)) {
133 xHighlightGuide
= xHighlight
;
137 void LineLayout::RestoreBracesHighlight(Range rangeLine
, Position braces
[]) {
138 if (rangeLine
.ContainsCharacter(braces
[0])) {
139 int braceOffset
= braces
[0] - rangeLine
.start
;
140 if (braceOffset
< numCharsInLine
) {
141 styles
[braceOffset
] = bracePreviousStyles
[0];
144 if (rangeLine
.ContainsCharacter(braces
[1])) {
145 int braceOffset
= braces
[1] - rangeLine
.start
;
146 if (braceOffset
< numCharsInLine
) {
147 styles
[braceOffset
] = bracePreviousStyles
[1];
153 LineLayoutCache::LineLayoutCache() :
154 level(0), length(0), size(0), cache(0),
155 allInvalidated(false), styleClock(-1) {
159 LineLayoutCache::~LineLayoutCache() {
163 void LineLayoutCache::Allocate(int length_
) {
164 allInvalidated
= false;
168 size
= (size
/ 16 + 1) * 16;
171 cache
= new LineLayout
* [size
];
173 for (int i
= 0; i
< size
; i
++)
177 void LineLayoutCache::AllocateForLevel(int linesOnScreen
, int linesInDoc
) {
178 int lengthForLevel
= 0;
179 if (level
== llcCaret
) {
181 } else if (level
== llcPage
) {
182 lengthForLevel
= linesOnScreen
+ 1;
183 } else if (level
== llcDocument
) {
184 lengthForLevel
= linesInDoc
;
186 if (lengthForLevel
> size
) {
188 } else if (lengthForLevel
< length
) {
189 for (int i
= lengthForLevel
; i
< length
; i
++) {
195 Allocate(lengthForLevel
);
199 void LineLayoutCache::Deallocate() {
200 for (int i
= 0; i
< length
; i
++)
207 void LineLayoutCache::Invalidate(LineLayout::validLevel validity_
) {
208 if (cache
&& !allInvalidated
) {
209 for (int i
= 0; i
< length
; i
++) {
211 cache
[i
]->Invalidate(validity_
);
214 if (validity_
== LineLayout::llInvalid
) {
215 allInvalidated
= true;
220 void LineLayoutCache::SetLevel(int level_
) {
221 allInvalidated
= false;
222 if ((level_
!= -1) && (level
!= level_
)) {
228 LineLayout
*LineLayoutCache::Retrieve(int lineNumber
, int lineCaret
, int maxChars
, int styleClock_
,
229 int linesOnScreen
, int linesInDoc
) {
230 AllocateForLevel(linesOnScreen
, linesInDoc
);
231 if (styleClock
!= styleClock_
) {
232 Invalidate(LineLayout::llCheckTextAndStyle
);
233 styleClock
= styleClock_
;
235 allInvalidated
= false;
238 if (((level
== llcCaret
) || (level
== llcPage
)) && (lineNumber
== lineCaret
)) {
240 } else if (level
== llcPage
) {
241 pos
= lineNumber
% length
;
242 } else if (level
== llcDocument
) {
246 if (cache
&& (pos
< length
)) {
248 if ((cache
[pos
]->lineNumber
!= lineNumber
) ||
249 (cache
[pos
]->maxLineLength
< maxChars
)) {
255 cache
[pos
] = new LineLayout(maxChars
);
258 cache
[pos
]->lineNumber
= lineNumber
;
259 cache
[pos
]->inCache
= true;
266 ret
= new LineLayout(maxChars
);
267 ret
->lineNumber
= lineNumber
;
273 void LineLayoutCache::Dispose(LineLayout
*ll
) {
274 allInvalidated
= false;
287 printMagnification
= 0;
288 printColourMode
= SC_PRINT_NORMAL
;
289 printWrapState
= eWrapWord
;
290 cursorMode
= SC_CURSORNORMAL
;
291 controlCharSymbol
= 0; /* Draw the control characters */
294 hideSelection
= false;
295 inOverstrike
= false;
297 mouseDownCaptures
= true;
303 dwellDelay
= SC_TIME_FOREVER
;
304 ticksToDwell
= SC_TIME_FOREVER
;
309 dropWentOutside
= false;
310 posDrag
= invalidPosition
;
311 posDrop
= invalidPosition
;
312 selectionType
= selChar
;
316 originalAnchorPos
= 0;
321 primarySelection
= true;
323 caretXPolicy
= CARET_SLOP
| CARET_EVEN
;
326 caretYPolicy
= CARET_EVEN
;
333 horizontalScrollBarVisible
= true;
335 verticalScrollBarVisible
= true;
336 endAtLastLine
= true;
338 pixmapLine
= Surface::Allocate();
339 pixmapSelMargin
= Surface::Allocate();
340 pixmapSelPattern
= Surface::Allocate();
341 pixmapIndentGuide
= Surface::Allocate();
342 pixmapIndentGuideHighlight
= Surface::Allocate();
355 braces
[0] = invalidPosition
;
356 braces
[1] = invalidPosition
;
357 bracesMatchStyle
= STYLE_BRACEBAD
;
358 highlightGuideColumn
= 0;
362 paintState
= notPainting
;
364 modEventMask
= SC_MODEVENTMASKALL
;
366 pdoc
= new Document();
368 pdoc
->AddWatcher(this, 0);
370 recordingMacro
= false;
373 wrapState
= eWrapNone
;
374 wrapWidth
= LineLayout::wrapWidthInfinite
;
375 docLineLastWrapped
= -1;
380 llc
.SetLevel(LineLayoutCache::llcCaret
);
384 pdoc
->RemoveWatcher(this, 0);
389 delete pixmapSelMargin
;
390 delete pixmapSelPattern
;
391 delete pixmapIndentGuide
;
392 delete pixmapIndentGuideHighlight
;
395 void Editor::Finalise() {
399 void Editor::DropGraphics() {
400 pixmapLine
->Release();
401 pixmapSelMargin
->Release();
402 pixmapSelPattern
->Release();
403 pixmapIndentGuide
->Release();
406 void Editor::InvalidateStyleData() {
410 llc
.Invalidate(LineLayout::llInvalid
);
413 void Editor::InvalidateStyleRedraw() {
415 InvalidateStyleData();
419 void Editor::RefreshColourPalette(Palette
&pal
, bool want
) {
420 vs
.RefreshColourPalette(pal
, want
);
423 void Editor::RefreshStyleData() {
426 AutoSurface
surface(this);
428 vs
.Refresh(*surface
);
429 RefreshColourPalette(palette
, true);
430 palette
.Allocate(wMain
);
431 RefreshColourPalette(palette
, false);
437 PRectangle
Editor::GetClientRectangle() {
438 return wMain
.GetClientPosition();
441 PRectangle
Editor::GetTextRectangle() {
442 PRectangle rc
= GetClientRectangle();
443 rc
.left
+= vs
.fixedColumnWidth
;
444 rc
.right
-= vs
.rightMarginWidth
;
448 int Editor::LinesOnScreen() {
449 PRectangle rcClient
= GetClientRectangle();
450 int htClient
= rcClient
.bottom
- rcClient
.top
;
451 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
452 return htClient
/ vs
.lineHeight
;
455 int Editor::LinesToScroll() {
456 int retVal
= LinesOnScreen() - 1;
463 int Editor::MaxScrollPos() {
464 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
465 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
466 int retVal
= cs
.LinesDisplayed();
468 retVal
-= LinesOnScreen();
479 static inline bool IsControlCharacter(char ch
) {
480 // iscntrl returns true for lots of chars > 127 which are displayable
481 return ch
>= 0 && ch
< ' ';
484 const char *ControlCharacterString(unsigned char ch
) {
485 const char *reps
[] = {
486 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
487 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
488 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
489 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
491 if (ch
< (sizeof(reps
) / sizeof(reps
[0]))) {
498 // Convenience class to ensure LineLayout objects are always disposed.
499 class AutoLineLayout
{
500 LineLayoutCache
&llc
;
502 AutoLineLayout
&operator=(const AutoLineLayout
&) { return * this; }
504 AutoLineLayout(LineLayoutCache
&llc_
, LineLayout
*ll_
) : llc(llc_
), ll(ll_
) {}
509 LineLayout
*operator->() const {
512 operator LineLayout
*() const {
515 void Set(LineLayout
*ll_
) {
521 Point
Editor::LocationFromPosition(int pos
) {
524 if (pos
== INVALID_POSITION
)
526 int line
= pdoc
->LineFromPosition(pos
);
527 int lineVisible
= cs
.DisplayFromDoc(line
);
528 //Platform::DebugPrintf("line=%d\n", line);
529 AutoSurface
surface(this);
530 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
532 // -1 because of adding in for visible lines in following loop.
533 pt
.y
= (lineVisible
- topLine
- 1) * vs
.lineHeight
;
535 unsigned int posLineStart
= pdoc
->LineStart(line
);
536 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
537 int posInLine
= pos
- posLineStart
;
538 // In case of very long line put x at arbitrary large position
539 if (posInLine
> ll
->maxLineLength
) {
540 pt
.x
= ll
->positions
[ll
->maxLineLength
] - ll
->positions
[ll
->LineStart(ll
->lines
)];
542 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
543 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
544 pt
.x
= ll
->positions
[posInLine
] - ll
->positions
[ll
->LineStart(subLine
)];
546 if (posInLine
>= ll
->LineStart(subLine
)) {
547 pt
.y
+= vs
.lineHeight
;
550 pt
.x
+= vs
.fixedColumnWidth
- xOffset
;
555 int Editor::XFromPosition(int pos
) {
556 Point pt
= LocationFromPosition(pos
);
557 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
560 int Editor::LineFromLocation(Point pt
) {
561 return cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
564 void Editor::SetTopLine(int topLineNew
) {
565 topLine
= topLineNew
;
566 posTopLine
= pdoc
->LineStart(topLine
);
569 static inline bool IsEOLChar(char ch
) {
570 return (ch
== '\r') || (ch
== '\n');
573 int Editor::PositionFromLocation(Point pt
) {
575 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
576 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
577 if (pt
.y
< 0) { // Division rounds towards 0
578 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
582 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
583 if (lineDoc
>= pdoc
->LinesTotal())
584 return pdoc
->Length();
585 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
586 int retVal
= posLineStart
;
587 AutoSurface
surface(this);
588 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
590 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
591 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
592 int subLine
= visibleLine
- lineStartSet
;
593 if (subLine
< ll
->lines
) {
594 int lineStart
= ll
->LineStart(subLine
);
595 int lineEnd
= ll
->LineStart(subLine
+ 1);
596 int subLineStart
= ll
->positions
[lineStart
];
597 for (int i
= lineStart
; i
< lineEnd
; i
++) {
598 if (pt
.x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
599 IsEOLChar(ll
->chars
[i
])) {
600 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
603 return lineEnd
+ posLineStart
;
605 retVal
= ll
->numCharsInLine
+ posLineStart
;
610 // Like PositionFromLocation but INVALID_POSITION returned when not near any text.
611 int Editor::PositionFromLocationClose(Point pt
) {
613 PRectangle rcClient
= GetTextRectangle();
614 if (!rcClient
.Contains(pt
))
615 return INVALID_POSITION
;
616 if (pt
.x
< vs
.fixedColumnWidth
)
617 return INVALID_POSITION
;
619 return INVALID_POSITION
;
620 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
621 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
622 if (pt
.y
< 0) { // Division rounds towards 0
623 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
625 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
627 return INVALID_POSITION
;
628 if (lineDoc
>= pdoc
->LinesTotal())
629 return INVALID_POSITION
;
630 AutoSurface
surface(this);
631 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
633 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
634 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
635 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
636 int subLine
= visibleLine
- lineStartSet
;
637 if (subLine
< ll
->lines
) {
638 int lineStart
= ll
->LineStart(subLine
);
639 int lineEnd
= ll
->LineStart(subLine
+ 1);
640 int subLineStart
= ll
->positions
[lineStart
];
641 for (int i
= lineStart
; i
< lineEnd
; i
++) {
642 if (pt
.x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
643 IsEOLChar(ll
->chars
[i
])) {
644 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
650 return INVALID_POSITION
;
654 * Find the document position corresponding to an x coordinate on a particular document line.
655 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
657 int Editor::PositionFromLineX(int lineDoc
, int x
) {
659 if (lineDoc
>= pdoc
->LinesTotal())
660 return pdoc
->Length();
661 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
662 AutoSurface
surface(this);
663 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
666 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
667 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
668 retVal
= ll
->numCharsInLine
+ posLineStart
;
670 int lineStart
= ll
->LineStart(subLine
);
671 int lineEnd
= ll
->LineStart(subLine
+ 1);
672 int subLineStart
= ll
->positions
[lineStart
];
673 for (int i
= lineStart
; i
< lineEnd
; i
++) {
674 if (x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
675 IsEOLChar(ll
->chars
[i
])) {
676 retVal
= pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
684 // If painting then abandon the painting because a wider redraw is needed.
685 // Return true if calling code should stop drawing
686 bool Editor::AbandonPaint() {
687 if ((paintState
== painting
) && !paintingAllText
) {
688 paintState
= paintAbandoned
;
690 return paintState
== paintAbandoned
;
693 void Editor::RedrawRect(PRectangle rc
) {
694 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
696 // Clip the redraw rectangle into the client area
697 PRectangle rcClient
= GetClientRectangle();
698 if (rc
.top
< rcClient
.top
)
699 rc
.top
= rcClient
.top
;
700 if (rc
.bottom
> rcClient
.bottom
)
701 rc
.bottom
= rcClient
.bottom
;
702 if (rc
.left
< rcClient
.left
)
703 rc
.left
= rcClient
.left
;
704 if (rc
.right
> rcClient
.right
)
705 rc
.right
= rcClient
.right
;
707 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
708 wMain
.InvalidateRectangle(rc
);
712 void Editor::Redraw() {
713 //Platform::DebugPrintf("Redraw all\n");
714 wMain
.InvalidateAll();
717 void Editor::RedrawSelMargin() {
718 if (!AbandonPaint()) {
722 PRectangle rcSelMargin
= GetClientRectangle();
723 rcSelMargin
.right
= vs
.fixedColumnWidth
;
724 wMain
.InvalidateRectangle(rcSelMargin
);
729 PRectangle
Editor::RectangleFromRange(int start
, int end
) {
736 int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(minPos
));
737 int lineDocMax
= pdoc
->LineFromPosition(maxPos
);
738 int maxLine
= cs
.DisplayFromDoc(lineDocMax
) + cs
.GetHeight(lineDocMax
) - 1;
739 PRectangle rcClient
= GetTextRectangle();
741 rc
.left
= vs
.fixedColumnWidth
;
742 rc
.top
= (minLine
- topLine
) * vs
.lineHeight
;
745 rc
.right
= rcClient
.right
;
746 rc
.bottom
= (maxLine
- topLine
+ 1) * vs
.lineHeight
;
747 // Ensure PRectangle is within 16 bit space
748 rc
.top
= Platform::Clamp(rc
.top
, -32000, 32000);
749 rc
.bottom
= Platform::Clamp(rc
.bottom
, -32000, 32000);
754 void Editor::InvalidateRange(int start
, int end
) {
755 RedrawRect(RectangleFromRange(start
, end
));
758 int Editor::CurrentPosition() {
762 bool Editor::SelectionEmpty() {
763 return anchor
== currentPos
;
766 int Editor::SelectionStart(int line
) {
767 if ((line
== -1) || (selType
== selStream
)) {
768 return Platform::Minimum(currentPos
, anchor
);
769 } else { // selType == selRectangle
770 int selStart
= SelectionStart();
771 int selEnd
= SelectionEnd();
772 int lineStart
= pdoc
->LineFromPosition(selStart
);
773 int lineEnd
= pdoc
->LineFromPosition(selEnd
);
774 if (line
< lineStart
|| line
> lineEnd
) {
777 int minX
= Platform::Minimum(xStartSelect
, xEndSelect
);
778 return PositionFromLineX(line
, minX
);
783 int Editor::SelectionEnd(int line
) {
784 if ((line
== -1) || (selType
== selStream
)) {
785 return Platform::Maximum(currentPos
, anchor
);
786 } else { // selType == selRectangle
787 int selStart
= SelectionStart();
788 int selEnd
= SelectionEnd();
789 int lineStart
= pdoc
->LineFromPosition(selStart
);
790 int lineEnd
= pdoc
->LineFromPosition(selEnd
);
791 if (line
< lineStart
|| line
> lineEnd
) {
794 int maxX
= Platform::Maximum(xStartSelect
, xEndSelect
);
795 // measure line and return character closest to minx
796 return PositionFromLineX(line
, maxX
);
801 void Editor::SetSelection(int currentPos_
, int anchor_
) {
802 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
803 anchor_
= pdoc
->ClampPositionIntoDocument(anchor_
);
804 if ((currentPos
!= currentPos_
) || (anchor
!= anchor_
)) {
805 int firstAffected
= anchor
;
806 if (firstAffected
> currentPos
)
807 firstAffected
= currentPos
;
808 if (firstAffected
> anchor_
)
809 firstAffected
= anchor_
;
810 if (firstAffected
> currentPos_
)
811 firstAffected
= currentPos_
;
812 int lastAffected
= anchor
;
813 if (lastAffected
< currentPos
)
814 lastAffected
= currentPos
;
815 if (lastAffected
< anchor_
)
816 lastAffected
= anchor_
;
817 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
818 lastAffected
= (currentPos_
+ 1);
819 currentPos
= currentPos_
;
822 InvalidateRange(firstAffected
, lastAffected
);
827 void Editor::SetSelection(int currentPos_
) {
828 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
829 if (currentPos
!= currentPos_
) {
830 int firstAffected
= anchor
;
831 if (firstAffected
> currentPos
)
832 firstAffected
= currentPos
;
833 if (firstAffected
> currentPos_
)
834 firstAffected
= currentPos_
;
835 int lastAffected
= anchor
;
836 if (lastAffected
< currentPos
)
837 lastAffected
= currentPos
;
838 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
839 lastAffected
= (currentPos_
+ 1);
840 currentPos
= currentPos_
;
842 InvalidateRange(firstAffected
, lastAffected
);
847 void Editor::SetEmptySelection(int currentPos_
) {
849 SetSelection(currentPos_
, currentPos_
);
852 bool Editor::RangeContainsProtected(int start
, int end
) const {
853 if (vs
.ProtectionActive()) {
859 int mask
= pdoc
->stylingBitsMask
;
860 for (int pos
= start
; pos
< end
; pos
++) {
861 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected())
868 bool Editor::SelectionContainsProtected() const {
869 // TODO: make support rectangular selection
870 return RangeContainsProtected(anchor
, currentPos
);
873 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) {
874 // Asks document to find a good position and then moves out of any invisible positions
875 pos
= pdoc
->MovePositionOutsideChar(pos
, moveDir
, checkLineEnd
);
876 if (vs
.ProtectionActive()) {
877 int mask
= pdoc
->stylingBitsMask
;
879 if ((pos
> 0) && vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()) {
880 while ((pos
< pdoc
->Length()) &&
881 (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected()))
884 } else if (moveDir
< 0) {
885 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected()) {
887 (vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()))
895 int Editor::MovePositionTo(int newPos
, bool extend
, bool ensureVisible
) {
896 int delta
= newPos
- currentPos
;
897 newPos
= pdoc
->ClampPositionIntoDocument(newPos
);
898 newPos
= MovePositionOutsideChar(newPos
, delta
);
900 SetSelection(newPos
);
902 SetEmptySelection(newPos
);
904 ShowCaretAtCurrentPosition();
906 EnsureCaretVisible();
911 int Editor::MovePositionSoVisible(int pos
, int moveDir
) {
912 pos
= pdoc
->ClampPositionIntoDocument(pos
);
913 pos
= MovePositionOutsideChar(pos
, moveDir
);
914 int lineDoc
= pdoc
->LineFromPosition(pos
);
915 if (cs
.GetVisible(lineDoc
)) {
918 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
920 // lineDisplay is already line before fold as lines in fold use display line of line after fold
921 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
922 return pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
));
924 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
925 return pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
));
930 // Choose the x position that the caret will try to stick to as it is moves up and down
931 void Editor::SetLastXChosen() {
932 Point pt
= LocationFromPosition(currentPos
);
936 void Editor::ScrollTo(int line
, bool moveThumb
) {
937 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
938 if (topLineNew
!= topLine
) {
939 // Try to optimise small scrolls
940 int linesToMove
= topLine
- topLineNew
;
941 SetTopLine(topLineNew
);
942 ShowCaretAtCurrentPosition();
943 // Perform redraw rather than scroll if many lines would be redrawn anyway.
944 if (abs(linesToMove
) <= 10) {
945 ScrollText(linesToMove
);
950 SetVerticalScrollPos();
955 void Editor::ScrollText(int /* linesToMove */) {
956 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
960 void Editor::HorizontalScrollTo(int xPos
) {
961 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
964 if ((wrapState
== eWrapNone
) && (xOffset
!= xPos
)) {
966 SetHorizontalScrollPos();
967 RedrawRect(GetClientRectangle());
971 void Editor::MoveCaretInsideView(bool ensureVisible
) {
972 PRectangle rcClient
= GetTextRectangle();
973 Point pt
= LocationFromPosition(currentPos
);
974 if (pt
.y
< rcClient
.top
) {
975 MovePositionTo(PositionFromLocation(
976 Point(lastXChosen
, rcClient
.top
)),
977 false, ensureVisible
);
978 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
979 int yOfLastLineFullyDisplayed
= rcClient
.top
+ (LinesOnScreen() - 1) * vs
.lineHeight
;
980 MovePositionTo(PositionFromLocation(
981 Point(lastXChosen
, rcClient
.top
+ yOfLastLineFullyDisplayed
)),
982 false, ensureVisible
);
986 int Editor::DisplayFromPosition(int pos
) {
987 int lineDoc
= pdoc
->LineFromPosition(pos
);
988 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
989 AutoSurface
surface(this);
990 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
992 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
993 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
994 int posInLine
= pos
- posLineStart
;
995 lineDisplay
--; // To make up for first increment ahead.
996 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
997 if (posInLine
>= ll
->LineStart(subLine
)) {
1006 * Ensure the caret is reasonably visible in context.
1008 Caret policy in SciTE
1010 If slop is set, we can define a slop value.
1011 This value defines an unwanted zone (UZ) where the caret is... unwanted.
1012 This zone is defined as a number of pixels near the vertical margins,
1013 and as a number of lines near the horizontal margins.
1014 By keeping the caret away from the edges, it is seen within its context,
1015 so it is likely that the identifier that the caret is on can be completely seen,
1016 and that the current line is seen with some of the lines following it which are
1017 often dependent on that line.
1019 If strict is set, the policy is enforced... strictly.
1020 The caret is centred on the display if slop is not set,
1021 and cannot go in the UZ if slop is set.
1023 If jumps is set, the display is moved more energetically
1024 so the caret can move in the same direction longer before the policy is applied again.
1025 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1027 If even is not set, instead of having symmetrical UZs,
1028 the left and bottom UZs are extended up to right and top UZs respectively.
1029 This way, we favour the displaying of useful information: the begining of lines,
1030 where most code reside, and the lines after the caret, eg. the body of a function.
1033 slop | strict | jumps | even | Caret can go to the margin | When reaching limit (caret going out of
1034 | | | | | visibility or going into the UZ) display is...
1035 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1036 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1037 0 | 0 | 0 | 1 | Yes | moved by one position
1038 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1039 0 | 0 | 1 | 1 | Yes | centred on the caret
1040 0 | 1 | - | 0 | Caret is always on top/on right of display | -
1041 0 | 1 | - | 1 | No, caret is always centred | -
1042 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1043 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1044 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1045 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1046 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1047 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1048 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1050 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
1051 //Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " ");
1052 PRectangle rcClient
= GetTextRectangle();
1053 //int rcClientFullWidth = rcClient.Width();
1054 int posCaret
= currentPos
;
1058 Point pt
= LocationFromPosition(posCaret
);
1059 Point ptBottomCaret
= pt
;
1060 ptBottomCaret
.y
+= vs
.lineHeight
- 1;
1061 int lineCaret
= DisplayFromPosition(posCaret
);
1062 bool bSlop
, bStrict
, bJump
, bEven
;
1064 // Vertical positioning
1065 if (vert
&& (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
> rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1066 int linesOnScreen
= LinesOnScreen();
1067 int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1068 int newTopLine
= topLine
;
1069 bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1070 bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1071 bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1072 bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1074 // It should be possible to scroll the window to show the caret,
1075 // but this fails to remove the caret on GTK+
1076 if (bSlop
) { // A margin is defined
1079 int yMarginT
, yMarginB
;
1081 // In drag mode, avoid moves
1082 // otherwise, a double click will select several lines.
1083 yMarginT
= yMarginB
= 0;
1085 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1086 // a maximum of slightly less than half the heigth of the text area.
1087 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1089 yMarginB
= yMarginT
;
1091 yMarginB
= linesOnScreen
- yMarginT
- 1;
1097 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1101 yMoveB
= linesOnScreen
- yMoveT
- 1;
1103 if (lineCaret
< topLine
+ yMarginT
) {
1104 // Caret goes too high
1105 newTopLine
= lineCaret
- yMoveT
;
1106 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1107 // Caret goes too low
1108 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1110 } else { // Not strict
1111 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1112 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1116 yMoveB
= linesOnScreen
- yMoveT
- 1;
1118 if (lineCaret
< topLine
) {
1119 // Caret goes too high
1120 newTopLine
= lineCaret
- yMoveT
;
1121 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1122 // Caret goes too low
1123 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1127 if (!bStrict
&& !bJump
) {
1129 if (lineCaret
< topLine
) {
1130 // Caret goes too high
1131 newTopLine
= lineCaret
;
1132 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1133 // Caret goes too low
1135 newTopLine
= lineCaret
- linesOnScreen
+ 1;
1137 newTopLine
= lineCaret
;
1140 } else { // Strict or going out of display
1142 // Always center caret
1143 newTopLine
= lineCaret
- halfScreen
;
1145 // Always put caret on top of display
1146 newTopLine
= lineCaret
;
1150 newTopLine
= Platform::Clamp(newTopLine
, 0, MaxScrollPos());
1151 if (newTopLine
!= topLine
) {
1153 SetTopLine(newTopLine
);
1154 SetVerticalScrollPos();
1158 // Horizontal positioning
1159 if (horiz
&& (wrapState
== eWrapNone
)) {
1160 int halfScreen
= Platform::Maximum(rcClient
.Width() - 4, 4) / 2;
1161 int xOffsetNew
= xOffset
;
1162 bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1163 bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1164 bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1165 bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1167 if (bSlop
) { // A margin is defined
1170 int xMarginL
, xMarginR
;
1172 // In drag mode, avoid moves unless very near of the margin
1173 // otherwise, a simple click will select text.
1174 xMarginL
= xMarginR
= 2;
1176 // xMargin must equal to caretXSlop, with a minimum of 2 and
1177 // a maximum of slightly less than half the width of the text area.
1178 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1180 xMarginL
= xMarginR
;
1182 xMarginL
= rcClient
.Width() - xMarginR
- 4;
1185 if (bJump
&& bEven
) {
1186 // Jump is used only in even mode
1187 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1189 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1191 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1192 // Caret is on the left of the display
1193 if (bJump
&& bEven
) {
1194 xOffsetNew
-= xMoveL
;
1196 // Move just enough to allow to display the caret
1197 xOffsetNew
-= (rcClient
.left
+ xMarginL
) - pt
.x
;
1199 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1200 // Caret is on the right of the display
1201 if (bJump
&& bEven
) {
1202 xOffsetNew
+= xMoveR
;
1204 // Move just enough to allow to display the caret
1205 xOffsetNew
+= pt
.x
- (rcClient
.right
- xMarginR
) + 1;
1208 } else { // Not strict
1209 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1210 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1214 xMoveL
= rcClient
.Width() - xMoveR
- 4;
1216 if (pt
.x
< rcClient
.left
) {
1217 // Caret is on the left of the display
1218 xOffsetNew
-= xMoveL
;
1219 } else if (pt
.x
>= rcClient
.right
) {
1220 // Caret is on the right of the display
1221 xOffsetNew
+= xMoveR
;
1226 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1227 // Strict or going out of display
1230 xOffsetNew
+= pt
.x
- rcClient
.left
- halfScreen
;
1232 // Put caret on right
1233 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1236 // Move just enough to allow to display the caret
1237 if (pt
.x
< rcClient
.left
) {
1238 // Caret is on the left of the display
1240 xOffsetNew
-= rcClient
.left
- pt
.x
;
1242 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1244 } else if (pt
.x
>= rcClient
.right
) {
1245 // Caret is on the right of the display
1246 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1250 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1251 if (pt
.x
+ xOffset
< rcClient
.left
+ xOffsetNew
) {
1252 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.left
;
1253 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ xOffsetNew
) {
1254 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.right
+ 1;
1256 if (xOffsetNew
< 0) {
1259 if (xOffset
!= xOffsetNew
) {
1260 xOffset
= xOffsetNew
;
1261 if (xOffsetNew
> 0) {
1262 PRectangle rcText
= GetTextRectangle();
1263 if (horizontalScrollBarVisible
== true &&
1264 rcText
.Width() + xOffset
> scrollWidth
) {
1265 scrollWidth
= xOffset
+ rcText
.Width();
1269 SetHorizontalScrollPos();
1275 void Editor::ShowCaretAtCurrentPosition() {
1277 caret
.active
= true;
1281 caret
.active
= false;
1287 void Editor::DropCaret() {
1288 caret
.active
= false;
1292 void Editor::InvalidateCaret() {
1294 InvalidateRange(posDrag
, posDrag
+ 1);
1296 InvalidateRange(currentPos
, currentPos
+ 1);
1299 void Editor::NeedWrapping(int docLineStartWrapping
) {
1300 if (docLineLastWrapped
> (docLineStartWrapping
- 1)) {
1301 docLineLastWrapped
= docLineStartWrapping
- 1;
1302 if (docLineLastWrapped
< -1)
1303 docLineLastWrapped
= -1;
1304 llc
.Invalidate(LineLayout::llPositions
);
1308 // Check if wrapping needed and perform any needed wrapping.
1309 // Return true if wrapping occurred.
1310 bool Editor::WrapLines() {
1311 int goodTopLine
= topLine
;
1312 bool wrapOccurred
= false;
1313 if (docLineLastWrapped
< pdoc
->LinesTotal()) {
1314 if (wrapState
== eWrapNone
) {
1315 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1316 wrapWidth
= LineLayout::wrapWidthInfinite
;
1317 for (int lineDoc
= 0; lineDoc
< pdoc
->LinesTotal(); lineDoc
++) {
1318 cs
.SetHeight(lineDoc
, 1);
1320 wrapOccurred
= true;
1322 docLineLastWrapped
= 0x7ffffff;
1325 int lineDocTop
= cs
.DocFromDisplay(topLine
);
1326 int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1327 PRectangle rcTextArea
= GetClientRectangle();
1328 rcTextArea
.left
= vs
.fixedColumnWidth
;
1329 rcTextArea
.right
-= vs
.rightMarginWidth
;
1330 wrapWidth
= rcTextArea
.Width();
1331 // Ensure all of the document is styled.
1332 pdoc
->EnsureStyledTo(pdoc
->Length());
1333 AutoSurface
surface(this);
1335 int lastLineToWrap
= pdoc
->LinesTotal();
1336 while (docLineLastWrapped
<= lastLineToWrap
) {
1337 docLineLastWrapped
++;
1338 AutoLineLayout
ll(llc
, RetrieveLineLayout(docLineLastWrapped
));
1339 int linesWrapped
= 1;
1341 LayoutLine(docLineLastWrapped
, surface
, vs
, ll
, wrapWidth
);
1342 linesWrapped
= ll
->lines
;
1344 if (cs
.SetHeight(docLineLastWrapped
, linesWrapped
)) {
1345 wrapOccurred
= true;
1349 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
);
1350 if (subLineTop
< cs
.GetHeight(lineDocTop
))
1351 goodTopLine
+= subLineTop
;
1353 goodTopLine
+= cs
.GetHeight(lineDocTop
);
1354 //double durWrap = et.Duration(true);
1355 //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap);
1360 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1361 SetVerticalScrollPos();
1363 return wrapOccurred
;
1366 void Editor::LinesJoin() {
1367 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1368 pdoc
->BeginUndoAction();
1369 bool prevNonWS
= true;
1370 for (int pos
= targetStart
; pos
< targetEnd
; pos
++) {
1371 if (IsEOLChar(pdoc
->CharAt(pos
))) {
1372 targetEnd
-= pdoc
->LenChar(pos
);
1375 // Ensure at least one space separating previous lines
1376 pdoc
->InsertChar(pos
, ' ');
1379 prevNonWS
= pdoc
->CharAt(pos
) != ' ';
1382 pdoc
->EndUndoAction();
1386 const char *StringFromEOLMode(int eolMode
) {
1387 if (eolMode
== SC_EOL_CRLF
) {
1389 } else if (eolMode
== SC_EOL_CR
) {
1396 void Editor::LinesSplit(int pixelWidth
) {
1397 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1398 if (pixelWidth
== 0) {
1399 PRectangle rcText
= GetTextRectangle();
1400 pixelWidth
= rcText
.Width();
1402 int lineStart
= pdoc
->LineFromPosition(targetStart
);
1403 int lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1404 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1405 pdoc
->BeginUndoAction();
1406 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
1407 AutoSurface
surface(this);
1408 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
1409 if (surface
&& ll
) {
1410 unsigned int posLineStart
= pdoc
->LineStart(line
);
1411 LayoutLine(line
, surface
, vs
, ll
, pixelWidth
);
1412 for (int subLine
= 1; subLine
< ll
->lines
; subLine
++) {
1413 pdoc
->InsertString(posLineStart
+ (subLine
- 1) * strlen(eol
) +
1414 ll
->LineStart(subLine
), eol
);
1415 targetEnd
+= strlen(eol
);
1419 pdoc
->EndUndoAction();
1423 int Editor::SubstituteMarkerIfEmpty(int markerCheck
, int markerDefault
) {
1424 if (vs
.markers
[markerCheck
].markType
== SC_MARK_EMPTY
)
1425 return markerDefault
;
1429 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1430 if (vs
.fixedColumnWidth
== 0)
1433 PRectangle rcMargin
= GetClientRectangle();
1434 rcMargin
.right
= vs
.fixedColumnWidth
;
1436 if (!rc
.Intersects(rcMargin
))
1441 surface
= pixmapSelMargin
;
1443 surface
= surfWindow
;
1446 PRectangle rcSelMargin
= rcMargin
;
1447 rcSelMargin
.right
= rcMargin
.left
;
1449 for (int margin
= 0; margin
< vs
.margins
; margin
++) {
1450 if (vs
.ms
[margin
].width
> 0) {
1452 rcSelMargin
.left
= rcSelMargin
.right
;
1453 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
1455 if (vs
.ms
[margin
].symbol
) {
1456 /* alternate scheme:
1457 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
1458 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1460 // Required because of special way brush is created for selection margin
1461 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
1463 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
1464 // Required because of special way brush is created for selection margin
1465 surface
->FillRectangle(rcSelMargin
, *pixmapSelPattern
);
1467 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1469 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1472 int visibleLine
= topLine
;
1475 // Work out whether the top line is whitespace located after a
1476 // lessening of fold level which implies a 'fold tail' but which should not
1477 // be displayed until the last of a sequence of whitespace.
1478 bool needWhiteClosure
= false;
1479 int level
= pdoc
->GetLevel(cs
.DocFromDisplay(topLine
));
1480 if (level
& SC_FOLDLEVELWHITEFLAG
) {
1481 int lineBack
= cs
.DocFromDisplay(topLine
);
1482 int levelPrev
= level
;
1483 while ((lineBack
> 0) && (levelPrev
& SC_FOLDLEVELWHITEFLAG
)) {
1485 levelPrev
= pdoc
->GetLevel(lineBack
);
1487 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
1488 if ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelPrev
& SC_FOLDLEVELNUMBERMASK
))
1489 needWhiteClosure
= true;
1493 // Old code does not know about new markers needed to distinguish all cases
1494 int folderOpenMid
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID
,
1495 SC_MARKNUM_FOLDEROPEN
);
1496 int folderEnd
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND
,
1499 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
1501 PLATFORM_ASSERT(visibleLine
< cs
.LinesDisplayed());
1503 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
1504 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
1505 bool firstSubLine
= visibleLine
== cs
.DisplayFromDoc(lineDoc
);
1507 // Decide which fold indicator should be displayed
1508 level
= pdoc
->GetLevel(lineDoc
);
1509 int levelNext
= pdoc
->GetLevel(lineDoc
+ 1);
1510 int marks
= pdoc
->GetMark(lineDoc
);
1513 int levelNum
= level
& SC_FOLDLEVELNUMBERMASK
;
1514 int levelNextNum
= levelNext
& SC_FOLDLEVELNUMBERMASK
;
1515 if (level
& SC_FOLDLEVELHEADERFLAG
) {
1517 if (cs
.GetExpanded(lineDoc
)) {
1518 if (levelNum
== SC_FOLDLEVELBASE
)
1519 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
1521 marks
|= 1 << folderOpenMid
;
1523 if (levelNum
== SC_FOLDLEVELBASE
)
1524 marks
|= 1 << SC_MARKNUM_FOLDER
;
1526 marks
|= 1 << folderEnd
;
1529 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1531 needWhiteClosure
= false;
1532 } else if (level
& SC_FOLDLEVELWHITEFLAG
) {
1533 if (needWhiteClosure
) {
1534 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1535 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1536 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1537 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1538 needWhiteClosure
= false;
1540 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1541 needWhiteClosure
= false;
1543 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1544 if (levelNextNum
< levelNum
) {
1545 if (levelNextNum
> SC_FOLDLEVELBASE
) {
1546 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1548 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1551 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1554 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1555 if (levelNextNum
< levelNum
) {
1556 needWhiteClosure
= false;
1557 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1558 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1559 needWhiteClosure
= true;
1560 } else if (levelNextNum
> SC_FOLDLEVELBASE
) {
1561 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1563 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1566 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1570 marks
&= vs
.ms
[margin
].mask
;
1571 PRectangle rcMarker
= rcSelMargin
;
1572 rcMarker
.top
= yposScreen
;
1573 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
1574 if (!vs
.ms
[margin
].symbol
) {
1578 sprintf(number
, "%d", lineDoc
+ 1);
1579 if (foldFlags
& SC_FOLDFLAG_LEVELNUMBERS
)
1580 sprintf(number
, "%X", pdoc
->GetLevel(lineDoc
));
1581 PRectangle rcNumber
= rcMarker
;
1583 int width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, strlen(number
));
1584 int xpos
= rcNumber
.right
- width
- 3;
1585 rcNumber
.left
= xpos
;
1586 surface
->DrawTextNoClip(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
1587 rcNumber
.top
+ vs
.maxAscent
, number
, strlen(number
),
1588 vs
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
1589 vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1593 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1595 vs
.markers
[markBit
].Draw(surface
, rcMarker
, vs
.styles
[STYLE_LINENUMBER
].font
);
1602 yposScreen
+= vs
.lineHeight
;
1607 PRectangle rcBlankMargin
= rcMargin
;
1608 rcBlankMargin
.left
= rcSelMargin
.right
;
1609 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1612 surfWindow
->Copy(rcMargin
, Point(), *pixmapSelMargin
);
1616 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
1617 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
1618 int xhead
= rcTab
.right
- 1 - ydiff
;
1619 if (xhead
<= rcTab
.left
) {
1620 ydiff
-= rcTab
.left
- xhead
- 1;
1621 xhead
= rcTab
.left
- 1;
1623 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
1624 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
1626 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1627 surface
->LineTo(rcTab
.right
- 1, ymid
);
1628 surface
->LineTo(xhead
, ymid
- ydiff
);
1629 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1630 surface
->LineTo(xhead
, ymid
+ ydiff
);
1633 static bool IsSpaceOrTab(char ch
) {
1634 return ch
== ' ' || ch
== '\t';
1637 LineLayout
*Editor::RetrieveLineLayout(int lineNumber
) {
1638 int posLineStart
= pdoc
->LineStart(lineNumber
);
1639 int posLineEnd
= pdoc
->LineStart(lineNumber
+ 1);
1640 int lineCaret
= pdoc
->LineFromPosition(currentPos
);
1641 return llc
.Retrieve(lineNumber
, lineCaret
,
1642 posLineEnd
- posLineStart
, pdoc
->GetStyleClock(),
1643 LinesOnScreen() + 1, pdoc
->LinesTotal());
1647 * Fill in the LineLayout data for the given line.
1648 * Copy the given @a line and its styles from the document into local arrays.
1649 * Also determine the x position at which each character starts.
1651 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
*ll
, int width
) {
1654 int posLineStart
= pdoc
->LineStart(line
);
1655 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1656 // If the line is very long, limit the treatment to a length that should fit in the viewport
1657 if (posLineEnd
> (posLineStart
+ ll
->maxLineLength
)) {
1658 posLineEnd
= posLineStart
+ ll
->maxLineLength
;
1660 if (ll
->validity
== LineLayout::llCheckTextAndStyle
) {
1662 for (int cid
= posLineStart
; cid
< posLineEnd
; cid
++) {
1663 char chDoc
= pdoc
->CharAt(cid
);
1664 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
1668 if (lineLength
== ll
->numCharsInLine
) {
1669 int numCharsInLine
= 0;
1670 // See if chars, styles, indicators, are all the same
1671 bool allSame
= true;
1673 int styleMask
= pdoc
->stylingBitsMask
;
1674 // Check base line layout
1675 for (int charInDoc
= posLineStart
; allSame
&& (charInDoc
< posLineEnd
); charInDoc
++) {
1676 char chDoc
= pdoc
->CharAt(charInDoc
);
1677 styleByte
= pdoc
->StyleAt(charInDoc
);
1678 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
!= '\r'))) {
1679 allSame
= allSame
&&
1680 (ll
->styles
[numCharsInLine
] == static_cast<char>(styleByte
& styleMask
));
1681 allSame
= allSame
&&
1682 (ll
->indicators
[numCharsInLine
] == static_cast<char>(styleByte
& ~styleMask
));
1683 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
1684 allSame
= allSame
&&
1685 (ll
->chars
[numCharsInLine
] == static_cast<char>(toupper(chDoc
)));
1686 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1687 allSame
= allSame
&&
1688 (ll
->chars
[numCharsInLine
] == static_cast<char>(tolower(chDoc
)));
1690 allSame
= allSame
&&
1691 (ll
->chars
[numCharsInLine
] == chDoc
);
1696 ll
->validity
= LineLayout::llPositions
;
1698 ll
->validity
= LineLayout::llInvalid
;
1701 ll
->validity
= LineLayout::llInvalid
;
1704 if (ll
->validity
== LineLayout::llInvalid
) {
1705 ll
->widthLine
= LineLayout::wrapWidthInfinite
;
1707 int numCharsInLine
= 0;
1708 if (vstyle
.edgeState
== EDGE_BACKGROUND
) {
1709 ll
->edgeColumn
= pdoc
->FindColumn(line
, theEdge
);
1710 if (ll
->edgeColumn
>= posLineStart
) {
1711 ll
->edgeColumn
-= posLineStart
;
1714 ll
->edgeColumn
= -1;
1718 int styleMask
= pdoc
->stylingBitsMask
;
1719 // Fill base line layout
1720 for (int charInDoc
= posLineStart
; charInDoc
< posLineEnd
; charInDoc
++) {
1721 char chDoc
= pdoc
->CharAt(charInDoc
);
1722 styleByte
= pdoc
->StyleAt(charInDoc
);
1723 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
1724 ll
->chars
[numCharsInLine
] = chDoc
;
1725 ll
->styles
[numCharsInLine
] = static_cast<char>(styleByte
& styleMask
);
1726 ll
->indicators
[numCharsInLine
] = static_cast<char>(styleByte
& ~styleMask
);
1727 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
1728 ll
->chars
[numCharsInLine
] = static_cast<char>(toupper(chDoc
));
1729 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1730 ll
->chars
[numCharsInLine
] = static_cast<char>(tolower(chDoc
));
1734 ll
->xHighlightGuide
= 0;
1735 // Extra element at the end of the line to hold end x position and act as
1736 ll
->chars
[numCharsInLine
] = 0; // Also triggers processing in the loops as this is a control character
1737 ll
->styles
[numCharsInLine
] = styleByte
; // For eolFilled
1738 ll
->indicators
[numCharsInLine
] = 0;
1740 // Layout the line, determining the position of each character,
1741 // with an extra element at the end for the end of the line.
1742 int startseg
= 0; // Start of the current segment, in char. number
1743 int startsegx
= 0; // Start of the current segment, in pixels
1744 ll
->positions
[0] = 0;
1745 unsigned int tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
1746 bool lastSegItalics
= false;
1747 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
1749 bool isControlNext
= IsControlCharacter(ll
->chars
[0]);
1750 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
1751 bool isControl
= isControlNext
;
1752 isControlNext
= IsControlCharacter(ll
->chars
[charInLine
+ 1]);
1753 if ((ll
->styles
[charInLine
] != ll
->styles
[charInLine
+ 1]) ||
1754 isControl
|| isControlNext
) {
1755 ll
->positions
[startseg
] = 0;
1756 if (vstyle
.styles
[ll
->styles
[charInLine
]].visible
) {
1758 if (ll
->chars
[charInLine
] == '\t') {
1759 ll
->positions
[charInLine
+ 1] = ((((startsegx
+ 2) /
1760 tabWidth
) + 1) * tabWidth
) - startsegx
;
1761 } else if (controlCharSymbol
< 32) {
1762 const char *ctrlChar
= ControlCharacterString(ll
->chars
[charInLine
]);
1763 // +3 For a blank on front and rounded edge each side:
1764 ll
->positions
[charInLine
+ 1] = surface
->WidthText(ctrlCharsFont
, ctrlChar
, strlen(ctrlChar
)) + 3;
1766 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
1767 surface
->MeasureWidths(ctrlCharsFont
, cc
, 1,
1768 ll
->positions
+ startseg
+ 1);
1770 lastSegItalics
= false;
1771 } else { // Regular character
1772 int lenSeg
= charInLine
- startseg
+ 1;
1773 if ((lenSeg
== 1) && (' ' == ll
->chars
[startseg
])) {
1774 lastSegItalics
= false;
1775 // Over half the segments are single characters and of these about half are space characters.
1776 ll
->positions
[charInLine
+ 1] = vstyle
.styles
[ll
->styles
[charInLine
]].spaceWidth
;
1778 lastSegItalics
= vstyle
.styles
[ll
->styles
[charInLine
]].italic
;
1779 surface
->MeasureWidths(vstyle
.styles
[ll
->styles
[charInLine
]].font
, ll
->chars
+ startseg
,
1780 lenSeg
, ll
->positions
+ startseg
+ 1);
1783 } else { // invisible
1784 for (int posToZero
= startseg
; posToZero
<= (charInLine
+ 1); posToZero
++) {
1785 ll
->positions
[posToZero
] = 0;
1788 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
1789 ll
->positions
[posToIncrease
] += startsegx
;
1791 startsegx
= ll
->positions
[charInLine
+ 1];
1792 startseg
= charInLine
+ 1;
1795 // Small hack to make lines that end with italics not cut off the edge of the last character
1796 if ((startseg
> 0) && lastSegItalics
) {
1797 ll
->positions
[startseg
] += 2;
1799 ll
->numCharsInLine
= numCharsInLine
;
1800 ll
->validity
= LineLayout::llPositions
;
1802 // Hard to cope when too narrow, so just assume there is space
1806 if ((ll
->validity
== LineLayout::llPositions
) || (ll
->widthLine
!= width
)) {
1807 ll
->widthLine
= width
;
1808 if (width
== LineLayout::wrapWidthInfinite
) {
1810 } else if (width
> ll
->positions
[ll
->numCharsInLine
]) {
1811 // Simple common case where line does not need wrapping.
1815 // Calculate line start positions based upon width.
1816 // For now this is simplistic - wraps on byte rather than character and
1817 // in the middle of words. Should search for spaces or style changes.
1818 int lastGoodBreak
= 0;
1819 int lastLineStart
= 0;
1820 int startOffset
= 0;
1822 while (p
< ll
->numCharsInLine
) {
1823 if ((ll
->positions
[p
+ 1] - startOffset
) >= width
) {
1824 if (lastGoodBreak
== lastLineStart
) {
1825 // Try moving to start of last character
1827 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
1830 if (lastGoodBreak
== lastLineStart
) {
1831 // Ensure at least one character on line.
1832 lastGoodBreak
= pdoc
->MovePositionOutsideChar(lastGoodBreak
+ posLineStart
+ 1, 1)
1836 lastLineStart
= lastGoodBreak
;
1838 ll
->SetLineStart(ll
->lines
, lastGoodBreak
);
1839 startOffset
= ll
->positions
[lastGoodBreak
];
1840 p
= lastGoodBreak
+ 1;
1844 if (ll
->styles
[p
] != ll
->styles
[p
- 1]) {
1846 } else if (IsSpaceOrTab(ll
->chars
[p
- 1]) && !IsSpaceOrTab(ll
->chars
[p
])) {
1854 ll
->validity
= LineLayout::llLines
;
1858 ColourAllocated
Editor::TextBackground(ViewStyle
&vsDraw
, bool overrideBackground
,
1859 ColourAllocated background
, bool inSelection
, bool inHotspot
, int styleMain
, int i
, LineLayout
*ll
) {
1861 if (vsDraw
.selbackset
) {
1862 if (primarySelection
)
1863 return vsDraw
.selbackground
.allocated
;
1865 return vsDraw
.selbackground2
.allocated
;
1868 if ((vsDraw
.edgeState
== EDGE_BACKGROUND
) &&
1869 (i
>= ll
->edgeColumn
) &&
1870 !IsEOLChar(ll
->chars
[i
]))
1871 return vsDraw
.edgecolour
.allocated
;
1873 return vsDraw
.hotspotBackground
.allocated
;
1874 if (overrideBackground
)
1877 return vsDraw
.styles
[styleMain
].back
.allocated
;
1880 void Editor::DrawIndentGuide(Surface
*surface
, int lineVisible
, int lineHeight
, int start
, PRectangle rcSegment
, bool highlight
) {
1881 Point
from(0, ((lineVisible
& 1) && (lineHeight
& 1)) ? 1 : 0);
1882 PRectangle
rcCopyArea(start
+ 1, rcSegment
.top
, start
+ 2, rcSegment
.bottom
);
1883 surface
->Copy(rcCopyArea
, from
,
1884 highlight
? *pixmapIndentGuideHighlight
: *pixmapIndentGuide
);
1887 void Editor::DrawEOL(Surface
*surface
, ViewStyle
&vsDraw
, PRectangle rcLine
, LineLayout
*ll
,
1888 int line
, int lineEnd
, int xStart
, int subLine
, int subLineStart
,
1889 bool overrideBackground
, ColourAllocated background
) {
1891 int styleMask
= pdoc
->stylingBitsMask
;
1892 PRectangle rcSegment
= rcLine
;
1894 // Fill in a PRectangle representing the end of line characters
1895 int xEol
= ll
->positions
[lineEnd
] - subLineStart
;
1896 rcSegment
.left
= xEol
+ xStart
;
1897 rcSegment
.right
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
1898 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1899 bool eolInSelection
= (subLine
== (ll
->lines
- 1)) &&
1900 (posLineEnd
> ll
->selStart
) && (posLineEnd
<= ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
1901 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1)) {
1902 if (primarySelection
)
1903 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground
.allocated
);
1905 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground2
.allocated
);
1906 } else if (overrideBackground
) {
1907 surface
->FillRectangle(rcSegment
, background
);
1909 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
1912 rcSegment
.left
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
1913 rcSegment
.right
= rcLine
.right
;
1914 if (overrideBackground
) {
1915 surface
->FillRectangle(rcSegment
, background
);
1916 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
1917 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
1919 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
1923 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int lineVisible
, int xStart
,
1924 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
1926 PRectangle rcSegment
= rcLine
;
1928 // Using one font for all control characters so it can be controlled independently to ensure
1929 // the box goes around the characters tightly. Seems to be no way to work out what height
1930 // is taken by an individual character - internal leading gives varying results.
1931 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
1933 // See if something overrides the line background color: Either if caret is on the line
1934 // and background color is set for that, or if a marker is defined that forces its background
1935 // color onto the line, or if a marker is defined but has no selection margin in which to
1936 // display itself. These are checked in order with the earlier taking precedence. When
1937 // multiple markers cause background override, the color for the highest numbered one is used.
1938 bool overrideBackground
= false;
1939 ColourAllocated background
;
1940 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& ll
->containsCaret
) {
1941 overrideBackground
= true;
1942 background
= vsDraw
.caretLineBackground
.allocated
;
1944 if (!overrideBackground
) {
1945 int marks
= pdoc
->GetMark(line
);
1946 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1947 if ((marks
& 1) && vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
) {
1948 background
= vsDraw
.markers
[markBit
].back
.allocated
;
1949 overrideBackground
= true;
1954 if (!overrideBackground
) {
1955 if (vsDraw
.maskInLine
) {
1956 int marks
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
1958 overrideBackground
= true;
1959 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1961 background
= vsDraw
.markers
[markBit
].back
.allocated
;
1969 bool drawWhitespaceBackground
= (vsDraw
.viewWhitespace
!= wsInvisible
) &&
1970 (!overrideBackground
) && (vsDraw
.whitespaceBackgroundSet
);
1972 bool inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
1973 int indentWidth
= pdoc
->indentInChars
* vsDraw
.spaceWidth
;
1974 if (indentWidth
== 0)
1975 indentWidth
= pdoc
->tabInChars
* vsDraw
.spaceWidth
;
1977 int posLineStart
= pdoc
->LineStart(line
);
1979 int startseg
= ll
->LineStart(subLine
);
1980 int subLineStart
= ll
->positions
[startseg
];
1983 if (subLine
< ll
->lines
) {
1984 lineStart
= ll
->LineStart(subLine
);
1985 lineEnd
= ll
->LineStart(subLine
+ 1);
1989 // Background drawing loop
1990 for (i
= lineStart
; twoPhaseDraw
&& (i
< lineEnd
); i
++) {
1992 int iDoc
= i
+ posLineStart
;
1993 // If there is the end of a style run for any reason
1994 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
1995 i
== (lineEnd
- 1) ||
1996 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
1997 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
1998 (i
== (ll
->edgeColumn
- 1))) {
1999 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2000 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2001 // Only try to draw if really visible - enhances performance by not calling environment to
2002 // draw strings that are completely past the right side of the window.
2003 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2004 int styleMain
= ll
->styles
[i
];
2005 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2006 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2007 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2008 if (ll
->chars
[i
] == '\t') {
2010 if (drawWhitespaceBackground
&&
2011 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2012 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2013 surface
->FillRectangle(rcSegment
, textBack
);
2014 } else if (IsControlCharacter(ll
->chars
[i
])) {
2015 // Control character display
2016 inIndentation
= false;
2017 surface
->FillRectangle(rcSegment
, textBack
);
2019 // Normal text display
2020 surface
->FillRectangle(rcSegment
, textBack
);
2021 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2022 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
2023 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2024 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2025 if (drawWhitespaceBackground
&&
2026 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2027 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
,
2028 ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2029 surface
->FillRectangle(rcSpace
, vsDraw
.whitespaceBackground
.allocated
);
2032 inIndentation
= false;
2043 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2044 xStart
, subLine
, subLineStart
, overrideBackground
, background
);
2047 inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2048 startseg
= ll
->LineStart(subLine
);
2049 // Foreground drawing loop
2050 for (i
= lineStart
; i
< lineEnd
; i
++) {
2052 int iDoc
= i
+ posLineStart
;
2053 // If there is the end of a style run for any reason
2054 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
2055 i
== (lineEnd
- 1) ||
2056 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
2057 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
2058 (i
== (ll
->edgeColumn
- 1))) {
2059 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2060 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2061 // Only try to draw if really visible - enhances performance by not calling environment to
2062 // draw strings that are completely past the right side of the window.
2063 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2064 int styleMain
= ll
->styles
[i
];
2065 ColourAllocated textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
2066 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
2067 //hotspot foreground
2068 if (ll
->hsStart
!= -1 && iDoc
>= ll
->hsStart
&& iDoc
< hsEnd
) {
2069 if (vsDraw
.hotspotForegroundSet
)
2070 textFore
= vsDraw
.hotspotForeground
.allocated
;
2072 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2073 if (inSelection
&& (vsDraw
.selforeset
)) {
2074 textFore
= vsDraw
.selforeground
.allocated
;
2076 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2077 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2078 if (ll
->chars
[i
] == '\t') {
2080 if (!twoPhaseDraw
) {
2081 if (drawWhitespaceBackground
&&
2082 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2083 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2084 surface
->FillRectangle(rcSegment
, textBack
);
2086 if ((vsDraw
.viewWhitespace
!= wsInvisible
) || ((inIndentation
&& vsDraw
.viewIndentationGuides
))) {
2087 if (vsDraw
.whitespaceForegroundSet
)
2088 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2089 surface
->PenColour(textFore
);
2091 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
2092 for (int xIG
= ll
->positions
[i
] / indentWidth
* indentWidth
; xIG
< ll
->positions
[i
+ 1]; xIG
+= indentWidth
) {
2093 if (xIG
>= ll
->positions
[i
] && xIG
> 0) {
2094 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIG
+ xStart
, rcSegment
,
2095 (ll
->xHighlightGuide
== xIG
));
2099 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2100 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2101 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
2102 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
2103 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
2106 } else if (IsControlCharacter(ll
->chars
[i
])) {
2107 // Control character display
2108 inIndentation
= false;
2109 if (controlCharSymbol
< 32) {
2110 // Draw the character
2111 const char *ctrlChar
= ControlCharacterString(ll
->chars
[i
]);
2112 if (!twoPhaseDraw
) {
2113 surface
->FillRectangle(rcSegment
, textBack
);
2115 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
2116 surface
->InternalLeading(ctrlCharsFont
);
2117 PRectangle rcCChar
= rcSegment
;
2118 rcCChar
.left
= rcCChar
.left
+ 1;
2119 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
2120 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
2121 PRectangle rcCentral
= rcCChar
;
2124 surface
->FillRectangle(rcCentral
, textFore
);
2125 PRectangle rcChar
= rcCChar
;
2128 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
2129 rcSegment
.top
+ vsDraw
.maxAscent
, ctrlChar
, strlen(ctrlChar
),
2130 textBack
, textFore
);
2132 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
2133 surface
->DrawTextNoClip(rcSegment
, ctrlCharsFont
,
2134 rcSegment
.top
+ vsDraw
.maxAscent
,
2135 cc
, 1, textBack
, textFore
);
2138 // Normal text display
2139 if (vsDraw
.styles
[styleMain
].visible
) {
2141 surface
->DrawTextTransparent(rcSegment
, textFont
,
2142 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2143 i
- startseg
+ 1, textFore
);
2145 surface
->DrawTextNoClip(rcSegment
, textFont
,
2146 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2147 i
- startseg
+ 1, textFore
, textBack
);
2150 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2151 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
2152 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2153 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2154 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2155 if (vsDraw
.whitespaceForegroundSet
)
2156 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2157 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2158 int xmid
= (ll
->positions
[cpos
+ startseg
] + ll
->positions
[cpos
+ startseg
+ 1]) / 2;
2159 if (!twoPhaseDraw
&& drawWhitespaceBackground
&&
2160 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2161 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2162 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
, ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2163 surface
->FillRectangle(rcSpace
, textBack
);
2165 PRectangle
rcDot(xmid
+ xStart
- subLineStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
2166 rcDot
.right
= rcDot
.left
+ 1;
2167 rcDot
.bottom
= rcDot
.top
+ 1;
2168 surface
->FillRectangle(rcDot
, textFore
);
2171 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
2172 int startSpace
= ll
->positions
[cpos
+ startseg
];
2173 if (startSpace
> 0 && (startSpace
% indentWidth
== 0)) {
2174 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, startSpace
+ xStart
, rcSegment
,
2175 (ll
->xHighlightGuide
== ll
->positions
[cpos
+ startseg
]));
2179 inIndentation
= false;
2184 if (ll
->hsStart
!= -1 && vsDraw
.hotspotUnderline
&& iDoc
>= ll
->hsStart
&& iDoc
< ll
->hsEnd
) {
2185 PRectangle rcUL
= rcSegment
;
2186 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2187 rcUL
.bottom
= rcUL
.top
+ 1;
2188 if (vsDraw
.hotspotForegroundSet
)
2189 surface
->FillRectangle(rcUL
, vsDraw
.hotspotForeground
.allocated
);
2191 surface
->FillRectangle(rcUL
, textFore
);
2192 } else if (vsDraw
.styles
[styleMain
].underline
) {
2193 PRectangle rcUL
= rcSegment
;
2194 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2195 rcUL
.bottom
= rcUL
.top
+ 1;
2196 surface
->FillRectangle(rcUL
, textFore
);
2204 int indStart
[INDIC_MAX
+ 1] = {0};
2205 for (int indica
= 0; indica
<= INDIC_MAX
; indica
++)
2206 indStart
[indica
] = 0;
2208 for (int indicPos
= 0; indicPos
< ll
->numCharsInLine
; indicPos
++) {
2209 if (ll
->indicators
[indicPos
] != ll
->indicators
[indicPos
+ 1]) {
2210 int mask
= 1 << pdoc
->stylingBits
;
2211 for (int indicnum
= 0; mask
< 0x100; indicnum
++) {
2212 if ((ll
->indicators
[indicPos
+ 1] & mask
) && !(ll
->indicators
[indicPos
] & mask
)) {
2213 indStart
[indicnum
] = ll
->positions
[indicPos
+ 1];
2215 if (!(ll
->indicators
[indicPos
+ 1] & mask
) && (ll
->indicators
[indicPos
] & mask
)) {
2217 indStart
[indicnum
] + xStart
,
2218 rcLine
.top
+ vsDraw
.maxAscent
,
2219 ll
->positions
[indicPos
+ 1] + xStart
,
2220 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
2221 vsDraw
.indicators
[indicnum
].Draw(surface
, rcIndic
);
2227 // End of the drawing of the current line
2229 if (!twoPhaseDraw
) {
2230 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2231 xStart
, subLine
, subLineStart
, overrideBackground
, background
);
2234 if (vsDraw
.edgeState
== EDGE_LINE
) {
2235 int edgeX
= theEdge
* vsDraw
.spaceWidth
;
2236 rcSegment
.left
= edgeX
+ xStart
;
2237 rcSegment
.right
= rcSegment
.left
+ 1;
2238 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
.allocated
);
2242 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
2243 if (!pixmapSelPattern
->Initialised()) {
2244 const int patternSize
= 8;
2245 pixmapSelPattern
->InitPixMap(patternSize
, patternSize
, surfaceWindow
, wMain
.GetID());
2246 // This complex procedure is to reproduce the checkerboard dithered pattern used by windows
2247 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
2248 // way between the chrome colour and the chrome highlight colour making a nice transition
2249 // between the window chrome and the content area. And it works in low colour depths.
2250 PRectangle
rcPattern(0, 0, patternSize
, patternSize
);
2252 // Initialize default colours based on the chrome colour scheme. Typically the highlight is white.
2253 ColourAllocated colourFMFill
= vs
.selbar
.allocated
;
2254 ColourAllocated colourFMStripes
= vs
.selbarlight
.allocated
;
2256 if (!(vs
.selbarlight
.desired
== ColourDesired(0xff, 0xff, 0xff))) {
2257 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
2258 // (Typically, the highlight colour is white.)
2259 colourFMFill
= vs
.selbarlight
.allocated
;
2262 if (vs
.foldmarginColourSet
) {
2263 // override default fold margin colour
2264 colourFMFill
= vs
.foldmarginColour
.allocated
;
2266 if (vs
.foldmarginHighlightColourSet
) {
2267 // override default fold margin highlight colour
2268 colourFMStripes
= vs
.foldmarginHighlightColour
.allocated
;
2271 pixmapSelPattern
->FillRectangle(rcPattern
, colourFMFill
);
2272 pixmapSelPattern
->PenColour(colourFMStripes
);
2273 for (int stripe
= 0; stripe
< patternSize
; stripe
++) {
2274 // Alternating 1 pixel stripes is same as checkerboard.
2275 pixmapSelPattern
->MoveTo(0, stripe
* 2);
2276 pixmapSelPattern
->LineTo(patternSize
, stripe
* 2 - patternSize
);
2280 if (!pixmapIndentGuide
->Initialised()) {
2281 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
2282 pixmapIndentGuide
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2283 pixmapIndentGuideHighlight
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2284 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
2285 pixmapIndentGuide
->FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
.allocated
);
2286 pixmapIndentGuide
->PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
2287 pixmapIndentGuideHighlight
->FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
.allocated
);
2288 pixmapIndentGuideHighlight
->PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
2289 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
2290 pixmapIndentGuide
->MoveTo(0, stripe
);
2291 pixmapIndentGuide
->LineTo(2, stripe
);
2292 pixmapIndentGuideHighlight
->MoveTo(0, stripe
);
2293 pixmapIndentGuideHighlight
->LineTo(2, stripe
);
2298 if (!pixmapLine
->Initialised()) {
2299 PRectangle rcClient
= GetClientRectangle();
2300 pixmapLine
->InitPixMap(rcClient
.Width(), rcClient
.Height(),
2301 surfaceWindow
, wMain
.GetID());
2302 pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
2303 rcClient
.Height(), surfaceWindow
, wMain
.GetID());
2308 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
2309 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
2310 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
2314 RefreshPixMaps(surfaceWindow
);
2316 PRectangle rcClient
= GetClientRectangle();
2317 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
2318 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
2320 surfaceWindow
->SetPalette(&palette
, true);
2321 pixmapLine
->SetPalette(&palette
, !hasFocus
);
2323 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
2324 // The area to be painted plus one extra line is styled.
2325 // The extra line is to determine when a style change, such as starting a comment flows on to other lines.
2326 int lineStyleLast
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
2327 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
2328 int endPosPaint
= pdoc
->Length();
2329 if (lineStyleLast
< cs
.LinesDisplayed())
2330 endPosPaint
= pdoc
->LineStart(cs
.DocFromDisplay(lineStyleLast
+ 1));
2332 int xStart
= vs
.fixedColumnWidth
- xOffset
;
2335 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
2336 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
2338 // Ensure we are styled as far as we are painting.
2339 pdoc
->EnsureStyledTo(endPosPaint
);
2340 bool paintAbandonedByStyling
= paintState
== paintAbandoned
;
2343 needUpdateUI
= false;
2346 PaintSelMargin(surfaceWindow
, rcArea
);
2349 // The wrapping process has changed the height of some lines so abandon this
2350 // paint for a complete repaint.
2351 if (AbandonPaint()) {
2356 PRectangle rcRightMargin
= rcClient
;
2357 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
2358 if (rcArea
.Intersects(rcRightMargin
)) {
2359 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2362 if (paintState
== paintAbandoned
) {
2363 // Either styling or NotifyUpdateUI noticed that painting is needed
2364 // outside the current painting rectangle
2365 //Platform::DebugPrintf("Abandoning paint\n");
2366 if (wrapState
!= eWrapNone
) {
2367 if (paintAbandonedByStyling
) {
2368 // Styling has spilled over a line end, such as occurs by starting a multiline
2369 // comment. The width of subsequent text may have changed, so rewrap.
2370 NeedWrapping(cs
.DocFromDisplay(topLine
));
2375 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
2378 if (rcArea
.right
> vs
.fixedColumnWidth
) {
2380 Surface
*surface
= surfaceWindow
;
2382 surface
= pixmapLine
;
2384 surface
->SetUnicodeMode(IsUnicodeMode());
2385 surface
->SetDBCSMode(CodePage());
2387 int visibleLine
= topLine
+ screenLinePaintFirst
;
2389 int posCaret
= currentPos
;
2392 int lineCaret
= pdoc
->LineFromPosition(posCaret
);
2394 // Remove selection margin from drawing area so text will not be drawn
2395 // on it in unbuffered mode.
2396 PRectangle rcTextArea
= rcClient
;
2397 rcTextArea
.left
= vs
.fixedColumnWidth
;
2398 rcTextArea
.right
-= vs
.rightMarginWidth
;
2399 surfaceWindow
->SetClip(rcTextArea
);
2401 // Loop on visible lines
2402 //double durLayout = 0.0;
2403 //double durPaint = 0.0;
2404 //double durCopy = 0.0;
2405 //ElapsedTime etWhole;
2406 int lineDocPrevious
= -1; // Used to avoid laying out one document line multiple times
2407 AutoLineLayout
ll(llc
, 0);
2408 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
2410 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
2411 // Only visible lines should be handled by the code within the loop
2412 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
2413 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
2414 int subLine
= visibleLine
- lineStartSet
;
2416 // Copy this line and its styles from the document into local arrays
2417 // and determine the x position at which each character starts.
2419 if (lineDoc
!= lineDocPrevious
) {
2420 ll
.Set(RetrieveLineLayout(lineDoc
));
2421 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
2422 lineDocPrevious
= lineDoc
;
2424 //durLayout += et.Duration(true);
2427 ll
->selStart
= SelectionStart(lineDoc
);
2428 ll
->selEnd
= SelectionEnd(lineDoc
);
2429 ll
->containsCaret
= lineDoc
== lineCaret
;
2430 if (hideSelection
) {
2433 ll
->containsCaret
= false;
2436 GetHotSpotRange(ll
->hsStart
, ll
->hsEnd
);
2438 PRectangle rcLine
= rcClient
;
2440 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
2442 Range
rangeLine(pdoc
->LineStart(lineDoc
), pdoc
->LineStart(lineDoc
+ 1));
2443 // Highlight the current braces if any
2444 ll
->SetBracesHighlight(rangeLine
, braces
, static_cast<char>(bracesMatchStyle
),
2445 highlightGuideColumn
* vs
.spaceWidth
);
2448 DrawLine(surface
, vs
, lineDoc
, visibleLine
, xStart
, rcLine
, ll
, subLine
);
2449 //durPaint += et.Duration(true);
2451 // Restore the precvious styles for the brace highlights in case layout is in cache.
2452 ll
->RestoreBracesHighlight(rangeLine
, braces
);
2454 bool expanded
= cs
.GetExpanded(lineDoc
);
2455 if ((foldFlags
& SC_FOLDFLAG_BOX
) == 0) {
2456 // Paint the line above the fold
2457 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_EXPANDED
))
2459 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_CONTRACTED
))) {
2460 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2461 PRectangle rcFoldLine
= rcLine
;
2462 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2463 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2466 // Paint the line below the fold
2467 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_EXPANDED
))
2469 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2470 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2471 PRectangle rcFoldLine
= rcLine
;
2472 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2473 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2477 int FoldLevelCurr
= (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2478 int FoldLevelPrev
= (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2479 int FoldLevelFlags
= (pdoc
->GetLevel(lineDoc
) & ~SC_FOLDLEVELNUMBERMASK
);
2480 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
2481 // Draw line above fold
2482 if ((FoldLevelPrev
< FoldLevelCurr
)
2484 (FoldLevelFlags
& SC_FOLDLEVELBOXHEADERFLAG
2486 (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELBOXFOOTERFLAG
) == 0)) {
2487 PRectangle rcFoldLine
= rcLine
;
2488 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2489 rcFoldLine
.left
+= xStart
+ FoldLevelCurr
* vs
.spaceWidth
* indentationStep
- 1;
2490 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2493 // Line below the fold (or below a contracted fold)
2494 if (FoldLevelFlags
& SC_FOLDLEVELBOXFOOTERFLAG
2496 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2497 PRectangle rcFoldLine
= rcLine
;
2498 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2499 rcFoldLine
.left
+= xStart
+ (FoldLevelCurr
) * vs
.spaceWidth
* indentationStep
- 1;
2500 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2503 PRectangle rcBoxLine
= rcLine
;
2504 // Draw vertical line for every fold level
2505 for (int i
= 0; i
<= FoldLevelCurr
; i
++) {
2506 rcBoxLine
.left
= xStart
+ i
* vs
.spaceWidth
* indentationStep
- 1;
2507 rcBoxLine
.right
= rcBoxLine
.left
+ 1;
2508 surface
->FillRectangle(rcBoxLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2513 if (lineDoc
== lineCaret
) {
2514 int offset
= Platform::Minimum(posCaret
- rangeLine
.start
, ll
->maxLineLength
);
2515 if ((offset
>= ll
->LineStart(subLine
)) &&
2516 ((offset
< ll
->LineStart(subLine
+ 1)) || offset
== ll
->numCharsInLine
)) {
2517 int xposCaret
= ll
->positions
[offset
] - ll
->positions
[ll
->LineStart(subLine
)] + xStart
;
2518 int widthOverstrikeCaret
;
2519 if (posCaret
== pdoc
->Length()) { // At end of document
2520 widthOverstrikeCaret
= vs
.aveCharWidth
;
2521 } else if ((posCaret
- rangeLine
.start
) >= ll
->numCharsInLine
) { // At end of line
2522 widthOverstrikeCaret
= vs
.aveCharWidth
;
2524 widthOverstrikeCaret
= ll
->positions
[offset
+ 1] - ll
->positions
[offset
];
2526 if (widthOverstrikeCaret
< 3) // Make sure its visible
2527 widthOverstrikeCaret
= 3;
2528 if (((caret
.active
&& caret
.on
) || (posDrag
>= 0)) && xposCaret
>= 0) {
2529 PRectangle rcCaret
= rcLine
;
2530 int caretWidthOffset
= 0;
2531 if ((offset
> 0) && (vs
.caretWidth
> 1))
2532 caretWidthOffset
= 1; // Move back so overlaps both character cells.
2534 rcCaret
.left
= xposCaret
- caretWidthOffset
;
2535 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
2538 rcCaret
.top
= rcCaret
.bottom
- 2;
2539 rcCaret
.left
= xposCaret
+ 1;
2540 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
2542 rcCaret
.left
= xposCaret
- caretWidthOffset
;
2543 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
2546 surface
->FillRectangle(rcCaret
, vs
.caretcolour
.allocated
);
2552 Point
from(vs
.fixedColumnWidth
, 0);
2553 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
2554 rcClient
.right
, yposScreen
+ vs
.lineHeight
);
2555 surfaceWindow
->Copy(rcCopyArea
, from
, *pixmapLine
);
2557 //durCopy += et.Duration(true);
2560 if (!bufferedDraw
) {
2561 ypos
+= vs
.lineHeight
;
2564 yposScreen
+= vs
.lineHeight
;
2568 //if (durPaint < 0.00000001)
2569 // durPaint = 0.00000001;
2571 // Right column limit indicator
2572 PRectangle rcBeyondEOF
= rcClient
;
2573 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
2574 rcBeyondEOF
.right
= rcBeyondEOF
.right
;
2575 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
2576 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
2577 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2578 if (vs
.edgeState
== EDGE_LINE
) {
2579 int edgeX
= theEdge
* vs
.spaceWidth
;
2580 rcBeyondEOF
.left
= edgeX
+ xStart
;
2581 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
2582 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
.allocated
);
2585 //Platform::DebugPrintf(
2586 //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
2587 //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
2592 // Space (3 space characters) between line numbers and text when printing.
2593 #define lineNumberPrintSpace " "
2595 ColourDesired
InvertedLight(ColourDesired orig
) {
2596 unsigned int r
= orig
.GetRed();
2597 unsigned int g
= orig
.GetGreen();
2598 unsigned int b
= orig
.GetBlue();
2599 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
2600 unsigned int il
= 0xff - l
;
2602 return ColourDesired(0xff, 0xff, 0xff);
2606 return ColourDesired(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
2609 // This is mostly copied from the Paint method but with some things omitted
2610 // such as the margin markers, line numbers, selection and caret
2611 // Should be merged back into a combined Draw method.
2612 long Editor::FormatRange(bool draw
, RangeToFormat
*pfr
) {
2616 AutoSurface
surface(pfr
->hdc
, this);
2619 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this);
2620 if (!surfaceMeasure
) {
2624 ViewStyle
vsPrint(vs
);
2626 // Modify the view style for printing as do not normally want any of the transient features to be printed
2627 // Printing supports only the line number margin.
2628 int lineNumberIndex
= -1;
2629 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
2630 if ((!vsPrint
.ms
[margin
].symbol
) && (vsPrint
.ms
[margin
].width
> 0)) {
2631 lineNumberIndex
= margin
;
2633 vsPrint
.ms
[margin
].width
= 0;
2636 vsPrint
.showMarkedLines
= false;
2637 vsPrint
.fixedColumnWidth
= 0;
2638 vsPrint
.zoomLevel
= printMagnification
;
2639 vsPrint
.viewIndentationGuides
= false;
2640 // Don't show the selection when printing
2641 vsPrint
.selbackset
= false;
2642 vsPrint
.selforeset
= false;
2643 vsPrint
.whitespaceBackgroundSet
= false;
2644 vsPrint
.whitespaceForegroundSet
= false;
2645 vsPrint
.showCaretLineBackground
= false;
2647 // Set colours for printing according to users settings
2648 for (int sty
= 0;sty
<= STYLE_MAX
;sty
++) {
2649 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
2650 vsPrint
.styles
[sty
].fore
.desired
= InvertedLight(vsPrint
.styles
[sty
].fore
.desired
);
2651 vsPrint
.styles
[sty
].back
.desired
= InvertedLight(vsPrint
.styles
[sty
].back
.desired
);
2652 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
2653 vsPrint
.styles
[sty
].fore
.desired
= ColourDesired(0, 0, 0);
2654 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2655 } else if (printColourMode
== SC_PRINT_COLOURONWHITE
) {
2656 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2657 } else if (printColourMode
== SC_PRINT_COLOURONWHITEDEFAULTBG
) {
2658 if (sty
<= STYLE_DEFAULT
) {
2659 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2663 // White background for the line numbers
2664 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2666 vsPrint
.Refresh(*surfaceMeasure
);
2667 // Ensure colours are set up
2668 vsPrint
.RefreshColourPalette(palette
, true);
2669 vsPrint
.RefreshColourPalette(palette
, false);
2670 // Determining width must hapen after fonts have been realised in Refresh
2671 int lineNumberWidth
= 0;
2672 if (lineNumberIndex
>= 0) {
2673 lineNumberWidth
= surfaceMeasure
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
2674 "99999" lineNumberPrintSpace
, 5 + strlen(lineNumberPrintSpace
));
2675 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
2678 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
2679 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
2680 if (linePrintLast
< linePrintStart
)
2681 linePrintLast
= linePrintStart
;
2682 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
);
2683 if (linePrintLast
> linePrintMax
)
2684 linePrintLast
= linePrintMax
;
2685 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
2686 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
2687 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
2688 int endPosPrint
= pdoc
->Length();
2689 if (linePrintLast
< pdoc
->LinesTotal())
2690 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
2692 // Ensure we are styled to where we are formatting.
2693 pdoc
->EnsureStyledTo(endPosPrint
);
2695 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
+ lineNumberWidth
;
2696 int ypos
= pfr
->rc
.top
;
2698 int lineDoc
= linePrintStart
;
2700 int nPrintPos
= pfr
->chrg
.cpMin
;
2701 int visibleLine
= 0;
2702 int widthPrint
= pfr
->rc
.Width() - lineNumberWidth
;
2703 if (printWrapState
== eWrapNone
)
2704 widthPrint
= LineLayout::wrapWidthInfinite
;
2706 while (lineDoc
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
2708 // When printing, the hdc and hdcTarget may be the same, so
2709 // changing the state of surfaceMeasure may change the underlying
2710 // state of surface. Therefore, any cached state is discarded before
2711 // using each surface.
2712 surfaceMeasure
->FlushCachedState();
2714 // Copy this line and its styles from the document into local arrays
2715 // and determine the x position at which each character starts.
2716 LineLayout
ll(8000);
2717 LayoutLine(lineDoc
, surfaceMeasure
, vsPrint
, &ll
, widthPrint
);
2721 ll
.containsCaret
= false;
2724 rcLine
.left
= pfr
->rc
.left
+ lineNumberWidth
;
2726 rcLine
.right
= pfr
->rc
.right
- 1;
2727 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
2729 // When document line is wrapped over multiple display lines, find where
2730 // to start printing from to ensure a particular position is on the first
2731 // line of the page.
2732 if (visibleLine
== 0) {
2733 int startWithinLine
= nPrintPos
- pdoc
->LineStart(lineDoc
);
2734 for (int iwl
= 0; iwl
< ll
.lines
- 1; iwl
++) {
2735 if (ll
.LineStart(iwl
) <= startWithinLine
&& ll
.LineStart(iwl
+ 1) >= startWithinLine
) {
2740 if (ll
.lines
> 1 && startWithinLine
>= ll
.LineStart(ll
.lines
- 1)) {
2741 visibleLine
= -(ll
.lines
- 1);
2745 if (draw
&& lineNumberWidth
&&
2746 (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) &&
2747 (visibleLine
>= 0)) {
2749 sprintf(number
, "%d" lineNumberPrintSpace
, lineDoc
+ 1);
2750 PRectangle rcNumber
= rcLine
;
2751 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
2753 rcNumber
.left
-= surfaceMeasure
->WidthText(
2754 vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, strlen(number
));
2755 surface
->FlushCachedState();
2756 surface
->DrawTextNoClip(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
2757 ypos
+ vsPrint
.maxAscent
, number
, strlen(number
),
2758 vsPrint
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
2759 vsPrint
.styles
[STYLE_LINENUMBER
].back
.allocated
);
2763 surface
->FlushCachedState();
2765 for (int iwl
= 0; iwl
< ll
.lines
; iwl
++) {
2766 if (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) {
2767 if (visibleLine
>= 0) {
2770 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
2771 DrawLine(surface
, vsPrint
, lineDoc
, visibleLine
, xStart
, rcLine
, &ll
, iwl
);
2773 ypos
+= vsPrint
.lineHeight
;
2776 if (iwl
== ll
.lines
- 1)
2777 nPrintPos
= pdoc
->LineStart(lineDoc
+ 1);
2779 nPrintPos
+= ll
.LineStart(iwl
+ 1) - ll
.LineStart(iwl
);
2789 int Editor::TextWidth(int style
, const char *text
) {
2791 AutoSurface
surface(this);
2793 return surface
->WidthText(vs
.styles
[style
].font
, text
, strlen(text
));
2799 // Empty method is overridden on GTK+ to show / hide scrollbars
2800 void Editor::ReconfigureScrollBars() {}
2802 void Editor::SetScrollBars() {
2805 int nMax
= MaxScrollPos();
2806 int nPage
= LinesOnScreen();
2807 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
2809 // TODO: ensure always showing as many lines as possible
2810 // May not be, if, for example, window made larger
2811 if (topLine
> MaxScrollPos()) {
2812 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
2813 SetVerticalScrollPos();
2817 if (!AbandonPaint())
2820 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
2823 void Editor::ChangeSize() {
2826 if (wrapState
!= eWrapNone
) {
2827 PRectangle rcTextArea
= GetClientRectangle();
2828 rcTextArea
.left
= vs
.fixedColumnWidth
;
2829 rcTextArea
.right
-= vs
.rightMarginWidth
;
2830 if (wrapWidth
!= rcTextArea
.Width()) {
2837 void Editor::AddChar(char ch
) {
2844 void Editor::AddCharUTF(char *s
, unsigned int len
, bool treatAsDBCS
) {
2845 bool wasSelection
= currentPos
!= anchor
;
2847 if (inOverstrike
&& !wasSelection
&& !RangeContainsProtected(currentPos
, currentPos
+ 1)) {
2848 if (currentPos
< (pdoc
->Length())) {
2849 if (!IsEOLChar(pdoc
->CharAt(currentPos
))) {
2850 pdoc
->DelChar(currentPos
);
2854 if (pdoc
->InsertString(currentPos
, s
, len
)) {
2855 SetEmptySelection(currentPos
+ len
);
2857 EnsureCaretVisible();
2858 // Avoid blinking during rapid typing:
2859 ShowCaretAtCurrentPosition();
2863 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
2864 static_cast<unsigned char>(s
[1]));
2866 int byte
= static_cast<unsigned char>(s
[0]);
2867 if ((byte
< 0xC0) || (1 == len
)) {
2868 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
2869 // characters when not in UTF-8 mode.
2870 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
2871 // characters representing themselves.
2873 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
2874 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
2875 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
2877 int byte2
= static_cast<unsigned char>(s
[1]);
2878 if ((byte2
& 0xC0) == 0x80) {
2879 // Two-byte-character lead-byte followed by a trail-byte.
2880 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
2882 // A two-byte-character lead-byte not followed by trail-byte
2883 // represents itself.
2884 } else if (byte
< 0xF0) {
2885 int byte2
= static_cast<unsigned char>(s
[1]);
2886 int byte3
= static_cast<unsigned char>(s
[2]);
2887 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
2888 // Three-byte-character lead byte followed by two trail bytes.
2889 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
2892 // A three-byte-character lead-byte not followed by two trail-bytes
2893 // represents itself.
2900 void Editor::ClearSelection() {
2901 if (!SelectionContainsProtected()) {
2902 if (selType
== selRectangle
) {
2903 pdoc
->BeginUndoAction();
2904 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2905 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2906 int startPos
= SelectionStart();
2907 for (int line
= lineEnd
; line
>= lineStart
; line
--) {
2908 startPos
= SelectionStart(line
);
2909 unsigned int chars
= SelectionEnd(line
) - startPos
;
2911 pdoc
->DeleteChars(startPos
, chars
);
2914 SetEmptySelection(startPos
);
2915 pdoc
->EndUndoAction();
2916 selType
= selStream
;
2918 int startPos
= SelectionStart();
2919 unsigned int chars
= SelectionEnd() - startPos
;
2920 SetEmptySelection(startPos
);
2922 pdoc
->BeginUndoAction();
2923 pdoc
->DeleteChars(startPos
, chars
);
2924 pdoc
->EndUndoAction();
2930 void Editor::ClearAll() {
2931 pdoc
->BeginUndoAction();
2932 if (0 != pdoc
->Length()) {
2933 pdoc
->DeleteChars(0, pdoc
->Length());
2935 if (!pdoc
->IsReadOnly()) {
2938 pdoc
->EndUndoAction();
2942 SetVerticalScrollPos();
2945 void Editor::ClearDocumentStyle() {
2946 pdoc
->StartStyling(0, '\377');
2947 pdoc
->SetStyleFor(pdoc
->Length(), 0);
2949 pdoc
->ClearLevels();
2952 void Editor::Cut() {
2953 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
2959 void Editor::PasteRectangular(int pos
, const char *ptr
, int len
) {
2960 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
2964 int xInsert
= XFromPosition(currentPos
);
2965 int line
= pdoc
->LineFromPosition(currentPos
);
2966 bool prevCr
= false;
2967 pdoc
->BeginUndoAction();
2968 for (int i
= 0; i
< len
; i
++) {
2969 if (IsEOLChar(ptr
[i
])) {
2970 if ((ptr
[i
] == '\r') || (!prevCr
))
2972 if (line
>= pdoc
->LinesTotal()) {
2973 if (pdoc
->eolMode
!= SC_EOL_LF
)
2974 pdoc
->InsertChar(pdoc
->Length(), '\r');
2975 if (pdoc
->eolMode
!= SC_EOL_CR
)
2976 pdoc
->InsertChar(pdoc
->Length(), '\n');
2978 // Pad the end of lines with spaces if required
2979 currentPos
= PositionFromLineX(line
, xInsert
);
2980 if ((XFromPosition(currentPos
) < xInsert
) && (i
+ 1 < len
)) {
2981 for (int i
= 0; i
< xInsert
- XFromPosition(currentPos
); i
++) {
2982 pdoc
->InsertChar(currentPos
, ' ');
2986 prevCr
= ptr
[i
] == '\r';
2988 pdoc
->InsertString(currentPos
, ptr
+ i
, 1);
2993 pdoc
->EndUndoAction();
2994 SetEmptySelection(pos
);
2997 bool Editor::CanPaste() {
2998 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
3001 void Editor::Clear() {
3002 if (currentPos
== anchor
) {
3003 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3009 SetEmptySelection(currentPos
);
3012 void Editor::SelectAll() {
3013 SetSelection(0, pdoc
->Length());
3017 void Editor::Undo() {
3018 if (pdoc
->CanUndo()) {
3020 int newPos
= pdoc
->Undo();
3021 SetEmptySelection(newPos
);
3022 EnsureCaretVisible();
3026 void Editor::Redo() {
3027 if (pdoc
->CanRedo()) {
3028 int newPos
= pdoc
->Redo();
3029 SetEmptySelection(newPos
);
3030 EnsureCaretVisible();
3034 void Editor::DelChar() {
3035 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3036 pdoc
->DelChar(currentPos
);
3038 // Avoid blinking during rapid typing:
3039 ShowCaretAtCurrentPosition();
3042 void Editor::DelCharBack(bool allowLineStartDeletion
) {
3043 if (currentPos
== anchor
) {
3044 if (!RangeContainsProtected(currentPos
- 1, currentPos
)) {
3045 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
3046 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != currentPos
)) {
3047 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3048 pdoc
->GetColumn(currentPos
) > 0 && pdoc
->backspaceUnindents
) {
3049 pdoc
->BeginUndoAction();
3050 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3051 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
3052 if (indentation
% indentationStep
== 0) {
3053 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3055 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- (indentation
% indentationStep
));
3057 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
3058 pdoc
->EndUndoAction();
3060 pdoc
->DelCharBack(currentPos
);
3066 SetEmptySelection(currentPos
);
3068 // Avoid blinking during rapid typing:
3069 ShowCaretAtCurrentPosition();
3072 void Editor::NotifyFocus(bool) {}
3074 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
3076 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
3077 scn
.position
= endStyleNeeded
;
3081 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
3082 NotifyStyleToNeeded(endStyleNeeded
);
3085 void Editor::NotifyChar(int ch
) {
3087 scn
.nmhdr
.code
= SCN_CHARADDED
;
3090 if (recordingMacro
) {
3092 txt
[0] = static_cast<char>(ch
);
3094 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
3098 void Editor::NotifySavePoint(bool isSavePoint
) {
3101 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
3103 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
3108 void Editor::NotifyModifyAttempt() {
3110 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
3114 void Editor::NotifyDoubleClick(Point
, bool) {
3116 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
3120 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3122 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
3123 scn
.position
= position
;
3124 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3125 (alt
? SCI_ALT
: 0);
3129 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3131 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
3132 scn
.position
= position
;
3133 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3134 (alt
? SCI_ALT
: 0);
3138 void Editor::NotifyUpdateUI() {
3140 scn
.nmhdr
.code
= SCN_UPDATEUI
;
3144 void Editor::NotifyPainted() {
3146 scn
.nmhdr
.code
= SCN_PAINTED
;
3150 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
3151 int marginClicked
= -1;
3153 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
3154 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
3155 marginClicked
= margin
;
3156 x
+= vs
.ms
[margin
].width
;
3158 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
3160 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
3161 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3162 (alt
? SCI_ALT
: 0);
3163 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
3164 scn
.margin
= marginClicked
;
3172 void Editor::NotifyNeedShown(int pos
, int len
) {
3174 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
3180 void Editor::NotifyDwelling(Point pt
, bool state
) {
3182 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
3183 scn
.position
= PositionFromLocationClose(pt
);
3189 void Editor::NotifyZoom() {
3191 scn
.nmhdr
.code
= SCN_ZOOM
;
3195 // Notifications from document
3196 void Editor::NotifyModifyAttempt(Document
*, void *) {
3197 //Platform::DebugPrintf("** Modify Attempt\n");
3198 NotifyModifyAttempt();
3201 void Editor::NotifyMove(int position
) {
3203 scn
.nmhdr
.code
= SCN_POSCHANGED
;
3204 scn
.position
= position
;
3208 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
3209 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
3210 NotifySavePoint(atSavePoint
);
3213 void Editor::CheckModificationForWrap(DocModification mh
) {
3214 if ((mh
.modificationType
& SC_MOD_INSERTTEXT
) ||
3215 (mh
.modificationType
& SC_MOD_DELETETEXT
)) {
3216 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
3217 if (wrapState
!= eWrapNone
) {
3218 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
3219 if (mh
.linesAdded
== 0) {
3220 AutoSurface
surface(this);
3221 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
3222 if (surface
&& ll
) {
3223 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
3224 if (cs
.GetHeight(lineDoc
) != ll
->lines
) {
3225 NeedWrapping(lineDoc
- 1);
3229 NeedWrapping(lineDoc
);
3232 NeedWrapping(lineDoc
);
3238 // Move a position so it is still after the same character as before the insertion.
3239 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
3240 if (position
> startInsertion
) {
3241 return position
+ length
;
3246 // Move a position so it is still after the same character as before the deletion if that
3247 // character is still present else after the previous surviving character.
3248 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
3249 if (position
> startDeletion
) {
3250 int endDeletion
= startDeletion
+ length
;
3251 if (position
> endDeletion
) {
3252 return position
- length
;
3254 return startDeletion
;
3261 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
3262 needUpdateUI
= true;
3263 if (paintState
== painting
) {
3264 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
3266 CheckModificationForWrap(mh
);
3267 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
3268 if (paintState
== notPainting
) {
3269 if (mh
.position
< pdoc
->LineStart(topLine
)) {
3270 // Styling performed before this view
3273 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3277 // Move selection and brace highlights
3278 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
3279 currentPos
= MovePositionForInsertion(currentPos
, mh
.position
, mh
.length
);
3280 anchor
= MovePositionForInsertion(anchor
, mh
.position
, mh
.length
);
3281 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
3282 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
3283 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
3284 currentPos
= MovePositionForDeletion(currentPos
, mh
.position
, mh
.length
);
3285 anchor
= MovePositionForDeletion(anchor
, mh
.position
, mh
.length
);
3286 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
3287 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
3289 if (cs
.LinesDisplayed() < cs
.LinesInDoc()) {
3290 // Some lines are hidden so may need shown.
3291 // TODO: check if the modified area is hidden.
3292 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
3293 NotifyNeedShown(mh
.position
, mh
.length
);
3294 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
3295 NotifyNeedShown(mh
.position
, mh
.length
);
3298 if (mh
.linesAdded
!= 0) {
3299 // Update contraction state for inserted and removed lines
3300 // lineOfPos should be calculated in context of state before modification, shouldn't it
3301 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
3302 if (mh
.linesAdded
> 0) {
3303 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
3305 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
3307 // Avoid scrolling of display if change before current display
3308 if (mh
.position
< posTopLine
) {
3309 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
3310 if (newTop
!= topLine
) {
3312 SetVerticalScrollPos();
3316 //Platform::DebugPrintf("** %x Doc Changed\n", this);
3317 // TODO: could invalidate from mh.startModification to end of screen
3318 //InvalidateRange(mh.position, mh.position + mh.length);
3319 if (paintState
== notPainting
) {
3323 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
3324 // mh.position, mh.position + mh.length);
3325 if (paintState
== notPainting
) {
3326 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3331 if (mh
.linesAdded
!= 0) {
3335 if (mh
.modificationType
& SC_MOD_CHANGEMARKER
) {
3336 if (paintState
== notPainting
) {
3341 // If client wants to see this modification
3342 if (mh
.modificationType
& modEventMask
) {
3343 if ((mh
.modificationType
& SC_MOD_CHANGESTYLE
) == 0) {
3344 // Real modification made to text of document.
3345 NotifyChange(); // Send EN_CHANGE
3349 scn
.nmhdr
.code
= SCN_MODIFIED
;
3350 scn
.position
= mh
.position
;
3351 scn
.modificationType
= mh
.modificationType
;
3353 scn
.length
= mh
.length
;
3354 scn
.linesAdded
= mh
.linesAdded
;
3356 scn
.foldLevelNow
= mh
.foldLevelNow
;
3357 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
3362 void Editor::NotifyDeleted(Document
*, void *) {
3366 void Editor::NotifyMacroRecord(unsigned int iMessage
, unsigned long wParam
, long lParam
) {
3368 // Enumerates all macroable messages
3374 case SCI_REPLACESEL
:
3376 case SCI_INSERTTEXT
:
3377 case SCI_APPENDTEXT
:
3382 case SCI_SEARCHANCHOR
:
3383 case SCI_SEARCHNEXT
:
3384 case SCI_SEARCHPREV
:
3386 case SCI_LINEDOWNEXTEND
:
3388 case SCI_PARADOWNEXTEND
:
3390 case SCI_LINEUPEXTEND
:
3392 case SCI_PARAUPEXTEND
:
3394 case SCI_CHARLEFTEXTEND
:
3396 case SCI_CHARRIGHTEXTEND
:
3398 case SCI_WORDLEFTEXTEND
:
3400 case SCI_WORDRIGHTEXTEND
:
3401 case SCI_WORDPARTLEFT
:
3402 case SCI_WORDPARTLEFTEXTEND
:
3403 case SCI_WORDPARTRIGHT
:
3404 case SCI_WORDPARTRIGHTEXTEND
:
3406 case SCI_HOMEEXTEND
:
3408 case SCI_LINEENDEXTEND
:
3410 case SCI_HOMEWRAPEXTEND
:
3411 case SCI_LINEENDWRAP
:
3412 case SCI_LINEENDWRAPEXTEND
:
3413 case SCI_DOCUMENTSTART
:
3414 case SCI_DOCUMENTSTARTEXTEND
:
3415 case SCI_DOCUMENTEND
:
3416 case SCI_DOCUMENTENDEXTEND
:
3418 case SCI_PAGEUPEXTEND
:
3420 case SCI_PAGEDOWNEXTEND
:
3421 case SCI_EDITTOGGLEOVERTYPE
:
3423 case SCI_DELETEBACK
:
3428 case SCI_VCHOMEEXTEND
:
3429 case SCI_VCHOMEWRAP
:
3430 case SCI_VCHOMEWRAPEXTEND
:
3431 case SCI_DELWORDLEFT
:
3432 case SCI_DELWORDRIGHT
:
3433 case SCI_DELLINELEFT
:
3434 case SCI_DELLINERIGHT
:
3436 case SCI_LINEDELETE
:
3437 case SCI_LINETRANSPOSE
:
3438 case SCI_LINEDUPLICATE
:
3441 case SCI_LINESCROLLDOWN
:
3442 case SCI_LINESCROLLUP
:
3443 case SCI_DELETEBACKNOTLINE
:
3444 case SCI_HOMEDISPLAY
:
3445 case SCI_HOMEDISPLAYEXTEND
:
3446 case SCI_LINEENDDISPLAY
:
3447 case SCI_LINEENDDISPLAYEXTEND
:
3450 // Filter out all others like display changes. Also, newlines are redundant
3451 // with char insert messages.
3454 // printf("Filtered out %ld of macro recording\n", iMessage);
3458 // Send notification
3460 scn
.nmhdr
.code
= SCN_MACRORECORD
;
3461 scn
.message
= iMessage
;
3462 scn
.wParam
= wParam
;
3463 scn
.lParam
= lParam
;
3467 // Force scroll and keep position relative to top of window
3468 void Editor::PageMove(int direction
, bool extend
) {
3469 Point pt
= LocationFromPosition(currentPos
);
3470 int topLineNew
= Platform::Clamp(
3471 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
3472 int newPos
= PositionFromLocation(
3473 Point(lastXChosen
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())));
3474 if (topLineNew
!= topLine
) {
3475 SetTopLine(topLineNew
);
3476 MovePositionTo(newPos
, extend
);
3478 SetVerticalScrollPos();
3480 MovePositionTo(newPos
, extend
);
3484 void Editor::ChangeCaseOfSelection(bool makeUpperCase
) {
3485 pdoc
->BeginUndoAction();
3486 int startCurrent
= currentPos
;
3487 int startAnchor
= anchor
;
3488 if (selType
== selRectangle
) {
3489 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
3490 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
3491 for (int line
= lineEnd
; line
>= lineStart
; line
--) {
3493 Range(SelectionStart(line
), SelectionEnd(line
)),
3496 // Would be nicer to keep the rectangular selection but this is complex
3497 selType
= selStream
;
3498 SetSelection(startCurrent
, startCurrent
);
3500 pdoc
->ChangeCase(Range(SelectionStart(), SelectionEnd()),
3502 SetSelection(startCurrent
, startAnchor
);
3504 pdoc
->EndUndoAction();
3507 void Editor::LineTranspose() {
3508 int line
= pdoc
->LineFromPosition(currentPos
);
3510 int startPrev
= pdoc
->LineStart(line
- 1);
3511 int endPrev
= pdoc
->LineEnd(line
- 1);
3512 int start
= pdoc
->LineStart(line
);
3513 int end
= pdoc
->LineEnd(line
);
3514 int startNext
= pdoc
->LineStart(line
+ 1);
3515 if (end
< pdoc
->Length()) {
3517 char *thisLine
= CopyRange(start
, end
);
3518 pdoc
->DeleteChars(start
, end
- start
);
3519 if (pdoc
->InsertString(startPrev
, thisLine
, end
- start
)) {
3520 MovePositionTo(startPrev
+ end
- start
);
3524 // Last line so line has no line end
3525 char *thisLine
= CopyRange(start
, end
);
3526 char *prevEnd
= CopyRange(endPrev
, start
);
3527 pdoc
->DeleteChars(endPrev
, end
- endPrev
);
3528 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
3529 if (pdoc
->InsertString(startPrev
+ end
- start
, prevEnd
, start
- endPrev
)) {
3530 MovePositionTo(startPrev
+ end
- endPrev
);
3539 void Editor::LineDuplicate() {
3540 int line
= pdoc
->LineFromPosition(currentPos
);
3541 int start
= pdoc
->LineStart(line
);
3542 int end
= pdoc
->LineEnd(line
);
3543 char *thisLine
= CopyRange(start
, end
);
3544 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
3545 pdoc
->InsertString(end
, eol
);
3546 pdoc
->InsertString(end
+ strlen(eol
), thisLine
, end
- start
);
3550 void Editor::CancelModes() {}
3552 void Editor::NewLine() {
3554 const char *eol
= "\n";
3555 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
3557 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
3559 } // else SC_EOL_LF -> "\n" already set
3560 if (pdoc
->InsertString(currentPos
, eol
)) {
3561 SetEmptySelection(currentPos
+ strlen(eol
));
3568 EnsureCaretVisible();
3571 void Editor::CursorUpOrDown(int direction
, bool extend
) {
3572 Point pt
= LocationFromPosition(currentPos
);
3573 int posNew
= PositionFromLocation(
3574 Point(lastXChosen
, pt
.y
+ direction
* vs
.lineHeight
));
3575 if (direction
< 0) {
3576 // Line wrapping may lead to a location on the same line, so
3577 // seek back if that is the case.
3578 // There is an equivalent case when moving down which skips
3579 // over a line but as that does not trap the user it is fine.
3580 Point ptNew
= LocationFromPosition(posNew
);
3581 while ((posNew
> 0) && (pt
.y
== ptNew
.y
)) {
3583 ptNew
= LocationFromPosition(posNew
);
3586 MovePositionTo(posNew
, extend
);
3589 int Editor::StartEndDisplayLine(int pos
, bool start
) {
3591 int line
= pdoc
->LineFromPosition(pos
);
3592 AutoSurface
surface(this);
3593 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
3594 int posRet
= INVALID_POSITION
;
3595 if (surface
&& ll
) {
3596 unsigned int posLineStart
= pdoc
->LineStart(line
);
3597 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
3598 int posInLine
= pos
- posLineStart
;
3599 if (posInLine
<= ll
->maxLineLength
) {
3600 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
3601 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
3603 posRet
= ll
->LineStart(subLine
) + posLineStart
;
3605 if (subLine
== ll
->lines
- 1)
3606 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
;
3608 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
- 1;
3614 if (posRet
== INVALID_POSITION
) {
3621 int Editor::KeyCommand(unsigned int iMessage
) {
3626 case SCI_LINEDOWNEXTEND
:
3627 CursorUpOrDown(1, true);
3630 MovePositionTo(pdoc
->ParaDown(currentPos
));
3632 case SCI_PARADOWNEXTEND
:
3633 MovePositionTo(pdoc
->ParaDown(currentPos
), true);
3635 case SCI_LINESCROLLDOWN
:
3636 ScrollTo(topLine
+ 1);
3637 MoveCaretInsideView(false);
3642 case SCI_LINEUPEXTEND
:
3643 CursorUpOrDown(-1, true);
3646 MovePositionTo(pdoc
->ParaUp(currentPos
));
3648 case SCI_PARAUPEXTEND
:
3649 MovePositionTo(pdoc
->ParaUp(currentPos
), true);
3651 case SCI_LINESCROLLUP
:
3652 ScrollTo(topLine
- 1);
3653 MoveCaretInsideView(false);
3656 if (SelectionEmpty()) {
3657 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1));
3659 MovePositionTo(SelectionStart());
3663 case SCI_CHARLEFTEXTEND
:
3664 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), true);
3668 if (SelectionEmpty()) {
3669 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1));
3671 MovePositionTo(SelectionEnd());
3675 case SCI_CHARRIGHTEXTEND
:
3676 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), true);
3680 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1));
3683 case SCI_WORDLEFTEXTEND
:
3684 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1), true);
3688 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1));
3691 case SCI_WORDRIGHTEXTEND
:
3692 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1), true);
3696 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)));
3699 case SCI_HOMEEXTEND
:
3700 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), true);
3704 MovePositionTo(pdoc
->LineEndPosition(currentPos
));
3707 case SCI_LINEENDEXTEND
:
3708 MovePositionTo(pdoc
->LineEndPosition(currentPos
), true);
3711 case SCI_HOMEWRAP
: {
3712 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
3713 if (currentPos
<= homePos
)
3714 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
3715 MovePositionTo(homePos
);
3719 case SCI_HOMEWRAPEXTEND
: {
3720 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
3721 if (currentPos
<= homePos
)
3722 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
3723 MovePositionTo(homePos
, true);
3727 case SCI_LINEENDWRAP
: {
3728 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
3729 if (currentPos
>= endPos
)
3730 endPos
= pdoc
->LineEndPosition(currentPos
);
3731 MovePositionTo(endPos
);
3735 case SCI_LINEENDWRAPEXTEND
: {
3736 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
3737 if (currentPos
>= endPos
)
3738 endPos
= pdoc
->LineEndPosition(currentPos
);
3739 MovePositionTo(endPos
, true);
3743 case SCI_DOCUMENTSTART
:
3747 case SCI_DOCUMENTSTARTEXTEND
:
3748 MovePositionTo(0, true);
3751 case SCI_DOCUMENTEND
:
3752 MovePositionTo(pdoc
->Length());
3755 case SCI_DOCUMENTENDEXTEND
:
3756 MovePositionTo(pdoc
->Length(), true);
3762 case SCI_PAGEUPEXTEND
:
3768 case SCI_PAGEDOWNEXTEND
:
3771 case SCI_EDITTOGGLEOVERTYPE
:
3772 inOverstrike
= !inOverstrike
;
3774 ShowCaretAtCurrentPosition();
3777 case SCI_CANCEL
: // Cancel any modes - handled in subclass
3778 // Also unselect text
3781 case SCI_DELETEBACK
:
3784 EnsureCaretVisible();
3786 case SCI_DELETEBACKNOTLINE
:
3789 EnsureCaretVisible();
3794 EnsureCaretVisible();
3799 EnsureCaretVisible();
3808 MovePositionTo(pdoc
->VCHomePosition(currentPos
));
3811 case SCI_VCHOMEEXTEND
:
3812 MovePositionTo(pdoc
->VCHomePosition(currentPos
), true);
3815 case SCI_VCHOMEWRAP
: {
3816 int homePos
= pdoc
->VCHomePosition(currentPos
);
3817 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
3818 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
3819 homePos
= viewLineStart
;
3821 MovePositionTo(homePos
);
3825 case SCI_VCHOMEWRAPEXTEND
: {
3826 int homePos
= pdoc
->VCHomePosition(currentPos
);
3827 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
3828 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
3829 homePos
= viewLineStart
;
3831 MovePositionTo(homePos
, true);
3836 if (vs
.zoomLevel
< 20) {
3838 InvalidateStyleRedraw();
3843 if (vs
.zoomLevel
> -10) {
3845 InvalidateStyleRedraw();
3849 case SCI_DELWORDLEFT
: {
3850 int startWord
= pdoc
->NextWordStart(currentPos
, -1);
3851 pdoc
->DeleteChars(startWord
, currentPos
- startWord
);
3855 case SCI_DELWORDRIGHT
: {
3856 int endWord
= pdoc
->NextWordStart(currentPos
, 1);
3857 pdoc
->DeleteChars(currentPos
, endWord
- currentPos
);
3860 case SCI_DELLINELEFT
: {
3861 int line
= pdoc
->LineFromPosition(currentPos
);
3862 int start
= pdoc
->LineStart(line
);
3863 pdoc
->DeleteChars(start
, currentPos
- start
);
3867 case SCI_DELLINERIGHT
: {
3868 int line
= pdoc
->LineFromPosition(currentPos
);
3869 int end
= pdoc
->LineEnd(line
);
3870 pdoc
->DeleteChars(currentPos
, end
- currentPos
);
3874 int lineStart
= pdoc
->LineFromPosition(currentPos
);
3875 int lineEnd
= pdoc
->LineFromPosition(anchor
);
3876 if (lineStart
> lineEnd
) {
3878 lineEnd
= lineStart
;
3881 int start
= pdoc
->LineStart(lineStart
);
3882 int end
= pdoc
->LineStart(lineEnd
+ 1);
3883 SetSelection(start
, end
);
3887 case SCI_LINEDELETE
: {
3888 int line
= pdoc
->LineFromPosition(currentPos
);
3889 int start
= pdoc
->LineStart(line
);
3890 int end
= pdoc
->LineStart(line
+ 1);
3891 pdoc
->DeleteChars(start
, end
- start
);
3894 case SCI_LINETRANSPOSE
:
3897 case SCI_LINEDUPLICATE
:
3901 ChangeCaseOfSelection(false);
3904 ChangeCaseOfSelection(true);
3906 case SCI_WORDPARTLEFT
:
3907 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1));
3910 case SCI_WORDPARTLEFTEXTEND
:
3911 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1), true);
3914 case SCI_WORDPARTRIGHT
:
3915 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1));
3918 case SCI_WORDPARTRIGHTEXTEND
:
3919 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1), true);
3922 case SCI_HOMEDISPLAY
:
3923 MovePositionTo(MovePositionSoVisible(
3924 StartEndDisplayLine(currentPos
, true), -1));
3927 case SCI_HOMEDISPLAYEXTEND
:
3928 MovePositionTo(MovePositionSoVisible(
3929 StartEndDisplayLine(currentPos
, true), -1), true);
3932 case SCI_LINEENDDISPLAY
:
3933 MovePositionTo(MovePositionSoVisible(
3934 StartEndDisplayLine(currentPos
, false), 1));
3937 case SCI_LINEENDDISPLAYEXTEND
:
3938 MovePositionTo(MovePositionSoVisible(
3939 StartEndDisplayLine(currentPos
, false), 1), true);
3946 int Editor::KeyDefault(int, int) {
3950 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
3952 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3953 (alt
? SCI_ALT
: 0);
3954 int msg
= kmap
.Find(key
, modifiers
);
3958 return WndProc(msg
, 0, 0);
3962 return KeyDefault(key
, modifiers
);
3966 void Editor::SetWhitespaceVisible(int view
) {
3967 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(view
);
3970 int Editor::GetWhitespaceVisible() {
3971 return vs
.viewWhitespace
;
3974 void Editor::Indent(bool forwards
) {
3975 //Platform::DebugPrintf("INdent %d\n", forwards);
3976 int lineOfAnchor
= pdoc
->LineFromPosition(anchor
);
3977 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
3978 if (lineOfAnchor
== lineCurrentPos
) {
3980 pdoc
->BeginUndoAction();
3982 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
3984 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3985 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
3986 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
+ indentationStep
);
3987 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
3989 if (pdoc
->useTabs
) {
3990 pdoc
->InsertChar(currentPos
, '\t');
3991 SetEmptySelection(currentPos
+ 1);
3993 int numSpaces
= (pdoc
->tabInChars
) -
3994 (pdoc
->GetColumn(currentPos
) % (pdoc
->tabInChars
));
3996 numSpaces
= pdoc
->tabInChars
;
3997 for (int i
= 0; i
< numSpaces
; i
++) {
3998 pdoc
->InsertChar(currentPos
+ i
, ' ');
4000 SetEmptySelection(currentPos
+ numSpaces
);
4003 pdoc
->EndUndoAction();
4005 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
4007 pdoc
->BeginUndoAction();
4008 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4009 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
4010 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
4011 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4012 pdoc
->EndUndoAction();
4014 int newColumn
= ((pdoc
->GetColumn(currentPos
) - 1) / pdoc
->tabInChars
) *
4018 int newPos
= currentPos
;
4019 while (pdoc
->GetColumn(newPos
) > newColumn
)
4021 SetEmptySelection(newPos
);
4025 int anchorPosOnLine
= anchor
- pdoc
->LineStart(lineOfAnchor
);
4026 int currentPosPosOnLine
= currentPos
- pdoc
->LineStart(lineCurrentPos
);
4027 // Multiple lines selected so indent / dedent
4028 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
4029 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
4030 if (pdoc
->LineStart(lineBottomSel
) == anchor
|| pdoc
->LineStart(lineBottomSel
) == currentPos
)
4031 lineBottomSel
--; // If not selecting any characters on a line, do not indent
4032 pdoc
->BeginUndoAction();
4033 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
4034 pdoc
->EndUndoAction();
4035 if (lineOfAnchor
< lineCurrentPos
) {
4036 if (currentPosPosOnLine
== 0)
4037 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4039 SetSelection(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
4041 if (anchorPosOnLine
== 0)
4042 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4044 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
4050 * Search of a text in the document, in the given range.
4051 * @return The position of the found text, -1 if not found.
4053 long Editor::FindText(
4054 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4055 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4056 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
4058 TextToFind
*ft
= reinterpret_cast<TextToFind
*>(lParam
);
4059 int lengthFound
= strlen(ft
->lpstrText
);
4060 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
4061 (wParam
& SCFIND_MATCHCASE
) != 0,
4062 (wParam
& SCFIND_WHOLEWORD
) != 0,
4063 (wParam
& SCFIND_WORDSTART
) != 0,
4064 (wParam
& SCFIND_REGEXP
) != 0,
4065 (wParam
& SCFIND_POSIX
) != 0,
4068 ft
->chrgText
.cpMin
= pos
;
4069 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
4075 * Relocatable search support : Searches relative to current selection
4076 * point and sets the selection to the found text range with
4080 * Anchor following searches at current selection start: This allows
4081 * multiple incremental interactive searches to be macro recorded
4082 * while still setting the selection to found text so the find/select
4083 * operation is self-contained.
4085 void Editor::SearchAnchor() {
4086 searchAnchor
= SelectionStart();
4090 * Find text from current search anchor: Must call @c SearchAnchor first.
4091 * Used for next text and previous text requests.
4092 * @return The position of the found text, -1 if not found.
4094 long Editor::SearchText(
4095 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
4096 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4097 ///< @c SCFIND_WORDSTART or @c SCFIND_REGEXP.
4098 sptr_t lParam
) { ///< The text to search for.
4100 const char *txt
= reinterpret_cast<char *>(lParam
);
4102 int lengthFound
= strlen(txt
);
4103 if (iMessage
== SCI_SEARCHNEXT
) {
4104 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
4105 (wParam
& SCFIND_MATCHCASE
) != 0,
4106 (wParam
& SCFIND_WHOLEWORD
) != 0,
4107 (wParam
& SCFIND_WORDSTART
) != 0,
4108 (wParam
& SCFIND_REGEXP
) != 0,
4109 (wParam
& SCFIND_POSIX
) != 0,
4112 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
4113 (wParam
& SCFIND_MATCHCASE
) != 0,
4114 (wParam
& SCFIND_WHOLEWORD
) != 0,
4115 (wParam
& SCFIND_WORDSTART
) != 0,
4116 (wParam
& SCFIND_REGEXP
) != 0,
4117 (wParam
& SCFIND_POSIX
) != 0,
4122 SetSelection(pos
, pos
+ lengthFound
);
4129 * Search for text in the target range of the document.
4130 * @return The position of the found text, -1 if not found.
4132 long Editor::SearchInTarget(const char *text
, int length
) {
4133 int lengthFound
= length
;
4134 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
4135 (searchFlags
& SCFIND_MATCHCASE
) != 0,
4136 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
4137 (searchFlags
& SCFIND_WORDSTART
) != 0,
4138 (searchFlags
& SCFIND_REGEXP
) != 0,
4139 (searchFlags
& SCFIND_POSIX
) != 0,
4143 targetEnd
= pos
+ lengthFound
;
4148 void Editor::GoToLine(int lineNo
) {
4149 if (lineNo
> pdoc
->LinesTotal())
4150 lineNo
= pdoc
->LinesTotal();
4153 SetEmptySelection(pdoc
->LineStart(lineNo
));
4154 ShowCaretAtCurrentPosition();
4155 EnsureCaretVisible();
4158 static bool Close(Point pt1
, Point pt2
) {
4159 if (abs(pt1
.x
- pt2
.x
) > 3)
4161 if (abs(pt1
.y
- pt2
.y
) > 3)
4166 char *Editor::CopyRange(int start
, int end
) {
4169 int len
= end
- start
;
4170 text
= new char[len
+ 1];
4172 for (int i
= 0; i
< len
; i
++) {
4173 text
[i
] = pdoc
->CharAt(start
+ i
);
4181 void Editor::CopySelectionRange(SelectionText
*ss
) {
4184 if (selType
== selRectangle
) {
4185 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4186 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4188 for (line
= lineStart
; line
<= lineEnd
; line
++) {
4189 size
+= SelectionEnd(line
) - SelectionStart(line
) + 1;
4190 if (pdoc
->eolMode
== SC_EOL_CRLF
)
4194 text
= new char[size
+ 1];
4197 for (line
= lineStart
; line
<= lineEnd
; line
++) {
4198 for (int i
= SelectionStart(line
);i
< SelectionEnd(line
);i
++) {
4199 text
[j
++] = pdoc
->CharAt(i
);
4201 if (pdoc
->eolMode
!= SC_EOL_LF
)
4203 if (pdoc
->eolMode
!= SC_EOL_CR
)
4210 size
= SelectionEnd() - SelectionStart();
4211 text
= CopyRange(SelectionStart(), SelectionEnd());
4213 ss
->Set(text
, size
, selType
== selRectangle
);
4216 void Editor::SetDragPosition(int newPos
) {
4218 newPos
= MovePositionOutsideChar(newPos
, 1);
4221 if (posDrag
!= newPos
) {
4230 void Editor::DisplayCursor(Window::Cursor c
) {
4231 if (cursorMode
== SC_CURSORNORMAL
)
4234 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
4237 void Editor::StartDrag() {
4238 // Always handled by subclasses
4239 //SetMouseCapture(true);
4240 //DisplayCursor(Window::cursorArrow);
4243 void Editor::DropAt(int position
, const char *value
, bool moving
, bool rectangular
) {
4244 //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
4246 dropWentOutside
= false;
4248 int positionWasInSelection
= PositionInSelection(position
);
4250 bool positionOnEdgeOfSelection
=
4251 (position
== SelectionStart()) || (position
== SelectionEnd());
4253 if ((!inDragDrop
) || !(0 == positionWasInSelection
) ||
4254 (positionOnEdgeOfSelection
&& !moving
)) {
4256 int selStart
= SelectionStart();
4257 int selEnd
= SelectionEnd();
4259 pdoc
->BeginUndoAction();
4261 int positionAfterDeletion
= position
;
4262 if (inDragDrop
&& moving
) {
4263 // Remove dragged out text
4265 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4266 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4267 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
4268 int startPos
= SelectionStart(line
);
4269 int endPos
= SelectionEnd(line
);
4270 if (position
>= startPos
) {
4271 if (position
> endPos
) {
4272 positionAfterDeletion
-= endPos
- startPos
;
4274 positionAfterDeletion
-= position
- startPos
;
4279 if (position
> selStart
) {
4280 positionAfterDeletion
-= selEnd
- selStart
;
4285 position
= positionAfterDeletion
;
4288 PasteRectangular(position
, value
, strlen(value
));
4289 pdoc
->EndUndoAction();
4290 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
4291 SetSelection(position
, position
);
4293 position
= MovePositionOutsideChar(position
, currentPos
- position
);
4294 if (pdoc
->InsertString(position
, value
)) {
4295 SetSelection(position
+ strlen(value
), position
);
4297 pdoc
->EndUndoAction();
4299 } else if (inDragDrop
) {
4300 SetSelection(position
, position
);
4304 static int BeforeInOrAfter(int val
, int minim
, int maxim
) {
4307 else if (val
> maxim
)
4313 int Editor::PositionInSelection(int pos
) {
4314 pos
= MovePositionOutsideChar(pos
, currentPos
- pos
);
4315 if (selType
== selRectangle
) {
4316 if (pos
< SelectionStart())
4318 if (pos
> SelectionEnd())
4320 int linePos
= pdoc
->LineFromPosition(pos
);
4321 return BeforeInOrAfter(pos
, SelectionStart(linePos
), SelectionEnd(linePos
));
4323 if (currentPos
> anchor
) {
4324 return BeforeInOrAfter(pos
, anchor
, currentPos
);
4325 } else if (currentPos
< anchor
) {
4326 return BeforeInOrAfter(pos
, currentPos
, anchor
);
4332 bool Editor::PointInSelection(Point pt
) {
4333 // TODO: fix up for rectangular selection
4334 int pos
= PositionFromLocation(pt
);
4335 if (0 == PositionInSelection(pos
)) {
4336 if (pos
== SelectionStart()) {
4337 // see if just before selection
4338 Point locStart
= LocationFromPosition(pos
);
4339 if (pt
.x
< locStart
.x
)
4342 if (pos
== SelectionEnd()) {
4343 // see if just after selection
4344 Point locEnd
= LocationFromPosition(pos
);
4345 if (pt
.x
> locEnd
.x
)
4353 bool Editor::PointInSelMargin(Point pt
) {
4354 // Really means: "Point in a margin"
4355 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4356 PRectangle rcSelMargin
= GetClientRectangle();
4357 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
4358 return rcSelMargin
.Contains(pt
);
4364 void Editor::LineSelection(int lineCurrent_
, int lineAnchor_
) {
4365 if (lineAnchor_
< lineCurrent_
) {
4366 SetSelection(pdoc
->LineStart(lineCurrent_
+ 1),
4367 pdoc
->LineStart(lineAnchor_
));
4368 } else if (lineAnchor_
> lineCurrent_
) {
4369 SetSelection(pdoc
->LineStart(lineCurrent_
),
4370 pdoc
->LineStart(lineAnchor_
+ 1));
4371 } else { // Same line, select it
4372 SetSelection(pdoc
->LineStart(lineAnchor_
+ 1),
4373 pdoc
->LineStart(lineAnchor_
));
4377 void Editor::DwellEnd(bool mouseMoved
) {
4379 ticksToDwell
= dwellDelay
;
4381 ticksToDwell
= SC_TIME_FOREVER
;
4382 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4384 NotifyDwelling(ptMouseLast
, dwelling
);
4388 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
4389 //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
4391 int newPos
= PositionFromLocation(pt
);
4392 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
4395 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
4399 bool inSelMargin
= PointInSelMargin(pt
);
4400 if (shift
& !inSelMargin
) {
4401 SetSelection(newPos
);
4403 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
4404 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
4405 SetMouseCapture(true);
4406 SetEmptySelection(newPos
);
4407 bool doubleClick
= false;
4408 // Stop mouse button bounce changing selection type
4409 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
4410 if (selectionType
== selChar
) {
4411 selectionType
= selWord
;
4413 } else if (selectionType
== selWord
) {
4414 selectionType
= selLine
;
4416 selectionType
= selChar
;
4417 originalAnchorPos
= currentPos
;
4421 if (selectionType
== selWord
) {
4422 if (currentPos
>= originalAnchorPos
) { // Moved forward
4423 SetSelection(pdoc
->ExtendWordSelect(currentPos
, 1),
4424 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
4425 } else { // Moved backward
4426 SetSelection(pdoc
->ExtendWordSelect(currentPos
, -1),
4427 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
4429 } else if (selectionType
== selLine
) {
4430 lineAnchor
= LineFromLocation(pt
);
4431 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
4432 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
4434 SetEmptySelection(currentPos
);
4436 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
4438 NotifyDoubleClick(pt
, shift
);
4439 if (PositionIsHotspot(newPos
))
4440 NotifyHotSpotDoubleClicked(newPos
, shift
, ctrl
, alt
);
4442 } else { // Single click
4444 selType
= selStream
;
4447 lastClickTime
= curTime
;
4451 lineAnchor
= LineFromLocation(pt
);
4452 // Single click in margin: select whole line
4453 LineSelection(lineAnchor
, lineAnchor
);
4454 SetSelection(pdoc
->LineStart(lineAnchor
+ 1),
4455 pdoc
->LineStart(lineAnchor
));
4457 // Single shift+click in margin: select from line anchor to clicked line
4458 if (anchor
> currentPos
)
4459 lineAnchor
= pdoc
->LineFromPosition(anchor
- 1);
4461 lineAnchor
= pdoc
->LineFromPosition(anchor
);
4462 int lineStart
= LineFromLocation(pt
);
4463 LineSelection(lineStart
, lineAnchor
);
4464 //lineAnchor = lineStart; // Keep the same anchor for ButtonMove
4467 SetDragPosition(invalidPosition
);
4468 SetMouseCapture(true);
4469 selectionType
= selLine
;
4471 if (PositionIsHotspot(newPos
)) {
4472 NotifyHotSpotClicked(newPos
, shift
, ctrl
, alt
);
4475 inDragDrop
= PointInSelection(pt
);
4478 SetMouseCapture(false);
4479 SetDragPosition(newPos
);
4480 CopySelectionRange(&drag
);
4483 xStartSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4484 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4485 SetDragPosition(invalidPosition
);
4486 SetMouseCapture(true);
4488 SetEmptySelection(newPos
);
4489 selType
= alt
? selRectangle
: selStream
;
4490 selectionType
= selChar
;
4491 originalAnchorPos
= currentPos
;
4495 lastClickTime
= curTime
;
4497 ShowCaretAtCurrentPosition();
4500 bool Editor::PositionIsHotspot(int position
) {
4501 return vs
.styles
[pdoc
->StyleAt(position
)].hotspot
;
4504 bool Editor::PointIsHotspot(Point pt
) {
4505 int pos
= PositionFromLocation(pt
);
4506 return PositionIsHotspot(pos
);
4509 void Editor::SetHotSpotRange(Point
*pt
) {
4511 int pos
= PositionFromLocation(*pt
);
4513 // If we don't limit this to word characters then the
4514 // range can encompass more than the run range and then
4515 // the underline will not be drawn properly.
4516 int hsStart_
= pdoc
->ExtendStyleRange(pos
, -1);
4517 int hsEnd_
= pdoc
->ExtendStyleRange(pos
, 1);
4519 // Only invalidate the range if the hotspot range has changed...
4520 if (hsStart_
!= hsStart
|| hsEnd_
!= hsEnd
) {
4521 if (hsStart
!= -1) {
4522 InvalidateRange(hsStart
, hsEnd
);
4526 InvalidateRange(hsStart
, hsEnd
);
4529 if (hsStart
!= -1) {
4530 int hsStart_
= hsStart
;
4534 InvalidateRange(hsStart_
, hsEnd_
);
4542 void Editor::GetHotSpotRange(int& hsStart_
, int& hsEnd_
) {
4547 void Editor::ButtonMove(Point pt
) {
4548 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
4552 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
4553 if (HaveMouseCapture()) {
4555 // Slow down autoscrolling/selection
4556 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
4557 if (autoScrollTimer
.ticksToWait
> 0)
4559 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
4562 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4563 int movePos
= PositionFromLocation(pt
);
4564 movePos
= MovePositionOutsideChar(movePos
, currentPos
- movePos
);
4566 SetDragPosition(movePos
);
4568 if (selectionType
== selChar
) {
4569 SetSelection(movePos
);
4570 } else if (selectionType
== selWord
) {
4571 // Continue selecting by word
4572 if (movePos
>= originalAnchorPos
) { // Moved forward
4573 SetSelection(pdoc
->ExtendWordSelect(movePos
, 1),
4574 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
4575 } else { // Moved backward
4576 SetSelection(pdoc
->ExtendWordSelect(movePos
, -1),
4577 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
4580 // Continue selecting by line
4581 int lineMove
= LineFromLocation(pt
);
4582 LineSelection(lineMove
, lineAnchor
);
4587 PRectangle rcClient
= GetClientRectangle();
4588 if (pt
.y
> rcClient
.bottom
) {
4589 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
4591 lineMove
= cs
.DisplayFromDoc(pdoc
->LinesTotal() - 1);
4593 ScrollTo(lineMove
- LinesOnScreen() + 5);
4595 } else if (pt
.y
< rcClient
.top
) {
4596 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
4597 ScrollTo(lineMove
- 5);
4600 EnsureCaretVisible(false, false, true);
4602 if (hsStart
!= -1 && !PositionIsHotspot(movePos
))
4603 SetHotSpotRange(NULL
);
4606 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4607 if (PointInSelMargin(pt
)) {
4608 DisplayCursor(Window::cursorReverseArrow
);
4609 return; // No need to test for selection
4612 // Display regular (drag) cursor over selection
4613 if (PointInSelection(pt
)) {
4614 DisplayCursor(Window::cursorArrow
);
4615 } else if (PointIsHotspot(pt
)) {
4616 DisplayCursor(Window::cursorHand
);
4617 SetHotSpotRange(&pt
);
4619 DisplayCursor(Window::cursorText
);
4620 SetHotSpotRange(NULL
);
4626 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
4627 //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
4628 if (HaveMouseCapture()) {
4629 if (PointInSelMargin(pt
)) {
4630 DisplayCursor(Window::cursorReverseArrow
);
4632 DisplayCursor(Window::cursorText
);
4633 SetHotSpotRange(NULL
);
4635 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4637 SetMouseCapture(false);
4638 int newPos
= PositionFromLocation(pt
);
4639 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
4641 int selStart
= SelectionStart();
4642 int selEnd
= SelectionEnd();
4643 if (selStart
< selEnd
) {
4646 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
4647 SetSelection(newPos
, newPos
+ drag
.len
);
4649 } else if (newPos
< selStart
) {
4650 pdoc
->DeleteChars(selStart
, drag
.len
);
4651 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
4652 SetSelection(newPos
, newPos
+ drag
.len
);
4654 } else if (newPos
> selEnd
) {
4655 pdoc
->DeleteChars(selStart
, drag
.len
);
4657 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
4658 SetSelection(newPos
, newPos
+ drag
.len
);
4661 SetEmptySelection(newPos
);
4665 selectionType
= selChar
;
4668 if (selectionType
== selChar
) {
4669 SetSelection(newPos
);
4672 lastClickTime
= curTime
;
4675 if (selType
== selStream
) {
4679 EnsureCaretVisible(false);
4683 // Called frequently to perform background UI including
4684 // caret blinking and automatic scrolling.
4685 void Editor::Tick() {
4686 if (HaveMouseCapture()) {
4688 ButtonMove(ptMouseLast
);
4690 if (caret
.period
> 0) {
4691 timer
.ticksToWait
-= timer
.tickSize
;
4692 if (timer
.ticksToWait
<= 0) {
4693 caret
.on
= !caret
.on
;
4694 timer
.ticksToWait
= caret
.period
;
4698 if ((dwellDelay
< SC_TIME_FOREVER
) &&
4699 (ticksToDwell
> 0) &&
4700 (!HaveMouseCapture())) {
4701 ticksToDwell
-= timer
.tickSize
;
4702 if (ticksToDwell
<= 0) {
4704 NotifyDwelling(ptMouseLast
, dwelling
);
4709 void Editor::SetFocusState(bool focusState
) {
4710 hasFocus
= focusState
;
4711 NotifyFocus(hasFocus
);
4713 ShowCaretAtCurrentPosition();
4720 static bool IsIn(int a
, int minimum
, int maximum
) {
4721 return (a
>= minimum
) && (a
<= maximum
);
4724 static bool IsOverlap(int mina
, int maxa
, int minb
, int maxb
) {
4726 IsIn(mina
, minb
, maxb
) ||
4727 IsIn(maxa
, minb
, maxb
) ||
4728 IsIn(minb
, mina
, maxa
) ||
4729 IsIn(maxb
, mina
, maxa
);
4732 void Editor::CheckForChangeOutsidePaint(Range r
) {
4733 if (paintState
== painting
&& !paintingAllText
) {
4734 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
4738 PRectangle rcText
= GetTextRectangle();
4739 // Determine number of lines displayed including a possible partially displayed last line
4740 int linesDisplayed
= (rcText
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1;
4741 int bottomLine
= topLine
+ linesDisplayed
- 1;
4743 int lineRangeStart
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.start
));
4744 int lineRangeEnd
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.end
));
4745 if (!IsOverlap(topLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
4746 //Platform::DebugPrintf("No overlap (%d-%d) with window(%d-%d)\n",
4747 // lineRangeStart, lineRangeEnd, topLine, bottomLine);
4751 // Assert rcPaint contained within or equal to rcText
4752 if (rcPaint
.top
> rcText
.top
) {
4753 // does range intersect rcText.top .. rcPaint.top
4754 int paintTopLine
= ((rcPaint
.top
- rcText
.top
- 1) / vs
.lineHeight
) + topLine
;
4755 // paintTopLine is the top line of the paint rectangle or the line just above if that line is completely inside the paint rectangle
4756 if (IsOverlap(topLine
, paintTopLine
, lineRangeStart
, lineRangeEnd
)) {
4757 //Platform::DebugPrintf("Change (%d-%d) in top npv(%d-%d)\n",
4758 // lineRangeStart, lineRangeEnd, topLine, paintTopLine);
4763 if (rcPaint
.bottom
< rcText
.bottom
) {
4764 // does range intersect rcPaint.bottom .. rcText.bottom
4765 int paintBottomLine
= ((rcPaint
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1) + topLine
;
4766 // paintTopLine is the bottom line of the paint rectangle or the line just below if that line is completely inside the paint rectangle
4767 if (IsOverlap(paintBottomLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
4768 //Platform::DebugPrintf("Change (%d-%d) in bottom npv(%d-%d)\n",
4769 // lineRangeStart, lineRangeEnd, paintBottomLine, bottomLine);
4777 char BraceOpposite(char ch
) {
4800 // TODO: should be able to extend styled region to find matching brace
4801 // TODO: may need to make DBCS safe
4802 // so should be moved into Document
4803 int Editor::BraceMatch(int position
, int /*maxReStyle*/) {
4804 char chBrace
= pdoc
->CharAt(position
);
4805 char chSeek
= BraceOpposite(chBrace
);
4808 char styBrace
= static_cast<char>(
4809 pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
4811 if (chBrace
== '(' || chBrace
== '[' || chBrace
== '{' || chBrace
== '<')
4814 position
= position
+ direction
;
4815 while ((position
>= 0) && (position
< pdoc
->Length())) {
4816 char chAtPos
= pdoc
->CharAt(position
);
4817 char styAtPos
= static_cast<char>(pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
4818 if ((position
> pdoc
->GetEndStyled()) || (styAtPos
== styBrace
)) {
4819 if (chAtPos
== chBrace
)
4821 if (chAtPos
== chSeek
)
4826 position
= position
+ direction
;
4831 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
4832 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
4833 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
4834 CheckForChangeOutsidePaint(Range(braces
[0]));
4835 CheckForChangeOutsidePaint(Range(pos0
));
4838 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
4839 CheckForChangeOutsidePaint(Range(braces
[1]));
4840 CheckForChangeOutsidePaint(Range(pos1
));
4843 bracesMatchStyle
= matchStyle
;
4844 if (paintState
== notPainting
) {
4850 void Editor::SetDocPointer(Document
*document
) {
4851 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
4852 pdoc
->RemoveWatcher(this, 0);
4854 if (document
== NULL
) {
4855 pdoc
= new Document();
4861 // Ensure all positions within document
4867 // Reset the contraction state to fully shown.
4869 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
4873 pdoc
->AddWatcher(this, 0);
4875 // Removed because of reentrance problems of GTK+ 2.x
4876 // where changing a scroll bar position causes synchronous
4877 // painting before lexer and styling state is set up.
4881 // Recursively expand a fold, making lines visible except where they have an unexpanded parent
4882 void Editor::Expand(int &line
, bool doExpand
) {
4883 int lineMaxSubord
= pdoc
->GetLastChild(line
);
4885 while (line
<= lineMaxSubord
) {
4887 cs
.SetVisible(line
, line
, true);
4888 int level
= pdoc
->GetLevel(line
);
4889 if (level
& SC_FOLDLEVELHEADERFLAG
) {
4890 if (doExpand
&& cs
.GetExpanded(line
)) {
4893 Expand(line
, false);
4901 void Editor::ToggleContraction(int line
) {
4902 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
4903 if (cs
.GetExpanded(line
)) {
4904 int lineMaxSubord
= pdoc
->GetLastChild(line
);
4905 cs
.SetExpanded(line
, 0);
4906 if (lineMaxSubord
> line
) {
4907 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
4912 cs
.SetExpanded(line
, 1);
4920 // Recurse up from this line to find any folds that prevent this line from being visible
4921 // and unfold them all->
4922 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
4924 // In case in need of wrapping to ensure DisplayFromDoc works.
4927 if (!cs
.GetVisible(lineDoc
)) {
4928 int lineParent
= pdoc
->GetFoldParent(lineDoc
);
4929 if (lineParent
>= 0) {
4930 if (lineDoc
!= lineParent
)
4931 EnsureLineVisible(lineParent
, enforcePolicy
);
4932 if (!cs
.GetExpanded(lineParent
)) {
4933 cs
.SetExpanded(lineParent
, 1);
4934 Expand(lineParent
, true);
4940 if (enforcePolicy
) {
4941 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
4942 if (visiblePolicy
& VISIBLE_SLOP
) {
4943 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
4944 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
4945 SetVerticalScrollPos();
4947 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
4948 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
4949 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
4950 SetVerticalScrollPos();
4954 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
4955 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
4956 SetVerticalScrollPos();
4963 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
4964 pdoc
->BeginUndoAction();
4966 length
= strlen(text
);
4967 if (replacePatterns
) {
4968 text
= pdoc
->SubstituteByPosition(text
, &length
);
4972 if (targetStart
!= targetEnd
)
4973 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
4974 targetEnd
= targetStart
;
4975 pdoc
->InsertString(targetStart
, text
, length
);
4976 targetEnd
= targetStart
+ length
;
4977 pdoc
->EndUndoAction();
4981 bool Editor::IsUnicodeMode() const {
4982 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
4985 int Editor::CodePage() const {
4987 return pdoc
->dbcsCodePage
;
4992 static bool ValidMargin(unsigned long wParam
) {
4993 return wParam
< ViewStyle::margins
;
4996 static char *CharPtrFromSPtr(sptr_t lParam
) {
4997 return reinterpret_cast<char *>(lParam
);
5000 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5001 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
5003 // Optional macro recording hook
5005 NotifyMacroRecord(iMessage
, wParam
, lParam
);
5014 char *ptr
= CharPtrFromSPtr(lParam
);
5015 unsigned int iChar
= 0;
5016 for (; iChar
< wParam
- 1; iChar
++)
5017 ptr
[iChar
] = pdoc
->CharAt(iChar
);
5025 pdoc
->DeleteChars(0, pdoc
->Length());
5026 SetEmptySelection(0);
5027 pdoc
->InsertString(0, CharPtrFromSPtr(lParam
));
5031 case SCI_GETTEXTLENGTH
:
5032 return pdoc
->Length();
5046 EnsureCaretVisible();
5052 EnsureCaretVisible();
5061 return pdoc
->CanUndo() ? 1 : 0;
5063 case SCI_EMPTYUNDOBUFFER
:
5064 pdoc
->DeleteUndoHistory();
5067 case SCI_GETFIRSTVISIBLELINE
:
5070 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
5074 int lineStart
= pdoc
->LineStart(wParam
);
5075 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
5076 char *ptr
= CharPtrFromSPtr(lParam
);
5078 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
5079 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5084 case SCI_GETLINECOUNT
:
5085 if (pdoc
->LinesTotal() == 0)
5088 return pdoc
->LinesTotal();
5091 return !pdoc
->IsSavePoint();
5094 int nStart
= static_cast<int>(wParam
);
5095 int nEnd
= static_cast<int>(lParam
);
5097 nEnd
= pdoc
->Length();
5099 nStart
= nEnd
; // Remove selection
5100 selType
= selStream
;
5101 SetSelection(nEnd
, nStart
);
5102 EnsureCaretVisible();
5106 case SCI_GETSELTEXT
: {
5109 SelectionText selectedText
;
5110 CopySelectionRange(&selectedText
);
5111 char *ptr
= CharPtrFromSPtr(lParam
);
5113 if (selectedText
.len
) {
5114 for (; iChar
< selectedText
.len
; iChar
++)
5115 ptr
[iChar
] = selectedText
.s
[iChar
];
5123 case SCI_LINEFROMPOSITION
:
5124 if (static_cast<int>(wParam
) < 0)
5126 return pdoc
->LineFromPosition(wParam
);
5128 case SCI_POSITIONFROMLINE
:
5129 if (static_cast<int>(wParam
) < 0)
5130 wParam
= pdoc
->LineFromPosition(SelectionStart());
5132 return 0; // Even if there is no text, there is a first line that starts at 0
5133 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
5135 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
5137 return pdoc
->LineStart(wParam
);
5139 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
5140 case SCI_LINELENGTH
:
5141 if ((static_cast<int>(wParam
) < 0) ||
5142 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
5144 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
5146 case SCI_REPLACESEL
: {
5149 pdoc
->BeginUndoAction();
5151 char *replacement
= CharPtrFromSPtr(lParam
);
5152 pdoc
->InsertString(currentPos
, replacement
);
5153 pdoc
->EndUndoAction();
5154 SetEmptySelection(currentPos
+ strlen(replacement
));
5155 EnsureCaretVisible();
5159 case SCI_SETTARGETSTART
:
5160 targetStart
= wParam
;
5163 case SCI_GETTARGETSTART
:
5166 case SCI_SETTARGETEND
:
5170 case SCI_GETTARGETEND
:
5173 case SCI_TARGETFROMSELECTION
:
5174 if (currentPos
< anchor
) {
5175 targetStart
= currentPos
;
5178 targetStart
= anchor
;
5179 targetEnd
= currentPos
;
5183 case SCI_REPLACETARGET
:
5184 PLATFORM_ASSERT(lParam
);
5185 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), wParam
);
5187 case SCI_REPLACETARGETRE
:
5188 PLATFORM_ASSERT(lParam
);
5189 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), wParam
);
5191 case SCI_SEARCHINTARGET
:
5192 PLATFORM_ASSERT(lParam
);
5193 return SearchInTarget(CharPtrFromSPtr(lParam
), wParam
);
5195 case SCI_SETSEARCHFLAGS
:
5196 searchFlags
= wParam
;
5199 case SCI_GETSEARCHFLAGS
:
5202 case SCI_LINESCROLL
:
5203 ScrollTo(topLine
+ lParam
);
5204 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
5207 case SCI_SETXOFFSET
:
5209 SetHorizontalScrollPos();
5213 case SCI_GETXOFFSET
:
5216 case SCI_CHOOSECARETX
:
5220 case SCI_SCROLLCARET
:
5221 EnsureCaretVisible();
5224 case SCI_SETREADONLY
:
5225 pdoc
->SetReadOnly(wParam
!= 0);
5228 case SCI_GETREADONLY
:
5229 return pdoc
->IsReadOnly();
5234 case SCI_POINTXFROMPOSITION
:
5238 Point pt
= LocationFromPosition(lParam
);
5242 case SCI_POINTYFROMPOSITION
:
5246 Point pt
= LocationFromPosition(lParam
);
5251 return FindText(wParam
, lParam
);
5253 case SCI_GETTEXTRANGE
: {
5256 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
5257 int cpMax
= tr
->chrg
.cpMax
;
5259 cpMax
= pdoc
->Length();
5260 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
5261 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
5262 // Spec says copied text is terminated with a NUL
5263 tr
->lpstrText
[len
] = '\0';
5264 return len
; // Not including NUL
5267 case SCI_HIDESELECTION
:
5268 hideSelection
= wParam
!= 0;
5272 case SCI_FORMATRANGE
:
5273 return FormatRange(wParam
!= 0, reinterpret_cast<RangeToFormat
*>(lParam
));
5275 case SCI_GETMARGINLEFT
:
5276 return vs
.leftMarginWidth
;
5278 case SCI_GETMARGINRIGHT
:
5279 return vs
.rightMarginWidth
;
5281 case SCI_SETMARGINLEFT
:
5282 vs
.leftMarginWidth
= lParam
;
5283 InvalidateStyleRedraw();
5286 case SCI_SETMARGINRIGHT
:
5287 vs
.rightMarginWidth
= lParam
;
5288 InvalidateStyleRedraw();
5291 // Control specific mesages
5296 pdoc
->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam
), wParam
);
5297 SetEmptySelection(currentPos
+ wParam
);
5301 case SCI_ADDSTYLEDTEXT
: {
5304 pdoc
->InsertStyledString(CurrentPosition() * 2, CharPtrFromSPtr(lParam
), wParam
);
5305 SetEmptySelection(currentPos
+ wParam
/ 2);
5309 case SCI_INSERTTEXT
: {
5312 int insertPos
= wParam
;
5313 if (static_cast<short>(wParam
) == -1)
5314 insertPos
= CurrentPosition();
5315 int newCurrent
= CurrentPosition();
5316 char *sz
= CharPtrFromSPtr(lParam
);
5317 pdoc
->InsertString(insertPos
, sz
);
5318 if (newCurrent
> insertPos
)
5319 newCurrent
+= strlen(sz
);
5320 SetEmptySelection(newCurrent
);
5324 case SCI_APPENDTEXT
:
5325 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), wParam
);
5332 case SCI_CLEARDOCUMENTSTYLE
:
5333 ClearDocumentStyle();
5336 case SCI_SETUNDOCOLLECTION
:
5337 pdoc
->SetUndoCollection(wParam
!= 0);
5340 case SCI_GETUNDOCOLLECTION
:
5341 return pdoc
->IsCollectingUndo();
5343 case SCI_BEGINUNDOACTION
:
5344 pdoc
->BeginUndoAction();
5347 case SCI_ENDUNDOACTION
:
5348 pdoc
->EndUndoAction();
5351 case SCI_GETCARETPERIOD
:
5352 return caret
.period
;
5354 case SCI_SETCARETPERIOD
:
5355 caret
.period
= wParam
;
5358 case SCI_SETWORDCHARS
: {
5361 pdoc
->SetWordChars(reinterpret_cast<unsigned char *>(lParam
));
5366 return pdoc
->Length();
5369 return pdoc
->CharAt(wParam
);
5371 case SCI_SETCURRENTPOS
:
5372 SetSelection(wParam
, anchor
);
5375 case SCI_GETCURRENTPOS
:
5379 SetSelection(currentPos
, wParam
);
5385 case SCI_SETSELECTIONSTART
:
5386 SetSelection(Platform::Maximum(currentPos
, wParam
), wParam
);
5389 case SCI_GETSELECTIONSTART
:
5390 return Platform::Minimum(anchor
, currentPos
);
5392 case SCI_SETSELECTIONEND
:
5393 SetSelection(wParam
, Platform::Minimum(anchor
, wParam
));
5396 case SCI_GETSELECTIONEND
:
5397 return Platform::Maximum(anchor
, currentPos
);
5399 case SCI_SETPRINTMAGNIFICATION
:
5400 printMagnification
= wParam
;
5403 case SCI_GETPRINTMAGNIFICATION
:
5404 return printMagnification
;
5406 case SCI_SETPRINTCOLOURMODE
:
5407 printColourMode
= wParam
;
5410 case SCI_GETPRINTCOLOURMODE
:
5411 return printColourMode
;
5413 case SCI_SETPRINTWRAPMODE
:
5414 printWrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
5417 case SCI_GETPRINTWRAPMODE
:
5418 return printWrapState
;
5420 case SCI_GETSTYLEAT
:
5421 if (static_cast<short>(wParam
) >= pdoc
->Length())
5424 return pdoc
->StyleAt(wParam
);
5434 case SCI_SETSAVEPOINT
:
5435 pdoc
->SetSavePoint();
5438 case SCI_GETSTYLEDTEXT
: {
5441 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
5443 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
5444 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
5445 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
5447 tr
->lpstrText
[iPlace
] = '\0';
5448 tr
->lpstrText
[iPlace
+ 1] = '\0';
5453 return pdoc
->CanRedo() ? 1 : 0;
5455 case SCI_MARKERLINEFROMHANDLE
:
5456 return pdoc
->LineFromHandle(wParam
);
5458 case SCI_MARKERDELETEHANDLE
:
5459 pdoc
->DeleteMarkFromHandle(wParam
);
5463 return vs
.viewWhitespace
;
5466 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
5470 case SCI_POSITIONFROMPOINT
:
5471 return PositionFromLocation(Point(wParam
, lParam
));
5473 case SCI_POSITIONFROMPOINTCLOSE
:
5474 return PositionFromLocationClose(Point(wParam
, lParam
));
5481 SetEmptySelection(wParam
);
5482 EnsureCaretVisible();
5486 case SCI_GETCURLINE
: {
5490 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
5491 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
5492 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
5493 char *ptr
= CharPtrFromSPtr(lParam
);
5494 unsigned int iPlace
= 0;
5495 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
5496 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5499 return currentPos
- lineStart
;
5502 case SCI_GETENDSTYLED
:
5503 return pdoc
->GetEndStyled();
5505 case SCI_GETEOLMODE
:
5506 return pdoc
->eolMode
;
5508 case SCI_SETEOLMODE
:
5509 pdoc
->eolMode
= wParam
;
5512 case SCI_STARTSTYLING
:
5513 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
5516 case SCI_SETSTYLING
:
5517 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
5520 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
5523 pdoc
->SetStyles(wParam
, CharPtrFromSPtr(lParam
));
5526 case SCI_SETBUFFEREDDRAW
:
5527 bufferedDraw
= wParam
!= 0;
5530 case SCI_GETBUFFEREDDRAW
:
5531 return bufferedDraw
;
5533 case SCI_GETTWOPHASEDRAW
:
5534 return twoPhaseDraw
;
5536 case SCI_SETTWOPHASEDRAW
:
5537 twoPhaseDraw
= wParam
!= 0;
5538 InvalidateStyleRedraw();
5541 case SCI_SETTABWIDTH
:
5543 pdoc
->tabInChars
= wParam
;
5544 InvalidateStyleRedraw();
5547 case SCI_GETTABWIDTH
:
5548 return pdoc
->tabInChars
;
5551 pdoc
->indentInChars
= wParam
;
5552 InvalidateStyleRedraw();
5556 return pdoc
->indentInChars
;
5558 case SCI_SETUSETABS
:
5559 pdoc
->useTabs
= wParam
!= 0;
5560 InvalidateStyleRedraw();
5563 case SCI_GETUSETABS
:
5564 return pdoc
->useTabs
;
5566 case SCI_SETLINEINDENTATION
:
5567 pdoc
->SetLineIndentation(wParam
, lParam
);
5570 case SCI_GETLINEINDENTATION
:
5571 return pdoc
->GetLineIndentation(wParam
);
5573 case SCI_GETLINEINDENTPOSITION
:
5574 return pdoc
->GetLineIndentPosition(wParam
);
5576 case SCI_SETTABINDENTS
:
5577 pdoc
->tabIndents
= wParam
!= 0;
5580 case SCI_GETTABINDENTS
:
5581 return pdoc
->tabIndents
;
5583 case SCI_SETBACKSPACEUNINDENTS
:
5584 pdoc
->backspaceUnindents
= wParam
!= 0;
5587 case SCI_GETBACKSPACEUNINDENTS
:
5588 return pdoc
->backspaceUnindents
;
5590 case SCI_SETMOUSEDWELLTIME
:
5591 dwellDelay
= wParam
;
5592 ticksToDwell
= dwellDelay
;
5595 case SCI_GETMOUSEDWELLTIME
:
5598 case SCI_WORDSTARTPOSITION
:
5599 return pdoc
->ExtendWordSelect(wParam
, -1, lParam
!= 0);
5601 case SCI_WORDENDPOSITION
:
5602 return pdoc
->ExtendWordSelect(wParam
, 1, lParam
!= 0);
5604 case SCI_SETWRAPMODE
:
5605 wrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
5607 InvalidateStyleRedraw();
5608 ReconfigureScrollBars();
5611 case SCI_GETWRAPMODE
:
5614 case SCI_SETLAYOUTCACHE
:
5615 llc
.SetLevel(wParam
);
5618 case SCI_GETLAYOUTCACHE
:
5619 return llc
.GetLevel();
5621 case SCI_SETSCROLLWIDTH
:
5622 PLATFORM_ASSERT(wParam
> 0);
5623 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
5624 scrollWidth
= wParam
;
5629 case SCI_GETSCROLLWIDTH
:
5636 case SCI_LINESSPLIT
:
5641 PLATFORM_ASSERT(wParam
<= STYLE_MAX
);
5642 PLATFORM_ASSERT(lParam
);
5643 return TextWidth(wParam
, CharPtrFromSPtr(lParam
));
5645 case SCI_TEXTHEIGHT
:
5646 return vs
.lineHeight
;
5648 case SCI_SETENDATLASTLINE
:
5649 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
5650 if (endAtLastLine
!= (wParam
!= 0)) {
5651 endAtLastLine
= wParam
!= 0;
5656 case SCI_GETENDATLASTLINE
:
5657 return endAtLastLine
;
5660 return pdoc
->GetColumn(wParam
);
5662 case SCI_SETHSCROLLBAR
:
5663 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
5664 horizontalScrollBarVisible
= wParam
!= 0;
5666 ReconfigureScrollBars();
5670 case SCI_GETHSCROLLBAR
:
5671 return horizontalScrollBarVisible
;
5673 case SCI_SETVSCROLLBAR
:
5674 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
5675 verticalScrollBarVisible
= wParam
!= 0;
5677 ReconfigureScrollBars();
5681 case SCI_GETVSCROLLBAR
:
5682 return verticalScrollBarVisible
;
5684 case SCI_SETINDENTATIONGUIDES
:
5685 vs
.viewIndentationGuides
= wParam
!= 0;
5689 case SCI_GETINDENTATIONGUIDES
:
5690 return vs
.viewIndentationGuides
;
5692 case SCI_SETHIGHLIGHTGUIDE
:
5693 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
5694 highlightGuideColumn
= wParam
;
5699 case SCI_GETHIGHLIGHTGUIDE
:
5700 return highlightGuideColumn
;
5702 case SCI_GETLINEENDPOSITION
:
5703 return pdoc
->LineEnd(wParam
);
5705 case SCI_SETCODEPAGE
:
5706 pdoc
->dbcsCodePage
= wParam
;
5707 InvalidateStyleRedraw();
5710 case SCI_GETCODEPAGE
:
5711 return pdoc
->dbcsCodePage
;
5713 case SCI_SETUSEPALETTE
:
5714 palette
.allowRealization
= wParam
!= 0;
5715 InvalidateStyleRedraw();
5718 case SCI_GETUSEPALETTE
:
5719 return palette
.allowRealization
;
5721 // Marker definition and setting
5722 case SCI_MARKERDEFINE
:
5723 if (wParam
<= MARKER_MAX
)
5724 vs
.markers
[wParam
].markType
= lParam
;
5725 InvalidateStyleData();
5728 case SCI_MARKERSETFORE
:
5729 if (wParam
<= MARKER_MAX
)
5730 vs
.markers
[wParam
].fore
.desired
= ColourDesired(lParam
);
5731 InvalidateStyleData();
5734 case SCI_MARKERSETBACK
:
5735 if (wParam
<= MARKER_MAX
)
5736 vs
.markers
[wParam
].back
.desired
= ColourDesired(lParam
);
5737 InvalidateStyleData();
5740 case SCI_MARKERADD
: {
5741 int markerID
= pdoc
->AddMark(wParam
, lParam
);
5745 case SCI_MARKERDELETE
:
5746 pdoc
->DeleteMark(wParam
, lParam
);
5749 case SCI_MARKERDELETEALL
:
5750 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
5754 return pdoc
->GetMark(wParam
);
5756 case SCI_MARKERNEXT
: {
5757 int lt
= pdoc
->LinesTotal();
5758 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
5759 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
5765 case SCI_MARKERPREVIOUS
: {
5766 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
5767 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
5773 case SCI_MARKERDEFINEPIXMAP
:
5774 if (wParam
<= MARKER_MAX
) {
5775 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
5777 InvalidateStyleData();
5781 case SCI_SETMARGINTYPEN
:
5782 if (ValidMargin(wParam
)) {
5783 vs
.ms
[wParam
].symbol
= (lParam
== SC_MARGIN_SYMBOL
);
5784 InvalidateStyleRedraw();
5788 case SCI_GETMARGINTYPEN
:
5789 if (ValidMargin(wParam
))
5790 return vs
.ms
[wParam
].symbol
? SC_MARGIN_SYMBOL
: SC_MARGIN_NUMBER
;
5794 case SCI_SETMARGINWIDTHN
:
5795 if (ValidMargin(wParam
)) {
5796 vs
.ms
[wParam
].width
= lParam
;
5797 InvalidateStyleRedraw();
5801 case SCI_GETMARGINWIDTHN
:
5802 if (ValidMargin(wParam
))
5803 return vs
.ms
[wParam
].width
;
5807 case SCI_SETMARGINMASKN
:
5808 if (ValidMargin(wParam
)) {
5809 vs
.ms
[wParam
].mask
= lParam
;
5810 InvalidateStyleRedraw();
5814 case SCI_GETMARGINMASKN
:
5815 if (ValidMargin(wParam
))
5816 return vs
.ms
[wParam
].mask
;
5820 case SCI_SETMARGINSENSITIVEN
:
5821 if (ValidMargin(wParam
)) {
5822 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
5823 InvalidateStyleRedraw();
5827 case SCI_GETMARGINSENSITIVEN
:
5828 if (ValidMargin(wParam
))
5829 return vs
.ms
[wParam
].sensitive
? 1 : 0;
5833 case SCI_STYLECLEARALL
:
5835 InvalidateStyleRedraw();
5838 case SCI_STYLESETFORE
:
5839 if (wParam
<= STYLE_MAX
) {
5840 vs
.styles
[wParam
].fore
.desired
= ColourDesired(lParam
);
5841 InvalidateStyleRedraw();
5844 case SCI_STYLESETBACK
:
5845 if (wParam
<= STYLE_MAX
) {
5846 vs
.styles
[wParam
].back
.desired
= ColourDesired(lParam
);
5847 InvalidateStyleRedraw();
5850 case SCI_STYLESETBOLD
:
5851 if (wParam
<= STYLE_MAX
) {
5852 vs
.styles
[wParam
].bold
= lParam
!= 0;
5853 InvalidateStyleRedraw();
5856 case SCI_STYLESETITALIC
:
5857 if (wParam
<= STYLE_MAX
) {
5858 vs
.styles
[wParam
].italic
= lParam
!= 0;
5859 InvalidateStyleRedraw();
5862 case SCI_STYLESETEOLFILLED
:
5863 if (wParam
<= STYLE_MAX
) {
5864 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
5865 InvalidateStyleRedraw();
5868 case SCI_STYLESETSIZE
:
5869 if (wParam
<= STYLE_MAX
) {
5870 vs
.styles
[wParam
].size
= lParam
;
5871 InvalidateStyleRedraw();
5874 case SCI_STYLESETFONT
:
5877 if (wParam
<= STYLE_MAX
) {
5878 vs
.SetStyleFontName(wParam
, CharPtrFromSPtr(lParam
));
5879 InvalidateStyleRedraw();
5882 case SCI_STYLESETUNDERLINE
:
5883 if (wParam
<= STYLE_MAX
) {
5884 vs
.styles
[wParam
].underline
= lParam
!= 0;
5885 InvalidateStyleRedraw();
5888 case SCI_STYLESETCASE
:
5889 if (wParam
<= STYLE_MAX
) {
5890 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
5891 InvalidateStyleRedraw();
5894 case SCI_STYLESETCHARACTERSET
:
5895 if (wParam
<= STYLE_MAX
) {
5896 vs
.styles
[wParam
].characterSet
= lParam
;
5897 InvalidateStyleRedraw();
5900 case SCI_STYLESETVISIBLE
:
5901 if (wParam
<= STYLE_MAX
) {
5902 vs
.styles
[wParam
].visible
= lParam
!= 0;
5903 InvalidateStyleRedraw();
5906 case SCI_STYLESETCHANGEABLE
:
5907 if (wParam
<= STYLE_MAX
) {
5908 vs
.styles
[wParam
].changeable
= lParam
!= 0;
5909 InvalidateStyleRedraw();
5912 case SCI_STYLESETHOTSPOT
:
5913 if (wParam
<= STYLE_MAX
) {
5914 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
5915 InvalidateStyleRedraw();
5919 case SCI_STYLERESETDEFAULT
:
5920 vs
.ResetDefaultStyle();
5921 InvalidateStyleRedraw();
5923 case SCI_SETSTYLEBITS
:
5924 pdoc
->SetStylingBits(wParam
);
5927 case SCI_GETSTYLEBITS
:
5928 return pdoc
->stylingBits
;
5930 case SCI_SETLINESTATE
:
5931 return pdoc
->SetLineState(wParam
, lParam
);
5933 case SCI_GETLINESTATE
:
5934 return pdoc
->GetLineState(wParam
);
5936 case SCI_GETMAXLINESTATE
:
5937 return pdoc
->GetMaxLineState();
5939 case SCI_GETCARETLINEVISIBLE
:
5940 return vs
.showCaretLineBackground
;
5941 case SCI_SETCARETLINEVISIBLE
:
5942 vs
.showCaretLineBackground
= wParam
!= 0;
5943 InvalidateStyleRedraw();
5945 case SCI_GETCARETLINEBACK
:
5946 return vs
.caretLineBackground
.desired
.AsLong();
5947 case SCI_SETCARETLINEBACK
:
5948 vs
.caretLineBackground
.desired
= wParam
;
5949 InvalidateStyleRedraw();
5954 case SCI_VISIBLEFROMDOCLINE
:
5955 return cs
.DisplayFromDoc(wParam
);
5957 case SCI_DOCLINEFROMVISIBLE
:
5958 return cs
.DocFromDisplay(wParam
);
5960 case SCI_SETFOLDLEVEL
: {
5961 int prev
= pdoc
->SetLevel(wParam
, lParam
);
5967 case SCI_GETFOLDLEVEL
:
5968 return pdoc
->GetLevel(wParam
);
5970 case SCI_GETLASTCHILD
:
5971 return pdoc
->GetLastChild(wParam
, lParam
);
5973 case SCI_GETFOLDPARENT
:
5974 return pdoc
->GetFoldParent(wParam
);
5977 cs
.SetVisible(wParam
, lParam
, true);
5983 cs
.SetVisible(wParam
, lParam
, false);
5988 case SCI_GETLINEVISIBLE
:
5989 return cs
.GetVisible(wParam
);
5991 case SCI_SETFOLDEXPANDED
:
5992 if (cs
.SetExpanded(wParam
, lParam
!= 0)) {
5997 case SCI_GETFOLDEXPANDED
:
5998 return cs
.GetExpanded(wParam
);
6000 case SCI_SETFOLDFLAGS
:
6005 case SCI_TOGGLEFOLD
:
6006 ToggleContraction(wParam
);
6009 case SCI_ENSUREVISIBLE
:
6010 EnsureLineVisible(wParam
, false);
6013 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
6014 EnsureLineVisible(wParam
, true);
6017 case SCI_SEARCHANCHOR
:
6021 case SCI_SEARCHNEXT
:
6022 case SCI_SEARCHPREV
:
6023 return SearchText(iMessage
, wParam
, lParam
);
6025 #ifdef INCLUDE_DEPRECATED_FEATURES
6026 case SCI_SETCARETPOLICY
: // Deprecated
6027 caretXPolicy
= caretYPolicy
= wParam
;
6028 caretXSlop
= caretYSlop
= lParam
;
6032 case SCI_SETXCARETPOLICY
:
6033 caretXPolicy
= wParam
;
6034 caretXSlop
= lParam
;
6037 case SCI_SETYCARETPOLICY
:
6038 caretYPolicy
= wParam
;
6039 caretYSlop
= lParam
;
6042 case SCI_SETVISIBLEPOLICY
:
6043 visiblePolicy
= wParam
;
6044 visibleSlop
= lParam
;
6047 case SCI_LINESONSCREEN
:
6048 return LinesOnScreen();
6050 case SCI_SETSELFORE
:
6051 vs
.selforeset
= wParam
!= 0;
6052 vs
.selforeground
.desired
= ColourDesired(lParam
);
6053 InvalidateStyleRedraw();
6056 case SCI_SETSELBACK
:
6057 vs
.selbackset
= wParam
!= 0;
6058 vs
.selbackground
.desired
= ColourDesired(lParam
);
6059 InvalidateStyleRedraw();
6062 case SCI_SETWHITESPACEFORE
:
6063 vs
.whitespaceForegroundSet
= wParam
!= 0;
6064 vs
.whitespaceForeground
.desired
= ColourDesired(lParam
);
6065 InvalidateStyleRedraw();
6068 case SCI_SETWHITESPACEBACK
:
6069 vs
.whitespaceBackgroundSet
= wParam
!= 0;
6070 vs
.whitespaceBackground
.desired
= ColourDesired(lParam
);
6071 InvalidateStyleRedraw();
6074 case SCI_SETCARETFORE
:
6075 vs
.caretcolour
.desired
= ColourDesired(wParam
);
6076 InvalidateStyleRedraw();
6079 case SCI_GETCARETFORE
:
6080 return vs
.caretcolour
.desired
.AsLong();
6082 case SCI_SETCARETWIDTH
:
6085 else if (wParam
>= 3)
6088 vs
.caretWidth
= wParam
;
6089 InvalidateStyleRedraw();
6092 case SCI_GETCARETWIDTH
:
6093 return vs
.caretWidth
;
6095 case SCI_ASSIGNCMDKEY
:
6096 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6097 Platform::HighShortFromLong(wParam
), lParam
);
6100 case SCI_CLEARCMDKEY
:
6101 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6102 Platform::HighShortFromLong(wParam
), SCI_NULL
);
6105 case SCI_CLEARALLCMDKEYS
:
6109 case SCI_INDICSETSTYLE
:
6110 if (wParam
<= INDIC_MAX
) {
6111 vs
.indicators
[wParam
].style
= lParam
;
6112 InvalidateStyleRedraw();
6116 case SCI_INDICGETSTYLE
:
6117 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
6119 case SCI_INDICSETFORE
:
6120 if (wParam
<= INDIC_MAX
) {
6121 vs
.indicators
[wParam
].fore
.desired
= ColourDesired(lParam
);
6122 InvalidateStyleRedraw();
6126 case SCI_INDICGETFORE
:
6127 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
6130 case SCI_LINEDOWNEXTEND
:
6132 case SCI_PARADOWNEXTEND
:
6134 case SCI_LINEUPEXTEND
:
6136 case SCI_PARAUPEXTEND
:
6138 case SCI_CHARLEFTEXTEND
:
6140 case SCI_CHARRIGHTEXTEND
:
6142 case SCI_WORDLEFTEXTEND
:
6144 case SCI_WORDRIGHTEXTEND
:
6146 case SCI_HOMEEXTEND
:
6148 case SCI_LINEENDEXTEND
:
6150 case SCI_HOMEWRAPEXTEND
:
6151 case SCI_LINEENDWRAP
:
6152 case SCI_LINEENDWRAPEXTEND
:
6153 case SCI_DOCUMENTSTART
:
6154 case SCI_DOCUMENTSTARTEXTEND
:
6155 case SCI_DOCUMENTEND
:
6156 case SCI_DOCUMENTENDEXTEND
:
6158 case SCI_PAGEUPEXTEND
:
6160 case SCI_PAGEDOWNEXTEND
:
6161 case SCI_EDITTOGGLEOVERTYPE
:
6163 case SCI_DELETEBACK
:
6169 case SCI_VCHOMEEXTEND
:
6170 case SCI_VCHOMEWRAP
:
6171 case SCI_VCHOMEWRAPEXTEND
:
6174 case SCI_DELWORDLEFT
:
6175 case SCI_DELWORDRIGHT
:
6176 case SCI_DELLINELEFT
:
6177 case SCI_DELLINERIGHT
:
6179 case SCI_LINEDELETE
:
6180 case SCI_LINETRANSPOSE
:
6181 case SCI_LINEDUPLICATE
:
6184 case SCI_LINESCROLLDOWN
:
6185 case SCI_LINESCROLLUP
:
6186 case SCI_WORDPARTLEFT
:
6187 case SCI_WORDPARTLEFTEXTEND
:
6188 case SCI_WORDPARTRIGHT
:
6189 case SCI_WORDPARTRIGHTEXTEND
:
6190 case SCI_DELETEBACKNOTLINE
:
6191 case SCI_HOMEDISPLAY
:
6192 case SCI_HOMEDISPLAYEXTEND
:
6193 case SCI_LINEENDDISPLAY
:
6194 case SCI_LINEENDDISPLAYEXTEND
:
6195 return KeyCommand(iMessage
);
6197 case SCI_BRACEHIGHLIGHT
:
6198 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
6201 case SCI_BRACEBADLIGHT
:
6202 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
6205 case SCI_BRACEMATCH
:
6206 // wParam is position of char to find brace for,
6207 // lParam is maximum amount of text to restyle to find it
6208 return BraceMatch(wParam
, lParam
);
6210 case SCI_GETVIEWEOL
:
6213 case SCI_SETVIEWEOL
:
6214 vs
.viewEOL
= wParam
!= 0;
6215 InvalidateStyleRedraw();
6219 vs
.zoomLevel
= wParam
;
6220 InvalidateStyleRedraw();
6225 return vs
.zoomLevel
;
6227 case SCI_GETEDGECOLUMN
:
6230 case SCI_SETEDGECOLUMN
:
6232 InvalidateStyleRedraw();
6235 case SCI_GETEDGEMODE
:
6236 return vs
.edgeState
;
6238 case SCI_SETEDGEMODE
:
6239 vs
.edgeState
= wParam
;
6240 InvalidateStyleRedraw();
6243 case SCI_GETEDGECOLOUR
:
6244 return vs
.edgecolour
.desired
.AsLong();
6246 case SCI_SETEDGECOLOUR
:
6247 vs
.edgecolour
.desired
= ColourDesired(wParam
);
6248 InvalidateStyleRedraw();
6251 case SCI_GETDOCPOINTER
:
6252 return reinterpret_cast<sptr_t
>(pdoc
);
6254 case SCI_SETDOCPOINTER
:
6256 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
6259 case SCI_CREATEDOCUMENT
: {
6260 Document
*doc
= new Document();
6264 return reinterpret_cast<sptr_t
>(doc
);
6267 case SCI_ADDREFDOCUMENT
:
6268 (reinterpret_cast<Document
*>(lParam
))->AddRef();
6271 case SCI_RELEASEDOCUMENT
:
6272 (reinterpret_cast<Document
*>(lParam
))->Release();
6275 case SCI_SETMODEVENTMASK
:
6276 modEventMask
= wParam
;
6279 case SCI_GETMODEVENTMASK
:
6280 return modEventMask
;
6282 case SCI_CONVERTEOLS
:
6283 pdoc
->ConvertLineEnds(wParam
);
6284 SetSelection(currentPos
, anchor
); // Ensure selection inside document
6287 case SCI_SELECTIONISRECTANGLE
:
6288 return (selType
== selRectangle
) ? 1 : 0;
6290 case SCI_SETOVERTYPE
:
6291 inOverstrike
= wParam
!= 0;
6294 case SCI_GETOVERTYPE
:
6295 return inOverstrike
? 1 : 0;
6298 SetFocusState(wParam
!= 0);
6305 errorStatus
= wParam
;
6311 case SCI_SETMOUSEDOWNCAPTURES
:
6312 mouseDownCaptures
= wParam
!= 0;
6315 case SCI_GETMOUSEDOWNCAPTURES
:
6316 return mouseDownCaptures
;
6319 cursorMode
= wParam
;
6320 DisplayCursor(Window::cursorText
);
6326 case SCI_SETCONTROLCHARSYMBOL
:
6327 controlCharSymbol
= wParam
;
6330 case SCI_GETCONTROLCHARSYMBOL
:
6331 return controlCharSymbol
;
6333 case SCI_STARTRECORD
:
6334 recordingMacro
= true;
6337 case SCI_STOPRECORD
:
6338 recordingMacro
= false;
6341 case SCI_MOVECARETINSIDEVIEW
:
6342 MoveCaretInsideView();
6345 case SCI_SETFOLDMARGINCOLOUR
:
6346 vs
.foldmarginColourSet
= wParam
!= 0;
6347 vs
.foldmarginColour
.desired
= ColourDesired(lParam
);
6348 InvalidateStyleRedraw();
6351 case SCI_SETFOLDMARGINHICOLOUR
:
6352 vs
.foldmarginHighlightColourSet
= wParam
!= 0;
6353 vs
.foldmarginHighlightColour
.desired
= ColourDesired(lParam
);
6354 InvalidateStyleRedraw();
6357 case SCI_SETHOTSPOTACTIVEFORE
:
6358 vs
.hotspotForegroundSet
= wParam
!= 0;
6359 vs
.hotspotForeground
.desired
= ColourDesired(lParam
);
6360 InvalidateStyleRedraw();
6363 case SCI_SETHOTSPOTACTIVEBACK
:
6364 vs
.hotspotBackgroundSet
= wParam
!= 0;
6365 vs
.hotspotBackground
.desired
= ColourDesired(lParam
);
6366 InvalidateStyleRedraw();
6369 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
6370 vs
.hotspotUnderline
= wParam
!= 0;
6371 InvalidateStyleRedraw();
6375 return DefWndProc(iMessage
, wParam
, lParam
);
6377 //Platform::DebugPrintf("end wnd proc\n");