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) {}
39 state(false), idlerID(0) {}
41 LineLayout::LineLayout(int maxLineLength_
) :
61 widthLine(wrapWidthInfinite
),
63 Resize(maxLineLength_
);
66 LineLayout::~LineLayout() {
70 void LineLayout::Resize(int maxLineLength_
) {
71 if (maxLineLength_
> maxLineLength
) {
73 chars
= new char[maxLineLength_
+ 1];
74 styles
= new char[maxLineLength_
+ 1];
75 indicators
= new char[maxLineLength_
+ 1];
76 // Extra position allocated as sometimes the Windows
77 // GetTextExtentExPoint API writes an extra element.
78 positions
= new int[maxLineLength_
+ 1 + 1];
79 maxLineLength
= maxLineLength_
;
83 void LineLayout::Free() {
96 void LineLayout::Invalidate(validLevel validity_
) {
97 if (validity
> validity_
)
101 void LineLayout::SetLineStart(int line
, int start
) {
102 if ((line
>= lenLineStarts
) && (line
!= 0)) {
103 int newMaxLines
= line
+ 20;
104 int *newLineStarts
= new int[newMaxLines
];
107 for (int i
= 0; i
< newMaxLines
; i
++) {
108 if (i
< lenLineStarts
)
109 newLineStarts
[i
] = lineStarts
[i
];
111 newLineStarts
[i
] = 0;
114 lineStarts
= newLineStarts
;
115 lenLineStarts
= newMaxLines
;
117 lineStarts
[line
] = start
;
120 void LineLayout::SetBracesHighlight(Range rangeLine
, Position braces
[],
121 char bracesMatchStyle
, int xHighlight
) {
122 if (rangeLine
.ContainsCharacter(braces
[0])) {
123 int braceOffset
= braces
[0] - rangeLine
.start
;
124 if (braceOffset
< numCharsInLine
) {
125 bracePreviousStyles
[0] = styles
[braceOffset
];
126 styles
[braceOffset
] = bracesMatchStyle
;
129 if (rangeLine
.ContainsCharacter(braces
[1])) {
130 int braceOffset
= braces
[1] - rangeLine
.start
;
131 if (braceOffset
< numCharsInLine
) {
132 bracePreviousStyles
[1] = styles
[braceOffset
];
133 styles
[braceOffset
] = bracesMatchStyle
;
136 if ((braces
[0] >= rangeLine
.start
&& braces
[1] <= rangeLine
.end
) ||
137 (braces
[1] >= rangeLine
.start
&& braces
[0] <= rangeLine
.end
)) {
138 xHighlightGuide
= xHighlight
;
142 void LineLayout::RestoreBracesHighlight(Range rangeLine
, Position braces
[]) {
143 if (rangeLine
.ContainsCharacter(braces
[0])) {
144 int braceOffset
= braces
[0] - rangeLine
.start
;
145 if (braceOffset
< numCharsInLine
) {
146 styles
[braceOffset
] = bracePreviousStyles
[0];
149 if (rangeLine
.ContainsCharacter(braces
[1])) {
150 int braceOffset
= braces
[1] - rangeLine
.start
;
151 if (braceOffset
< numCharsInLine
) {
152 styles
[braceOffset
] = bracePreviousStyles
[1];
158 LineLayoutCache::LineLayoutCache() :
159 level(0), length(0), size(0), cache(0),
160 allInvalidated(false), styleClock(-1) {
164 LineLayoutCache::~LineLayoutCache() {
168 void LineLayoutCache::Allocate(int length_
) {
169 allInvalidated
= false;
173 size
= (size
/ 16 + 1) * 16;
176 cache
= new LineLayout
* [size
];
178 for (int i
= 0; i
< size
; i
++)
182 void LineLayoutCache::AllocateForLevel(int linesOnScreen
, int linesInDoc
) {
183 int lengthForLevel
= 0;
184 if (level
== llcCaret
) {
186 } else if (level
== llcPage
) {
187 lengthForLevel
= linesOnScreen
+ 1;
188 } else if (level
== llcDocument
) {
189 lengthForLevel
= linesInDoc
;
191 if (lengthForLevel
> size
) {
193 } else if (lengthForLevel
< length
) {
194 for (int i
= lengthForLevel
; i
< length
; i
++) {
200 Allocate(lengthForLevel
);
204 void LineLayoutCache::Deallocate() {
205 for (int i
= 0; i
< length
; i
++)
212 void LineLayoutCache::Invalidate(LineLayout::validLevel validity_
) {
213 if (cache
&& !allInvalidated
) {
214 for (int i
= 0; i
< length
; i
++) {
216 cache
[i
]->Invalidate(validity_
);
219 if (validity_
== LineLayout::llInvalid
) {
220 allInvalidated
= true;
225 void LineLayoutCache::SetLevel(int level_
) {
226 allInvalidated
= false;
227 if ((level_
!= -1) && (level
!= level_
)) {
233 LineLayout
*LineLayoutCache::Retrieve(int lineNumber
, int lineCaret
, int maxChars
, int styleClock_
,
234 int linesOnScreen
, int linesInDoc
) {
235 AllocateForLevel(linesOnScreen
, linesInDoc
);
236 if (styleClock
!= styleClock_
) {
237 Invalidate(LineLayout::llCheckTextAndStyle
);
238 styleClock
= styleClock_
;
240 allInvalidated
= false;
243 if (((level
== llcCaret
) || (level
== llcPage
)) && (lineNumber
== lineCaret
)) {
245 } else if (level
== llcPage
) {
246 pos
= lineNumber
% length
;
247 } else if (level
== llcDocument
) {
251 if (cache
&& (pos
< length
)) {
253 if ((cache
[pos
]->lineNumber
!= lineNumber
) ||
254 (cache
[pos
]->maxLineLength
< maxChars
)) {
260 cache
[pos
] = new LineLayout(maxChars
);
263 cache
[pos
]->lineNumber
= lineNumber
;
264 cache
[pos
]->inCache
= true;
271 ret
= new LineLayout(maxChars
);
272 ret
->lineNumber
= lineNumber
;
278 void LineLayoutCache::Dispose(LineLayout
*ll
) {
279 allInvalidated
= false;
292 printMagnification
= 0;
293 printColourMode
= SC_PRINT_NORMAL
;
294 printWrapState
= eWrapWord
;
295 cursorMode
= SC_CURSORNORMAL
;
296 controlCharSymbol
= 0; /* Draw the control characters */
299 hideSelection
= false;
300 inOverstrike
= false;
302 mouseDownCaptures
= true;
308 dwellDelay
= SC_TIME_FOREVER
;
309 ticksToDwell
= SC_TIME_FOREVER
;
314 dropWentOutside
= false;
315 posDrag
= invalidPosition
;
316 posDrop
= invalidPosition
;
317 selectionType
= selChar
;
321 originalAnchorPos
= 0;
324 moveExtendsSelection
= false;
327 primarySelection
= true;
329 caretXPolicy
= CARET_SLOP
| CARET_EVEN
;
332 caretYPolicy
= CARET_EVEN
;
339 horizontalScrollBarVisible
= true;
341 verticalScrollBarVisible
= true;
342 endAtLastLine
= true;
344 pixmapLine
= Surface::Allocate();
345 pixmapSelMargin
= Surface::Allocate();
346 pixmapSelPattern
= Surface::Allocate();
347 pixmapIndentGuide
= Surface::Allocate();
348 pixmapIndentGuideHighlight
= Surface::Allocate();
361 braces
[0] = invalidPosition
;
362 braces
[1] = invalidPosition
;
363 bracesMatchStyle
= STYLE_BRACEBAD
;
364 highlightGuideColumn
= 0;
368 paintState
= notPainting
;
370 modEventMask
= SC_MODEVENTMASKALL
;
372 pdoc
= new Document();
374 pdoc
->AddWatcher(this, 0);
376 recordingMacro
= false;
379 wrapState
= eWrapNone
;
380 wrapWidth
= LineLayout::wrapWidthInfinite
;
381 docLineLastWrapped
= -1;
382 docLastLineToWrap
= -1;
383 backgroundWrapEnabled
= true;
388 llc
.SetLevel(LineLayoutCache::llcCaret
);
392 pdoc
->RemoveWatcher(this, 0);
397 delete pixmapSelMargin
;
398 delete pixmapSelPattern
;
399 delete pixmapIndentGuide
;
400 delete pixmapIndentGuideHighlight
;
403 void Editor::Finalise() {
408 void Editor::DropGraphics() {
409 pixmapLine
->Release();
410 pixmapSelMargin
->Release();
411 pixmapSelPattern
->Release();
412 pixmapIndentGuide
->Release();
415 void Editor::InvalidateStyleData() {
419 llc
.Invalidate(LineLayout::llInvalid
);
420 if (selType
== selRectangle
) {
421 xStartSelect
= XFromPosition(anchor
);
422 xEndSelect
= XFromPosition(currentPos
);
426 void Editor::InvalidateStyleRedraw() {
428 InvalidateStyleData();
432 void Editor::RefreshColourPalette(Palette
&pal
, bool want
) {
433 vs
.RefreshColourPalette(pal
, want
);
436 void Editor::RefreshStyleData() {
439 AutoSurface
surface(this);
441 vs
.Refresh(*surface
);
442 RefreshColourPalette(palette
, true);
443 palette
.Allocate(wMain
);
444 RefreshColourPalette(palette
, false);
450 PRectangle
Editor::GetClientRectangle() {
451 return wMain
.GetClientPosition();
454 PRectangle
Editor::GetTextRectangle() {
455 PRectangle rc
= GetClientRectangle();
456 rc
.left
+= vs
.fixedColumnWidth
;
457 rc
.right
-= vs
.rightMarginWidth
;
461 int Editor::LinesOnScreen() {
462 PRectangle rcClient
= GetClientRectangle();
463 int htClient
= rcClient
.bottom
- rcClient
.top
;
464 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
465 return htClient
/ vs
.lineHeight
;
468 int Editor::LinesToScroll() {
469 int retVal
= LinesOnScreen() - 1;
476 int Editor::MaxScrollPos() {
477 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
478 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
479 int retVal
= cs
.LinesDisplayed();
481 retVal
-= LinesOnScreen();
492 static inline bool IsControlCharacter(char ch
) {
493 // iscntrl returns true for lots of chars > 127 which are displayable
494 return ch
>= 0 && ch
< ' ';
497 const char *ControlCharacterString(unsigned char ch
) {
498 const char *reps
[] = {
499 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
500 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
501 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
502 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
504 if (ch
< (sizeof(reps
) / sizeof(reps
[0]))) {
512 * Convenience class to ensure LineLayout objects are always disposed.
514 class AutoLineLayout
{
515 LineLayoutCache
&llc
;
517 AutoLineLayout
&operator=(const AutoLineLayout
&) { return * this; }
519 AutoLineLayout(LineLayoutCache
&llc_
, LineLayout
*ll_
) : llc(llc_
), ll(ll_
) {}
524 LineLayout
*operator->() const {
527 operator LineLayout
*() const {
530 void Set(LineLayout
*ll_
) {
537 * Allows to iterate through the lines of a selection.
538 * Althought it can be called for a stream selection, in most cases
539 * it is inefficient and it should be used only for
540 * a rectangular or a line selection.
542 class SelectionLineIterator
{
545 int line
; ///< Current line within the iteration.
546 bool forward
; ///< True if iterating by increasing line number, false otherwise.
547 int selStart
, selEnd
; ///< Positions of the start and end of the selection relative to the start of the document.
548 int minX
, maxX
; ///< Left and right of selection rectangle.
551 int lineStart
, lineEnd
; ///< Line numbers, first and last lines of the selection.
552 int startPos
, endPos
; ///< Positions of the beginning and end of the selection on the current line.
562 SelectionLineIterator(Editor
*ed_
, bool forward_
= true) : line(0), startPos(0), endPos(0) {
565 selStart
= ed
->SelectionStart();
566 selEnd
= ed
->SelectionEnd();
567 lineStart
= ed
->pdoc
->LineFromPosition(selStart
);
568 lineEnd
= ed
->pdoc
->LineFromPosition(selEnd
);
570 minX
= Platform::Minimum(ed
->xStartSelect
, ed
->xEndSelect
);
571 // Right of rectangle
572 maxX
= Platform::Maximum(ed
->xStartSelect
, ed
->xEndSelect
);
575 ~SelectionLineIterator() {}
577 void SetAt(int line
) {
578 if (line
< lineStart
|| line
> lineEnd
) {
579 startPos
= endPos
= INVALID_POSITION
;
581 if (ed
->selType
== ed
->selRectangle
) {
582 // Measure line and return character closest to minX
583 startPos
= ed
->PositionFromLineX(line
, minX
);
584 // Measure line and return character closest to maxX
585 endPos
= ed
->PositionFromLineX(line
, maxX
);
586 } else if (ed
->selType
== ed
->selLines
) {
587 startPos
= ed
->pdoc
->LineStart(line
);
588 endPos
= ed
->pdoc
->LineStart(line
+ 1);
589 } else { // Stream selection, here only for completion
590 if (line
== lineStart
) {
593 startPos
= ed
->pdoc
->LineStart(line
);
595 if (line
== lineEnd
) {
598 endPos
= ed
->pdoc
->LineStart(line
+ 1);
610 return startPos
!= INVALID_POSITION
;
614 Point
Editor::LocationFromPosition(int pos
) {
617 if (pos
== INVALID_POSITION
)
619 int line
= pdoc
->LineFromPosition(pos
);
620 int lineVisible
= cs
.DisplayFromDoc(line
);
621 //Platform::DebugPrintf("line=%d\n", line);
622 AutoSurface
surface(this);
623 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
625 // -1 because of adding in for visible lines in following loop.
626 pt
.y
= (lineVisible
- topLine
- 1) * vs
.lineHeight
;
628 unsigned int posLineStart
= pdoc
->LineStart(line
);
629 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
630 int posInLine
= pos
- posLineStart
;
631 // In case of very long line put x at arbitrary large position
632 if (posInLine
> ll
->maxLineLength
) {
633 pt
.x
= ll
->positions
[ll
->maxLineLength
] - ll
->positions
[ll
->LineStart(ll
->lines
)];
635 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
636 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
637 pt
.x
= ll
->positions
[posInLine
] - ll
->positions
[ll
->LineStart(subLine
)];
639 if (posInLine
>= ll
->LineStart(subLine
)) {
640 pt
.y
+= vs
.lineHeight
;
643 pt
.x
+= vs
.fixedColumnWidth
- xOffset
;
648 int Editor::XFromPosition(int pos
) {
649 Point pt
= LocationFromPosition(pos
);
650 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
653 int Editor::LineFromLocation(Point pt
) {
654 return cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
657 void Editor::SetTopLine(int topLineNew
) {
658 topLine
= topLineNew
;
659 posTopLine
= pdoc
->LineStart(topLine
);
662 static inline bool IsEOLChar(char ch
) {
663 return (ch
== '\r') || (ch
== '\n');
666 int Editor::PositionFromLocation(Point pt
) {
668 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
669 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
670 if (pt
.y
< 0) { // Division rounds towards 0
671 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
675 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
676 if (lineDoc
>= pdoc
->LinesTotal())
677 return pdoc
->Length();
678 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
679 int retVal
= posLineStart
;
680 AutoSurface
surface(this);
681 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
683 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
684 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
685 int subLine
= visibleLine
- lineStartSet
;
686 if (subLine
< ll
->lines
) {
687 int lineStart
= ll
->LineStart(subLine
);
688 int lineEnd
= ll
->LineStart(subLine
+ 1);
689 int subLineStart
= ll
->positions
[lineStart
];
690 for (int i
= lineStart
; i
< lineEnd
; i
++) {
691 if (pt
.x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
692 IsEOLChar(ll
->chars
[i
])) {
693 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
696 return lineEnd
+ posLineStart
;
698 retVal
= ll
->numCharsInLine
+ posLineStart
;
703 // Like PositionFromLocation but INVALID_POSITION returned when not near any text.
704 int Editor::PositionFromLocationClose(Point pt
) {
706 PRectangle rcClient
= GetTextRectangle();
707 if (!rcClient
.Contains(pt
))
708 return INVALID_POSITION
;
709 if (pt
.x
< vs
.fixedColumnWidth
)
710 return INVALID_POSITION
;
712 return INVALID_POSITION
;
713 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
714 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
715 if (pt
.y
< 0) { // Division rounds towards 0
716 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
718 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
720 return INVALID_POSITION
;
721 if (lineDoc
>= pdoc
->LinesTotal())
722 return INVALID_POSITION
;
723 AutoSurface
surface(this);
724 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
726 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
727 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
728 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
729 int subLine
= visibleLine
- lineStartSet
;
730 if (subLine
< ll
->lines
) {
731 int lineStart
= ll
->LineStart(subLine
);
732 int lineEnd
= ll
->LineStart(subLine
+ 1);
733 int subLineStart
= ll
->positions
[lineStart
];
734 for (int i
= lineStart
; i
< lineEnd
; i
++) {
735 if (pt
.x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
736 IsEOLChar(ll
->chars
[i
])) {
737 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
743 return INVALID_POSITION
;
747 * Find the document position corresponding to an x coordinate on a particular document line.
748 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
750 int Editor::PositionFromLineX(int lineDoc
, int x
) {
752 if (lineDoc
>= pdoc
->LinesTotal())
753 return pdoc
->Length();
754 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
755 AutoSurface
surface(this);
756 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
759 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
760 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
761 retVal
= ll
->numCharsInLine
+ posLineStart
;
763 int lineStart
= ll
->LineStart(subLine
);
764 int lineEnd
= ll
->LineStart(subLine
+ 1);
765 int subLineStart
= ll
->positions
[lineStart
];
766 for (int i
= lineStart
; i
< lineEnd
; i
++) {
767 if (x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
768 IsEOLChar(ll
->chars
[i
])) {
769 retVal
= pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
778 * If painting then abandon the painting because a wider redraw is needed.
779 * @return true if calling code should stop drawing.
781 bool Editor::AbandonPaint() {
782 if ((paintState
== painting
) && !paintingAllText
) {
783 paintState
= paintAbandoned
;
785 return paintState
== paintAbandoned
;
788 void Editor::RedrawRect(PRectangle rc
) {
789 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
791 // Clip the redraw rectangle into the client area
792 PRectangle rcClient
= GetClientRectangle();
793 if (rc
.top
< rcClient
.top
)
794 rc
.top
= rcClient
.top
;
795 if (rc
.bottom
> rcClient
.bottom
)
796 rc
.bottom
= rcClient
.bottom
;
797 if (rc
.left
< rcClient
.left
)
798 rc
.left
= rcClient
.left
;
799 if (rc
.right
> rcClient
.right
)
800 rc
.right
= rcClient
.right
;
802 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
803 wMain
.InvalidateRectangle(rc
);
807 void Editor::Redraw() {
808 //Platform::DebugPrintf("Redraw all\n");
809 PRectangle rcClient
= GetClientRectangle();
810 wMain
.InvalidateRectangle(rcClient
);
811 //wMain.InvalidateAll();
814 void Editor::RedrawSelMargin() {
815 if (!AbandonPaint()) {
819 PRectangle rcSelMargin
= GetClientRectangle();
820 rcSelMargin
.right
= vs
.fixedColumnWidth
;
821 wMain
.InvalidateRectangle(rcSelMargin
);
826 PRectangle
Editor::RectangleFromRange(int start
, int end
) {
833 int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(minPos
));
834 int lineDocMax
= pdoc
->LineFromPosition(maxPos
);
835 int maxLine
= cs
.DisplayFromDoc(lineDocMax
) + cs
.GetHeight(lineDocMax
) - 1;
836 PRectangle rcClient
= GetTextRectangle();
838 rc
.left
= vs
.fixedColumnWidth
;
839 rc
.top
= (minLine
- topLine
) * vs
.lineHeight
;
842 rc
.right
= rcClient
.right
;
843 rc
.bottom
= (maxLine
- topLine
+ 1) * vs
.lineHeight
;
844 // Ensure PRectangle is within 16 bit space
845 rc
.top
= Platform::Clamp(rc
.top
, -32000, 32000);
846 rc
.bottom
= Platform::Clamp(rc
.bottom
, -32000, 32000);
851 void Editor::InvalidateRange(int start
, int end
) {
852 RedrawRect(RectangleFromRange(start
, end
));
855 int Editor::CurrentPosition() {
859 bool Editor::SelectionEmpty() {
860 return anchor
== currentPos
;
863 int Editor::SelectionStart() {
864 return Platform::Minimum(currentPos
, anchor
);
867 int Editor::SelectionEnd() {
868 return Platform::Maximum(currentPos
, anchor
);
871 void Editor::InvalidateSelection(int currentPos_
, int anchor_
) {
872 int firstAffected
= anchor
;
873 if (firstAffected
> currentPos
)
874 firstAffected
= currentPos
;
875 if (firstAffected
> anchor_
)
876 firstAffected
= anchor_
;
877 if (firstAffected
> currentPos_
)
878 firstAffected
= currentPos_
;
879 int lastAffected
= anchor
;
880 if (lastAffected
< currentPos
)
881 lastAffected
= currentPos
;
882 if (lastAffected
< anchor_
)
883 lastAffected
= anchor_
;
884 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
885 lastAffected
= (currentPos_
+ 1);
887 InvalidateRange(firstAffected
, lastAffected
);
890 void Editor::SetSelection(int currentPos_
, int anchor_
) {
891 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
892 anchor_
= pdoc
->ClampPositionIntoDocument(anchor_
);
893 if ((currentPos
!= currentPos_
) || (anchor
!= anchor_
)) {
894 InvalidateSelection(currentPos_
, anchor_
);
895 currentPos
= currentPos_
;
898 if (selType
== selRectangle
) {
899 xStartSelect
= XFromPosition(anchor
);
900 xEndSelect
= XFromPosition(currentPos
);
905 void Editor::SetSelection(int currentPos_
) {
906 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
907 if (currentPos
!= currentPos_
) {
908 InvalidateSelection(currentPos_
, currentPos_
);
909 currentPos
= currentPos_
;
911 if (selType
== selRectangle
) {
912 xStartSelect
= XFromPosition(anchor
);
913 xEndSelect
= XFromPosition(currentPos
);
918 void Editor::SetEmptySelection(int currentPos_
) {
920 moveExtendsSelection
= false;
921 SetSelection(currentPos_
, currentPos_
);
924 bool Editor::RangeContainsProtected(int start
, int end
) const {
925 if (vs
.ProtectionActive()) {
931 int mask
= pdoc
->stylingBitsMask
;
932 for (int pos
= start
; pos
< end
; pos
++) {
933 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected())
940 bool Editor::SelectionContainsProtected() {
941 // DONE, but untested...: make support rectangular selection
943 if (selType
== selStream
) {
944 scp
= RangeContainsProtected(anchor
, currentPos
);
946 SelectionLineIterator
lineIterator(this);
947 while (lineIterator
.Iterate()) {
948 if (RangeContainsProtected(lineIterator
.startPos
, lineIterator
.endPos
)) {
958 * Asks document to find a good position and then moves out of any invisible positions.
960 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) {
961 pos
= pdoc
->MovePositionOutsideChar(pos
, moveDir
, checkLineEnd
);
962 if (vs
.ProtectionActive()) {
963 int mask
= pdoc
->stylingBitsMask
;
965 if ((pos
> 0) && vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()) {
966 while ((pos
< pdoc
->Length()) &&
967 (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected()))
970 } else if (moveDir
< 0) {
971 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected()) {
973 (vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()))
981 int Editor::MovePositionTo(int newPos
, selTypes sel
, bool ensureVisible
) {
982 int delta
= newPos
- currentPos
;
983 newPos
= pdoc
->ClampPositionIntoDocument(newPos
);
984 newPos
= MovePositionOutsideChar(newPos
, delta
);
988 if (sel
!= noSel
|| moveExtendsSelection
) {
989 SetSelection(newPos
);
991 SetEmptySelection(newPos
);
993 ShowCaretAtCurrentPosition();
995 EnsureCaretVisible();
1001 int Editor::MovePositionSoVisible(int pos
, int moveDir
) {
1002 pos
= pdoc
->ClampPositionIntoDocument(pos
);
1003 pos
= MovePositionOutsideChar(pos
, moveDir
);
1004 int lineDoc
= pdoc
->LineFromPosition(pos
);
1005 if (cs
.GetVisible(lineDoc
)) {
1008 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
1010 // lineDisplay is already line before fold as lines in fold use display line of line after fold
1011 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
1012 return pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
));
1014 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
1015 return pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
));
1021 * Choose the x position that the caret will try to stick to
1022 * as it moves up and down.
1024 void Editor::SetLastXChosen() {
1025 Point pt
= LocationFromPosition(currentPos
);
1029 void Editor::ScrollTo(int line
, bool moveThumb
) {
1030 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
1031 if (topLineNew
!= topLine
) {
1032 // Try to optimise small scrolls
1033 int linesToMove
= topLine
- topLineNew
;
1034 SetTopLine(topLineNew
);
1035 ShowCaretAtCurrentPosition();
1036 // Perform redraw rather than scroll if many lines would be redrawn anyway.
1037 if (abs(linesToMove
) <= 10) {
1038 ScrollText(linesToMove
);
1043 SetVerticalScrollPos();
1048 void Editor::ScrollText(int /* linesToMove */) {
1049 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
1053 void Editor::HorizontalScrollTo(int xPos
) {
1054 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
1057 if ((wrapState
== eWrapNone
) && (xOffset
!= xPos
)) {
1059 SetHorizontalScrollPos();
1060 RedrawRect(GetClientRectangle());
1064 void Editor::MoveCaretInsideView(bool ensureVisible
) {
1065 PRectangle rcClient
= GetTextRectangle();
1066 Point pt
= LocationFromPosition(currentPos
);
1067 if (pt
.y
< rcClient
.top
) {
1068 MovePositionTo(PositionFromLocation(
1069 Point(lastXChosen
, rcClient
.top
)),
1070 noSel
, ensureVisible
);
1071 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
1072 int yOfLastLineFullyDisplayed
= rcClient
.top
+ (LinesOnScreen() - 1) * vs
.lineHeight
;
1073 MovePositionTo(PositionFromLocation(
1074 Point(lastXChosen
, rcClient
.top
+ yOfLastLineFullyDisplayed
)),
1075 noSel
, ensureVisible
);
1079 int Editor::DisplayFromPosition(int pos
) {
1080 int lineDoc
= pdoc
->LineFromPosition(pos
);
1081 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
1082 AutoSurface
surface(this);
1083 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
1084 if (surface
&& ll
) {
1085 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
1086 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
1087 int posInLine
= pos
- posLineStart
;
1088 lineDisplay
--; // To make up for first increment ahead.
1089 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
1090 if (posInLine
>= ll
->LineStart(subLine
)) {
1099 * Ensure the caret is reasonably visible in context.
1101 Caret policy in SciTE
1103 If slop is set, we can define a slop value.
1104 This value defines an unwanted zone (UZ) where the caret is... unwanted.
1105 This zone is defined as a number of pixels near the vertical margins,
1106 and as a number of lines near the horizontal margins.
1107 By keeping the caret away from the edges, it is seen within its context,
1108 so it is likely that the identifier that the caret is on can be completely seen,
1109 and that the current line is seen with some of the lines following it which are
1110 often dependent on that line.
1112 If strict is set, the policy is enforced... strictly.
1113 The caret is centred on the display if slop is not set,
1114 and cannot go in the UZ if slop is set.
1116 If jumps is set, the display is moved more energetically
1117 so the caret can move in the same direction longer before the policy is applied again.
1118 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1120 If even is not set, instead of having symmetrical UZs,
1121 the left and bottom UZs are extended up to right and top UZs respectively.
1122 This way, we favour the displaying of useful information: the begining of lines,
1123 where most code reside, and the lines after the caret, eg. the body of a function.
1126 slop | strict | jumps | even | Caret can go to the margin | When reaching limitÝ(caret going out of
1127 | | | | | visibility or going into the UZ) display is...
1128 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1129 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1130 0 | 0 | 0 | 1 | Yes | moved by one position
1131 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1132 0 | 0 | 1 | 1 | Yes | centred on the caret
1133 0 | 1 | - | 0 | Caret is always on top/on right of display | -
1134 0 | 1 | - | 1 | No, caret is always centred | -
1135 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1136 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1137 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1138 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1139 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1140 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1141 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1143 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
1144 //Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " ");
1145 PRectangle rcClient
= GetTextRectangle();
1146 //int rcClientFullWidth = rcClient.Width();
1147 int posCaret
= currentPos
;
1151 Point pt
= LocationFromPosition(posCaret
);
1152 Point ptBottomCaret
= pt
;
1153 ptBottomCaret
.y
+= vs
.lineHeight
- 1;
1154 int lineCaret
= DisplayFromPosition(posCaret
);
1155 bool bSlop
, bStrict
, bJump
, bEven
;
1157 // Vertical positioning
1158 if (vert
&& (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
> rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1159 int linesOnScreen
= LinesOnScreen();
1160 int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1161 int newTopLine
= topLine
;
1162 bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1163 bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1164 bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1165 bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1167 // It should be possible to scroll the window to show the caret,
1168 // but this fails to remove the caret on GTK+
1169 if (bSlop
) { // A margin is defined
1172 int yMarginT
, yMarginB
;
1174 // In drag mode, avoid moves
1175 // otherwise, a double click will select several lines.
1176 yMarginT
= yMarginB
= 0;
1178 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1179 // a maximum of slightly less than half the heigth of the text area.
1180 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1182 yMarginB
= yMarginT
;
1184 yMarginB
= linesOnScreen
- yMarginT
- 1;
1190 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1194 yMoveB
= linesOnScreen
- yMoveT
- 1;
1196 if (lineCaret
< topLine
+ yMarginT
) {
1197 // Caret goes too high
1198 newTopLine
= lineCaret
- yMoveT
;
1199 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1200 // Caret goes too low
1201 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1203 } else { // Not strict
1204 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1205 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1209 yMoveB
= linesOnScreen
- yMoveT
- 1;
1211 if (lineCaret
< topLine
) {
1212 // Caret goes too high
1213 newTopLine
= lineCaret
- yMoveT
;
1214 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1215 // Caret goes too low
1216 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1220 if (!bStrict
&& !bJump
) {
1222 if (lineCaret
< topLine
) {
1223 // Caret goes too high
1224 newTopLine
= lineCaret
;
1225 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1226 // Caret goes too low
1228 newTopLine
= lineCaret
- linesOnScreen
+ 1;
1230 newTopLine
= lineCaret
;
1233 } else { // Strict or going out of display
1235 // Always center caret
1236 newTopLine
= lineCaret
- halfScreen
;
1238 // Always put caret on top of display
1239 newTopLine
= lineCaret
;
1243 newTopLine
= Platform::Clamp(newTopLine
, 0, MaxScrollPos());
1244 if (newTopLine
!= topLine
) {
1246 SetTopLine(newTopLine
);
1247 SetVerticalScrollPos();
1251 // Horizontal positioning
1252 if (horiz
&& (wrapState
== eWrapNone
)) {
1253 int halfScreen
= Platform::Maximum(rcClient
.Width() - 4, 4) / 2;
1254 int xOffsetNew
= xOffset
;
1255 bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1256 bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1257 bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1258 bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1260 if (bSlop
) { // A margin is defined
1263 int xMarginL
, xMarginR
;
1265 // In drag mode, avoid moves unless very near of the margin
1266 // otherwise, a simple click will select text.
1267 xMarginL
= xMarginR
= 2;
1269 // xMargin must equal to caretXSlop, with a minimum of 2 and
1270 // a maximum of slightly less than half the width of the text area.
1271 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1273 xMarginL
= xMarginR
;
1275 xMarginL
= rcClient
.Width() - xMarginR
- 4;
1278 if (bJump
&& bEven
) {
1279 // Jump is used only in even mode
1280 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1282 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1284 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1285 // Caret is on the left of the display
1286 if (bJump
&& bEven
) {
1287 xOffsetNew
-= xMoveL
;
1289 // Move just enough to allow to display the caret
1290 xOffsetNew
-= (rcClient
.left
+ xMarginL
) - pt
.x
;
1292 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1293 // Caret is on the right of the display
1294 if (bJump
&& bEven
) {
1295 xOffsetNew
+= xMoveR
;
1297 // Move just enough to allow to display the caret
1298 xOffsetNew
+= pt
.x
- (rcClient
.right
- xMarginR
) + 1;
1301 } else { // Not strict
1302 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1303 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1307 xMoveL
= rcClient
.Width() - xMoveR
- 4;
1309 if (pt
.x
< rcClient
.left
) {
1310 // Caret is on the left of the display
1311 xOffsetNew
-= xMoveL
;
1312 } else if (pt
.x
>= rcClient
.right
) {
1313 // Caret is on the right of the display
1314 xOffsetNew
+= xMoveR
;
1319 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1320 // Strict or going out of display
1323 xOffsetNew
+= pt
.x
- rcClient
.left
- halfScreen
;
1325 // Put caret on right
1326 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1329 // Move just enough to allow to display the caret
1330 if (pt
.x
< rcClient
.left
) {
1331 // Caret is on the left of the display
1333 xOffsetNew
-= rcClient
.left
- pt
.x
;
1335 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1337 } else if (pt
.x
>= rcClient
.right
) {
1338 // Caret is on the right of the display
1339 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1343 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1344 if (pt
.x
+ xOffset
< rcClient
.left
+ xOffsetNew
) {
1345 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.left
;
1346 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ xOffsetNew
) {
1347 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.right
+ 1;
1349 if (xOffsetNew
< 0) {
1352 if (xOffset
!= xOffsetNew
) {
1353 xOffset
= xOffsetNew
;
1354 if (xOffsetNew
> 0) {
1355 PRectangle rcText
= GetTextRectangle();
1356 if (horizontalScrollBarVisible
== true &&
1357 rcText
.Width() + xOffset
> scrollWidth
) {
1358 scrollWidth
= xOffset
+ rcText
.Width();
1362 SetHorizontalScrollPos();
1368 void Editor::ShowCaretAtCurrentPosition() {
1370 caret
.active
= true;
1374 caret
.active
= false;
1380 void Editor::DropCaret() {
1381 caret
.active
= false;
1385 void Editor::InvalidateCaret() {
1387 InvalidateRange(posDrag
, posDrag
+ 1);
1389 InvalidateRange(currentPos
, currentPos
+ 1);
1392 void Editor::NeedWrapping(int docLineStartWrapping
, int docLineEndWrapping
) {
1393 bool noWrap
= (docLastLineToWrap
== docLineLastWrapped
);
1394 if (docLineLastWrapped
> (docLineStartWrapping
- 1)) {
1395 docLineLastWrapped
= docLineStartWrapping
- 1;
1396 if (docLineLastWrapped
< -1)
1397 docLineLastWrapped
= -1;
1398 llc
.Invalidate(LineLayout::llPositions
);
1401 docLastLineToWrap
= docLineEndWrapping
;
1402 } else if (docLastLineToWrap
< docLineEndWrapping
) {
1403 docLastLineToWrap
= docLineEndWrapping
+ 1;
1405 if (docLastLineToWrap
< -1)
1406 docLastLineToWrap
= -1;
1407 if (docLastLineToWrap
>= pdoc
->LinesTotal())
1408 docLastLineToWrap
= pdoc
->LinesTotal()-1;
1409 // Wrap lines during idle.
1410 if (backgroundWrapEnabled
&& docLastLineToWrap
!= docLineLastWrapped
) {
1415 // Check if wrapping needed and perform any needed wrapping.
1416 // fullwrap: if true, all lines which need wrapping will be done,
1417 // in this single call.
1418 // priorityWrapLineStart: If greater than zero, all lines starting from
1419 // here to 100 lines past will be wrapped (even if there are
1420 // more lines under wrapping process in idle).
1421 // If it is neither fullwrap, nor priorityWrap, then 100 lines will be
1422 // wrapped, if there are any wrapping going on in idle. (Generally this
1423 // condition is called only from idler).
1424 // Return true if wrapping occurred.
1425 bool Editor::WrapLines(bool fullWrap
, int priorityWrapLineStart
) {
1426 // If there are any pending wraps, do them during idle if possible.
1427 if (wrapState
!= eWrapNone
) {
1428 if (docLineLastWrapped
< docLastLineToWrap
) {
1429 if (!(backgroundWrapEnabled
&& SetIdle(true))) {
1430 // Background wrapping is disabled, or idle processing
1431 // not supported. A full wrap is required.
1435 if (!fullWrap
&& priorityWrapLineStart
>= 0 &&
1436 // .. and if the paint window is outside pending wraps
1437 (((priorityWrapLineStart
+ 100) < docLineLastWrapped
) ||
1438 (priorityWrapLineStart
> docLastLineToWrap
))) {
1439 // No priority wrap pending
1443 int goodTopLine
= topLine
;
1444 bool wrapOccurred
= false;
1445 if (docLineLastWrapped
< pdoc
->LinesTotal()) {
1446 if (wrapState
== eWrapNone
) {
1447 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1448 wrapWidth
= LineLayout::wrapWidthInfinite
;
1449 for (int lineDoc
= 0; lineDoc
< pdoc
->LinesTotal(); lineDoc
++) {
1450 cs
.SetHeight(lineDoc
, 1);
1452 wrapOccurred
= true;
1454 docLineLastWrapped
= 0x7ffffff;
1457 int lineDocTop
= cs
.DocFromDisplay(topLine
);
1458 int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1459 PRectangle rcTextArea
= GetClientRectangle();
1460 rcTextArea
.left
= vs
.fixedColumnWidth
;
1461 rcTextArea
.right
-= vs
.rightMarginWidth
;
1462 wrapWidth
= rcTextArea
.Width();
1463 // Ensure all of the document is styled.
1464 pdoc
->EnsureStyledTo(pdoc
->Length());
1466 AutoSurface
surface(this);
1468 bool priorityWrap
= false;
1469 int lastLineToWrap
= docLastLineToWrap
;
1470 int firstLineToWrap
= docLineLastWrapped
;
1472 if (priorityWrapLineStart
>= 0) {
1473 // This is a priority wrap.
1474 firstLineToWrap
= priorityWrapLineStart
;
1475 lastLineToWrap
= firstLineToWrap
+ 100;
1476 priorityWrap
= true;
1478 // This is idle wrap.
1479 lastLineToWrap
= docLineLastWrapped
+ 100;
1481 if (lastLineToWrap
>= docLastLineToWrap
)
1482 lastLineToWrap
= docLastLineToWrap
;
1483 } // else do a fullWrap.
1485 // printf("Wraplines: full = %d, priorityStart = %d (wrapping: %d to %d)\n", fullWrap, priorityWrapLineStart, firstLineToWrap, lastLineToWrap);
1486 // printf("Pending wraps: %d to %d\n", docLineLastWrapped, docLastLineToWrap);
1487 while (firstLineToWrap
< lastLineToWrap
) {
1490 docLineLastWrapped
++;
1491 AutoLineLayout
ll(llc
, RetrieveLineLayout(firstLineToWrap
));
1492 int linesWrapped
= 1;
1494 LayoutLine(firstLineToWrap
, surface
, vs
, ll
, wrapWidth
);
1495 linesWrapped
= ll
->lines
;
1497 if (cs
.SetHeight(firstLineToWrap
, linesWrapped
)) {
1498 wrapOccurred
= true;
1501 // If wrapping is done, bring it to resting position
1502 if (docLineLastWrapped
> docLastLineToWrap
) {
1503 docLineLastWrapped
= -1;
1504 docLastLineToWrap
= -1;
1507 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
);
1508 if (subLineTop
< cs
.GetHeight(lineDocTop
))
1509 goodTopLine
+= subLineTop
;
1511 goodTopLine
+= cs
.GetHeight(lineDocTop
);
1512 //double durWrap = et.Duration(true);
1513 //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap);
1518 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1519 SetVerticalScrollPos();
1521 return wrapOccurred
;
1524 void Editor::LinesJoin() {
1525 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1526 pdoc
->BeginUndoAction();
1527 bool prevNonWS
= true;
1528 for (int pos
= targetStart
; pos
< targetEnd
; pos
++) {
1529 if (IsEOLChar(pdoc
->CharAt(pos
))) {
1530 targetEnd
-= pdoc
->LenChar(pos
);
1533 // Ensure at least one space separating previous lines
1534 pdoc
->InsertChar(pos
, ' ');
1537 prevNonWS
= pdoc
->CharAt(pos
) != ' ';
1540 pdoc
->EndUndoAction();
1544 const char *StringFromEOLMode(int eolMode
) {
1545 if (eolMode
== SC_EOL_CRLF
) {
1547 } else if (eolMode
== SC_EOL_CR
) {
1554 void Editor::LinesSplit(int pixelWidth
) {
1555 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1556 if (pixelWidth
== 0) {
1557 PRectangle rcText
= GetTextRectangle();
1558 pixelWidth
= rcText
.Width();
1560 int lineStart
= pdoc
->LineFromPosition(targetStart
);
1561 int lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1562 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1563 pdoc
->BeginUndoAction();
1564 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
1565 AutoSurface
surface(this);
1566 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
1567 if (surface
&& ll
) {
1568 unsigned int posLineStart
= pdoc
->LineStart(line
);
1569 LayoutLine(line
, surface
, vs
, ll
, pixelWidth
);
1570 for (int subLine
= 1; subLine
< ll
->lines
; subLine
++) {
1571 pdoc
->InsertString(posLineStart
+ (subLine
- 1) * strlen(eol
) +
1572 ll
->LineStart(subLine
), eol
);
1573 targetEnd
+= static_cast<int>(strlen(eol
));
1577 pdoc
->EndUndoAction();
1581 int Editor::SubstituteMarkerIfEmpty(int markerCheck
, int markerDefault
) {
1582 if (vs
.markers
[markerCheck
].markType
== SC_MARK_EMPTY
)
1583 return markerDefault
;
1587 // Avoid 64 bit compiler warnings.
1588 // Scintilla does not support text buffers larger than 2**31
1589 static int istrlen(const char *s
) {
1590 return static_cast<int>(strlen(s
));
1593 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1594 if (vs
.fixedColumnWidth
== 0)
1597 PRectangle rcMargin
= GetClientRectangle();
1598 rcMargin
.right
= vs
.fixedColumnWidth
;
1600 if (!rc
.Intersects(rcMargin
))
1605 surface
= pixmapSelMargin
;
1607 surface
= surfWindow
;
1610 PRectangle rcSelMargin
= rcMargin
;
1611 rcSelMargin
.right
= rcMargin
.left
;
1613 for (int margin
= 0; margin
< vs
.margins
; margin
++) {
1614 if (vs
.ms
[margin
].width
> 0) {
1616 rcSelMargin
.left
= rcSelMargin
.right
;
1617 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
1619 if (vs
.ms
[margin
].symbol
) {
1620 /* alternate scheme:
1621 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
1622 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1624 // Required because of special way brush is created for selection margin
1625 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
1627 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
1628 // Required because of special way brush is created for selection margin
1629 surface
->FillRectangle(rcSelMargin
, *pixmapSelPattern
);
1631 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1633 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1636 int visibleLine
= topLine
;
1639 // Work out whether the top line is whitespace located after a
1640 // lessening of fold level which implies a 'fold tail' but which should not
1641 // be displayed until the last of a sequence of whitespace.
1642 bool needWhiteClosure
= false;
1643 int level
= pdoc
->GetLevel(cs
.DocFromDisplay(topLine
));
1644 if (level
& SC_FOLDLEVELWHITEFLAG
) {
1645 int lineBack
= cs
.DocFromDisplay(topLine
);
1646 int levelPrev
= level
;
1647 while ((lineBack
> 0) && (levelPrev
& SC_FOLDLEVELWHITEFLAG
)) {
1649 levelPrev
= pdoc
->GetLevel(lineBack
);
1651 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
1652 if ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelPrev
& SC_FOLDLEVELNUMBERMASK
))
1653 needWhiteClosure
= true;
1657 // Old code does not know about new markers needed to distinguish all cases
1658 int folderOpenMid
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID
,
1659 SC_MARKNUM_FOLDEROPEN
);
1660 int folderEnd
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND
,
1663 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
1665 PLATFORM_ASSERT(visibleLine
< cs
.LinesDisplayed());
1667 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
1668 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
1669 bool firstSubLine
= visibleLine
== cs
.DisplayFromDoc(lineDoc
);
1671 // Decide which fold indicator should be displayed
1672 level
= pdoc
->GetLevel(lineDoc
);
1673 int levelNext
= pdoc
->GetLevel(lineDoc
+ 1);
1674 int marks
= pdoc
->GetMark(lineDoc
);
1677 int levelNum
= level
& SC_FOLDLEVELNUMBERMASK
;
1678 int levelNextNum
= levelNext
& SC_FOLDLEVELNUMBERMASK
;
1679 if (level
& SC_FOLDLEVELHEADERFLAG
) {
1681 if (cs
.GetExpanded(lineDoc
)) {
1682 if (levelNum
== SC_FOLDLEVELBASE
)
1683 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
1685 marks
|= 1 << folderOpenMid
;
1687 if (levelNum
== SC_FOLDLEVELBASE
)
1688 marks
|= 1 << SC_MARKNUM_FOLDER
;
1690 marks
|= 1 << folderEnd
;
1693 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1695 needWhiteClosure
= false;
1696 } else if (level
& SC_FOLDLEVELWHITEFLAG
) {
1697 if (needWhiteClosure
) {
1698 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1699 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1700 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1701 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1702 needWhiteClosure
= false;
1704 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1705 needWhiteClosure
= false;
1707 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1708 if (levelNextNum
< levelNum
) {
1709 if (levelNextNum
> SC_FOLDLEVELBASE
) {
1710 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1712 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1715 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1718 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1719 if (levelNextNum
< levelNum
) {
1720 needWhiteClosure
= false;
1721 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1722 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1723 needWhiteClosure
= true;
1724 } else if (levelNextNum
> SC_FOLDLEVELBASE
) {
1725 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1727 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1730 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1734 marks
&= vs
.ms
[margin
].mask
;
1735 PRectangle rcMarker
= rcSelMargin
;
1736 rcMarker
.top
= yposScreen
;
1737 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
1738 if (!vs
.ms
[margin
].symbol
) {
1742 sprintf(number
, "%d", lineDoc
+ 1);
1743 if (foldFlags
& SC_FOLDFLAG_LEVELNUMBERS
) {
1744 int lev
= pdoc
->GetLevel(lineDoc
);
1745 sprintf(number
, "%c%c %03X %03X",
1746 (lev
& SC_FOLDLEVELHEADERFLAG
) ? 'H' : '_',
1747 (lev
& SC_FOLDLEVELWHITEFLAG
) ? 'W' : '_',
1748 lev
& SC_FOLDLEVELNUMBERMASK
,
1752 PRectangle rcNumber
= rcMarker
;
1754 int width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
1755 int xpos
= rcNumber
.right
- width
- 3;
1756 rcNumber
.left
= xpos
;
1757 surface
->DrawTextNoClip(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
1758 rcNumber
.top
+ vs
.maxAscent
, number
, istrlen(number
),
1759 vs
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
1760 vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1764 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1766 vs
.markers
[markBit
].Draw(surface
, rcMarker
, vs
.styles
[STYLE_LINENUMBER
].font
);
1773 yposScreen
+= vs
.lineHeight
;
1778 PRectangle rcBlankMargin
= rcMargin
;
1779 rcBlankMargin
.left
= rcSelMargin
.right
;
1780 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1783 surfWindow
->Copy(rcMargin
, Point(), *pixmapSelMargin
);
1787 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
1788 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
1789 int xhead
= rcTab
.right
- 1 - ydiff
;
1790 if (xhead
<= rcTab
.left
) {
1791 ydiff
-= rcTab
.left
- xhead
- 1;
1792 xhead
= rcTab
.left
- 1;
1794 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
1795 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
1797 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1798 surface
->LineTo(rcTab
.right
- 1, ymid
);
1799 surface
->LineTo(xhead
, ymid
- ydiff
);
1800 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1801 surface
->LineTo(xhead
, ymid
+ ydiff
);
1804 static bool IsSpaceOrTab(char ch
) {
1805 return ch
== ' ' || ch
== '\t';
1808 LineLayout
*Editor::RetrieveLineLayout(int lineNumber
) {
1809 int posLineStart
= pdoc
->LineStart(lineNumber
);
1810 int posLineEnd
= pdoc
->LineStart(lineNumber
+ 1);
1811 int lineCaret
= pdoc
->LineFromPosition(currentPos
);
1812 return llc
.Retrieve(lineNumber
, lineCaret
,
1813 posLineEnd
- posLineStart
, pdoc
->GetStyleClock(),
1814 LinesOnScreen() + 1, pdoc
->LinesTotal());
1818 * Fill in the LineLayout data for the given line.
1819 * Copy the given @a line and its styles from the document into local arrays.
1820 * Also determine the x position at which each character starts.
1822 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
*ll
, int width
) {
1825 PLATFORM_ASSERT(line
< pdoc
->LinesTotal());
1826 int posLineStart
= pdoc
->LineStart(line
);
1827 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1828 // If the line is very long, limit the treatment to a length that should fit in the viewport
1829 if (posLineEnd
> (posLineStart
+ ll
->maxLineLength
)) {
1830 posLineEnd
= posLineStart
+ ll
->maxLineLength
;
1832 if (ll
->validity
== LineLayout::llCheckTextAndStyle
) {
1834 for (int cid
= posLineStart
; cid
< posLineEnd
; cid
++) {
1835 char chDoc
= pdoc
->CharAt(cid
);
1836 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
1840 if (lineLength
== ll
->numCharsInLine
) {
1841 int numCharsInLine
= 0;
1842 // See if chars, styles, indicators, are all the same
1843 bool allSame
= true;
1844 const int styleMask
= pdoc
->stylingBitsMask
;
1845 // Check base line layout
1846 for (int charInDoc
= posLineStart
; allSame
&& (charInDoc
< posLineEnd
); charInDoc
++) {
1847 char chDoc
= pdoc
->CharAt(charInDoc
);
1848 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
1849 char styleByte
= pdoc
->StyleAt(charInDoc
);
1850 allSame
= allSame
&&
1851 (ll
->styles
[numCharsInLine
] == static_cast<char>(styleByte
& styleMask
));
1852 allSame
= allSame
&&
1853 (ll
->indicators
[numCharsInLine
] == static_cast<char>(styleByte
& ~styleMask
));
1854 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
1855 allSame
= allSame
&&
1856 (ll
->chars
[numCharsInLine
] == static_cast<char>(toupper(chDoc
)));
1857 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1858 allSame
= allSame
&&
1859 (ll
->chars
[numCharsInLine
] == static_cast<char>(tolower(chDoc
)));
1861 allSame
= allSame
&&
1862 (ll
->chars
[numCharsInLine
] == chDoc
);
1867 ll
->validity
= LineLayout::llPositions
;
1869 ll
->validity
= LineLayout::llInvalid
;
1872 ll
->validity
= LineLayout::llInvalid
;
1875 if (ll
->validity
== LineLayout::llInvalid
) {
1876 ll
->widthLine
= LineLayout::wrapWidthInfinite
;
1878 int numCharsInLine
= 0;
1879 if (vstyle
.edgeState
== EDGE_BACKGROUND
) {
1880 ll
->edgeColumn
= pdoc
->FindColumn(line
, theEdge
);
1881 if (ll
->edgeColumn
>= posLineStart
) {
1882 ll
->edgeColumn
-= posLineStart
;
1885 ll
->edgeColumn
= -1;
1889 int styleMask
= pdoc
->stylingBitsMask
;
1890 // Fill base line layout
1891 for (int charInDoc
= posLineStart
; charInDoc
< posLineEnd
; charInDoc
++) {
1892 char chDoc
= pdoc
->CharAt(charInDoc
);
1893 styleByte
= pdoc
->StyleAt(charInDoc
);
1894 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
1895 ll
->chars
[numCharsInLine
] = chDoc
;
1896 ll
->styles
[numCharsInLine
] = static_cast<char>(styleByte
& styleMask
);
1897 ll
->indicators
[numCharsInLine
] = static_cast<char>(styleByte
& ~styleMask
);
1898 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
1899 ll
->chars
[numCharsInLine
] = static_cast<char>(toupper(chDoc
));
1900 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1901 ll
->chars
[numCharsInLine
] = static_cast<char>(tolower(chDoc
));
1905 ll
->xHighlightGuide
= 0;
1906 // Extra element at the end of the line to hold end x position and act as
1907 ll
->chars
[numCharsInLine
] = 0; // Also triggers processing in the loops as this is a control character
1908 ll
->styles
[numCharsInLine
] = styleByte
; // For eolFilled
1909 ll
->indicators
[numCharsInLine
] = 0;
1911 // Layout the line, determining the position of each character,
1912 // with an extra element at the end for the end of the line.
1913 int startseg
= 0; // Start of the current segment, in char. number
1914 int startsegx
= 0; // Start of the current segment, in pixels
1915 ll
->positions
[0] = 0;
1916 unsigned int tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
1917 bool lastSegItalics
= false;
1918 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
1920 bool isControlNext
= IsControlCharacter(ll
->chars
[0]);
1921 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
1922 bool isControl
= isControlNext
;
1923 isControlNext
= IsControlCharacter(ll
->chars
[charInLine
+ 1]);
1924 if ((ll
->styles
[charInLine
] != ll
->styles
[charInLine
+ 1]) ||
1925 isControl
|| isControlNext
) {
1926 ll
->positions
[startseg
] = 0;
1927 if (vstyle
.styles
[ll
->styles
[charInLine
]].visible
) {
1929 if (ll
->chars
[charInLine
] == '\t') {
1930 ll
->positions
[charInLine
+ 1] = ((((startsegx
+ 2) /
1931 tabWidth
) + 1) * tabWidth
) - startsegx
;
1932 } else if (controlCharSymbol
< 32) {
1933 const char *ctrlChar
= ControlCharacterString(ll
->chars
[charInLine
]);
1934 // +3 For a blank on front and rounded edge each side:
1935 ll
->positions
[charInLine
+ 1] = surface
->WidthText(ctrlCharsFont
, ctrlChar
, istrlen(ctrlChar
)) + 3;
1937 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
1938 surface
->MeasureWidths(ctrlCharsFont
, cc
, 1,
1939 ll
->positions
+ startseg
+ 1);
1941 lastSegItalics
= false;
1942 } else { // Regular character
1943 int lenSeg
= charInLine
- startseg
+ 1;
1944 if ((lenSeg
== 1) && (' ' == ll
->chars
[startseg
])) {
1945 lastSegItalics
= false;
1946 // Over half the segments are single characters and of these about half are space characters.
1947 ll
->positions
[charInLine
+ 1] = vstyle
.styles
[ll
->styles
[charInLine
]].spaceWidth
;
1949 lastSegItalics
= vstyle
.styles
[ll
->styles
[charInLine
]].italic
;
1950 surface
->MeasureWidths(vstyle
.styles
[ll
->styles
[charInLine
]].font
, ll
->chars
+ startseg
,
1951 lenSeg
, ll
->positions
+ startseg
+ 1);
1954 } else { // invisible
1955 for (int posToZero
= startseg
; posToZero
<= (charInLine
+ 1); posToZero
++) {
1956 ll
->positions
[posToZero
] = 0;
1959 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
1960 ll
->positions
[posToIncrease
] += startsegx
;
1962 startsegx
= ll
->positions
[charInLine
+ 1];
1963 startseg
= charInLine
+ 1;
1966 // Small hack to make lines that end with italics not cut off the edge of the last character
1967 if ((startseg
> 0) && lastSegItalics
) {
1968 ll
->positions
[startseg
] += 2;
1970 ll
->numCharsInLine
= numCharsInLine
;
1971 ll
->validity
= LineLayout::llPositions
;
1973 // Hard to cope when too narrow, so just assume there is space
1977 if ((ll
->validity
== LineLayout::llPositions
) || (ll
->widthLine
!= width
)) {
1978 ll
->widthLine
= width
;
1979 if (width
== LineLayout::wrapWidthInfinite
) {
1981 } else if (width
> ll
->positions
[ll
->numCharsInLine
]) {
1982 // Simple common case where line does not need wrapping.
1986 // Calculate line start positions based upon width.
1987 // For now this is simplistic - wraps on byte rather than character and
1988 // in the middle of words. Should search for spaces or style changes.
1989 int lastGoodBreak
= 0;
1990 int lastLineStart
= 0;
1991 int startOffset
= 0;
1993 while (p
< ll
->numCharsInLine
) {
1994 if ((ll
->positions
[p
+ 1] - startOffset
) >= width
) {
1995 if (lastGoodBreak
== lastLineStart
) {
1996 // Try moving to start of last character
1998 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
2001 if (lastGoodBreak
== lastLineStart
) {
2002 // Ensure at least one character on line.
2003 lastGoodBreak
= pdoc
->MovePositionOutsideChar(lastGoodBreak
+ posLineStart
+ 1, 1)
2007 lastLineStart
= lastGoodBreak
;
2009 ll
->SetLineStart(ll
->lines
, lastGoodBreak
);
2010 startOffset
= ll
->positions
[lastGoodBreak
];
2011 p
= lastGoodBreak
+ 1;
2015 if (ll
->styles
[p
] != ll
->styles
[p
- 1]) {
2017 } else if (IsSpaceOrTab(ll
->chars
[p
- 1]) && !IsSpaceOrTab(ll
->chars
[p
])) {
2025 ll
->validity
= LineLayout::llLines
;
2029 ColourAllocated
Editor::TextBackground(ViewStyle
&vsDraw
, bool overrideBackground
,
2030 ColourAllocated background
, bool inSelection
, bool inHotspot
, int styleMain
, int i
, LineLayout
*ll
) {
2032 if (vsDraw
.selbackset
) {
2033 if (primarySelection
)
2034 return vsDraw
.selbackground
.allocated
;
2036 return vsDraw
.selbackground2
.allocated
;
2039 if ((vsDraw
.edgeState
== EDGE_BACKGROUND
) &&
2040 (i
>= ll
->edgeColumn
) &&
2041 !IsEOLChar(ll
->chars
[i
]))
2042 return vsDraw
.edgecolour
.allocated
;
2043 if (inHotspot
&& vsDraw
.hotspotBackgroundSet
)
2044 return vsDraw
.hotspotBackground
.allocated
;
2045 if (overrideBackground
)
2048 return vsDraw
.styles
[styleMain
].back
.allocated
;
2051 void Editor::DrawIndentGuide(Surface
*surface
, int lineVisible
, int lineHeight
, int start
, PRectangle rcSegment
, bool highlight
) {
2052 Point
from(0, ((lineVisible
& 1) && (lineHeight
& 1)) ? 1 : 0);
2053 PRectangle
rcCopyArea(start
+ 1, rcSegment
.top
, start
+ 2, rcSegment
.bottom
);
2054 surface
->Copy(rcCopyArea
, from
,
2055 highlight
? *pixmapIndentGuideHighlight
: *pixmapIndentGuide
);
2058 void Editor::DrawEOL(Surface
*surface
, ViewStyle
&vsDraw
, PRectangle rcLine
, LineLayout
*ll
,
2059 int line
, int lineEnd
, int xStart
, int subLine
, int subLineStart
,
2060 bool overrideBackground
, ColourAllocated background
) {
2062 int styleMask
= pdoc
->stylingBitsMask
;
2063 PRectangle rcSegment
= rcLine
;
2065 // Fill in a PRectangle representing the end of line characters
2066 int xEol
= ll
->positions
[lineEnd
] - subLineStart
;
2067 rcSegment
.left
= xEol
+ xStart
;
2068 rcSegment
.right
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
2069 int posLineEnd
= pdoc
->LineStart(line
+ 1);
2070 bool eolInSelection
= (subLine
== (ll
->lines
- 1)) &&
2071 (posLineEnd
> ll
->selStart
) && (posLineEnd
<= ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2072 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1)) {
2073 if (primarySelection
)
2074 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground
.allocated
);
2076 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground2
.allocated
);
2077 } else if (overrideBackground
) {
2078 surface
->FillRectangle(rcSegment
, background
);
2080 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2083 rcSegment
.left
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
2084 rcSegment
.right
= rcLine
.right
;
2085 if (overrideBackground
) {
2086 surface
->FillRectangle(rcSegment
, background
);
2087 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
2088 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2090 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
2094 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int lineVisible
, int xStart
,
2095 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
2097 PRectangle rcSegment
= rcLine
;
2099 // Using one font for all control characters so it can be controlled independently to ensure
2100 // the box goes around the characters tightly. Seems to be no way to work out what height
2101 // is taken by an individual character - internal leading gives varying results.
2102 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
2104 // See if something overrides the line background color: Either if caret is on the line
2105 // and background color is set for that, or if a marker is defined that forces its background
2106 // color onto the line, or if a marker is defined but has no selection margin in which to
2107 // display itself. These are checked in order with the earlier taking precedence. When
2108 // multiple markers cause background override, the color for the highest numbered one is used.
2109 bool overrideBackground
= false;
2110 ColourAllocated background
;
2111 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& ll
->containsCaret
) {
2112 overrideBackground
= true;
2113 background
= vsDraw
.caretLineBackground
.allocated
;
2115 if (!overrideBackground
) {
2116 int marks
= pdoc
->GetMark(line
);
2117 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2118 if ((marks
& 1) && vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
) {
2119 background
= vsDraw
.markers
[markBit
].back
.allocated
;
2120 overrideBackground
= true;
2125 if (!overrideBackground
) {
2126 if (vsDraw
.maskInLine
) {
2127 int marks
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
2129 overrideBackground
= true;
2130 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2132 background
= vsDraw
.markers
[markBit
].back
.allocated
;
2140 bool drawWhitespaceBackground
= (vsDraw
.viewWhitespace
!= wsInvisible
) &&
2141 (!overrideBackground
) && (vsDraw
.whitespaceBackgroundSet
);
2143 bool inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2144 int indentWidth
= pdoc
->indentInChars
* vsDraw
.spaceWidth
;
2145 if (indentWidth
== 0)
2146 indentWidth
= pdoc
->tabInChars
* vsDraw
.spaceWidth
;
2148 int posLineStart
= pdoc
->LineStart(line
);
2150 int startseg
= ll
->LineStart(subLine
);
2151 int subLineStart
= ll
->positions
[startseg
];
2154 if (subLine
< ll
->lines
) {
2155 lineStart
= ll
->LineStart(subLine
);
2156 lineEnd
= ll
->LineStart(subLine
+ 1);
2160 // Background drawing loop
2161 for (i
= lineStart
; twoPhaseDraw
&& (i
< lineEnd
); i
++) {
2163 int iDoc
= i
+ posLineStart
;
2164 // If there is the end of a style run for any reason
2165 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
2166 i
== (lineEnd
- 1) ||
2167 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
2168 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
2169 (i
== (ll
->edgeColumn
- 1))) {
2170 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2171 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2172 // Only try to draw if really visible - enhances performance by not calling environment to
2173 // draw strings that are completely past the right side of the window.
2174 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2175 int styleMain
= ll
->styles
[i
];
2176 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2177 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2178 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2179 if (ll
->chars
[i
] == '\t') {
2181 if (drawWhitespaceBackground
&&
2182 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2183 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2184 surface
->FillRectangle(rcSegment
, textBack
);
2185 } else if (IsControlCharacter(ll
->chars
[i
])) {
2186 // Control character display
2187 inIndentation
= false;
2188 surface
->FillRectangle(rcSegment
, textBack
);
2190 // Normal text display
2191 surface
->FillRectangle(rcSegment
, textBack
);
2192 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2193 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
2194 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2195 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2196 if (drawWhitespaceBackground
&&
2197 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2198 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
,
2199 ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2200 surface
->FillRectangle(rcSpace
, vsDraw
.whitespaceBackground
.allocated
);
2203 inIndentation
= false;
2214 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2215 xStart
, subLine
, subLineStart
, overrideBackground
, background
);
2218 inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2219 startseg
= ll
->LineStart(subLine
);
2220 // Foreground drawing loop
2221 for (i
= lineStart
; i
< lineEnd
; i
++) {
2223 int iDoc
= i
+ posLineStart
;
2224 // If there is the end of a style run for any reason
2225 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
2226 i
== (lineEnd
- 1) ||
2227 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
2228 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
2229 (i
== (ll
->edgeColumn
- 1))) {
2230 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2231 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2232 // Only try to draw if really visible - enhances performance by not calling environment to
2233 // draw strings that are completely past the right side of the window.
2234 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2235 int styleMain
= ll
->styles
[i
];
2236 ColourAllocated textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
2237 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
2238 //hotspot foreground
2239 if (ll
->hsStart
!= -1 && iDoc
>= ll
->hsStart
&& iDoc
< hsEnd
) {
2240 if (vsDraw
.hotspotForegroundSet
)
2241 textFore
= vsDraw
.hotspotForeground
.allocated
;
2243 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2244 if (inSelection
&& (vsDraw
.selforeset
)) {
2245 textFore
= vsDraw
.selforeground
.allocated
;
2247 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2248 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2249 if (ll
->chars
[i
] == '\t') {
2251 if (!twoPhaseDraw
) {
2252 if (drawWhitespaceBackground
&&
2253 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2254 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2255 surface
->FillRectangle(rcSegment
, textBack
);
2257 if ((vsDraw
.viewWhitespace
!= wsInvisible
) || ((inIndentation
&& vsDraw
.viewIndentationGuides
))) {
2258 if (vsDraw
.whitespaceForegroundSet
)
2259 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2260 surface
->PenColour(textFore
);
2262 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
2263 for (int xIG
= ll
->positions
[i
] / indentWidth
* indentWidth
; xIG
< ll
->positions
[i
+ 1]; xIG
+= indentWidth
) {
2264 if (xIG
>= ll
->positions
[i
] && xIG
> 0) {
2265 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIG
+ xStart
, rcSegment
,
2266 (ll
->xHighlightGuide
== xIG
));
2270 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2271 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2272 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
2273 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
2274 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
2277 } else if (IsControlCharacter(ll
->chars
[i
])) {
2278 // Control character display
2279 inIndentation
= false;
2280 if (controlCharSymbol
< 32) {
2281 // Draw the character
2282 const char *ctrlChar
= ControlCharacterString(ll
->chars
[i
]);
2283 if (!twoPhaseDraw
) {
2284 surface
->FillRectangle(rcSegment
, textBack
);
2286 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
2287 surface
->InternalLeading(ctrlCharsFont
);
2288 PRectangle rcCChar
= rcSegment
;
2289 rcCChar
.left
= rcCChar
.left
+ 1;
2290 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
2291 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
2292 PRectangle rcCentral
= rcCChar
;
2295 surface
->FillRectangle(rcCentral
, textFore
);
2296 PRectangle rcChar
= rcCChar
;
2299 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
2300 rcSegment
.top
+ vsDraw
.maxAscent
, ctrlChar
, istrlen(ctrlChar
),
2301 textBack
, textFore
);
2303 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
2304 surface
->DrawTextNoClip(rcSegment
, ctrlCharsFont
,
2305 rcSegment
.top
+ vsDraw
.maxAscent
,
2306 cc
, 1, textBack
, textFore
);
2309 // Normal text display
2310 if (vsDraw
.styles
[styleMain
].visible
) {
2312 surface
->DrawTextTransparent(rcSegment
, textFont
,
2313 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2314 i
- startseg
+ 1, textFore
);
2316 surface
->DrawTextNoClip(rcSegment
, textFont
,
2317 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2318 i
- startseg
+ 1, textFore
, textBack
);
2321 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2322 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
2323 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2324 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2325 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2326 if (vsDraw
.whitespaceForegroundSet
)
2327 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2328 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2329 int xmid
= (ll
->positions
[cpos
+ startseg
] + ll
->positions
[cpos
+ startseg
+ 1]) / 2;
2330 if (!twoPhaseDraw
&& drawWhitespaceBackground
&&
2331 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2332 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2333 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
, ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2334 surface
->FillRectangle(rcSpace
, textBack
);
2336 PRectangle
rcDot(xmid
+ xStart
- subLineStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
2337 rcDot
.right
= rcDot
.left
+ 1;
2338 rcDot
.bottom
= rcDot
.top
+ 1;
2339 surface
->FillRectangle(rcDot
, textFore
);
2342 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
2343 int startSpace
= ll
->positions
[cpos
+ startseg
];
2344 if (startSpace
> 0 && (startSpace
% indentWidth
== 0)) {
2345 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, startSpace
+ xStart
, rcSegment
,
2346 (ll
->xHighlightGuide
== ll
->positions
[cpos
+ startseg
]));
2350 inIndentation
= false;
2355 if (ll
->hsStart
!= -1 && vsDraw
.hotspotUnderline
&& iDoc
>= ll
->hsStart
&& iDoc
< ll
->hsEnd
) {
2356 PRectangle rcUL
= rcSegment
;
2357 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2358 rcUL
.bottom
= rcUL
.top
+ 1;
2359 if (vsDraw
.hotspotForegroundSet
)
2360 surface
->FillRectangle(rcUL
, vsDraw
.hotspotForeground
.allocated
);
2362 surface
->FillRectangle(rcUL
, textFore
);
2363 } else if (vsDraw
.styles
[styleMain
].underline
) {
2364 PRectangle rcUL
= rcSegment
;
2365 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2366 rcUL
.bottom
= rcUL
.top
+ 1;
2367 surface
->FillRectangle(rcUL
, textFore
);
2375 int indStart
[INDIC_MAX
+ 1] = {0};
2376 for (int indica
= 0; indica
<= INDIC_MAX
; indica
++)
2377 indStart
[indica
] = 0;
2379 for (int indicPos
= lineStart
; indicPos
<= lineEnd
; indicPos
++) {
2380 if ((indicPos
== lineEnd
) || (ll
->indicators
[indicPos
] != ll
->indicators
[indicPos
+ 1])) {
2381 int mask
= 1 << pdoc
->stylingBits
;
2382 for (int indicnum
= 0; mask
< 0x100; indicnum
++) {
2383 if ((indicPos
== lineEnd
)) {
2384 indStart
[indicnum
] = ll
->positions
[indicPos
];
2385 } else if ((ll
->indicators
[indicPos
+ 1] & mask
) && !(ll
->indicators
[indicPos
] & mask
)) {
2386 indStart
[indicnum
] = ll
->positions
[indicPos
+ 1];
2388 if ((ll
->indicators
[indicPos
] & mask
) &&
2389 ((indicPos
== lineEnd
) || !(ll
->indicators
[indicPos
+ 1] & mask
))) {
2390 int endIndicator
= indicPos
;
2391 if (endIndicator
>= lineEnd
)
2392 endIndicator
= lineEnd
-1;
2394 indStart
[indicnum
] + xStart
- subLineStart
,
2395 rcLine
.top
+ vsDraw
.maxAscent
,
2396 ll
->positions
[endIndicator
+ 1] + xStart
- subLineStart
,
2397 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
2398 vsDraw
.indicators
[indicnum
].Draw(surface
, rcIndic
, rcLine
);
2404 // End of the drawing of the current line
2406 if (!twoPhaseDraw
) {
2407 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2408 xStart
, subLine
, subLineStart
, overrideBackground
, background
);
2411 if (vsDraw
.edgeState
== EDGE_LINE
) {
2412 int edgeX
= theEdge
* vsDraw
.spaceWidth
;
2413 rcSegment
.left
= edgeX
+ xStart
;
2414 rcSegment
.right
= rcSegment
.left
+ 1;
2415 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
.allocated
);
2419 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
2420 if (!pixmapSelPattern
->Initialised()) {
2421 const int patternSize
= 8;
2422 pixmapSelPattern
->InitPixMap(patternSize
, patternSize
, surfaceWindow
, wMain
.GetID());
2423 // This complex procedure is to reproduce the checkerboard dithered pattern used by windows
2424 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
2425 // way between the chrome colour and the chrome highlight colour making a nice transition
2426 // between the window chrome and the content area. And it works in low colour depths.
2427 PRectangle
rcPattern(0, 0, patternSize
, patternSize
);
2429 // Initialize default colours based on the chrome colour scheme. Typically the highlight is white.
2430 ColourAllocated colourFMFill
= vs
.selbar
.allocated
;
2431 ColourAllocated colourFMStripes
= vs
.selbarlight
.allocated
;
2433 if (!(vs
.selbarlight
.desired
== ColourDesired(0xff, 0xff, 0xff))) {
2434 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
2435 // (Typically, the highlight colour is white.)
2436 colourFMFill
= vs
.selbarlight
.allocated
;
2439 if (vs
.foldmarginColourSet
) {
2440 // override default fold margin colour
2441 colourFMFill
= vs
.foldmarginColour
.allocated
;
2443 if (vs
.foldmarginHighlightColourSet
) {
2444 // override default fold margin highlight colour
2445 colourFMStripes
= vs
.foldmarginHighlightColour
.allocated
;
2448 pixmapSelPattern
->FillRectangle(rcPattern
, colourFMFill
);
2449 pixmapSelPattern
->PenColour(colourFMStripes
);
2450 for (int stripe
= 0; stripe
< patternSize
; stripe
++) {
2451 // Alternating 1 pixel stripes is same as checkerboard.
2452 pixmapSelPattern
->MoveTo(0, stripe
* 2);
2453 pixmapSelPattern
->LineTo(patternSize
, stripe
* 2 - patternSize
);
2457 if (!pixmapIndentGuide
->Initialised()) {
2458 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
2459 pixmapIndentGuide
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2460 pixmapIndentGuideHighlight
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2461 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
2462 pixmapIndentGuide
->FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
.allocated
);
2463 pixmapIndentGuide
->PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
2464 pixmapIndentGuideHighlight
->FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
.allocated
);
2465 pixmapIndentGuideHighlight
->PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
2466 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
2467 pixmapIndentGuide
->MoveTo(0, stripe
);
2468 pixmapIndentGuide
->LineTo(2, stripe
);
2469 pixmapIndentGuideHighlight
->MoveTo(0, stripe
);
2470 pixmapIndentGuideHighlight
->LineTo(2, stripe
);
2475 if (!pixmapLine
->Initialised()) {
2476 PRectangle rcClient
= GetClientRectangle();
2477 pixmapLine
->InitPixMap(rcClient
.Width(), rcClient
.Height(),
2478 surfaceWindow
, wMain
.GetID());
2479 pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
2480 rcClient
.Height(), surfaceWindow
, wMain
.GetID());
2485 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
2486 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
2487 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
2491 RefreshPixMaps(surfaceWindow
);
2493 PRectangle rcClient
= GetClientRectangle();
2494 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
2495 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
2497 surfaceWindow
->SetPalette(&palette
, true);
2498 pixmapLine
->SetPalette(&palette
, !hasFocus
);
2500 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
2501 // The area to be painted plus one extra line is styled.
2502 // The extra line is to determine when a style change, such as starting a comment flows on to other lines.
2503 int lineStyleLast
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
2504 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
2505 int endPosPaint
= pdoc
->Length();
2506 if (lineStyleLast
< cs
.LinesDisplayed())
2507 endPosPaint
= pdoc
->LineStart(cs
.DocFromDisplay(lineStyleLast
+ 1));
2509 int xStart
= vs
.fixedColumnWidth
- xOffset
;
2512 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
2513 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
2515 // Ensure we are styled as far as we are painting.
2516 pdoc
->EnsureStyledTo(endPosPaint
);
2517 bool paintAbandonedByStyling
= paintState
== paintAbandoned
;
2520 needUpdateUI
= false;
2523 // Call priority lines wrap on a window of lines which are likely
2524 // to rendered with the following paint (that is wrap the visible
2526 int startLineToWrap
= cs
.DocFromDisplay(topLine
) - 5;
2527 if (startLineToWrap
< 0)
2528 startLineToWrap
= -1;
2529 if (WrapLines(false, startLineToWrap
)) {
2530 // The wrapping process has changed the height of some lines so
2531 // abandon this paint for a complete repaint.
2532 if (AbandonPaint()) {
2535 RefreshPixMaps(surfaceWindow
); // In case pixmaps invalidated by scrollbar change
2537 PLATFORM_ASSERT(pixmapSelPattern
->Initialised());
2539 PaintSelMargin(surfaceWindow
, rcArea
);
2541 PRectangle rcRightMargin
= rcClient
;
2542 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
2543 if (rcArea
.Intersects(rcRightMargin
)) {
2544 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2547 if (paintState
== paintAbandoned
) {
2548 // Either styling or NotifyUpdateUI noticed that painting is needed
2549 // outside the current painting rectangle
2550 //Platform::DebugPrintf("Abandoning paint\n");
2551 if (wrapState
!= eWrapNone
) {
2552 if (paintAbandonedByStyling
) {
2553 // Styling has spilled over a line end, such as occurs by starting a multiline
2554 // comment. The width of subsequent text may have changed, so rewrap.
2555 NeedWrapping(cs
.DocFromDisplay(topLine
));
2560 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
2563 if (rcArea
.right
> vs
.fixedColumnWidth
) {
2565 Surface
*surface
= surfaceWindow
;
2567 surface
= pixmapLine
;
2568 PLATFORM_ASSERT(pixmapLine
->Initialised());
2570 surface
->SetUnicodeMode(IsUnicodeMode());
2571 surface
->SetDBCSMode(CodePage());
2573 int visibleLine
= topLine
+ screenLinePaintFirst
;
2575 int posCaret
= currentPos
;
2578 int lineCaret
= pdoc
->LineFromPosition(posCaret
);
2580 // Remove selection margin from drawing area so text will not be drawn
2581 // on it in unbuffered mode.
2582 PRectangle rcTextArea
= rcClient
;
2583 rcTextArea
.left
= vs
.fixedColumnWidth
;
2584 rcTextArea
.right
-= vs
.rightMarginWidth
;
2585 surfaceWindow
->SetClip(rcTextArea
);
2587 // Loop on visible lines
2588 //double durLayout = 0.0;
2589 //double durPaint = 0.0;
2590 //double durCopy = 0.0;
2591 //ElapsedTime etWhole;
2592 int lineDocPrevious
= -1; // Used to avoid laying out one document line multiple times
2593 AutoLineLayout
ll(llc
, 0);
2594 SelectionLineIterator
lineIterator(this);
2595 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
2597 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
2598 // Only visible lines should be handled by the code within the loop
2599 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
2600 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
2601 int subLine
= visibleLine
- lineStartSet
;
2603 // Copy this line and its styles from the document into local arrays
2604 // and determine the x position at which each character starts.
2606 if (lineDoc
!= lineDocPrevious
) {
2607 ll
.Set(RetrieveLineLayout(lineDoc
));
2608 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
2609 lineDocPrevious
= lineDoc
;
2611 //durLayout += et.Duration(true);
2614 if (selType
== selStream
) {
2615 ll
->selStart
= SelectionStart();
2616 ll
->selEnd
= SelectionEnd();
2618 lineIterator
.SetAt(lineDoc
);
2619 ll
->selStart
= lineIterator
.startPos
;
2620 ll
->selEnd
= lineIterator
.endPos
;
2622 ll
->containsCaret
= lineDoc
== lineCaret
;
2623 if (hideSelection
) {
2626 ll
->containsCaret
= false;
2629 GetHotSpotRange(ll
->hsStart
, ll
->hsEnd
);
2631 PRectangle rcLine
= rcClient
;
2633 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
2635 Range
rangeLine(pdoc
->LineStart(lineDoc
), pdoc
->LineStart(lineDoc
+ 1));
2636 // Highlight the current braces if any
2637 ll
->SetBracesHighlight(rangeLine
, braces
, static_cast<char>(bracesMatchStyle
),
2638 highlightGuideColumn
* vs
.spaceWidth
);
2641 DrawLine(surface
, vs
, lineDoc
, visibleLine
, xStart
, rcLine
, ll
, subLine
);
2642 //durPaint += et.Duration(true);
2644 // Restore the previous styles for the brace highlights in case layout is in cache.
2645 ll
->RestoreBracesHighlight(rangeLine
, braces
);
2647 bool expanded
= cs
.GetExpanded(lineDoc
);
2648 if ((foldFlags
& SC_FOLDFLAG_BOX
) == 0) {
2649 // Paint the line above the fold
2650 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_EXPANDED
))
2652 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_CONTRACTED
))) {
2653 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2654 PRectangle rcFoldLine
= rcLine
;
2655 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2656 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2659 // Paint the line below the fold
2660 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_EXPANDED
))
2662 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2663 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2664 PRectangle rcFoldLine
= rcLine
;
2665 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2666 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2670 int FoldLevelCurr
= (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2671 int FoldLevelPrev
= (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2672 int FoldLevelFlags
= (pdoc
->GetLevel(lineDoc
) & ~SC_FOLDLEVELNUMBERMASK
) & ~(0xFFF0000);
2673 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
2674 // Draw line above fold
2675 if ((FoldLevelPrev
< FoldLevelCurr
)
2677 (FoldLevelFlags
& SC_FOLDLEVELBOXHEADERFLAG
2679 (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELBOXFOOTERFLAG
) == 0)) {
2680 PRectangle rcFoldLine
= rcLine
;
2681 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2682 rcFoldLine
.left
+= xStart
+ FoldLevelCurr
* vs
.spaceWidth
* indentationStep
- 1;
2683 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2686 // Line below the fold (or below a contracted fold)
2687 if (FoldLevelFlags
& SC_FOLDLEVELBOXFOOTERFLAG
2689 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2690 PRectangle rcFoldLine
= rcLine
;
2691 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2692 rcFoldLine
.left
+= xStart
+ (FoldLevelCurr
) * vs
.spaceWidth
* indentationStep
- 1;
2693 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2696 PRectangle rcBoxLine
= rcLine
;
2697 // Draw vertical line for every fold level
2698 for (int i
= 0; i
<= FoldLevelCurr
; i
++) {
2699 rcBoxLine
.left
= xStart
+ i
* vs
.spaceWidth
* indentationStep
- 1;
2700 rcBoxLine
.right
= rcBoxLine
.left
+ 1;
2701 surface
->FillRectangle(rcBoxLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2706 if (lineDoc
== lineCaret
) {
2707 int offset
= Platform::Minimum(posCaret
- rangeLine
.start
, ll
->maxLineLength
);
2708 if ((offset
>= ll
->LineStart(subLine
)) &&
2709 ((offset
< ll
->LineStart(subLine
+ 1)) || offset
== ll
->numCharsInLine
)) {
2710 int xposCaret
= ll
->positions
[offset
] - ll
->positions
[ll
->LineStart(subLine
)] + xStart
;
2711 int widthOverstrikeCaret
;
2712 if (posCaret
== pdoc
->Length()) { // At end of document
2713 widthOverstrikeCaret
= vs
.aveCharWidth
;
2714 } else if ((posCaret
- rangeLine
.start
) >= ll
->numCharsInLine
) { // At end of line
2715 widthOverstrikeCaret
= vs
.aveCharWidth
;
2717 widthOverstrikeCaret
= ll
->positions
[offset
+ 1] - ll
->positions
[offset
];
2719 if (widthOverstrikeCaret
< 3) // Make sure its visible
2720 widthOverstrikeCaret
= 3;
2721 if (((caret
.active
&& caret
.on
) || (posDrag
>= 0)) && xposCaret
>= 0) {
2722 PRectangle rcCaret
= rcLine
;
2723 int caretWidthOffset
= 0;
2724 if ((offset
> 0) && (vs
.caretWidth
> 1))
2725 caretWidthOffset
= 1; // Move back so overlaps both character cells.
2727 rcCaret
.left
= xposCaret
- caretWidthOffset
;
2728 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
2731 rcCaret
.top
= rcCaret
.bottom
- 2;
2732 rcCaret
.left
= xposCaret
+ 1;
2733 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
2735 rcCaret
.left
= xposCaret
- caretWidthOffset
;
2736 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
2739 surface
->FillRectangle(rcCaret
, vs
.caretcolour
.allocated
);
2745 Point
from(vs
.fixedColumnWidth
, 0);
2746 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
2747 rcClient
.right
, yposScreen
+ vs
.lineHeight
);
2748 surfaceWindow
->Copy(rcCopyArea
, from
, *pixmapLine
);
2750 //durCopy += et.Duration(true);
2753 if (!bufferedDraw
) {
2754 ypos
+= vs
.lineHeight
;
2757 yposScreen
+= vs
.lineHeight
;
2761 //if (durPaint < 0.00000001)
2762 // durPaint = 0.00000001;
2764 // Right column limit indicator
2765 PRectangle rcBeyondEOF
= rcClient
;
2766 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
2767 rcBeyondEOF
.right
= rcBeyondEOF
.right
;
2768 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
2769 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
2770 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2771 if (vs
.edgeState
== EDGE_LINE
) {
2772 int edgeX
= theEdge
* vs
.spaceWidth
;
2773 rcBeyondEOF
.left
= edgeX
+ xStart
;
2774 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
2775 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
.allocated
);
2778 //Platform::DebugPrintf(
2779 //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
2780 //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
2785 // Space (3 space characters) between line numbers and text when printing.
2786 #define lineNumberPrintSpace " "
2788 ColourDesired
InvertedLight(ColourDesired orig
) {
2789 unsigned int r
= orig
.GetRed();
2790 unsigned int g
= orig
.GetGreen();
2791 unsigned int b
= orig
.GetBlue();
2792 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
2793 unsigned int il
= 0xff - l
;
2795 return ColourDesired(0xff, 0xff, 0xff);
2799 return ColourDesired(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
2802 // This is mostly copied from the Paint method but with some things omitted
2803 // such as the margin markers, line numbers, selection and caret
2804 // Should be merged back into a combined Draw method.
2805 long Editor::FormatRange(bool draw
, RangeToFormat
*pfr
) {
2809 AutoSurface
surface(pfr
->hdc
, this);
2812 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this);
2813 if (!surfaceMeasure
) {
2817 ViewStyle
vsPrint(vs
);
2819 // Modify the view style for printing as do not normally want any of the transient features to be printed
2820 // Printing supports only the line number margin.
2821 int lineNumberIndex
= -1;
2822 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
2823 if ((!vsPrint
.ms
[margin
].symbol
) && (vsPrint
.ms
[margin
].width
> 0)) {
2824 lineNumberIndex
= margin
;
2826 vsPrint
.ms
[margin
].width
= 0;
2829 vsPrint
.showMarkedLines
= false;
2830 vsPrint
.fixedColumnWidth
= 0;
2831 vsPrint
.zoomLevel
= printMagnification
;
2832 vsPrint
.viewIndentationGuides
= false;
2833 // Don't show the selection when printing
2834 vsPrint
.selbackset
= false;
2835 vsPrint
.selforeset
= false;
2836 vsPrint
.whitespaceBackgroundSet
= false;
2837 vsPrint
.whitespaceForegroundSet
= false;
2838 vsPrint
.showCaretLineBackground
= false;
2840 // Set colours for printing according to users settings
2841 for (int sty
= 0;sty
<= STYLE_MAX
;sty
++) {
2842 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
2843 vsPrint
.styles
[sty
].fore
.desired
= InvertedLight(vsPrint
.styles
[sty
].fore
.desired
);
2844 vsPrint
.styles
[sty
].back
.desired
= InvertedLight(vsPrint
.styles
[sty
].back
.desired
);
2845 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
2846 vsPrint
.styles
[sty
].fore
.desired
= ColourDesired(0, 0, 0);
2847 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2848 } else if (printColourMode
== SC_PRINT_COLOURONWHITE
) {
2849 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2850 } else if (printColourMode
== SC_PRINT_COLOURONWHITEDEFAULTBG
) {
2851 if (sty
<= STYLE_DEFAULT
) {
2852 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2856 // White background for the line numbers
2857 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2859 vsPrint
.Refresh(*surfaceMeasure
);
2860 // Ensure colours are set up
2861 vsPrint
.RefreshColourPalette(palette
, true);
2862 vsPrint
.RefreshColourPalette(palette
, false);
2863 // Determining width must hapen after fonts have been realised in Refresh
2864 int lineNumberWidth
= 0;
2865 if (lineNumberIndex
>= 0) {
2866 lineNumberWidth
= surfaceMeasure
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
2867 "99999" lineNumberPrintSpace
, 5 + istrlen(lineNumberPrintSpace
));
2868 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
2871 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
2872 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
2873 if (linePrintLast
< linePrintStart
)
2874 linePrintLast
= linePrintStart
;
2875 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
);
2876 if (linePrintLast
> linePrintMax
)
2877 linePrintLast
= linePrintMax
;
2878 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
2879 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
2880 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
2881 int endPosPrint
= pdoc
->Length();
2882 if (linePrintLast
< pdoc
->LinesTotal())
2883 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
2885 // Ensure we are styled to where we are formatting.
2886 pdoc
->EnsureStyledTo(endPosPrint
);
2888 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
+ lineNumberWidth
;
2889 int ypos
= pfr
->rc
.top
;
2891 int lineDoc
= linePrintStart
;
2893 int nPrintPos
= pfr
->chrg
.cpMin
;
2894 int visibleLine
= 0;
2895 int widthPrint
= pfr
->rc
.Width() - lineNumberWidth
;
2896 if (printWrapState
== eWrapNone
)
2897 widthPrint
= LineLayout::wrapWidthInfinite
;
2899 while (lineDoc
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
2901 // When printing, the hdc and hdcTarget may be the same, so
2902 // changing the state of surfaceMeasure may change the underlying
2903 // state of surface. Therefore, any cached state is discarded before
2904 // using each surface.
2905 surfaceMeasure
->FlushCachedState();
2907 // Copy this line and its styles from the document into local arrays
2908 // and determine the x position at which each character starts.
2909 LineLayout
ll(8000);
2910 LayoutLine(lineDoc
, surfaceMeasure
, vsPrint
, &ll
, widthPrint
);
2914 ll
.containsCaret
= false;
2917 rcLine
.left
= pfr
->rc
.left
+ lineNumberWidth
;
2919 rcLine
.right
= pfr
->rc
.right
- 1;
2920 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
2922 // When document line is wrapped over multiple display lines, find where
2923 // to start printing from to ensure a particular position is on the first
2924 // line of the page.
2925 if (visibleLine
== 0) {
2926 int startWithinLine
= nPrintPos
- pdoc
->LineStart(lineDoc
);
2927 for (int iwl
= 0; iwl
< ll
.lines
- 1; iwl
++) {
2928 if (ll
.LineStart(iwl
) <= startWithinLine
&& ll
.LineStart(iwl
+ 1) >= startWithinLine
) {
2933 if (ll
.lines
> 1 && startWithinLine
>= ll
.LineStart(ll
.lines
- 1)) {
2934 visibleLine
= -(ll
.lines
- 1);
2938 if (draw
&& lineNumberWidth
&&
2939 (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) &&
2940 (visibleLine
>= 0)) {
2942 sprintf(number
, "%d" lineNumberPrintSpace
, lineDoc
+ 1);
2943 PRectangle rcNumber
= rcLine
;
2944 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
2946 rcNumber
.left
-= surfaceMeasure
->WidthText(
2947 vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
2948 surface
->FlushCachedState();
2949 surface
->DrawTextNoClip(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
2950 ypos
+ vsPrint
.maxAscent
, number
, istrlen(number
),
2951 vsPrint
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
2952 vsPrint
.styles
[STYLE_LINENUMBER
].back
.allocated
);
2956 surface
->FlushCachedState();
2958 for (int iwl
= 0; iwl
< ll
.lines
; iwl
++) {
2959 if (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) {
2960 if (visibleLine
>= 0) {
2963 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
2964 DrawLine(surface
, vsPrint
, lineDoc
, visibleLine
, xStart
, rcLine
, &ll
, iwl
);
2966 ypos
+= vsPrint
.lineHeight
;
2969 if (iwl
== ll
.lines
- 1)
2970 nPrintPos
= pdoc
->LineStart(lineDoc
+ 1);
2972 nPrintPos
+= ll
.LineStart(iwl
+ 1) - ll
.LineStart(iwl
);
2982 int Editor::TextWidth(int style
, const char *text
) {
2984 AutoSurface
surface(this);
2986 return surface
->WidthText(vs
.styles
[style
].font
, text
, istrlen(text
));
2992 // Empty method is overridden on GTK+ to show / hide scrollbars
2993 void Editor::ReconfigureScrollBars() {}
2995 void Editor::SetScrollBars() {
2998 int nMax
= MaxScrollPos();
2999 int nPage
= LinesOnScreen();
3000 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
3002 // TODO: ensure always showing as many lines as possible
3003 // May not be, if, for example, window made larger
3004 if (topLine
> MaxScrollPos()) {
3005 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
3006 SetVerticalScrollPos();
3010 if (!AbandonPaint())
3013 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
3016 void Editor::ChangeSize() {
3019 if (wrapState
!= eWrapNone
) {
3020 PRectangle rcTextArea
= GetClientRectangle();
3021 rcTextArea
.left
= vs
.fixedColumnWidth
;
3022 rcTextArea
.right
-= vs
.rightMarginWidth
;
3023 if (wrapWidth
!= rcTextArea
.Width()) {
3030 void Editor::AddChar(char ch
) {
3037 void Editor::AddCharUTF(char *s
, unsigned int len
, bool treatAsDBCS
) {
3038 bool wasSelection
= currentPos
!= anchor
;
3040 if (inOverstrike
&& !wasSelection
&& !RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3041 if (currentPos
< (pdoc
->Length())) {
3042 if (!IsEOLChar(pdoc
->CharAt(currentPos
))) {
3043 pdoc
->DelChar(currentPos
);
3047 if (pdoc
->InsertString(currentPos
, s
, len
)) {
3048 SetEmptySelection(currentPos
+ len
);
3050 EnsureCaretVisible();
3051 // Avoid blinking during rapid typing:
3052 ShowCaretAtCurrentPosition();
3056 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
3057 static_cast<unsigned char>(s
[1]));
3059 int byte
= static_cast<unsigned char>(s
[0]);
3060 if ((byte
< 0xC0) || (1 == len
)) {
3061 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
3062 // characters when not in UTF-8 mode.
3063 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
3064 // characters representing themselves.
3066 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
3067 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
3068 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
3070 int byte2
= static_cast<unsigned char>(s
[1]);
3071 if ((byte2
& 0xC0) == 0x80) {
3072 // Two-byte-character lead-byte followed by a trail-byte.
3073 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
3075 // A two-byte-character lead-byte not followed by trail-byte
3076 // represents itself.
3077 } else if (byte
< 0xF0) {
3078 int byte2
= static_cast<unsigned char>(s
[1]);
3079 int byte3
= static_cast<unsigned char>(s
[2]);
3080 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
3081 // Three-byte-character lead byte followed by two trail bytes.
3082 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
3085 // A three-byte-character lead-byte not followed by two trail-bytes
3086 // represents itself.
3093 void Editor::ClearSelection() {
3094 if (!SelectionContainsProtected()) {
3095 int startPos
= SelectionStart();
3096 if (selType
== selStream
) {
3097 unsigned int chars
= SelectionEnd() - startPos
;
3099 pdoc
->BeginUndoAction();
3100 pdoc
->DeleteChars(startPos
, chars
);
3101 pdoc
->EndUndoAction();
3104 pdoc
->BeginUndoAction();
3105 SelectionLineIterator
lineIterator(this, false);
3106 while (lineIterator
.Iterate()) {
3107 startPos
= lineIterator
.startPos
;
3108 unsigned int chars
= lineIterator
.endPos
- startPos
;
3110 pdoc
->DeleteChars(startPos
, chars
);
3113 pdoc
->EndUndoAction();
3114 selType
= selStream
;
3116 SetEmptySelection(startPos
);
3120 void Editor::ClearAll() {
3121 pdoc
->BeginUndoAction();
3122 if (0 != pdoc
->Length()) {
3123 pdoc
->DeleteChars(0, pdoc
->Length());
3125 if (!pdoc
->IsReadOnly()) {
3128 pdoc
->EndUndoAction();
3132 SetVerticalScrollPos();
3135 void Editor::ClearDocumentStyle() {
3136 pdoc
->StartStyling(0, '\377');
3137 pdoc
->SetStyleFor(pdoc
->Length(), 0);
3139 pdoc
->ClearLevels();
3142 void Editor::Cut() {
3143 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
3149 void Editor::PasteRectangular(int pos
, const char *ptr
, int len
) {
3150 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
3154 int xInsert
= XFromPosition(currentPos
);
3155 int line
= pdoc
->LineFromPosition(currentPos
);
3156 bool prevCr
= false;
3157 pdoc
->BeginUndoAction();
3158 for (int i
= 0; i
< len
; i
++) {
3159 if (IsEOLChar(ptr
[i
])) {
3160 if ((ptr
[i
] == '\r') || (!prevCr
))
3162 if (line
>= pdoc
->LinesTotal()) {
3163 if (pdoc
->eolMode
!= SC_EOL_LF
)
3164 pdoc
->InsertChar(pdoc
->Length(), '\r');
3165 if (pdoc
->eolMode
!= SC_EOL_CR
)
3166 pdoc
->InsertChar(pdoc
->Length(), '\n');
3168 // Pad the end of lines with spaces if required
3169 currentPos
= PositionFromLineX(line
, xInsert
);
3170 if ((XFromPosition(currentPos
) < xInsert
) && (i
+ 1 < len
)) {
3171 for (int i
= 0; i
< xInsert
- XFromPosition(currentPos
); i
++) {
3172 pdoc
->InsertChar(currentPos
, ' ');
3176 prevCr
= ptr
[i
] == '\r';
3178 pdoc
->InsertString(currentPos
, ptr
+ i
, 1);
3183 pdoc
->EndUndoAction();
3184 SetEmptySelection(pos
);
3187 bool Editor::CanPaste() {
3188 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
3191 void Editor::Clear() {
3192 if (currentPos
== anchor
) {
3193 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3199 SetEmptySelection(currentPos
);
3202 void Editor::SelectAll() {
3203 SetSelection(0, pdoc
->Length());
3207 void Editor::Undo() {
3208 if (pdoc
->CanUndo()) {
3210 int newPos
= pdoc
->Undo();
3211 SetEmptySelection(newPos
);
3212 EnsureCaretVisible();
3216 void Editor::Redo() {
3217 if (pdoc
->CanRedo()) {
3218 int newPos
= pdoc
->Redo();
3219 SetEmptySelection(newPos
);
3220 EnsureCaretVisible();
3224 void Editor::DelChar() {
3225 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3226 pdoc
->DelChar(currentPos
);
3228 // Avoid blinking during rapid typing:
3229 ShowCaretAtCurrentPosition();
3232 void Editor::DelCharBack(bool allowLineStartDeletion
) {
3233 if (currentPos
== anchor
) {
3234 if (!RangeContainsProtected(currentPos
- 1, currentPos
)) {
3235 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
3236 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != currentPos
)) {
3237 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3238 pdoc
->GetColumn(currentPos
) > 0 && pdoc
->backspaceUnindents
) {
3239 pdoc
->BeginUndoAction();
3240 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3241 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
3242 if (indentation
% indentationStep
== 0) {
3243 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3245 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- (indentation
% indentationStep
));
3247 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
3248 pdoc
->EndUndoAction();
3250 pdoc
->DelCharBack(currentPos
);
3256 SetEmptySelection(currentPos
);
3258 // Avoid blinking during rapid typing:
3259 ShowCaretAtCurrentPosition();
3262 void Editor::NotifyFocus(bool) {}
3264 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
3266 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
3267 scn
.position
= endStyleNeeded
;
3271 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
3272 NotifyStyleToNeeded(endStyleNeeded
);
3275 void Editor::NotifyChar(int ch
) {
3277 scn
.nmhdr
.code
= SCN_CHARADDED
;
3280 if (recordingMacro
) {
3282 txt
[0] = static_cast<char>(ch
);
3284 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
3288 void Editor::NotifySavePoint(bool isSavePoint
) {
3291 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
3293 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
3298 void Editor::NotifyModifyAttempt() {
3300 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
3304 void Editor::NotifyDoubleClick(Point
, bool) {
3306 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
3310 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3312 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
3313 scn
.position
= position
;
3314 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3315 (alt
? SCI_ALT
: 0);
3319 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3321 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
3322 scn
.position
= position
;
3323 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3324 (alt
? SCI_ALT
: 0);
3328 void Editor::NotifyUpdateUI() {
3330 scn
.nmhdr
.code
= SCN_UPDATEUI
;
3334 void Editor::NotifyPainted() {
3336 scn
.nmhdr
.code
= SCN_PAINTED
;
3340 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
3341 int marginClicked
= -1;
3343 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
3344 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
3345 marginClicked
= margin
;
3346 x
+= vs
.ms
[margin
].width
;
3348 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
3350 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
3351 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3352 (alt
? SCI_ALT
: 0);
3353 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
3354 scn
.margin
= marginClicked
;
3362 void Editor::NotifyNeedShown(int pos
, int len
) {
3364 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
3370 void Editor::NotifyDwelling(Point pt
, bool state
) {
3372 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
3373 scn
.position
= PositionFromLocationClose(pt
);
3379 void Editor::NotifyZoom() {
3381 scn
.nmhdr
.code
= SCN_ZOOM
;
3385 // Notifications from document
3386 void Editor::NotifyModifyAttempt(Document
*, void *) {
3387 //Platform::DebugPrintf("** Modify Attempt\n");
3388 NotifyModifyAttempt();
3391 void Editor::NotifyMove(int position
) {
3393 scn
.nmhdr
.code
= SCN_POSCHANGED
;
3394 scn
.position
= position
;
3398 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
3399 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
3400 NotifySavePoint(atSavePoint
);
3403 void Editor::CheckModificationForWrap(DocModification mh
) {
3404 if ((mh
.modificationType
& SC_MOD_INSERTTEXT
) ||
3405 (mh
.modificationType
& SC_MOD_DELETETEXT
)) {
3406 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
3407 if (wrapState
!= eWrapNone
) {
3408 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
3409 if (mh
.linesAdded
<= 0) {
3410 AutoSurface
surface(this);
3411 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
3412 if (surface
&& ll
) {
3413 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
3414 if (cs
.GetHeight(lineDoc
) != ll
->lines
) {
3415 NeedWrapping(lineDoc
- 1, lineDoc
+ 1);
3420 NeedWrapping(lineDoc
, lineDoc
+ 1 + mh
.linesAdded
);
3426 // Move a position so it is still after the same character as before the insertion.
3427 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
3428 if (position
> startInsertion
) {
3429 return position
+ length
;
3434 // Move a position so it is still after the same character as before the deletion if that
3435 // character is still present else after the previous surviving character.
3436 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
3437 if (position
> startDeletion
) {
3438 int endDeletion
= startDeletion
+ length
;
3439 if (position
> endDeletion
) {
3440 return position
- length
;
3442 return startDeletion
;
3449 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
3450 needUpdateUI
= true;
3451 if (paintState
== painting
) {
3452 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
3454 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
3455 if (paintState
== notPainting
) {
3456 if (mh
.position
< pdoc
->LineStart(topLine
)) {
3457 // Styling performed before this view
3460 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3464 // Move selection and brace highlights
3465 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
3466 currentPos
= MovePositionForInsertion(currentPos
, mh
.position
, mh
.length
);
3467 anchor
= MovePositionForInsertion(anchor
, mh
.position
, mh
.length
);
3468 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
3469 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
3470 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
3471 currentPos
= MovePositionForDeletion(currentPos
, mh
.position
, mh
.length
);
3472 anchor
= MovePositionForDeletion(anchor
, mh
.position
, mh
.length
);
3473 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
3474 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
3476 if (cs
.LinesDisplayed() < cs
.LinesInDoc()) {
3477 // Some lines are hidden so may need shown.
3478 // TODO: check if the modified area is hidden.
3479 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
3480 NotifyNeedShown(mh
.position
, mh
.length
);
3481 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
3482 NotifyNeedShown(mh
.position
, mh
.length
);
3485 if (mh
.linesAdded
!= 0) {
3486 // Update contraction state for inserted and removed lines
3487 // lineOfPos should be calculated in context of state before modification, shouldn't it
3488 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
3489 if (mh
.linesAdded
> 0) {
3490 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
3492 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
3495 CheckModificationForWrap(mh
);
3496 if (mh
.linesAdded
!= 0) {
3497 // Avoid scrolling of display if change before current display
3498 if (mh
.position
< posTopLine
) {
3499 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
3500 if (newTop
!= topLine
) {
3502 SetVerticalScrollPos();
3506 //Platform::DebugPrintf("** %x Doc Changed\n", this);
3507 // TODO: could invalidate from mh.startModification to end of screen
3508 //InvalidateRange(mh.position, mh.position + mh.length);
3509 if (paintState
== notPainting
) {
3513 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
3514 // mh.position, mh.position + mh.length);
3515 if (paintState
== notPainting
) {
3516 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3521 if (mh
.linesAdded
!= 0) {
3525 if (mh
.modificationType
& SC_MOD_CHANGEMARKER
) {
3526 if (paintState
== notPainting
) {
3531 // If client wants to see this modification
3532 if (mh
.modificationType
& modEventMask
) {
3533 if ((mh
.modificationType
& SC_MOD_CHANGESTYLE
) == 0) {
3534 // Real modification made to text of document.
3535 NotifyChange(); // Send EN_CHANGE
3539 scn
.nmhdr
.code
= SCN_MODIFIED
;
3540 scn
.position
= mh
.position
;
3541 scn
.modificationType
= mh
.modificationType
;
3543 scn
.length
= mh
.length
;
3544 scn
.linesAdded
= mh
.linesAdded
;
3546 scn
.foldLevelNow
= mh
.foldLevelNow
;
3547 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
3552 void Editor::NotifyDeleted(Document
*, void *) {
3556 void Editor::NotifyMacroRecord(unsigned int iMessage
, unsigned long wParam
, long lParam
) {
3558 // Enumerates all macroable messages
3564 case SCI_REPLACESEL
:
3566 case SCI_INSERTTEXT
:
3567 case SCI_APPENDTEXT
:
3572 case SCI_SEARCHANCHOR
:
3573 case SCI_SEARCHNEXT
:
3574 case SCI_SEARCHPREV
:
3576 case SCI_LINEDOWNEXTEND
:
3578 case SCI_PARADOWNEXTEND
:
3580 case SCI_LINEUPEXTEND
:
3582 case SCI_PARAUPEXTEND
:
3584 case SCI_CHARLEFTEXTEND
:
3586 case SCI_CHARRIGHTEXTEND
:
3588 case SCI_WORDLEFTEXTEND
:
3590 case SCI_WORDRIGHTEXTEND
:
3591 case SCI_WORDPARTLEFT
:
3592 case SCI_WORDPARTLEFTEXTEND
:
3593 case SCI_WORDPARTRIGHT
:
3594 case SCI_WORDPARTRIGHTEXTEND
:
3595 case SCI_WORDLEFTEND
:
3596 case SCI_WORDLEFTENDEXTEND
:
3597 case SCI_WORDRIGHTEND
:
3598 case SCI_WORDRIGHTENDEXTEND
:
3600 case SCI_HOMEEXTEND
:
3602 case SCI_LINEENDEXTEND
:
3604 case SCI_HOMEWRAPEXTEND
:
3605 case SCI_LINEENDWRAP
:
3606 case SCI_LINEENDWRAPEXTEND
:
3607 case SCI_DOCUMENTSTART
:
3608 case SCI_DOCUMENTSTARTEXTEND
:
3609 case SCI_DOCUMENTEND
:
3610 case SCI_DOCUMENTENDEXTEND
:
3611 case SCI_STUTTEREDPAGEUP
:
3612 case SCI_STUTTEREDPAGEUPEXTEND
:
3613 case SCI_STUTTEREDPAGEDOWN
:
3614 case SCI_STUTTEREDPAGEDOWNEXTEND
:
3616 case SCI_PAGEUPEXTEND
:
3618 case SCI_PAGEDOWNEXTEND
:
3619 case SCI_EDITTOGGLEOVERTYPE
:
3621 case SCI_DELETEBACK
:
3626 case SCI_VCHOMEEXTEND
:
3627 case SCI_VCHOMEWRAP
:
3628 case SCI_VCHOMEWRAPEXTEND
:
3629 case SCI_DELWORDLEFT
:
3630 case SCI_DELWORDRIGHT
:
3631 case SCI_DELLINELEFT
:
3632 case SCI_DELLINERIGHT
:
3635 case SCI_LINEDELETE
:
3636 case SCI_LINETRANSPOSE
:
3637 case SCI_LINEDUPLICATE
:
3640 case SCI_LINESCROLLDOWN
:
3641 case SCI_LINESCROLLUP
:
3642 case SCI_DELETEBACKNOTLINE
:
3643 case SCI_HOMEDISPLAY
:
3644 case SCI_HOMEDISPLAYEXTEND
:
3645 case SCI_LINEENDDISPLAY
:
3646 case SCI_LINEENDDISPLAYEXTEND
:
3647 case SCI_SETSELECTIONMODE
:
3648 case SCI_LINEDOWNRECTEXTEND
:
3649 case SCI_LINEUPRECTEXTEND
:
3650 case SCI_CHARLEFTRECTEXTEND
:
3651 case SCI_CHARRIGHTRECTEXTEND
:
3652 case SCI_HOMERECTEXTEND
:
3653 case SCI_VCHOMERECTEXTEND
:
3654 case SCI_LINEENDRECTEXTEND
:
3655 case SCI_PAGEUPRECTEXTEND
:
3656 case SCI_PAGEDOWNRECTEXTEND
:
3659 // Filter out all others like display changes. Also, newlines are redundant
3660 // with char insert messages.
3663 // printf("Filtered out %ld of macro recording\n", iMessage);
3667 // Send notification
3669 scn
.nmhdr
.code
= SCN_MACRORECORD
;
3670 scn
.message
= iMessage
;
3671 scn
.wParam
= wParam
;
3672 scn
.lParam
= lParam
;
3677 * Force scroll and keep position relative to top of window.
3679 * If stuttered = true and not already at first/last row, move to first/last row of window.
3680 * If stuttered = true and already at first/last row, scroll as normal.
3682 void Editor::PageMove(int direction
, selTypes sel
, bool stuttered
) {
3683 int topLineNew
, newPos
;
3685 // I consider only the caretYSlop, and ignore the caretYPolicy-- is that a problem?
3686 int currentLine
= pdoc
->LineFromPosition(currentPos
);
3687 int topStutterLine
= topLine
+ caretYSlop
;
3688 int bottomStutterLine
= topLine
+ LinesToScroll() - caretYSlop
;
3690 if (stuttered
&& (direction
< 0 && currentLine
> topStutterLine
)) {
3691 topLineNew
= topLine
;
3692 newPos
= PositionFromLocation(Point(lastXChosen
, vs
.lineHeight
* caretYSlop
));
3694 } else if (stuttered
&& (direction
> 0 && currentLine
< bottomStutterLine
)) {
3695 topLineNew
= topLine
;
3696 newPos
= PositionFromLocation(Point(lastXChosen
, vs
.lineHeight
* (LinesToScroll() - caretYSlop
)));
3699 Point pt
= LocationFromPosition(currentPos
);
3701 topLineNew
= Platform::Clamp(
3702 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
3703 newPos
= PositionFromLocation(
3704 Point(lastXChosen
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())));
3707 if (topLineNew
!= topLine
) {
3708 SetTopLine(topLineNew
);
3709 MovePositionTo(newPos
, sel
);
3711 SetVerticalScrollPos();
3713 MovePositionTo(newPos
, sel
);
3717 void Editor::ChangeCaseOfSelection(bool makeUpperCase
) {
3718 pdoc
->BeginUndoAction();
3719 int startCurrent
= currentPos
;
3720 int startAnchor
= anchor
;
3721 if (selType
== selStream
) {
3722 pdoc
->ChangeCase(Range(SelectionStart(), SelectionEnd()),
3724 SetSelection(startCurrent
, startAnchor
);
3726 SelectionLineIterator
lineIterator(this, false);
3727 while (lineIterator
.Iterate()) {
3729 Range(lineIterator
.startPos
, lineIterator
.endPos
),
3732 // Would be nicer to keep the rectangular selection but this is complex
3733 SetEmptySelection(startCurrent
);
3735 pdoc
->EndUndoAction();
3738 void Editor::LineTranspose() {
3739 int line
= pdoc
->LineFromPosition(currentPos
);
3741 int startPrev
= pdoc
->LineStart(line
- 1);
3742 int endPrev
= pdoc
->LineEnd(line
- 1);
3743 int start
= pdoc
->LineStart(line
);
3744 int end
= pdoc
->LineEnd(line
);
3745 int startNext
= pdoc
->LineStart(line
+ 1);
3746 if (end
< pdoc
->Length()) {
3748 char *thisLine
= CopyRange(start
, end
);
3749 pdoc
->DeleteChars(start
, end
- start
);
3750 if (pdoc
->InsertString(startPrev
, thisLine
, end
- start
)) {
3751 MovePositionTo(startPrev
+ end
- start
);
3755 // Last line so line has no line end
3756 char *thisLine
= CopyRange(start
, end
);
3757 char *prevEnd
= CopyRange(endPrev
, start
);
3758 pdoc
->DeleteChars(endPrev
, end
- endPrev
);
3759 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
3760 if (pdoc
->InsertString(startPrev
+ end
- start
, prevEnd
, start
- endPrev
)) {
3761 MovePositionTo(startPrev
+ end
- endPrev
);
3770 void Editor::LineDuplicate() {
3771 int line
= pdoc
->LineFromPosition(currentPos
);
3772 int start
= pdoc
->LineStart(line
);
3773 int end
= pdoc
->LineEnd(line
);
3774 char *thisLine
= CopyRange(start
, end
);
3775 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
3776 pdoc
->InsertString(end
, eol
);
3777 pdoc
->InsertString(end
+ istrlen(eol
), thisLine
, end
- start
);
3781 void Editor::CancelModes() {
3782 moveExtendsSelection
= false;
3785 void Editor::NewLine() {
3787 const char *eol
= "\n";
3788 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
3790 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
3792 } // else SC_EOL_LF -> "\n" already set
3793 if (pdoc
->InsertString(currentPos
, eol
)) {
3794 SetEmptySelection(currentPos
+ istrlen(eol
));
3801 EnsureCaretVisible();
3804 void Editor::CursorUpOrDown(int direction
, selTypes sel
) {
3805 Point pt
= LocationFromPosition(currentPos
);
3806 int posNew
= PositionFromLocation(
3807 Point(lastXChosen
, pt
.y
+ direction
* vs
.lineHeight
));
3808 if (direction
< 0) {
3809 // Line wrapping may lead to a location on the same line, so
3810 // seek back if that is the case.
3811 // There is an equivalent case when moving down which skips
3812 // over a line but as that does not trap the user it is fine.
3813 Point ptNew
= LocationFromPosition(posNew
);
3814 while ((posNew
> 0) && (pt
.y
== ptNew
.y
)) {
3816 ptNew
= LocationFromPosition(posNew
);
3819 MovePositionTo(posNew
, sel
);
3822 int Editor::StartEndDisplayLine(int pos
, bool start
) {
3824 int line
= pdoc
->LineFromPosition(pos
);
3825 AutoSurface
surface(this);
3826 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
3827 int posRet
= INVALID_POSITION
;
3828 if (surface
&& ll
) {
3829 unsigned int posLineStart
= pdoc
->LineStart(line
);
3830 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
3831 int posInLine
= pos
- posLineStart
;
3832 if (posInLine
<= ll
->maxLineLength
) {
3833 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
3834 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
3836 posRet
= ll
->LineStart(subLine
) + posLineStart
;
3838 if (subLine
== ll
->lines
- 1)
3839 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
;
3841 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
- 1;
3847 if (posRet
== INVALID_POSITION
) {
3854 int Editor::KeyCommand(unsigned int iMessage
) {
3859 case SCI_LINEDOWNEXTEND
:
3860 CursorUpOrDown(1, selStream
);
3862 case SCI_LINEDOWNRECTEXTEND
:
3863 CursorUpOrDown(1, selRectangle
);
3866 MovePositionTo(pdoc
->ParaDown(currentPos
));
3868 case SCI_PARADOWNEXTEND
:
3869 MovePositionTo(pdoc
->ParaDown(currentPos
), selStream
);
3871 case SCI_LINESCROLLDOWN
:
3872 ScrollTo(topLine
+ 1);
3873 MoveCaretInsideView(false);
3878 case SCI_LINEUPEXTEND
:
3879 CursorUpOrDown(-1, selStream
);
3881 case SCI_LINEUPRECTEXTEND
:
3882 CursorUpOrDown(-1, selRectangle
);
3885 MovePositionTo(pdoc
->ParaUp(currentPos
));
3887 case SCI_PARAUPEXTEND
:
3888 MovePositionTo(pdoc
->ParaUp(currentPos
), selStream
);
3890 case SCI_LINESCROLLUP
:
3891 ScrollTo(topLine
- 1);
3892 MoveCaretInsideView(false);
3895 if (SelectionEmpty() || moveExtendsSelection
) {
3896 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1));
3898 MovePositionTo(SelectionStart());
3902 case SCI_CHARLEFTEXTEND
:
3903 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), selStream
);
3906 case SCI_CHARLEFTRECTEXTEND
:
3907 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), selRectangle
);
3911 if (SelectionEmpty() || moveExtendsSelection
) {
3912 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1));
3914 MovePositionTo(SelectionEnd());
3918 case SCI_CHARRIGHTEXTEND
:
3919 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), selStream
);
3922 case SCI_CHARRIGHTRECTEXTEND
:
3923 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), selRectangle
);
3927 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1));
3930 case SCI_WORDLEFTEXTEND
:
3931 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1), selStream
);
3935 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1));
3938 case SCI_WORDRIGHTEXTEND
:
3939 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1), selStream
);
3943 case SCI_WORDLEFTEND
:
3944 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, -1), -1));
3947 case SCI_WORDLEFTENDEXTEND
:
3948 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, -1), -1), selStream
);
3951 case SCI_WORDRIGHTEND
:
3952 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, 1), 1));
3955 case SCI_WORDRIGHTENDEXTEND
:
3956 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, 1), 1), selStream
);
3961 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)));
3964 case SCI_HOMEEXTEND
:
3965 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), selStream
);
3968 case SCI_HOMERECTEXTEND
:
3969 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), selRectangle
);
3973 MovePositionTo(pdoc
->LineEndPosition(currentPos
));
3976 case SCI_LINEENDEXTEND
:
3977 MovePositionTo(pdoc
->LineEndPosition(currentPos
), selStream
);
3980 case SCI_LINEENDRECTEXTEND
:
3981 MovePositionTo(pdoc
->LineEndPosition(currentPos
), selRectangle
);
3984 case SCI_HOMEWRAP
: {
3985 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
3986 if (currentPos
<= homePos
)
3987 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
3988 MovePositionTo(homePos
);
3992 case SCI_HOMEWRAPEXTEND
: {
3993 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
3994 if (currentPos
<= homePos
)
3995 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
3996 MovePositionTo(homePos
, selStream
);
4000 case SCI_LINEENDWRAP
: {
4001 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
4002 if (currentPos
>= endPos
)
4003 endPos
= pdoc
->LineEndPosition(currentPos
);
4004 MovePositionTo(endPos
);
4008 case SCI_LINEENDWRAPEXTEND
: {
4009 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
4010 if (currentPos
>= endPos
)
4011 endPos
= pdoc
->LineEndPosition(currentPos
);
4012 MovePositionTo(endPos
, selStream
);
4016 case SCI_DOCUMENTSTART
:
4020 case SCI_DOCUMENTSTARTEXTEND
:
4021 MovePositionTo(0, selStream
);
4024 case SCI_DOCUMENTEND
:
4025 MovePositionTo(pdoc
->Length());
4028 case SCI_DOCUMENTENDEXTEND
:
4029 MovePositionTo(pdoc
->Length(), selStream
);
4032 case SCI_STUTTEREDPAGEUP
:
4033 PageMove(-1, noSel
, true);
4035 case SCI_STUTTEREDPAGEUPEXTEND
:
4036 PageMove(-1, selStream
, true);
4038 case SCI_STUTTEREDPAGEDOWN
:
4039 PageMove(1, noSel
, true);
4041 case SCI_STUTTEREDPAGEDOWNEXTEND
:
4042 PageMove(1, selStream
, true);
4047 case SCI_PAGEUPEXTEND
:
4048 PageMove(-1, selStream
);
4050 case SCI_PAGEUPRECTEXTEND
:
4051 PageMove(-1, selRectangle
);
4056 case SCI_PAGEDOWNEXTEND
:
4057 PageMove(1, selStream
);
4059 case SCI_PAGEDOWNRECTEXTEND
:
4060 PageMove(1, selRectangle
);
4062 case SCI_EDITTOGGLEOVERTYPE
:
4063 inOverstrike
= !inOverstrike
;
4065 ShowCaretAtCurrentPosition();
4068 case SCI_CANCEL
: // Cancel any modes - handled in subclass
4069 // Also unselect text
4072 case SCI_DELETEBACK
:
4075 EnsureCaretVisible();
4077 case SCI_DELETEBACKNOTLINE
:
4080 EnsureCaretVisible();
4085 EnsureCaretVisible();
4090 EnsureCaretVisible();
4099 MovePositionTo(pdoc
->VCHomePosition(currentPos
));
4102 case SCI_VCHOMEEXTEND
:
4103 MovePositionTo(pdoc
->VCHomePosition(currentPos
), selStream
);
4106 case SCI_VCHOMERECTEXTEND
:
4107 MovePositionTo(pdoc
->VCHomePosition(currentPos
), selRectangle
);
4110 case SCI_VCHOMEWRAP
: {
4111 int homePos
= pdoc
->VCHomePosition(currentPos
);
4112 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4113 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
4114 homePos
= viewLineStart
;
4116 MovePositionTo(homePos
);
4120 case SCI_VCHOMEWRAPEXTEND
: {
4121 int homePos
= pdoc
->VCHomePosition(currentPos
);
4122 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4123 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
4124 homePos
= viewLineStart
;
4126 MovePositionTo(homePos
, selStream
);
4131 if (vs
.zoomLevel
< 20) {
4133 InvalidateStyleRedraw();
4138 if (vs
.zoomLevel
> -10) {
4140 InvalidateStyleRedraw();
4144 case SCI_DELWORDLEFT
: {
4145 int startWord
= pdoc
->NextWordStart(currentPos
, -1);
4146 pdoc
->DeleteChars(startWord
, currentPos
- startWord
);
4150 case SCI_DELWORDRIGHT
: {
4151 int endWord
= pdoc
->NextWordStart(currentPos
, 1);
4152 pdoc
->DeleteChars(currentPos
, endWord
- currentPos
);
4155 case SCI_DELLINELEFT
: {
4156 int line
= pdoc
->LineFromPosition(currentPos
);
4157 int start
= pdoc
->LineStart(line
);
4158 pdoc
->DeleteChars(start
, currentPos
- start
);
4162 case SCI_DELLINERIGHT
: {
4163 int line
= pdoc
->LineFromPosition(currentPos
);
4164 int end
= pdoc
->LineEnd(line
);
4165 pdoc
->DeleteChars(currentPos
, end
- currentPos
);
4168 case SCI_LINECOPY
: {
4169 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4170 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4171 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
4172 pdoc
->LineStart(lineEnd
+ 1));
4176 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4177 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4178 int start
= pdoc
->LineStart(lineStart
);
4179 int end
= pdoc
->LineStart(lineEnd
+ 1);
4180 SetSelection(start
, end
);
4185 case SCI_LINEDELETE
: {
4186 int line
= pdoc
->LineFromPosition(currentPos
);
4187 int start
= pdoc
->LineStart(line
);
4188 int end
= pdoc
->LineStart(line
+ 1);
4189 pdoc
->DeleteChars(start
, end
- start
);
4192 case SCI_LINETRANSPOSE
:
4195 case SCI_LINEDUPLICATE
:
4199 ChangeCaseOfSelection(false);
4202 ChangeCaseOfSelection(true);
4204 case SCI_WORDPARTLEFT
:
4205 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1));
4208 case SCI_WORDPARTLEFTEXTEND
:
4209 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1), selStream
);
4212 case SCI_WORDPARTRIGHT
:
4213 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1));
4216 case SCI_WORDPARTRIGHTEXTEND
:
4217 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1), selStream
);
4220 case SCI_HOMEDISPLAY
:
4221 MovePositionTo(MovePositionSoVisible(
4222 StartEndDisplayLine(currentPos
, true), -1));
4225 case SCI_HOMEDISPLAYEXTEND
:
4226 MovePositionTo(MovePositionSoVisible(
4227 StartEndDisplayLine(currentPos
, true), -1), selStream
);
4230 case SCI_LINEENDDISPLAY
:
4231 MovePositionTo(MovePositionSoVisible(
4232 StartEndDisplayLine(currentPos
, false), 1));
4235 case SCI_LINEENDDISPLAYEXTEND
:
4236 MovePositionTo(MovePositionSoVisible(
4237 StartEndDisplayLine(currentPos
, false), 1), selStream
);
4244 int Editor::KeyDefault(int, int) {
4248 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
4250 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4251 (alt
? SCI_ALT
: 0);
4252 int msg
= kmap
.Find(key
, modifiers
);
4256 return WndProc(msg
, 0, 0);
4260 return KeyDefault(key
, modifiers
);
4264 void Editor::SetWhitespaceVisible(int view
) {
4265 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(view
);
4268 int Editor::GetWhitespaceVisible() {
4269 return vs
.viewWhitespace
;
4272 void Editor::Indent(bool forwards
) {
4273 //Platform::DebugPrintf("INdent %d\n", forwards);
4274 int lineOfAnchor
= pdoc
->LineFromPosition(anchor
);
4275 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
4276 if (lineOfAnchor
== lineCurrentPos
) {
4278 pdoc
->BeginUndoAction();
4280 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
4282 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4283 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
4284 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
+ indentationStep
);
4285 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4287 if (pdoc
->useTabs
) {
4288 pdoc
->InsertChar(currentPos
, '\t');
4289 SetEmptySelection(currentPos
+ 1);
4291 int numSpaces
= (pdoc
->tabInChars
) -
4292 (pdoc
->GetColumn(currentPos
) % (pdoc
->tabInChars
));
4294 numSpaces
= pdoc
->tabInChars
;
4295 for (int i
= 0; i
< numSpaces
; i
++) {
4296 pdoc
->InsertChar(currentPos
+ i
, ' ');
4298 SetEmptySelection(currentPos
+ numSpaces
);
4301 pdoc
->EndUndoAction();
4303 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
4305 pdoc
->BeginUndoAction();
4306 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4307 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
4308 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
4309 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4310 pdoc
->EndUndoAction();
4312 int newColumn
= ((pdoc
->GetColumn(currentPos
) - 1) / pdoc
->tabInChars
) *
4316 int newPos
= currentPos
;
4317 while (pdoc
->GetColumn(newPos
) > newColumn
)
4319 SetEmptySelection(newPos
);
4323 int anchorPosOnLine
= anchor
- pdoc
->LineStart(lineOfAnchor
);
4324 int currentPosPosOnLine
= currentPos
- pdoc
->LineStart(lineCurrentPos
);
4325 // Multiple lines selected so indent / dedent
4326 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
4327 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
4328 if (pdoc
->LineStart(lineBottomSel
) == anchor
|| pdoc
->LineStart(lineBottomSel
) == currentPos
)
4329 lineBottomSel
--; // If not selecting any characters on a line, do not indent
4330 pdoc
->BeginUndoAction();
4331 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
4332 pdoc
->EndUndoAction();
4333 if (lineOfAnchor
< lineCurrentPos
) {
4334 if (currentPosPosOnLine
== 0)
4335 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4337 SetSelection(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
4339 if (anchorPosOnLine
== 0)
4340 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4342 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
4348 * Search of a text in the document, in the given range.
4349 * @return The position of the found text, -1 if not found.
4351 long Editor::FindText(
4352 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4353 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4354 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
4356 TextToFind
*ft
= reinterpret_cast<TextToFind
*>(lParam
);
4357 int lengthFound
= istrlen(ft
->lpstrText
);
4358 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
4359 (wParam
& SCFIND_MATCHCASE
) != 0,
4360 (wParam
& SCFIND_WHOLEWORD
) != 0,
4361 (wParam
& SCFIND_WORDSTART
) != 0,
4362 (wParam
& SCFIND_REGEXP
) != 0,
4363 (wParam
& SCFIND_POSIX
) != 0,
4366 ft
->chrgText
.cpMin
= pos
;
4367 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
4373 * Relocatable search support : Searches relative to current selection
4374 * point and sets the selection to the found text range with
4378 * Anchor following searches at current selection start: This allows
4379 * multiple incremental interactive searches to be macro recorded
4380 * while still setting the selection to found text so the find/select
4381 * operation is self-contained.
4383 void Editor::SearchAnchor() {
4384 searchAnchor
= SelectionStart();
4388 * Find text from current search anchor: Must call @c SearchAnchor first.
4389 * Used for next text and previous text requests.
4390 * @return The position of the found text, -1 if not found.
4392 long Editor::SearchText(
4393 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
4394 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4395 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4396 sptr_t lParam
) { ///< The text to search for.
4398 const char *txt
= reinterpret_cast<char *>(lParam
);
4400 int lengthFound
= istrlen(txt
);
4401 if (iMessage
== SCI_SEARCHNEXT
) {
4402 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
4403 (wParam
& SCFIND_MATCHCASE
) != 0,
4404 (wParam
& SCFIND_WHOLEWORD
) != 0,
4405 (wParam
& SCFIND_WORDSTART
) != 0,
4406 (wParam
& SCFIND_REGEXP
) != 0,
4407 (wParam
& SCFIND_POSIX
) != 0,
4410 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
4411 (wParam
& SCFIND_MATCHCASE
) != 0,
4412 (wParam
& SCFIND_WHOLEWORD
) != 0,
4413 (wParam
& SCFIND_WORDSTART
) != 0,
4414 (wParam
& SCFIND_REGEXP
) != 0,
4415 (wParam
& SCFIND_POSIX
) != 0,
4420 SetSelection(pos
, pos
+ lengthFound
);
4427 * Search for text in the target range of the document.
4428 * @return The position of the found text, -1 if not found.
4430 long Editor::SearchInTarget(const char *text
, int length
) {
4431 int lengthFound
= length
;
4432 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
4433 (searchFlags
& SCFIND_MATCHCASE
) != 0,
4434 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
4435 (searchFlags
& SCFIND_WORDSTART
) != 0,
4436 (searchFlags
& SCFIND_REGEXP
) != 0,
4437 (searchFlags
& SCFIND_POSIX
) != 0,
4441 targetEnd
= pos
+ lengthFound
;
4446 void Editor::GoToLine(int lineNo
) {
4447 if (lineNo
> pdoc
->LinesTotal())
4448 lineNo
= pdoc
->LinesTotal();
4451 SetEmptySelection(pdoc
->LineStart(lineNo
));
4452 ShowCaretAtCurrentPosition();
4453 EnsureCaretVisible();
4456 static bool Close(Point pt1
, Point pt2
) {
4457 if (abs(pt1
.x
- pt2
.x
) > 3)
4459 if (abs(pt1
.y
- pt2
.y
) > 3)
4464 char *Editor::CopyRange(int start
, int end
) {
4467 int len
= end
- start
;
4468 text
= new char[len
+ 1];
4470 for (int i
= 0; i
< len
; i
++) {
4471 text
[i
] = pdoc
->CharAt(start
+ i
);
4479 void Editor::CopySelectionFromRange(SelectionText
*ss
, int start
, int end
) {
4480 ss
->Set(CopyRange(start
, end
), end
- start
+ 1, false);
4483 void Editor::CopySelectionRange(SelectionText
*ss
) {
4484 if (selType
== selStream
) {
4485 CopySelectionFromRange(ss
, SelectionStart(), SelectionEnd());
4489 SelectionLineIterator
lineIterator(this);
4490 while (lineIterator
.Iterate()) {
4491 size
+= lineIterator
.endPos
- lineIterator
.startPos
;
4492 if (selType
!= selLines
) {
4494 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
4500 text
= new char[size
+ 1];
4503 lineIterator
.Reset();
4504 while (lineIterator
.Iterate()) {
4505 for (int i
= lineIterator
.startPos
;
4506 i
< lineIterator
.endPos
;
4508 text
[j
++] = pdoc
->CharAt(i
);
4510 if (selType
!= selLines
) {
4511 if (pdoc
->eolMode
!= SC_EOL_LF
) {
4514 if (pdoc
->eolMode
!= SC_EOL_CR
) {
4522 ss
->Set(text
, size
+ 1, selType
== selRectangle
);
4526 void Editor::CopyRangeToClipboard(int start
, int end
) {
4527 start
= pdoc
->ClampPositionIntoDocument(start
);
4528 end
= pdoc
->ClampPositionIntoDocument(end
);
4529 SelectionText selectedText
;
4530 selectedText
.Set(CopyRange(start
, end
), end
- start
+ 1);
4531 CopyToClipboard(selectedText
);
4534 void Editor::CopyText(int length
, const char *text
) {
4535 SelectionText selectedText
;
4536 selectedText
.Copy(text
, length
);
4537 CopyToClipboard(selectedText
);
4540 void Editor::SetDragPosition(int newPos
) {
4542 newPos
= MovePositionOutsideChar(newPos
, 1);
4545 if (posDrag
!= newPos
) {
4554 void Editor::DisplayCursor(Window::Cursor c
) {
4555 if (cursorMode
== SC_CURSORNORMAL
)
4558 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
4561 void Editor::StartDrag() {
4562 // Always handled by subclasses
4563 //SetMouseCapture(true);
4564 //DisplayCursor(Window::cursorArrow);
4567 void Editor::DropAt(int position
, const char *value
, bool moving
, bool rectangular
) {
4568 //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
4570 dropWentOutside
= false;
4572 int positionWasInSelection
= PositionInSelection(position
);
4574 bool positionOnEdgeOfSelection
=
4575 (position
== SelectionStart()) || (position
== SelectionEnd());
4577 if ((!inDragDrop
) || !(0 == positionWasInSelection
) ||
4578 (positionOnEdgeOfSelection
&& !moving
)) {
4580 int selStart
= SelectionStart();
4581 int selEnd
= SelectionEnd();
4583 pdoc
->BeginUndoAction();
4585 int positionAfterDeletion
= position
;
4586 if (inDragDrop
&& moving
) {
4587 // Remove dragged out text
4588 if (rectangular
|| selType
== selLines
) {
4589 SelectionLineIterator
lineIterator(this);
4590 while (lineIterator
.Iterate()) {
4591 if (position
>= lineIterator
.startPos
) {
4592 if (position
> lineIterator
.endPos
) {
4593 positionAfterDeletion
-= lineIterator
.endPos
- lineIterator
.startPos
;
4595 positionAfterDeletion
-= position
- lineIterator
.startPos
;
4600 if (position
> selStart
) {
4601 positionAfterDeletion
-= selEnd
- selStart
;
4606 position
= positionAfterDeletion
;
4609 PasteRectangular(position
, value
, istrlen(value
));
4610 pdoc
->EndUndoAction();
4611 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
4612 SetEmptySelection(position
);
4614 position
= MovePositionOutsideChar(position
, currentPos
- position
);
4615 if (pdoc
->InsertString(position
, value
)) {
4616 SetSelection(position
+ istrlen(value
), position
);
4618 pdoc
->EndUndoAction();
4620 } else if (inDragDrop
) {
4621 SetEmptySelection(position
);
4626 * @return -1 if given position is before the selection,
4627 * 1 if position is after the selection,
4628 * 0 if position is inside the selection,
4630 int Editor::PositionInSelection(int pos
) {
4631 pos
= MovePositionOutsideChar(pos
, currentPos
- pos
);
4632 if (pos
< SelectionStart()) {
4635 if (pos
> SelectionEnd()) {
4638 if (selType
== selStream
) {
4641 SelectionLineIterator
lineIterator(this);
4642 lineIterator
.SetAt(pdoc
->LineFromPosition(pos
));
4643 if (pos
< lineIterator
.startPos
) {
4645 } else if (pos
> lineIterator
.endPos
) {
4653 bool Editor::PointInSelection(Point pt
) {
4654 int pos
= PositionFromLocation(pt
);
4655 if (0 == PositionInSelection(pos
)) {
4656 // Probably inside, but we must make a finer test
4657 int selStart
, selEnd
;
4658 if (selType
== selStream
) {
4659 selStart
= SelectionStart();
4660 selEnd
= SelectionEnd();
4662 SelectionLineIterator
lineIterator(this);
4663 lineIterator
.SetAt(pdoc
->LineFromPosition(pos
));
4664 selStart
= lineIterator
.startPos
;
4665 selEnd
= lineIterator
.endPos
;
4667 if (pos
== selStart
) {
4668 // see if just before selection
4669 Point locStart
= LocationFromPosition(pos
);
4670 if (pt
.x
< locStart
.x
) {
4674 if (pos
== selEnd
) {
4675 // see if just after selection
4676 Point locEnd
= LocationFromPosition(pos
);
4677 if (pt
.x
> locEnd
.x
) {
4686 bool Editor::PointInSelMargin(Point pt
) {
4687 // Really means: "Point in a margin"
4688 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4689 PRectangle rcSelMargin
= GetClientRectangle();
4690 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
4691 return rcSelMargin
.Contains(pt
);
4697 void Editor::LineSelection(int lineCurrent_
, int lineAnchor_
) {
4698 if (lineAnchor_
< lineCurrent_
) {
4699 SetSelection(pdoc
->LineStart(lineCurrent_
+ 1),
4700 pdoc
->LineStart(lineAnchor_
));
4701 } else if (lineAnchor_
> lineCurrent_
) {
4702 SetSelection(pdoc
->LineStart(lineCurrent_
),
4703 pdoc
->LineStart(lineAnchor_
+ 1));
4704 } else { // Same line, select it
4705 SetSelection(pdoc
->LineStart(lineAnchor_
+ 1),
4706 pdoc
->LineStart(lineAnchor_
));
4710 void Editor::DwellEnd(bool mouseMoved
) {
4712 ticksToDwell
= dwellDelay
;
4714 ticksToDwell
= SC_TIME_FOREVER
;
4715 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4717 NotifyDwelling(ptMouseLast
, dwelling
);
4721 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
4722 //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
4724 int newPos
= PositionFromLocation(pt
);
4725 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
4727 moveExtendsSelection
= false;
4729 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
4733 bool inSelMargin
= PointInSelMargin(pt
);
4734 if (shift
& !inSelMargin
) {
4735 SetSelection(newPos
);
4737 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
4738 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
4739 SetMouseCapture(true);
4740 SetEmptySelection(newPos
);
4741 bool doubleClick
= false;
4742 // Stop mouse button bounce changing selection type
4743 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
4744 if (selectionType
== selChar
) {
4745 selectionType
= selWord
;
4747 } else if (selectionType
== selWord
) {
4748 selectionType
= selLine
;
4750 selectionType
= selChar
;
4751 originalAnchorPos
= currentPos
;
4755 if (selectionType
== selWord
) {
4756 if (currentPos
>= originalAnchorPos
) { // Moved forward
4757 SetSelection(pdoc
->ExtendWordSelect(currentPos
, 1),
4758 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
4759 } else { // Moved backward
4760 SetSelection(pdoc
->ExtendWordSelect(currentPos
, -1),
4761 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
4763 } else if (selectionType
== selLine
) {
4764 lineAnchor
= LineFromLocation(pt
);
4765 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
4766 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
4768 SetEmptySelection(currentPos
);
4770 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
4772 NotifyDoubleClick(pt
, shift
);
4773 if (PointIsHotspot(newPos
))
4774 NotifyHotSpotDoubleClicked(newPos
, shift
, ctrl
, alt
);
4776 } else { // Single click
4778 selType
= selStream
;
4781 lastClickTime
= curTime
;
4785 lineAnchor
= LineFromLocation(pt
);
4786 // Single click in margin: select whole line
4787 LineSelection(lineAnchor
, lineAnchor
);
4788 SetSelection(pdoc
->LineStart(lineAnchor
+ 1),
4789 pdoc
->LineStart(lineAnchor
));
4791 // Single shift+click in margin: select from line anchor to clicked line
4792 if (anchor
> currentPos
)
4793 lineAnchor
= pdoc
->LineFromPosition(anchor
- 1);
4795 lineAnchor
= pdoc
->LineFromPosition(anchor
);
4796 int lineStart
= LineFromLocation(pt
);
4797 LineSelection(lineStart
, lineAnchor
);
4798 //lineAnchor = lineStart; // Keep the same anchor for ButtonMove
4801 SetDragPosition(invalidPosition
);
4802 SetMouseCapture(true);
4803 selectionType
= selLine
;
4805 if (PointIsHotspot(pt
)) {
4806 NotifyHotSpotClicked(newPos
, shift
, ctrl
, alt
);
4809 inDragDrop
= PointInSelection(pt
);
4812 SetMouseCapture(false);
4813 SetDragPosition(newPos
);
4814 CopySelectionRange(&drag
);
4817 SetDragPosition(invalidPosition
);
4818 SetMouseCapture(true);
4820 SetEmptySelection(newPos
);
4822 selType
= alt
? selRectangle
: selStream
;
4823 xStartSelect
= xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4824 selectionType
= selChar
;
4825 originalAnchorPos
= currentPos
;
4829 lastClickTime
= curTime
;
4831 ShowCaretAtCurrentPosition();
4834 bool Editor::PositionIsHotspot(int position
) {
4835 return vs
.styles
[pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
].hotspot
;
4838 bool Editor::PointIsHotspot(Point pt
) {
4839 int pos
= PositionFromLocationClose(pt
);
4840 if (pos
== INVALID_POSITION
)
4842 return PositionIsHotspot(pos
);
4845 void Editor::SetHotSpotRange(Point
*pt
) {
4847 int pos
= PositionFromLocation(*pt
);
4849 // If we don't limit this to word characters then the
4850 // range can encompass more than the run range and then
4851 // the underline will not be drawn properly.
4852 int hsStart_
= pdoc
->ExtendStyleRange(pos
, -1, vs
.hotspotSingleLine
);
4853 int hsEnd_
= pdoc
->ExtendStyleRange(pos
, 1, vs
.hotspotSingleLine
);
4855 // Only invalidate the range if the hotspot range has changed...
4856 if (hsStart_
!= hsStart
|| hsEnd_
!= hsEnd
) {
4857 if (hsStart
!= -1) {
4858 InvalidateRange(hsStart
, hsEnd
);
4862 InvalidateRange(hsStart
, hsEnd
);
4865 if (hsStart
!= -1) {
4866 int hsStart_
= hsStart
;
4870 InvalidateRange(hsStart_
, hsEnd_
);
4878 void Editor::GetHotSpotRange(int& hsStart_
, int& hsEnd_
) {
4883 void Editor::ButtonMove(Point pt
) {
4884 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
4888 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
4889 if (HaveMouseCapture()) {
4891 // Slow down autoscrolling/selection
4892 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
4893 if (autoScrollTimer
.ticksToWait
> 0)
4895 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
4898 int movePos
= PositionFromLocation(pt
);
4899 movePos
= MovePositionOutsideChar(movePos
, currentPos
- movePos
);
4901 SetDragPosition(movePos
);
4903 if (selectionType
== selChar
) {
4904 SetSelection(movePos
);
4905 } else if (selectionType
== selWord
) {
4906 // Continue selecting by word
4907 if (movePos
== originalAnchorPos
) { // Didn't move
4908 // No need to do anything. Previously this case was lumped
4909 // in with "Moved forward", but that can be harmful in this
4910 // case: a handler for the NotifyDoubleClick re-adjusts
4911 // the selection for a fancier definition of "word" (for
4912 // example, in Perl it is useful to include the leading
4913 // '$', '%' or '@' on variables for word selection). In this
4914 // the ButtonMove() called via Tick() for auto-scrolling
4915 // could result in the fancier word selection adjustment
4917 } else if (movePos
> originalAnchorPos
) { // Moved forward
4918 SetSelection(pdoc
->ExtendWordSelect(movePos
, 1),
4919 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
4920 } else { // Moved backward
4921 SetSelection(pdoc
->ExtendWordSelect(movePos
, -1),
4922 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
4925 // Continue selecting by line
4926 int lineMove
= LineFromLocation(pt
);
4927 LineSelection(lineMove
, lineAnchor
);
4930 // While dragging to make rectangular selection, we don't want the current
4931 // position to jump to the end of smaller or empty lines.
4932 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4935 PRectangle rcClient
= GetClientRectangle();
4936 if (pt
.y
> rcClient
.bottom
) {
4937 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
4939 lineMove
= cs
.DisplayFromDoc(pdoc
->LinesTotal() - 1);
4941 ScrollTo(lineMove
- LinesOnScreen() + 5);
4943 } else if (pt
.y
< rcClient
.top
) {
4944 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
4945 ScrollTo(lineMove
- 5);
4948 EnsureCaretVisible(false, false, true);
4950 if (hsStart
!= -1 && !PositionIsHotspot(movePos
))
4951 SetHotSpotRange(NULL
);
4954 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4955 if (PointInSelMargin(pt
)) {
4956 DisplayCursor(Window::cursorReverseArrow
);
4957 return; // No need to test for selection
4960 // Display regular (drag) cursor over selection
4961 if (PointInSelection(pt
)) {
4962 DisplayCursor(Window::cursorArrow
);
4963 } else if (PointIsHotspot(pt
)) {
4964 DisplayCursor(Window::cursorHand
);
4965 SetHotSpotRange(&pt
);
4967 DisplayCursor(Window::cursorText
);
4968 SetHotSpotRange(NULL
);
4973 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
4974 //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
4975 if (HaveMouseCapture()) {
4976 if (PointInSelMargin(pt
)) {
4977 DisplayCursor(Window::cursorReverseArrow
);
4979 DisplayCursor(Window::cursorText
);
4980 SetHotSpotRange(NULL
);
4983 SetMouseCapture(false);
4984 int newPos
= PositionFromLocation(pt
);
4985 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
4987 int selStart
= SelectionStart();
4988 int selEnd
= SelectionEnd();
4989 if (selStart
< selEnd
) {
4992 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
4993 SetSelection(newPos
, newPos
+ drag
.len
);
4995 } else if (newPos
< selStart
) {
4996 pdoc
->DeleteChars(selStart
, drag
.len
);
4997 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
4998 SetSelection(newPos
, newPos
+ drag
.len
);
5000 } else if (newPos
> selEnd
) {
5001 pdoc
->DeleteChars(selStart
, drag
.len
);
5003 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5004 SetSelection(newPos
, newPos
+ drag
.len
);
5007 SetEmptySelection(newPos
);
5011 selectionType
= selChar
;
5014 if (selectionType
== selChar
) {
5015 SetSelection(newPos
);
5018 // Now we rely on the current pos to compute rectangular selection
5019 xStartSelect
= XFromPosition(anchor
);
5020 xEndSelect
= XFromPosition(currentPos
);
5021 lastClickTime
= curTime
;
5024 if (selType
== selStream
) {
5028 EnsureCaretVisible(false);
5032 // Called frequently to perform background UI including
5033 // caret blinking and automatic scrolling.
5034 void Editor::Tick() {
5035 if (HaveMouseCapture()) {
5037 ButtonMove(ptMouseLast
);
5039 if (caret
.period
> 0) {
5040 timer
.ticksToWait
-= timer
.tickSize
;
5041 if (timer
.ticksToWait
<= 0) {
5042 caret
.on
= !caret
.on
;
5043 timer
.ticksToWait
= caret
.period
;
5047 if ((dwellDelay
< SC_TIME_FOREVER
) &&
5048 (ticksToDwell
> 0) &&
5049 (!HaveMouseCapture())) {
5050 ticksToDwell
-= timer
.tickSize
;
5051 if (ticksToDwell
<= 0) {
5053 NotifyDwelling(ptMouseLast
, dwelling
);
5058 bool Editor::Idle() {
5062 bool wrappingDone
= (wrapState
== eWrapNone
) || (!backgroundWrapEnabled
);
5064 if (!wrappingDone
) {
5065 // Wrap lines during idle.
5066 WrapLines(false, -1);
5068 if (docLineLastWrapped
== docLastLineToWrap
)
5069 wrappingDone
= true;
5072 // Add more idle things to do here, but make sure idleDone is
5073 // set correctly before the function returns. returning
5074 // false will stop calling this idle funtion until SetIdle() is
5077 idleDone
= wrappingDone
; // && thatDone && theOtherThingDone...
5082 void Editor::SetFocusState(bool focusState
) {
5083 hasFocus
= focusState
;
5084 NotifyFocus(hasFocus
);
5086 ShowCaretAtCurrentPosition();
5093 static bool IsIn(int a
, int minimum
, int maximum
) {
5094 return (a
>= minimum
) && (a
<= maximum
);
5097 static bool IsOverlap(int mina
, int maxa
, int minb
, int maxb
) {
5099 IsIn(mina
, minb
, maxb
) ||
5100 IsIn(maxa
, minb
, maxb
) ||
5101 IsIn(minb
, mina
, maxa
) ||
5102 IsIn(maxb
, mina
, maxa
);
5105 void Editor::CheckForChangeOutsidePaint(Range r
) {
5106 if (paintState
== painting
&& !paintingAllText
) {
5107 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
5111 PRectangle rcText
= GetTextRectangle();
5112 // Determine number of lines displayed including a possible partially displayed last line
5113 int linesDisplayed
= (rcText
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1;
5114 int bottomLine
= topLine
+ linesDisplayed
- 1;
5116 int lineRangeStart
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.start
));
5117 int lineRangeEnd
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.end
));
5118 if (!IsOverlap(topLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
5119 //Platform::DebugPrintf("No overlap (%d-%d) with window(%d-%d)\n",
5120 // lineRangeStart, lineRangeEnd, topLine, bottomLine);
5124 // Assert rcPaint contained within or equal to rcText
5125 if (rcPaint
.top
> rcText
.top
) {
5126 // does range intersect rcText.top .. rcPaint.top
5127 int paintTopLine
= ((rcPaint
.top
- rcText
.top
- 1) / vs
.lineHeight
) + topLine
;
5128 // paintTopLine is the top line of the paint rectangle or the line just above if that line is completely inside the paint rectangle
5129 if (IsOverlap(topLine
, paintTopLine
, lineRangeStart
, lineRangeEnd
)) {
5130 //Platform::DebugPrintf("Change (%d-%d) in top npv(%d-%d)\n",
5131 // lineRangeStart, lineRangeEnd, topLine, paintTopLine);
5136 if (rcPaint
.bottom
< rcText
.bottom
) {
5137 // does range intersect rcPaint.bottom .. rcText.bottom
5138 int paintBottomLine
= ((rcPaint
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1) + topLine
;
5139 // paintTopLine is the bottom line of the paint rectangle or the line just below if that line is completely inside the paint rectangle
5140 if (IsOverlap(paintBottomLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
5141 //Platform::DebugPrintf("Change (%d-%d) in bottom npv(%d-%d)\n",
5142 // lineRangeStart, lineRangeEnd, paintBottomLine, bottomLine);
5150 char BraceOpposite(char ch
) {
5173 // TODO: should be able to extend styled region to find matching brace
5174 // TODO: may need to make DBCS safe
5175 // so should be moved into Document
5176 int Editor::BraceMatch(int position
, int /*maxReStyle*/) {
5177 char chBrace
= pdoc
->CharAt(position
);
5178 char chSeek
= BraceOpposite(chBrace
);
5181 char styBrace
= static_cast<char>(
5182 pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
5184 if (chBrace
== '(' || chBrace
== '[' || chBrace
== '{' || chBrace
== '<')
5187 position
= position
+ direction
;
5188 while ((position
>= 0) && (position
< pdoc
->Length())) {
5189 char chAtPos
= pdoc
->CharAt(position
);
5190 char styAtPos
= static_cast<char>(pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
5191 if ((position
> pdoc
->GetEndStyled()) || (styAtPos
== styBrace
)) {
5192 if (chAtPos
== chBrace
)
5194 if (chAtPos
== chSeek
)
5199 position
= position
+ direction
;
5204 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
5205 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
5206 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
5207 CheckForChangeOutsidePaint(Range(braces
[0]));
5208 CheckForChangeOutsidePaint(Range(pos0
));
5211 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
5212 CheckForChangeOutsidePaint(Range(braces
[1]));
5213 CheckForChangeOutsidePaint(Range(pos1
));
5216 bracesMatchStyle
= matchStyle
;
5217 if (paintState
== notPainting
) {
5223 void Editor::SetDocPointer(Document
*document
) {
5224 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
5225 pdoc
->RemoveWatcher(this, 0);
5227 if (document
== NULL
) {
5228 pdoc
= new Document();
5234 // Ensure all positions within document
5235 selType
= selStream
;
5241 // Reset the contraction state to fully shown.
5243 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
5247 pdoc
->AddWatcher(this, 0);
5253 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
5255 void Editor::Expand(int &line
, bool doExpand
) {
5256 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5258 while (line
<= lineMaxSubord
) {
5260 cs
.SetVisible(line
, line
, true);
5261 int level
= pdoc
->GetLevel(line
);
5262 if (level
& SC_FOLDLEVELHEADERFLAG
) {
5263 if (doExpand
&& cs
.GetExpanded(line
)) {
5266 Expand(line
, false);
5274 void Editor::ToggleContraction(int line
) {
5275 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
5276 if (cs
.GetExpanded(line
)) {
5277 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5278 cs
.SetExpanded(line
, 0);
5279 if (lineMaxSubord
> line
) {
5280 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
5285 cs
.SetExpanded(line
, 1);
5294 * Recurse up from this line to find any folds that prevent this line from being visible
5295 * and unfold them all.
5297 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
5299 // In case in need of wrapping to ensure DisplayFromDoc works.
5300 WrapLines(true, -1);
5302 if (!cs
.GetVisible(lineDoc
)) {
5303 int lineParent
= pdoc
->GetFoldParent(lineDoc
);
5304 if (lineParent
>= 0) {
5305 if (lineDoc
!= lineParent
)
5306 EnsureLineVisible(lineParent
, enforcePolicy
);
5307 if (!cs
.GetExpanded(lineParent
)) {
5308 cs
.SetExpanded(lineParent
, 1);
5309 Expand(lineParent
, true);
5315 if (enforcePolicy
) {
5316 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
5317 if (visiblePolicy
& VISIBLE_SLOP
) {
5318 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
5319 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
5320 SetVerticalScrollPos();
5322 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
5323 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
5324 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
5325 SetVerticalScrollPos();
5329 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
5330 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
5331 SetVerticalScrollPos();
5338 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
5339 pdoc
->BeginUndoAction();
5341 length
= istrlen(text
);
5342 if (replacePatterns
) {
5343 text
= pdoc
->SubstituteByPosition(text
, &length
);
5347 if (targetStart
!= targetEnd
)
5348 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
5349 targetEnd
= targetStart
;
5350 pdoc
->InsertString(targetStart
, text
, length
);
5351 targetEnd
= targetStart
+ length
;
5352 pdoc
->EndUndoAction();
5356 bool Editor::IsUnicodeMode() const {
5357 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
5360 int Editor::CodePage() const {
5362 return pdoc
->dbcsCodePage
;
5367 static bool ValidMargin(unsigned long wParam
) {
5368 return wParam
< ViewStyle::margins
;
5371 static char *CharPtrFromSPtr(sptr_t lParam
) {
5372 return reinterpret_cast<char *>(lParam
);
5375 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5376 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
5378 // Optional macro recording hook
5380 NotifyMacroRecord(iMessage
, wParam
, lParam
);
5389 char *ptr
= CharPtrFromSPtr(lParam
);
5390 unsigned int iChar
= 0;
5391 for (; iChar
< wParam
- 1; iChar
++)
5392 ptr
[iChar
] = pdoc
->CharAt(iChar
);
5400 pdoc
->DeleteChars(0, pdoc
->Length());
5401 SetEmptySelection(0);
5402 pdoc
->InsertString(0, CharPtrFromSPtr(lParam
));
5406 case SCI_GETTEXTLENGTH
:
5407 return pdoc
->Length();
5419 CopyRangeToClipboard(wParam
, lParam
);
5423 CopyText(wParam
, CharPtrFromSPtr(lParam
));
5429 EnsureCaretVisible();
5435 EnsureCaretVisible();
5444 return pdoc
->CanUndo() ? 1 : 0;
5446 case SCI_EMPTYUNDOBUFFER
:
5447 pdoc
->DeleteUndoHistory();
5450 case SCI_GETFIRSTVISIBLELINE
:
5453 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
5457 int lineStart
= pdoc
->LineStart(wParam
);
5458 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
5459 char *ptr
= CharPtrFromSPtr(lParam
);
5461 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
5462 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5467 case SCI_GETLINECOUNT
:
5468 if (pdoc
->LinesTotal() == 0)
5471 return pdoc
->LinesTotal();
5474 return !pdoc
->IsSavePoint();
5477 int nStart
= static_cast<int>(wParam
);
5478 int nEnd
= static_cast<int>(lParam
);
5480 nEnd
= pdoc
->Length();
5482 nStart
= nEnd
; // Remove selection
5483 selType
= selStream
;
5484 SetSelection(nEnd
, nStart
);
5485 EnsureCaretVisible();
5489 case SCI_GETSELTEXT
: {
5492 SelectionText selectedText
;
5493 CopySelectionRange(&selectedText
);
5494 char *ptr
= CharPtrFromSPtr(lParam
);
5496 if (selectedText
.len
) {
5497 for (; iChar
< selectedText
.len
; iChar
++)
5498 ptr
[iChar
] = selectedText
.s
[iChar
];
5505 case SCI_LINEFROMPOSITION
:
5506 if (static_cast<int>(wParam
) < 0)
5508 return pdoc
->LineFromPosition(wParam
);
5510 case SCI_POSITIONFROMLINE
:
5511 if (static_cast<int>(wParam
) < 0)
5512 wParam
= pdoc
->LineFromPosition(SelectionStart());
5514 return 0; // Even if there is no text, there is a first line that starts at 0
5515 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
5517 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
5519 return pdoc
->LineStart(wParam
);
5521 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
5522 case SCI_LINELENGTH
:
5523 if ((static_cast<int>(wParam
) < 0) ||
5524 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
5526 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
5528 case SCI_REPLACESEL
: {
5531 pdoc
->BeginUndoAction();
5533 char *replacement
= CharPtrFromSPtr(lParam
);
5534 pdoc
->InsertString(currentPos
, replacement
);
5535 pdoc
->EndUndoAction();
5536 SetEmptySelection(currentPos
+ istrlen(replacement
));
5537 EnsureCaretVisible();
5541 case SCI_SETTARGETSTART
:
5542 targetStart
= wParam
;
5545 case SCI_GETTARGETSTART
:
5548 case SCI_SETTARGETEND
:
5552 case SCI_GETTARGETEND
:
5555 case SCI_TARGETFROMSELECTION
:
5556 if (currentPos
< anchor
) {
5557 targetStart
= currentPos
;
5560 targetStart
= anchor
;
5561 targetEnd
= currentPos
;
5565 case SCI_REPLACETARGET
:
5566 PLATFORM_ASSERT(lParam
);
5567 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), wParam
);
5569 case SCI_REPLACETARGETRE
:
5570 PLATFORM_ASSERT(lParam
);
5571 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), wParam
);
5573 case SCI_SEARCHINTARGET
:
5574 PLATFORM_ASSERT(lParam
);
5575 return SearchInTarget(CharPtrFromSPtr(lParam
), wParam
);
5577 case SCI_SETSEARCHFLAGS
:
5578 searchFlags
= wParam
;
5581 case SCI_GETSEARCHFLAGS
:
5584 case SCI_POSITIONBEFORE
:
5585 return pdoc
->MovePositionOutsideChar(wParam
-1, -1, true);
5587 case SCI_POSITIONAFTER
:
5588 return pdoc
->MovePositionOutsideChar(wParam
+1, 1, true);
5590 case SCI_LINESCROLL
:
5591 ScrollTo(topLine
+ lParam
);
5592 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
5595 case SCI_SETXOFFSET
:
5597 SetHorizontalScrollPos();
5601 case SCI_GETXOFFSET
:
5604 case SCI_CHOOSECARETX
:
5608 case SCI_SCROLLCARET
:
5609 EnsureCaretVisible();
5612 case SCI_SETREADONLY
:
5613 pdoc
->SetReadOnly(wParam
!= 0);
5616 case SCI_GETREADONLY
:
5617 return pdoc
->IsReadOnly();
5622 case SCI_POINTXFROMPOSITION
:
5626 Point pt
= LocationFromPosition(lParam
);
5630 case SCI_POINTYFROMPOSITION
:
5634 Point pt
= LocationFromPosition(lParam
);
5639 return FindText(wParam
, lParam
);
5641 case SCI_GETTEXTRANGE
: {
5644 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
5645 int cpMax
= tr
->chrg
.cpMax
;
5647 cpMax
= pdoc
->Length();
5648 PLATFORM_ASSERT(cpMax
<= pdoc
->Length());
5649 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
5650 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
5651 // Spec says copied text is terminated with a NUL
5652 tr
->lpstrText
[len
] = '\0';
5653 return len
; // Not including NUL
5656 case SCI_HIDESELECTION
:
5657 hideSelection
= wParam
!= 0;
5661 case SCI_FORMATRANGE
:
5662 return FormatRange(wParam
!= 0, reinterpret_cast<RangeToFormat
*>(lParam
));
5664 case SCI_GETMARGINLEFT
:
5665 return vs
.leftMarginWidth
;
5667 case SCI_GETMARGINRIGHT
:
5668 return vs
.rightMarginWidth
;
5670 case SCI_SETMARGINLEFT
:
5671 vs
.leftMarginWidth
= lParam
;
5672 InvalidateStyleRedraw();
5675 case SCI_SETMARGINRIGHT
:
5676 vs
.rightMarginWidth
= lParam
;
5677 InvalidateStyleRedraw();
5680 // Control specific mesages
5685 pdoc
->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam
), wParam
);
5686 SetEmptySelection(currentPos
+ wParam
);
5690 case SCI_ADDSTYLEDTEXT
: {
5693 pdoc
->InsertStyledString(CurrentPosition() * 2, CharPtrFromSPtr(lParam
), wParam
);
5694 SetEmptySelection(currentPos
+ wParam
/ 2);
5698 case SCI_INSERTTEXT
: {
5701 int insertPos
= wParam
;
5702 if (static_cast<int>(wParam
) == -1)
5703 insertPos
= CurrentPosition();
5704 int newCurrent
= CurrentPosition();
5705 char *sz
= CharPtrFromSPtr(lParam
);
5706 pdoc
->InsertString(insertPos
, sz
);
5707 if (newCurrent
> insertPos
)
5708 newCurrent
+= istrlen(sz
);
5709 SetEmptySelection(newCurrent
);
5713 case SCI_APPENDTEXT
:
5714 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), wParam
);
5721 case SCI_CLEARDOCUMENTSTYLE
:
5722 ClearDocumentStyle();
5725 case SCI_SETUNDOCOLLECTION
:
5726 pdoc
->SetUndoCollection(wParam
!= 0);
5729 case SCI_GETUNDOCOLLECTION
:
5730 return pdoc
->IsCollectingUndo();
5732 case SCI_BEGINUNDOACTION
:
5733 pdoc
->BeginUndoAction();
5736 case SCI_ENDUNDOACTION
:
5737 pdoc
->EndUndoAction();
5740 case SCI_GETCARETPERIOD
:
5741 return caret
.period
;
5743 case SCI_SETCARETPERIOD
:
5744 caret
.period
= wParam
;
5747 case SCI_SETWORDCHARS
: {
5748 pdoc
->SetDefaultCharClasses();
5751 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), Document::ccWord
);
5755 case SCI_SETWHITESPACECHARS
: {
5758 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), Document::ccSpace
);
5762 case SCI_SETCHARSDEFAULT
:
5763 pdoc
->SetDefaultCharClasses();
5767 return pdoc
->Length();
5770 return pdoc
->CharAt(wParam
);
5772 case SCI_SETCURRENTPOS
:
5773 SetSelection(wParam
, anchor
);
5776 case SCI_GETCURRENTPOS
:
5780 SetSelection(currentPos
, wParam
);
5786 case SCI_SETSELECTIONSTART
:
5787 SetSelection(Platform::Maximum(currentPos
, wParam
), wParam
);
5790 case SCI_GETSELECTIONSTART
:
5791 return Platform::Minimum(anchor
, currentPos
);
5793 case SCI_SETSELECTIONEND
:
5794 SetSelection(wParam
, Platform::Minimum(anchor
, wParam
));
5797 case SCI_GETSELECTIONEND
:
5798 return Platform::Maximum(anchor
, currentPos
);
5800 case SCI_SETPRINTMAGNIFICATION
:
5801 printMagnification
= wParam
;
5804 case SCI_GETPRINTMAGNIFICATION
:
5805 return printMagnification
;
5807 case SCI_SETPRINTCOLOURMODE
:
5808 printColourMode
= wParam
;
5811 case SCI_GETPRINTCOLOURMODE
:
5812 return printColourMode
;
5814 case SCI_SETPRINTWRAPMODE
:
5815 printWrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
5818 case SCI_GETPRINTWRAPMODE
:
5819 return printWrapState
;
5821 case SCI_GETSTYLEAT
:
5822 if (static_cast<int>(wParam
) >= pdoc
->Length())
5825 return pdoc
->StyleAt(wParam
);
5835 case SCI_SETSAVEPOINT
:
5836 pdoc
->SetSavePoint();
5839 case SCI_GETSTYLEDTEXT
: {
5842 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
5844 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
5845 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
5846 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
5848 tr
->lpstrText
[iPlace
] = '\0';
5849 tr
->lpstrText
[iPlace
+ 1] = '\0';
5854 return pdoc
->CanRedo() ? 1 : 0;
5856 case SCI_MARKERLINEFROMHANDLE
:
5857 return pdoc
->LineFromHandle(wParam
);
5859 case SCI_MARKERDELETEHANDLE
:
5860 pdoc
->DeleteMarkFromHandle(wParam
);
5864 return vs
.viewWhitespace
;
5867 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
5871 case SCI_POSITIONFROMPOINT
:
5872 return PositionFromLocation(Point(wParam
, lParam
));
5874 case SCI_POSITIONFROMPOINTCLOSE
:
5875 return PositionFromLocationClose(Point(wParam
, lParam
));
5882 SetEmptySelection(wParam
);
5883 EnsureCaretVisible();
5887 case SCI_GETCURLINE
: {
5891 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
5892 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
5893 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
5894 char *ptr
= CharPtrFromSPtr(lParam
);
5895 unsigned int iPlace
= 0;
5896 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
5897 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5900 return currentPos
- lineStart
;
5903 case SCI_GETENDSTYLED
:
5904 return pdoc
->GetEndStyled();
5906 case SCI_GETEOLMODE
:
5907 return pdoc
->eolMode
;
5909 case SCI_SETEOLMODE
:
5910 pdoc
->eolMode
= wParam
;
5913 case SCI_STARTSTYLING
:
5914 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
5917 case SCI_SETSTYLING
:
5918 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
5921 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
5924 pdoc
->SetStyles(wParam
, CharPtrFromSPtr(lParam
));
5927 case SCI_SETBUFFEREDDRAW
:
5928 bufferedDraw
= wParam
!= 0;
5931 case SCI_GETBUFFEREDDRAW
:
5932 return bufferedDraw
;
5934 case SCI_GETTWOPHASEDRAW
:
5935 return twoPhaseDraw
;
5937 case SCI_SETTWOPHASEDRAW
:
5938 twoPhaseDraw
= wParam
!= 0;
5939 InvalidateStyleRedraw();
5942 case SCI_SETTABWIDTH
:
5944 pdoc
->tabInChars
= wParam
;
5945 InvalidateStyleRedraw();
5948 case SCI_GETTABWIDTH
:
5949 return pdoc
->tabInChars
;
5952 pdoc
->indentInChars
= wParam
;
5953 InvalidateStyleRedraw();
5957 return pdoc
->indentInChars
;
5959 case SCI_SETUSETABS
:
5960 pdoc
->useTabs
= wParam
!= 0;
5961 InvalidateStyleRedraw();
5964 case SCI_GETUSETABS
:
5965 return pdoc
->useTabs
;
5967 case SCI_SETLINEINDENTATION
:
5968 pdoc
->SetLineIndentation(wParam
, lParam
);
5971 case SCI_GETLINEINDENTATION
:
5972 return pdoc
->GetLineIndentation(wParam
);
5974 case SCI_GETLINEINDENTPOSITION
:
5975 return pdoc
->GetLineIndentPosition(wParam
);
5977 case SCI_SETTABINDENTS
:
5978 pdoc
->tabIndents
= wParam
!= 0;
5981 case SCI_GETTABINDENTS
:
5982 return pdoc
->tabIndents
;
5984 case SCI_SETBACKSPACEUNINDENTS
:
5985 pdoc
->backspaceUnindents
= wParam
!= 0;
5988 case SCI_GETBACKSPACEUNINDENTS
:
5989 return pdoc
->backspaceUnindents
;
5991 case SCI_SETMOUSEDWELLTIME
:
5992 dwellDelay
= wParam
;
5993 ticksToDwell
= dwellDelay
;
5996 case SCI_GETMOUSEDWELLTIME
:
5999 case SCI_WORDSTARTPOSITION
:
6000 return pdoc
->ExtendWordSelect(wParam
, -1, lParam
!= 0);
6002 case SCI_WORDENDPOSITION
:
6003 return pdoc
->ExtendWordSelect(wParam
, 1, lParam
!= 0);
6005 case SCI_SETWRAPMODE
:
6006 wrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
6008 InvalidateStyleRedraw();
6009 ReconfigureScrollBars();
6012 case SCI_GETWRAPMODE
:
6015 case SCI_SETLAYOUTCACHE
:
6016 llc
.SetLevel(wParam
);
6019 case SCI_GETLAYOUTCACHE
:
6020 return llc
.GetLevel();
6022 case SCI_SETSCROLLWIDTH
:
6023 PLATFORM_ASSERT(wParam
> 0);
6024 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
6025 scrollWidth
= wParam
;
6030 case SCI_GETSCROLLWIDTH
:
6037 case SCI_LINESSPLIT
:
6042 PLATFORM_ASSERT(wParam
<= STYLE_MAX
);
6043 PLATFORM_ASSERT(lParam
);
6044 return TextWidth(wParam
, CharPtrFromSPtr(lParam
));
6046 case SCI_TEXTHEIGHT
:
6047 return vs
.lineHeight
;
6049 case SCI_SETENDATLASTLINE
:
6050 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
6051 if (endAtLastLine
!= (wParam
!= 0)) {
6052 endAtLastLine
= wParam
!= 0;
6057 case SCI_GETENDATLASTLINE
:
6058 return endAtLastLine
;
6061 return pdoc
->GetColumn(wParam
);
6063 case SCI_SETHSCROLLBAR
:
6064 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
6065 horizontalScrollBarVisible
= wParam
!= 0;
6067 ReconfigureScrollBars();
6071 case SCI_GETHSCROLLBAR
:
6072 return horizontalScrollBarVisible
;
6074 case SCI_SETVSCROLLBAR
:
6075 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
6076 verticalScrollBarVisible
= wParam
!= 0;
6078 ReconfigureScrollBars();
6082 case SCI_GETVSCROLLBAR
:
6083 return verticalScrollBarVisible
;
6085 case SCI_SETINDENTATIONGUIDES
:
6086 vs
.viewIndentationGuides
= wParam
!= 0;
6090 case SCI_GETINDENTATIONGUIDES
:
6091 return vs
.viewIndentationGuides
;
6093 case SCI_SETHIGHLIGHTGUIDE
:
6094 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
6095 highlightGuideColumn
= wParam
;
6100 case SCI_GETHIGHLIGHTGUIDE
:
6101 return highlightGuideColumn
;
6103 case SCI_GETLINEENDPOSITION
:
6104 return pdoc
->LineEnd(wParam
);
6106 case SCI_SETCODEPAGE
:
6107 pdoc
->dbcsCodePage
= wParam
;
6108 InvalidateStyleRedraw();
6111 case SCI_GETCODEPAGE
:
6112 return pdoc
->dbcsCodePage
;
6114 case SCI_SETUSEPALETTE
:
6115 palette
.allowRealization
= wParam
!= 0;
6116 InvalidateStyleRedraw();
6119 case SCI_GETUSEPALETTE
:
6120 return palette
.allowRealization
;
6122 // Marker definition and setting
6123 case SCI_MARKERDEFINE
:
6124 if (wParam
<= MARKER_MAX
)
6125 vs
.markers
[wParam
].markType
= lParam
;
6126 InvalidateStyleData();
6129 case SCI_MARKERSETFORE
:
6130 if (wParam
<= MARKER_MAX
)
6131 vs
.markers
[wParam
].fore
.desired
= ColourDesired(lParam
);
6132 InvalidateStyleData();
6135 case SCI_MARKERSETBACK
:
6136 if (wParam
<= MARKER_MAX
)
6137 vs
.markers
[wParam
].back
.desired
= ColourDesired(lParam
);
6138 InvalidateStyleData();
6141 case SCI_MARKERADD
: {
6142 int markerID
= pdoc
->AddMark(wParam
, lParam
);
6146 case SCI_MARKERDELETE
:
6147 pdoc
->DeleteMark(wParam
, lParam
);
6150 case SCI_MARKERDELETEALL
:
6151 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
6155 return pdoc
->GetMark(wParam
);
6157 case SCI_MARKERNEXT
: {
6158 int lt
= pdoc
->LinesTotal();
6159 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
6160 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6166 case SCI_MARKERPREVIOUS
: {
6167 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
6168 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6174 case SCI_MARKERDEFINEPIXMAP
:
6175 if (wParam
<= MARKER_MAX
) {
6176 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
6178 InvalidateStyleData();
6182 case SCI_SETMARGINTYPEN
:
6183 if (ValidMargin(wParam
)) {
6184 vs
.ms
[wParam
].symbol
= (lParam
== SC_MARGIN_SYMBOL
);
6185 InvalidateStyleRedraw();
6189 case SCI_GETMARGINTYPEN
:
6190 if (ValidMargin(wParam
))
6191 return vs
.ms
[wParam
].symbol
? SC_MARGIN_SYMBOL
: SC_MARGIN_NUMBER
;
6195 case SCI_SETMARGINWIDTHN
:
6196 if (ValidMargin(wParam
)) {
6197 // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
6198 if (vs
.ms
[wParam
].width
!= lParam
) {
6199 vs
.ms
[wParam
].width
= lParam
;
6200 InvalidateStyleRedraw();
6205 case SCI_GETMARGINWIDTHN
:
6206 if (ValidMargin(wParam
))
6207 return vs
.ms
[wParam
].width
;
6211 case SCI_SETMARGINMASKN
:
6212 if (ValidMargin(wParam
)) {
6213 vs
.ms
[wParam
].mask
= lParam
;
6214 InvalidateStyleRedraw();
6218 case SCI_GETMARGINMASKN
:
6219 if (ValidMargin(wParam
))
6220 return vs
.ms
[wParam
].mask
;
6224 case SCI_SETMARGINSENSITIVEN
:
6225 if (ValidMargin(wParam
)) {
6226 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
6227 InvalidateStyleRedraw();
6231 case SCI_GETMARGINSENSITIVEN
:
6232 if (ValidMargin(wParam
))
6233 return vs
.ms
[wParam
].sensitive
? 1 : 0;
6237 case SCI_STYLECLEARALL
:
6239 InvalidateStyleRedraw();
6242 case SCI_STYLESETFORE
:
6243 if (wParam
<= STYLE_MAX
) {
6244 vs
.styles
[wParam
].fore
.desired
= ColourDesired(lParam
);
6245 InvalidateStyleRedraw();
6248 case SCI_STYLESETBACK
:
6249 if (wParam
<= STYLE_MAX
) {
6250 vs
.styles
[wParam
].back
.desired
= ColourDesired(lParam
);
6251 InvalidateStyleRedraw();
6254 case SCI_STYLESETBOLD
:
6255 if (wParam
<= STYLE_MAX
) {
6256 vs
.styles
[wParam
].bold
= lParam
!= 0;
6257 InvalidateStyleRedraw();
6260 case SCI_STYLESETITALIC
:
6261 if (wParam
<= STYLE_MAX
) {
6262 vs
.styles
[wParam
].italic
= lParam
!= 0;
6263 InvalidateStyleRedraw();
6266 case SCI_STYLESETEOLFILLED
:
6267 if (wParam
<= STYLE_MAX
) {
6268 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
6269 InvalidateStyleRedraw();
6272 case SCI_STYLESETSIZE
:
6273 if (wParam
<= STYLE_MAX
) {
6274 vs
.styles
[wParam
].size
= lParam
;
6275 InvalidateStyleRedraw();
6278 case SCI_STYLESETFONT
:
6281 if (wParam
<= STYLE_MAX
) {
6282 vs
.SetStyleFontName(wParam
, CharPtrFromSPtr(lParam
));
6283 InvalidateStyleRedraw();
6286 case SCI_STYLESETUNDERLINE
:
6287 if (wParam
<= STYLE_MAX
) {
6288 vs
.styles
[wParam
].underline
= lParam
!= 0;
6289 InvalidateStyleRedraw();
6292 case SCI_STYLESETCASE
:
6293 if (wParam
<= STYLE_MAX
) {
6294 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
6295 InvalidateStyleRedraw();
6298 case SCI_STYLESETCHARACTERSET
:
6299 if (wParam
<= STYLE_MAX
) {
6300 vs
.styles
[wParam
].characterSet
= lParam
;
6301 InvalidateStyleRedraw();
6304 case SCI_STYLESETVISIBLE
:
6305 if (wParam
<= STYLE_MAX
) {
6306 vs
.styles
[wParam
].visible
= lParam
!= 0;
6307 InvalidateStyleRedraw();
6310 case SCI_STYLESETCHANGEABLE
:
6311 if (wParam
<= STYLE_MAX
) {
6312 vs
.styles
[wParam
].changeable
= lParam
!= 0;
6313 InvalidateStyleRedraw();
6316 case SCI_STYLESETHOTSPOT
:
6317 if (wParam
<= STYLE_MAX
) {
6318 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
6319 InvalidateStyleRedraw();
6323 case SCI_STYLERESETDEFAULT
:
6324 vs
.ResetDefaultStyle();
6325 InvalidateStyleRedraw();
6327 case SCI_SETSTYLEBITS
:
6328 pdoc
->SetStylingBits(wParam
);
6331 case SCI_GETSTYLEBITS
:
6332 return pdoc
->stylingBits
;
6334 case SCI_SETLINESTATE
:
6335 return pdoc
->SetLineState(wParam
, lParam
);
6337 case SCI_GETLINESTATE
:
6338 return pdoc
->GetLineState(wParam
);
6340 case SCI_GETMAXLINESTATE
:
6341 return pdoc
->GetMaxLineState();
6343 case SCI_GETCARETLINEVISIBLE
:
6344 return vs
.showCaretLineBackground
;
6345 case SCI_SETCARETLINEVISIBLE
:
6346 vs
.showCaretLineBackground
= wParam
!= 0;
6347 InvalidateStyleRedraw();
6349 case SCI_GETCARETLINEBACK
:
6350 return vs
.caretLineBackground
.desired
.AsLong();
6351 case SCI_SETCARETLINEBACK
:
6352 vs
.caretLineBackground
.desired
= wParam
;
6353 InvalidateStyleRedraw();
6358 case SCI_VISIBLEFROMDOCLINE
:
6359 return cs
.DisplayFromDoc(wParam
);
6361 case SCI_DOCLINEFROMVISIBLE
:
6362 return cs
.DocFromDisplay(wParam
);
6364 case SCI_SETFOLDLEVEL
: {
6365 int prev
= pdoc
->SetLevel(wParam
, lParam
);
6371 case SCI_GETFOLDLEVEL
:
6372 return pdoc
->GetLevel(wParam
);
6374 case SCI_GETLASTCHILD
:
6375 return pdoc
->GetLastChild(wParam
, lParam
);
6377 case SCI_GETFOLDPARENT
:
6378 return pdoc
->GetFoldParent(wParam
);
6381 cs
.SetVisible(wParam
, lParam
, true);
6387 cs
.SetVisible(wParam
, lParam
, false);
6392 case SCI_GETLINEVISIBLE
:
6393 return cs
.GetVisible(wParam
);
6395 case SCI_SETFOLDEXPANDED
:
6396 if (cs
.SetExpanded(wParam
, lParam
!= 0)) {
6401 case SCI_GETFOLDEXPANDED
:
6402 return cs
.GetExpanded(wParam
);
6404 case SCI_SETFOLDFLAGS
:
6409 case SCI_TOGGLEFOLD
:
6410 ToggleContraction(wParam
);
6413 case SCI_ENSUREVISIBLE
:
6414 EnsureLineVisible(wParam
, false);
6417 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
6418 EnsureLineVisible(wParam
, true);
6421 case SCI_SEARCHANCHOR
:
6425 case SCI_SEARCHNEXT
:
6426 case SCI_SEARCHPREV
:
6427 return SearchText(iMessage
, wParam
, lParam
);
6429 #ifdef INCLUDE_DEPRECATED_FEATURES
6430 case SCI_SETCARETPOLICY
: // Deprecated
6431 caretXPolicy
= caretYPolicy
= wParam
;
6432 caretXSlop
= caretYSlop
= lParam
;
6436 case SCI_SETXCARETPOLICY
:
6437 caretXPolicy
= wParam
;
6438 caretXSlop
= lParam
;
6441 case SCI_SETYCARETPOLICY
:
6442 caretYPolicy
= wParam
;
6443 caretYSlop
= lParam
;
6446 case SCI_SETVISIBLEPOLICY
:
6447 visiblePolicy
= wParam
;
6448 visibleSlop
= lParam
;
6451 case SCI_LINESONSCREEN
:
6452 return LinesOnScreen();
6454 case SCI_SETSELFORE
:
6455 vs
.selforeset
= wParam
!= 0;
6456 vs
.selforeground
.desired
= ColourDesired(lParam
);
6457 InvalidateStyleRedraw();
6460 case SCI_SETSELBACK
:
6461 vs
.selbackset
= wParam
!= 0;
6462 vs
.selbackground
.desired
= ColourDesired(lParam
);
6463 InvalidateStyleRedraw();
6466 case SCI_SETWHITESPACEFORE
:
6467 vs
.whitespaceForegroundSet
= wParam
!= 0;
6468 vs
.whitespaceForeground
.desired
= ColourDesired(lParam
);
6469 InvalidateStyleRedraw();
6472 case SCI_SETWHITESPACEBACK
:
6473 vs
.whitespaceBackgroundSet
= wParam
!= 0;
6474 vs
.whitespaceBackground
.desired
= ColourDesired(lParam
);
6475 InvalidateStyleRedraw();
6478 case SCI_SETCARETFORE
:
6479 vs
.caretcolour
.desired
= ColourDesired(wParam
);
6480 InvalidateStyleRedraw();
6483 case SCI_GETCARETFORE
:
6484 return vs
.caretcolour
.desired
.AsLong();
6486 case SCI_SETCARETWIDTH
:
6489 else if (wParam
>= 3)
6492 vs
.caretWidth
= wParam
;
6493 InvalidateStyleRedraw();
6496 case SCI_GETCARETWIDTH
:
6497 return vs
.caretWidth
;
6499 case SCI_ASSIGNCMDKEY
:
6500 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6501 Platform::HighShortFromLong(wParam
), lParam
);
6504 case SCI_CLEARCMDKEY
:
6505 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6506 Platform::HighShortFromLong(wParam
), SCI_NULL
);
6509 case SCI_CLEARALLCMDKEYS
:
6513 case SCI_INDICSETSTYLE
:
6514 if (wParam
<= INDIC_MAX
) {
6515 vs
.indicators
[wParam
].style
= lParam
;
6516 InvalidateStyleRedraw();
6520 case SCI_INDICGETSTYLE
:
6521 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
6523 case SCI_INDICSETFORE
:
6524 if (wParam
<= INDIC_MAX
) {
6525 vs
.indicators
[wParam
].fore
.desired
= ColourDesired(lParam
);
6526 InvalidateStyleRedraw();
6530 case SCI_INDICGETFORE
:
6531 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
6534 case SCI_LINEDOWNEXTEND
:
6536 case SCI_PARADOWNEXTEND
:
6538 case SCI_LINEUPEXTEND
:
6540 case SCI_PARAUPEXTEND
:
6542 case SCI_CHARLEFTEXTEND
:
6544 case SCI_CHARRIGHTEXTEND
:
6546 case SCI_WORDLEFTEXTEND
:
6548 case SCI_WORDRIGHTEXTEND
:
6549 case SCI_WORDLEFTEND
:
6550 case SCI_WORDLEFTENDEXTEND
:
6551 case SCI_WORDRIGHTEND
:
6552 case SCI_WORDRIGHTENDEXTEND
:
6554 case SCI_HOMEEXTEND
:
6556 case SCI_LINEENDEXTEND
:
6558 case SCI_HOMEWRAPEXTEND
:
6559 case SCI_LINEENDWRAP
:
6560 case SCI_LINEENDWRAPEXTEND
:
6561 case SCI_DOCUMENTSTART
:
6562 case SCI_DOCUMENTSTARTEXTEND
:
6563 case SCI_DOCUMENTEND
:
6564 case SCI_DOCUMENTENDEXTEND
:
6566 case SCI_STUTTEREDPAGEUP
:
6567 case SCI_STUTTEREDPAGEUPEXTEND
:
6568 case SCI_STUTTEREDPAGEDOWN
:
6569 case SCI_STUTTEREDPAGEDOWNEXTEND
:
6572 case SCI_PAGEUPEXTEND
:
6574 case SCI_PAGEDOWNEXTEND
:
6575 case SCI_EDITTOGGLEOVERTYPE
:
6577 case SCI_DELETEBACK
:
6583 case SCI_VCHOMEEXTEND
:
6584 case SCI_VCHOMEWRAP
:
6585 case SCI_VCHOMEWRAPEXTEND
:
6588 case SCI_DELWORDLEFT
:
6589 case SCI_DELWORDRIGHT
:
6590 case SCI_DELLINELEFT
:
6591 case SCI_DELLINERIGHT
:
6594 case SCI_LINEDELETE
:
6595 case SCI_LINETRANSPOSE
:
6596 case SCI_LINEDUPLICATE
:
6599 case SCI_LINESCROLLDOWN
:
6600 case SCI_LINESCROLLUP
:
6601 case SCI_WORDPARTLEFT
:
6602 case SCI_WORDPARTLEFTEXTEND
:
6603 case SCI_WORDPARTRIGHT
:
6604 case SCI_WORDPARTRIGHTEXTEND
:
6605 case SCI_DELETEBACKNOTLINE
:
6606 case SCI_HOMEDISPLAY
:
6607 case SCI_HOMEDISPLAYEXTEND
:
6608 case SCI_LINEENDDISPLAY
:
6609 case SCI_LINEENDDISPLAYEXTEND
:
6610 case SCI_LINEDOWNRECTEXTEND
:
6611 case SCI_LINEUPRECTEXTEND
:
6612 case SCI_CHARLEFTRECTEXTEND
:
6613 case SCI_CHARRIGHTRECTEXTEND
:
6614 case SCI_HOMERECTEXTEND
:
6615 case SCI_VCHOMERECTEXTEND
:
6616 case SCI_LINEENDRECTEXTEND
:
6617 case SCI_PAGEUPRECTEXTEND
:
6618 case SCI_PAGEDOWNRECTEXTEND
:
6619 return KeyCommand(iMessage
);
6621 case SCI_BRACEHIGHLIGHT
:
6622 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
6625 case SCI_BRACEBADLIGHT
:
6626 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
6629 case SCI_BRACEMATCH
:
6630 // wParam is position of char to find brace for,
6631 // lParam is maximum amount of text to restyle to find it
6632 return BraceMatch(wParam
, lParam
);
6634 case SCI_GETVIEWEOL
:
6637 case SCI_SETVIEWEOL
:
6638 vs
.viewEOL
= wParam
!= 0;
6639 InvalidateStyleRedraw();
6643 vs
.zoomLevel
= wParam
;
6644 InvalidateStyleRedraw();
6649 return vs
.zoomLevel
;
6651 case SCI_GETEDGECOLUMN
:
6654 case SCI_SETEDGECOLUMN
:
6656 InvalidateStyleRedraw();
6659 case SCI_GETEDGEMODE
:
6660 return vs
.edgeState
;
6662 case SCI_SETEDGEMODE
:
6663 vs
.edgeState
= wParam
;
6664 InvalidateStyleRedraw();
6667 case SCI_GETEDGECOLOUR
:
6668 return vs
.edgecolour
.desired
.AsLong();
6670 case SCI_SETEDGECOLOUR
:
6671 vs
.edgecolour
.desired
= ColourDesired(wParam
);
6672 InvalidateStyleRedraw();
6675 case SCI_GETDOCPOINTER
:
6676 return reinterpret_cast<sptr_t
>(pdoc
);
6678 case SCI_SETDOCPOINTER
:
6680 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
6683 case SCI_CREATEDOCUMENT
: {
6684 Document
*doc
= new Document();
6688 return reinterpret_cast<sptr_t
>(doc
);
6691 case SCI_ADDREFDOCUMENT
:
6692 (reinterpret_cast<Document
*>(lParam
))->AddRef();
6695 case SCI_RELEASEDOCUMENT
:
6696 (reinterpret_cast<Document
*>(lParam
))->Release();
6699 case SCI_SETMODEVENTMASK
:
6700 modEventMask
= wParam
;
6703 case SCI_GETMODEVENTMASK
:
6704 return modEventMask
;
6706 case SCI_CONVERTEOLS
:
6707 pdoc
->ConvertLineEnds(wParam
);
6708 SetSelection(currentPos
, anchor
); // Ensure selection inside document
6711 case SCI_SELECTIONISRECTANGLE
:
6712 return selType
== selRectangle
? 1 : 0;
6714 case SCI_SETSELECTIONMODE
: {
6717 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selStream
);
6718 selType
= selStream
;
6720 case SC_SEL_RECTANGLE
:
6721 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selRectangle
);
6722 selType
= selRectangle
;
6725 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selLines
);
6729 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selStream
);
6730 selType
= selStream
;
6732 InvalidateSelection(currentPos
, anchor
);
6734 case SCI_GETSELECTIONMODE
:
6737 return SC_SEL_STREAM
;
6739 return SC_SEL_RECTANGLE
;
6741 return SC_SEL_LINES
;
6743 return SC_SEL_STREAM
;
6745 case SCI_GETLINESELSTARTPOSITION
: {
6746 SelectionLineIterator
lineIterator(this);
6747 lineIterator
.SetAt(wParam
);
6748 return lineIterator
.startPos
;
6750 case SCI_GETLINESELENDPOSITION
: {
6751 SelectionLineIterator
lineIterator(this);
6752 lineIterator
.SetAt(wParam
);
6753 return lineIterator
.endPos
;
6756 case SCI_SETOVERTYPE
:
6757 inOverstrike
= wParam
!= 0;
6760 case SCI_GETOVERTYPE
:
6761 return inOverstrike
? 1 : 0;
6764 SetFocusState(wParam
!= 0);
6771 errorStatus
= wParam
;
6777 case SCI_SETMOUSEDOWNCAPTURES
:
6778 mouseDownCaptures
= wParam
!= 0;
6781 case SCI_GETMOUSEDOWNCAPTURES
:
6782 return mouseDownCaptures
;
6785 cursorMode
= wParam
;
6786 DisplayCursor(Window::cursorText
);
6792 case SCI_SETCONTROLCHARSYMBOL
:
6793 controlCharSymbol
= wParam
;
6796 case SCI_GETCONTROLCHARSYMBOL
:
6797 return controlCharSymbol
;
6799 case SCI_STARTRECORD
:
6800 recordingMacro
= true;
6803 case SCI_STOPRECORD
:
6804 recordingMacro
= false;
6807 case SCI_MOVECARETINSIDEVIEW
:
6808 MoveCaretInsideView();
6811 case SCI_SETFOLDMARGINCOLOUR
:
6812 vs
.foldmarginColourSet
= wParam
!= 0;
6813 vs
.foldmarginColour
.desired
= ColourDesired(lParam
);
6814 InvalidateStyleRedraw();
6817 case SCI_SETFOLDMARGINHICOLOUR
:
6818 vs
.foldmarginHighlightColourSet
= wParam
!= 0;
6819 vs
.foldmarginHighlightColour
.desired
= ColourDesired(lParam
);
6820 InvalidateStyleRedraw();
6823 case SCI_SETHOTSPOTACTIVEFORE
:
6824 vs
.hotspotForegroundSet
= wParam
!= 0;
6825 vs
.hotspotForeground
.desired
= ColourDesired(lParam
);
6826 InvalidateStyleRedraw();
6829 case SCI_SETHOTSPOTACTIVEBACK
:
6830 vs
.hotspotBackgroundSet
= wParam
!= 0;
6831 vs
.hotspotBackground
.desired
= ColourDesired(lParam
);
6832 InvalidateStyleRedraw();
6835 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
6836 vs
.hotspotUnderline
= wParam
!= 0;
6837 InvalidateStyleRedraw();
6840 case SCI_SETHOTSPOTSINGLELINE
:
6841 vs
.hotspotSingleLine
= wParam
!= 0;
6842 InvalidateStyleRedraw();
6846 return DefWndProc(iMessage
, wParam
, lParam
);
6848 //Platform::DebugPrintf("end wnd proc\n");