1 // Scintilla source code edit control
3 ** Main code for the edit control.
5 // Copyright 1998-2004 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 return whether this modification represents an operation that
34 may reasonably be deferred (not done now OR [possibly] at all)
36 static bool CanDeferToLastStep(const DocModification
& mh
) {
37 if (mh
.modificationType
& (SC_MOD_BEFOREINSERT
|SC_MOD_BEFOREDELETE
))
38 return true; // CAN skip
39 if (!(mh
.modificationType
& (SC_PERFORMED_UNDO
|SC_PERFORMED_REDO
)))
40 return false; // MUST do
41 if (mh
.modificationType
& SC_MULTISTEPUNDOREDO
)
42 return true; // CAN skip
43 return false; // PRESUMABLY must do
46 static bool CanEliminate(const DocModification
& mh
) {
48 (mh
.modificationType
& (SC_MOD_BEFOREINSERT
|SC_MOD_BEFOREDELETE
)) != 0;
52 return whether this modification represents the FINAL step
53 in a [possibly lengthy] multi-step Undo/Redo sequence
55 static bool IsLastStep(const DocModification
& mh
) {
57 (mh
.modificationType
& (SC_PERFORMED_UNDO
|SC_PERFORMED_REDO
)) != 0
58 && (mh
.modificationType
& SC_MULTISTEPUNDOREDO
) != 0
59 && (mh
.modificationType
& SC_LASTSTEPINUNDOREDO
) != 0
60 && (mh
.modificationType
& SC_MULTILINEUNDOREDO
) != 0;
64 active(false), on(false), period(500) {}
67 ticking(false), ticksToWait(0), tickerID(0) {}
70 state(false), idlerID(0) {}
72 LineLayout::LineLayout(int maxLineLength_
) :
93 widthLine(wrapWidthInfinite
),
95 Resize(maxLineLength_
);
98 LineLayout::~LineLayout() {
102 void LineLayout::Resize(int maxLineLength_
) {
103 if (maxLineLength_
> maxLineLength
) {
105 chars
= new char[maxLineLength_
+ 1];
106 styles
= new unsigned char[maxLineLength_
+ 1];
107 indicators
= new char[maxLineLength_
+ 1];
108 // Extra position allocated as sometimes the Windows
109 // GetTextExtentExPoint API writes an extra element.
110 positions
= new int[maxLineLength_
+ 1 + 1];
111 maxLineLength
= maxLineLength_
;
115 void LineLayout::Free() {
128 void LineLayout::Invalidate(validLevel validity_
) {
129 if (validity
> validity_
)
130 validity
= validity_
;
133 void LineLayout::SetLineStart(int line
, int start
) {
134 if ((line
>= lenLineStarts
) && (line
!= 0)) {
135 int newMaxLines
= line
+ 20;
136 int *newLineStarts
= new int[newMaxLines
];
139 for (int i
= 0; i
< newMaxLines
; i
++) {
140 if (i
< lenLineStarts
)
141 newLineStarts
[i
] = lineStarts
[i
];
143 newLineStarts
[i
] = 0;
146 lineStarts
= newLineStarts
;
147 lenLineStarts
= newMaxLines
;
149 lineStarts
[line
] = start
;
152 void LineLayout::SetBracesHighlight(Range rangeLine
, Position braces
[],
153 char bracesMatchStyle
, int xHighlight
) {
154 if (rangeLine
.ContainsCharacter(braces
[0])) {
155 int braceOffset
= braces
[0] - rangeLine
.start
;
156 if (braceOffset
< numCharsInLine
) {
157 bracePreviousStyles
[0] = styles
[braceOffset
];
158 styles
[braceOffset
] = bracesMatchStyle
;
161 if (rangeLine
.ContainsCharacter(braces
[1])) {
162 int braceOffset
= braces
[1] - rangeLine
.start
;
163 if (braceOffset
< numCharsInLine
) {
164 bracePreviousStyles
[1] = styles
[braceOffset
];
165 styles
[braceOffset
] = bracesMatchStyle
;
168 if ((braces
[0] >= rangeLine
.start
&& braces
[1] <= rangeLine
.end
) ||
169 (braces
[1] >= rangeLine
.start
&& braces
[0] <= rangeLine
.end
)) {
170 xHighlightGuide
= xHighlight
;
174 void LineLayout::RestoreBracesHighlight(Range rangeLine
, Position braces
[]) {
175 if (rangeLine
.ContainsCharacter(braces
[0])) {
176 int braceOffset
= braces
[0] - rangeLine
.start
;
177 if (braceOffset
< numCharsInLine
) {
178 styles
[braceOffset
] = bracePreviousStyles
[0];
181 if (rangeLine
.ContainsCharacter(braces
[1])) {
182 int braceOffset
= braces
[1] - rangeLine
.start
;
183 if (braceOffset
< numCharsInLine
) {
184 styles
[braceOffset
] = bracePreviousStyles
[1];
190 LineLayoutCache::LineLayoutCache() :
191 level(0), length(0), size(0), cache(0),
192 allInvalidated(false), styleClock(-1), useCount(0) {
196 LineLayoutCache::~LineLayoutCache() {
200 void LineLayoutCache::Allocate(int length_
) {
201 PLATFORM_ASSERT(cache
== NULL
);
202 allInvalidated
= false;
206 size
= (size
/ 16 + 1) * 16;
209 cache
= new LineLayout
* [size
];
211 for (int i
= 0; i
< size
; i
++)
215 void LineLayoutCache::AllocateForLevel(int linesOnScreen
, int linesInDoc
) {
216 PLATFORM_ASSERT(useCount
== 0);
217 int lengthForLevel
= 0;
218 if (level
== llcCaret
) {
220 } else if (level
== llcPage
) {
221 lengthForLevel
= linesOnScreen
+ 1;
222 } else if (level
== llcDocument
) {
223 lengthForLevel
= linesInDoc
;
225 if (lengthForLevel
> size
) {
227 Allocate(lengthForLevel
);
229 if (lengthForLevel
< length
) {
230 for (int i
= lengthForLevel
; i
< length
; i
++) {
235 length
= lengthForLevel
;
237 PLATFORM_ASSERT(length
== lengthForLevel
);
238 PLATFORM_ASSERT(cache
!= NULL
|| length
== 0);
241 void LineLayoutCache::Deallocate() {
242 PLATFORM_ASSERT(useCount
== 0);
243 for (int i
= 0; i
< length
; i
++)
251 void LineLayoutCache::Invalidate(LineLayout::validLevel validity_
) {
252 if (cache
&& !allInvalidated
) {
253 for (int i
= 0; i
< length
; i
++) {
255 cache
[i
]->Invalidate(validity_
);
258 if (validity_
== LineLayout::llInvalid
) {
259 allInvalidated
= true;
264 void LineLayoutCache::SetLevel(int level_
) {
265 allInvalidated
= false;
266 if ((level_
!= -1) && (level
!= level_
)) {
272 LineLayout
*LineLayoutCache::Retrieve(int lineNumber
, int lineCaret
, int maxChars
, int styleClock_
,
273 int linesOnScreen
, int linesInDoc
) {
274 AllocateForLevel(linesOnScreen
, linesInDoc
);
275 if (styleClock
!= styleClock_
) {
276 Invalidate(LineLayout::llCheckTextAndStyle
);
277 styleClock
= styleClock_
;
279 allInvalidated
= false;
282 if (level
== llcCaret
) {
284 } else if (level
== llcPage
) {
285 if (lineNumber
== lineCaret
) {
288 pos
= 1 + (lineNumber
% (length
- 1));
290 } else if (level
== llcDocument
) {
294 PLATFORM_ASSERT(useCount
== 0);
295 if (cache
&& (pos
< length
)) {
297 if ((cache
[pos
]->lineNumber
!= lineNumber
) ||
298 (cache
[pos
]->maxLineLength
< maxChars
)) {
304 cache
[pos
] = new LineLayout(maxChars
);
307 cache
[pos
]->lineNumber
= lineNumber
;
308 cache
[pos
]->inCache
= true;
316 ret
= new LineLayout(maxChars
);
317 ret
->lineNumber
= lineNumber
;
323 void LineLayoutCache::Dispose(LineLayout
*ll
) {
324 allInvalidated
= false;
339 printMagnification
= 0;
340 printColourMode
= SC_PRINT_NORMAL
;
341 printWrapState
= eWrapWord
;
342 cursorMode
= SC_CURSORNORMAL
;
343 controlCharSymbol
= 0; /* Draw the control characters */
346 hideSelection
= false;
347 inOverstrike
= false;
349 mouseDownCaptures
= true;
355 dwellDelay
= SC_TIME_FOREVER
;
356 ticksToDwell
= SC_TIME_FOREVER
;
361 dropWentOutside
= false;
362 posDrag
= invalidPosition
;
363 posDrop
= invalidPosition
;
364 selectionType
= selChar
;
368 originalAnchorPos
= 0;
371 moveExtendsSelection
= false;
374 primarySelection
= true;
376 caretXPolicy
= CARET_SLOP
| CARET_EVEN
;
379 caretYPolicy
= CARET_EVEN
;
386 horizontalScrollBarVisible
= true;
388 verticalScrollBarVisible
= true;
389 endAtLastLine
= true;
392 pixmapLine
= Surface::Allocate();
393 pixmapSelMargin
= Surface::Allocate();
394 pixmapSelPattern
= Surface::Allocate();
395 pixmapIndentGuide
= Surface::Allocate();
396 pixmapIndentGuideHighlight
= Surface::Allocate();
408 lengthForEncode
= -1;
411 braces
[0] = invalidPosition
;
412 braces
[1] = invalidPosition
;
413 bracesMatchStyle
= STYLE_BRACEBAD
;
414 highlightGuideColumn
= 0;
418 paintState
= notPainting
;
420 modEventMask
= SC_MODEVENTMASKALL
;
422 pdoc
= new Document();
424 pdoc
->AddWatcher(this, 0);
426 recordingMacro
= false;
429 wrapState
= eWrapNone
;
430 wrapWidth
= LineLayout::wrapWidthInfinite
;
431 docLineLastWrapped
= -1;
432 docLastLineToWrap
= -1;
433 backgroundWrapEnabled
= true;
435 wrapVisualFlagsLocation
= 0;
436 wrapVisualStartIndent
= 0;
437 actualWrapVisualStartIndent
= 0;
439 convertPastes
= true;
444 llc
.SetLevel(LineLayoutCache::llcCaret
);
448 pdoc
->RemoveWatcher(this, 0);
453 delete pixmapSelMargin
;
454 delete pixmapSelPattern
;
455 delete pixmapIndentGuide
;
456 delete pixmapIndentGuideHighlight
;
459 void Editor::Finalise() {
464 void Editor::DropGraphics() {
465 pixmapLine
->Release();
466 pixmapSelMargin
->Release();
467 pixmapSelPattern
->Release();
468 pixmapIndentGuide
->Release();
469 pixmapIndentGuideHighlight
->Release();
472 void Editor::InvalidateStyleData() {
476 llc
.Invalidate(LineLayout::llInvalid
);
477 if (selType
== selRectangle
) {
478 xStartSelect
= XFromPosition(anchor
);
479 xEndSelect
= XFromPosition(currentPos
);
483 void Editor::InvalidateStyleRedraw() {
485 InvalidateStyleData();
489 void Editor::RefreshColourPalette(Palette
&pal
, bool want
) {
490 vs
.RefreshColourPalette(pal
, want
);
493 void Editor::RefreshStyleData() {
496 AutoSurface
surface(this);
498 vs
.Refresh(*surface
);
499 RefreshColourPalette(palette
, true);
500 palette
.Allocate(wMain
);
501 RefreshColourPalette(palette
, false);
507 PRectangle
Editor::GetClientRectangle() {
508 return wMain
.GetClientPosition();
511 PRectangle
Editor::GetTextRectangle() {
512 PRectangle rc
= GetClientRectangle();
513 rc
.left
+= vs
.fixedColumnWidth
;
514 rc
.right
-= vs
.rightMarginWidth
;
518 int Editor::LinesOnScreen() {
519 PRectangle rcClient
= GetClientRectangle();
520 int htClient
= rcClient
.bottom
- rcClient
.top
;
521 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
522 return htClient
/ vs
.lineHeight
;
525 int Editor::LinesToScroll() {
526 int retVal
= LinesOnScreen() - 1;
533 int Editor::MaxScrollPos() {
534 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
535 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
536 int retVal
= cs
.LinesDisplayed();
538 retVal
-= LinesOnScreen();
549 static inline bool IsControlCharacter(int ch
) {
550 // iscntrl returns true for lots of chars > 127 which are displayable
551 return ch
>= 0 && ch
< ' ';
554 const char *ControlCharacterString(unsigned char ch
) {
555 const char *reps
[] = {
556 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
557 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
558 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
559 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
561 if (ch
< (sizeof(reps
) / sizeof(reps
[0]))) {
569 * Convenience class to ensure LineLayout objects are always disposed.
571 class AutoLineLayout
{
572 LineLayoutCache
&llc
;
574 AutoLineLayout
&operator=(const AutoLineLayout
&) { return * this; }
576 AutoLineLayout(LineLayoutCache
&llc_
, LineLayout
*ll_
) : llc(llc_
), ll(ll_
) {}
581 LineLayout
*operator->() const {
584 operator LineLayout
*() const {
587 void Set(LineLayout
*ll_
) {
594 * Allows to iterate through the lines of a selection.
595 * Althought it can be called for a stream selection, in most cases
596 * it is inefficient and it should be used only for
597 * a rectangular or a line selection.
599 class SelectionLineIterator
{
602 int line
; ///< Current line within the iteration.
603 bool forward
; ///< True if iterating by increasing line number, false otherwise.
604 int selStart
, selEnd
; ///< Positions of the start and end of the selection relative to the start of the document.
605 int minX
, maxX
; ///< Left and right of selection rectangle.
608 int lineStart
, lineEnd
; ///< Line numbers, first and last lines of the selection.
609 int startPos
, endPos
; ///< Positions of the beginning and end of the selection on the current line.
619 SelectionLineIterator(Editor
*ed_
, bool forward_
= true) : line(0), startPos(0), endPos(0) {
622 selStart
= ed
->SelectionStart();
623 selEnd
= ed
->SelectionEnd();
624 lineStart
= ed
->pdoc
->LineFromPosition(selStart
);
625 lineEnd
= ed
->pdoc
->LineFromPosition(selEnd
);
627 minX
= Platform::Minimum(ed
->xStartSelect
, ed
->xEndSelect
);
628 // Right of rectangle
629 maxX
= Platform::Maximum(ed
->xStartSelect
, ed
->xEndSelect
);
632 ~SelectionLineIterator() {}
634 void SetAt(int line
) {
635 if (line
< lineStart
|| line
> lineEnd
) {
636 startPos
= endPos
= INVALID_POSITION
;
638 if (ed
->selType
== ed
->selRectangle
) {
639 // Measure line and return character closest to minX
640 startPos
= ed
->PositionFromLineX(line
, minX
);
641 // Measure line and return character closest to maxX
642 endPos
= ed
->PositionFromLineX(line
, maxX
);
643 } else if (ed
->selType
== ed
->selLines
) {
644 startPos
= ed
->pdoc
->LineStart(line
);
645 endPos
= ed
->pdoc
->LineStart(line
+ 1);
646 } else { // Stream selection, here only for completion
647 if (line
== lineStart
) {
650 startPos
= ed
->pdoc
->LineStart(line
);
652 if (line
== lineEnd
) {
655 endPos
= ed
->pdoc
->LineStart(line
+ 1);
667 return startPos
!= INVALID_POSITION
;
671 Point
Editor::LocationFromPosition(int pos
) {
674 if (pos
== INVALID_POSITION
)
676 int line
= pdoc
->LineFromPosition(pos
);
677 int lineVisible
= cs
.DisplayFromDoc(line
);
678 //Platform::DebugPrintf("line=%d\n", line);
679 AutoSurface
surface(this);
680 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
682 // -1 because of adding in for visible lines in following loop.
683 pt
.y
= (lineVisible
- topLine
- 1) * vs
.lineHeight
;
685 unsigned int posLineStart
= pdoc
->LineStart(line
);
686 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
687 int posInLine
= pos
- posLineStart
;
688 // In case of very long line put x at arbitrary large position
689 if (posInLine
> ll
->maxLineLength
) {
690 pt
.x
= ll
->positions
[ll
->maxLineLength
] - ll
->positions
[ll
->LineStart(ll
->lines
)];
693 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
694 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
695 pt
.x
= ll
->positions
[posInLine
] - ll
->positions
[ll
->LineStart(subLine
)];
696 if (actualWrapVisualStartIndent
!= 0) {
697 int lineStart
= ll
->LineStart(subLine
);
698 if (lineStart
!= 0) // Wrapped
699 pt
.x
+= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
702 if (posInLine
>= ll
->LineStart(subLine
)) {
703 pt
.y
+= vs
.lineHeight
;
706 pt
.x
+= vs
.fixedColumnWidth
- xOffset
;
711 int Editor::XFromPosition(int pos
) {
712 Point pt
= LocationFromPosition(pos
);
713 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
716 int Editor::LineFromLocation(Point pt
) {
717 return cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
720 void Editor::SetTopLine(int topLineNew
) {
721 topLine
= topLineNew
;
722 posTopLine
= pdoc
->LineStart(cs
.DocFromDisplay(topLine
));
725 static inline bool IsEOLChar(char ch
) {
726 return (ch
== '\r') || (ch
== '\n');
729 int Editor::PositionFromLocation(Point pt
) {
731 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
732 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
733 if (pt
.y
< 0) { // Division rounds towards 0
734 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
738 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
739 if (lineDoc
>= pdoc
->LinesTotal())
740 return pdoc
->Length();
741 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
742 int retVal
= posLineStart
;
743 AutoSurface
surface(this);
744 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
746 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
747 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
748 int subLine
= visibleLine
- lineStartSet
;
749 if (subLine
< ll
->lines
) {
750 int lineStart
= ll
->LineStart(subLine
);
751 int lineEnd
= ll
->LineStart(subLine
+ 1);
752 int subLineStart
= ll
->positions
[lineStart
];
754 if (actualWrapVisualStartIndent
!= 0) {
755 if (lineStart
!= 0) // Wrapped
756 pt
.x
-= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
758 for (int i
= lineStart
; i
< lineEnd
; i
++) {
759 if (pt
.x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
760 IsEOLChar(ll
->chars
[i
])) {
761 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
764 return lineEnd
+ posLineStart
;
766 retVal
= ll
->numCharsInLine
+ posLineStart
;
771 // Like PositionFromLocation but INVALID_POSITION returned when not near any text.
772 int Editor::PositionFromLocationClose(Point pt
) {
774 PRectangle rcClient
= GetTextRectangle();
775 if (!rcClient
.Contains(pt
))
776 return INVALID_POSITION
;
777 if (pt
.x
< vs
.fixedColumnWidth
)
778 return INVALID_POSITION
;
780 return INVALID_POSITION
;
781 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
782 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
783 if (pt
.y
< 0) { // Division rounds towards 0
784 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
786 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
788 return INVALID_POSITION
;
789 if (lineDoc
>= pdoc
->LinesTotal())
790 return INVALID_POSITION
;
791 AutoSurface
surface(this);
792 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
794 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
795 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
796 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
797 int subLine
= visibleLine
- lineStartSet
;
798 if (subLine
< ll
->lines
) {
799 int lineStart
= ll
->LineStart(subLine
);
800 int lineEnd
= ll
->LineStart(subLine
+ 1);
801 int subLineStart
= ll
->positions
[lineStart
];
803 if (actualWrapVisualStartIndent
!= 0) {
804 if (lineStart
!= 0) // Wrapped
805 pt
.x
-= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
807 for (int i
= lineStart
; i
< lineEnd
; i
++) {
808 if (pt
.x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
809 IsEOLChar(ll
->chars
[i
])) {
810 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
816 return INVALID_POSITION
;
820 * Find the document position corresponding to an x coordinate on a particular document line.
821 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
823 int Editor::PositionFromLineX(int lineDoc
, int x
) {
825 if (lineDoc
>= pdoc
->LinesTotal())
826 return pdoc
->Length();
827 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
828 AutoSurface
surface(this);
829 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
832 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
833 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
834 retVal
= ll
->numCharsInLine
+ posLineStart
;
836 int lineStart
= ll
->LineStart(subLine
);
837 int lineEnd
= ll
->LineStart(subLine
+ 1);
838 int subLineStart
= ll
->positions
[lineStart
];
840 if (actualWrapVisualStartIndent
!= 0) {
841 if (lineStart
!= 0) // Wrapped
842 x
-= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
844 for (int i
= lineStart
; i
< lineEnd
; i
++) {
845 if (x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
846 IsEOLChar(ll
->chars
[i
])) {
847 retVal
= pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
856 * If painting then abandon the painting because a wider redraw is needed.
857 * @return true if calling code should stop drawing.
859 bool Editor::AbandonPaint() {
860 if ((paintState
== painting
) && !paintingAllText
) {
861 paintState
= paintAbandoned
;
863 return paintState
== paintAbandoned
;
866 void Editor::RedrawRect(PRectangle rc
) {
867 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
869 // Clip the redraw rectangle into the client area
870 PRectangle rcClient
= GetClientRectangle();
871 if (rc
.top
< rcClient
.top
)
872 rc
.top
= rcClient
.top
;
873 if (rc
.bottom
> rcClient
.bottom
)
874 rc
.bottom
= rcClient
.bottom
;
875 if (rc
.left
< rcClient
.left
)
876 rc
.left
= rcClient
.left
;
877 if (rc
.right
> rcClient
.right
)
878 rc
.right
= rcClient
.right
;
880 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
881 wMain
.InvalidateRectangle(rc
);
885 void Editor::Redraw() {
886 //Platform::DebugPrintf("Redraw all\n");
887 PRectangle rcClient
= GetClientRectangle();
888 wMain
.InvalidateRectangle(rcClient
);
889 //wMain.InvalidateAll();
892 void Editor::RedrawSelMargin(int line
) {
893 if (!AbandonPaint()) {
897 PRectangle rcSelMargin
= GetClientRectangle();
898 rcSelMargin
.right
= vs
.fixedColumnWidth
;
900 int position
= pdoc
->LineStart(line
);
901 PRectangle rcLine
= RectangleFromRange(position
, position
);
902 rcSelMargin
.top
= rcLine
.top
;
903 rcSelMargin
.bottom
= rcLine
.bottom
;
905 wMain
.InvalidateRectangle(rcSelMargin
);
910 PRectangle
Editor::RectangleFromRange(int start
, int end
) {
917 int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(minPos
));
918 int lineDocMax
= pdoc
->LineFromPosition(maxPos
);
919 int maxLine
= cs
.DisplayFromDoc(lineDocMax
) + cs
.GetHeight(lineDocMax
) - 1;
920 PRectangle rcClient
= GetTextRectangle();
922 rc
.left
= vs
.fixedColumnWidth
;
923 rc
.top
= (minLine
- topLine
) * vs
.lineHeight
;
926 rc
.right
= rcClient
.right
;
927 rc
.bottom
= (maxLine
- topLine
+ 1) * vs
.lineHeight
;
928 // Ensure PRectangle is within 16 bit space
929 rc
.top
= Platform::Clamp(rc
.top
, -32000, 32000);
930 rc
.bottom
= Platform::Clamp(rc
.bottom
, -32000, 32000);
935 void Editor::InvalidateRange(int start
, int end
) {
936 RedrawRect(RectangleFromRange(start
, end
));
939 int Editor::CurrentPosition() {
943 bool Editor::SelectionEmpty() {
944 return anchor
== currentPos
;
947 int Editor::SelectionStart() {
948 return Platform::Minimum(currentPos
, anchor
);
951 int Editor::SelectionEnd() {
952 return Platform::Maximum(currentPos
, anchor
);
955 void Editor::SetRectangularRange() {
956 if (selType
== selRectangle
) {
957 xStartSelect
= XFromPosition(anchor
);
958 xEndSelect
= XFromPosition(currentPos
);
962 void Editor::InvalidateSelection(int currentPos_
, int anchor_
) {
963 int firstAffected
= anchor
;
964 if (firstAffected
> currentPos
)
965 firstAffected
= currentPos
;
966 if (firstAffected
> anchor_
)
967 firstAffected
= anchor_
;
968 if (firstAffected
> currentPos_
)
969 firstAffected
= currentPos_
;
970 int lastAffected
= anchor
;
971 if (lastAffected
< currentPos
)
972 lastAffected
= currentPos
;
973 if (lastAffected
< anchor_
)
974 lastAffected
= anchor_
;
975 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
976 lastAffected
= (currentPos_
+ 1);
978 InvalidateRange(firstAffected
, lastAffected
);
981 void Editor::SetSelection(int currentPos_
, int anchor_
) {
982 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
983 anchor_
= pdoc
->ClampPositionIntoDocument(anchor_
);
984 if ((currentPos
!= currentPos_
) || (anchor
!= anchor_
)) {
985 InvalidateSelection(currentPos_
, anchor_
);
986 currentPos
= currentPos_
;
989 SetRectangularRange();
993 void Editor::SetSelection(int currentPos_
) {
994 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
995 if (currentPos
!= currentPos_
) {
996 InvalidateSelection(currentPos_
, currentPos_
);
997 currentPos
= currentPos_
;
999 SetRectangularRange();
1003 void Editor::SetEmptySelection(int currentPos_
) {
1004 selType
= selStream
;
1005 moveExtendsSelection
= false;
1006 SetSelection(currentPos_
, currentPos_
);
1009 bool Editor::RangeContainsProtected(int start
, int end
) const {
1010 if (vs
.ProtectionActive()) {
1016 int mask
= pdoc
->stylingBitsMask
;
1017 for (int pos
= start
; pos
< end
; pos
++) {
1018 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected())
1025 bool Editor::SelectionContainsProtected() {
1026 // DONE, but untested...: make support rectangular selection
1028 if (selType
== selStream
) {
1029 scp
= RangeContainsProtected(anchor
, currentPos
);
1031 SelectionLineIterator
lineIterator(this);
1032 while (lineIterator
.Iterate()) {
1033 if (RangeContainsProtected(lineIterator
.startPos
, lineIterator
.endPos
)) {
1043 * Asks document to find a good position and then moves out of any invisible positions.
1045 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) {
1046 pos
= pdoc
->MovePositionOutsideChar(pos
, moveDir
, checkLineEnd
);
1047 if (vs
.ProtectionActive()) {
1048 int mask
= pdoc
->stylingBitsMask
;
1050 if ((pos
> 0) && vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()) {
1051 while ((pos
< pdoc
->Length()) &&
1052 (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected()))
1055 } else if (moveDir
< 0) {
1056 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected()) {
1058 (vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()))
1066 int Editor::MovePositionTo(int newPos
, selTypes sel
, bool ensureVisible
) {
1067 int delta
= newPos
- currentPos
;
1068 newPos
= pdoc
->ClampPositionIntoDocument(newPos
);
1069 newPos
= MovePositionOutsideChar(newPos
, delta
);
1073 if (sel
!= noSel
|| moveExtendsSelection
) {
1074 SetSelection(newPos
);
1076 SetEmptySelection(newPos
);
1078 ShowCaretAtCurrentPosition();
1079 if (ensureVisible
) {
1080 EnsureCaretVisible();
1086 int Editor::MovePositionSoVisible(int pos
, int moveDir
) {
1087 pos
= pdoc
->ClampPositionIntoDocument(pos
);
1088 pos
= MovePositionOutsideChar(pos
, moveDir
);
1089 int lineDoc
= pdoc
->LineFromPosition(pos
);
1090 if (cs
.GetVisible(lineDoc
)) {
1093 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
1095 // lineDisplay is already line before fold as lines in fold use display line of line after fold
1096 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
1097 return pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
));
1099 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
1100 return pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
));
1106 * Choose the x position that the caret will try to stick to
1107 * as it moves up and down.
1109 void Editor::SetLastXChosen() {
1110 Point pt
= LocationFromPosition(currentPos
);
1114 void Editor::ScrollTo(int line
, bool moveThumb
) {
1115 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
1116 if (topLineNew
!= topLine
) {
1117 // Try to optimise small scrolls
1118 int linesToMove
= topLine
- topLineNew
;
1119 SetTopLine(topLineNew
);
1120 ShowCaretAtCurrentPosition();
1121 // Perform redraw rather than scroll if many lines would be redrawn anyway.
1123 if (abs(linesToMove
) <= 10) {
1124 ScrollText(linesToMove
);
1132 SetVerticalScrollPos();
1137 void Editor::ScrollText(int /* linesToMove */) {
1138 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
1142 void Editor::HorizontalScrollTo(int xPos
) {
1143 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
1146 if ((wrapState
== eWrapNone
) && (xOffset
!= xPos
)) {
1148 SetHorizontalScrollPos();
1149 RedrawRect(GetClientRectangle());
1153 void Editor::MoveCaretInsideView(bool ensureVisible
) {
1154 PRectangle rcClient
= GetTextRectangle();
1155 Point pt
= LocationFromPosition(currentPos
);
1156 if (pt
.y
< rcClient
.top
) {
1157 MovePositionTo(PositionFromLocation(
1158 Point(lastXChosen
, rcClient
.top
)),
1159 noSel
, ensureVisible
);
1160 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
1161 int yOfLastLineFullyDisplayed
= rcClient
.top
+ (LinesOnScreen() - 1) * vs
.lineHeight
;
1162 MovePositionTo(PositionFromLocation(
1163 Point(lastXChosen
, rcClient
.top
+ yOfLastLineFullyDisplayed
)),
1164 noSel
, ensureVisible
);
1168 int Editor::DisplayFromPosition(int pos
) {
1169 int lineDoc
= pdoc
->LineFromPosition(pos
);
1170 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
1171 AutoSurface
surface(this);
1172 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
1173 if (surface
&& ll
) {
1174 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
1175 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
1176 int posInLine
= pos
- posLineStart
;
1177 lineDisplay
--; // To make up for first increment ahead.
1178 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
1179 if (posInLine
>= ll
->LineStart(subLine
)) {
1188 * Ensure the caret is reasonably visible in context.
1190 Caret policy in SciTE
1192 If slop is set, we can define a slop value.
1193 This value defines an unwanted zone (UZ) where the caret is... unwanted.
1194 This zone is defined as a number of pixels near the vertical margins,
1195 and as a number of lines near the horizontal margins.
1196 By keeping the caret away from the edges, it is seen within its context,
1197 so it is likely that the identifier that the caret is on can be completely seen,
1198 and that the current line is seen with some of the lines following it which are
1199 often dependent on that line.
1201 If strict is set, the policy is enforced... strictly.
1202 The caret is centred on the display if slop is not set,
1203 and cannot go in the UZ if slop is set.
1205 If jumps is set, the display is moved more energetically
1206 so the caret can move in the same direction longer before the policy is applied again.
1207 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1209 If even is not set, instead of having symmetrical UZs,
1210 the left and bottom UZs are extended up to right and top UZs respectively.
1211 This way, we favour the displaying of useful information: the begining of lines,
1212 where most code reside, and the lines after the caret, eg. the body of a function.
1215 slop | strict | jumps | even | Caret can go to the margin | When reaching limitÝ(caret going out of
1216 | | | | | visibility or going into the UZ) display is...
1217 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1218 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1219 0 | 0 | 0 | 1 | Yes | moved by one position
1220 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1221 0 | 0 | 1 | 1 | Yes | centred on the caret
1222 0 | 1 | - | 0 | Caret is always on top/on right of display | -
1223 0 | 1 | - | 1 | No, caret is always centred | -
1224 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1225 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1226 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1227 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1228 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1229 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1230 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1232 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
1233 //Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " ");
1234 PRectangle rcClient
= GetTextRectangle();
1235 //int rcClientFullWidth = rcClient.Width();
1236 int posCaret
= currentPos
;
1240 Point pt
= LocationFromPosition(posCaret
);
1241 Point ptBottomCaret
= pt
;
1242 ptBottomCaret
.y
+= vs
.lineHeight
- 1;
1243 int lineCaret
= DisplayFromPosition(posCaret
);
1244 bool bSlop
, bStrict
, bJump
, bEven
;
1246 // Vertical positioning
1247 if (vert
&& (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
> rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1248 int linesOnScreen
= LinesOnScreen();
1249 int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1250 int newTopLine
= topLine
;
1251 bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1252 bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1253 bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1254 bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1256 // It should be possible to scroll the window to show the caret,
1257 // but this fails to remove the caret on GTK+
1258 if (bSlop
) { // A margin is defined
1261 int yMarginT
, yMarginB
;
1263 // In drag mode, avoid moves
1264 // otherwise, a double click will select several lines.
1265 yMarginT
= yMarginB
= 0;
1267 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1268 // a maximum of slightly less than half the heigth of the text area.
1269 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1271 yMarginB
= yMarginT
;
1273 yMarginB
= linesOnScreen
- yMarginT
- 1;
1279 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1283 yMoveB
= linesOnScreen
- yMoveT
- 1;
1285 if (lineCaret
< topLine
+ yMarginT
) {
1286 // Caret goes too high
1287 newTopLine
= lineCaret
- yMoveT
;
1288 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1289 // Caret goes too low
1290 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1292 } else { // Not strict
1293 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1294 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1298 yMoveB
= linesOnScreen
- yMoveT
- 1;
1300 if (lineCaret
< topLine
) {
1301 // Caret goes too high
1302 newTopLine
= lineCaret
- yMoveT
;
1303 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1304 // Caret goes too low
1305 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1309 if (!bStrict
&& !bJump
) {
1311 if (lineCaret
< topLine
) {
1312 // Caret goes too high
1313 newTopLine
= lineCaret
;
1314 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1315 // Caret goes too low
1317 newTopLine
= lineCaret
- linesOnScreen
+ 1;
1319 newTopLine
= lineCaret
;
1322 } else { // Strict or going out of display
1324 // Always center caret
1325 newTopLine
= lineCaret
- halfScreen
;
1327 // Always put caret on top of display
1328 newTopLine
= lineCaret
;
1332 newTopLine
= Platform::Clamp(newTopLine
, 0, MaxScrollPos());
1333 if (newTopLine
!= topLine
) {
1335 SetTopLine(newTopLine
);
1336 SetVerticalScrollPos();
1340 // Horizontal positioning
1341 if (horiz
&& (wrapState
== eWrapNone
)) {
1342 int halfScreen
= Platform::Maximum(rcClient
.Width() - 4, 4) / 2;
1343 int xOffsetNew
= xOffset
;
1344 bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1345 bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1346 bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1347 bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1349 if (bSlop
) { // A margin is defined
1352 int xMarginL
, xMarginR
;
1354 // In drag mode, avoid moves unless very near of the margin
1355 // otherwise, a simple click will select text.
1356 xMarginL
= xMarginR
= 2;
1358 // xMargin must equal to caretXSlop, with a minimum of 2 and
1359 // a maximum of slightly less than half the width of the text area.
1360 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1362 xMarginL
= xMarginR
;
1364 xMarginL
= rcClient
.Width() - xMarginR
- 4;
1367 if (bJump
&& bEven
) {
1368 // Jump is used only in even mode
1369 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1371 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1373 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1374 // Caret is on the left of the display
1375 if (bJump
&& bEven
) {
1376 xOffsetNew
-= xMoveL
;
1378 // Move just enough to allow to display the caret
1379 xOffsetNew
-= (rcClient
.left
+ xMarginL
) - pt
.x
;
1381 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1382 // Caret is on the right of the display
1383 if (bJump
&& bEven
) {
1384 xOffsetNew
+= xMoveR
;
1386 // Move just enough to allow to display the caret
1387 xOffsetNew
+= pt
.x
- (rcClient
.right
- xMarginR
) + 1;
1390 } else { // Not strict
1391 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1392 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1396 xMoveL
= rcClient
.Width() - xMoveR
- 4;
1398 if (pt
.x
< rcClient
.left
) {
1399 // Caret is on the left of the display
1400 xOffsetNew
-= xMoveL
;
1401 } else if (pt
.x
>= rcClient
.right
) {
1402 // Caret is on the right of the display
1403 xOffsetNew
+= xMoveR
;
1408 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1409 // Strict or going out of display
1412 xOffsetNew
+= pt
.x
- rcClient
.left
- halfScreen
;
1414 // Put caret on right
1415 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1418 // Move just enough to allow to display the caret
1419 if (pt
.x
< rcClient
.left
) {
1420 // Caret is on the left of the display
1422 xOffsetNew
-= rcClient
.left
- pt
.x
;
1424 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1426 } else if (pt
.x
>= rcClient
.right
) {
1427 // Caret is on the right of the display
1428 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1432 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1433 if (pt
.x
+ xOffset
< rcClient
.left
+ xOffsetNew
) {
1434 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.left
;
1435 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ xOffsetNew
) {
1436 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.right
+ 1;
1438 if (xOffsetNew
< 0) {
1441 if (xOffset
!= xOffsetNew
) {
1442 xOffset
= xOffsetNew
;
1443 if (xOffsetNew
> 0) {
1444 PRectangle rcText
= GetTextRectangle();
1445 if (horizontalScrollBarVisible
== true &&
1446 rcText
.Width() + xOffset
> scrollWidth
) {
1447 scrollWidth
= xOffset
+ rcText
.Width();
1451 SetHorizontalScrollPos();
1455 UpdateSystemCaret();
1458 void Editor::ShowCaretAtCurrentPosition() {
1460 caret
.active
= true;
1464 caret
.active
= false;
1470 void Editor::DropCaret() {
1471 caret
.active
= false;
1475 void Editor::InvalidateCaret() {
1477 InvalidateRange(posDrag
, posDrag
+ 1);
1479 InvalidateRange(currentPos
, currentPos
+ 1);
1480 UpdateSystemCaret();
1483 void Editor::UpdateSystemCaret() {
1486 void Editor::NeedWrapping(int docLineStartWrapping
, int docLineEndWrapping
) {
1487 docLineStartWrapping
= Platform::Minimum(docLineStartWrapping
, pdoc
->LinesTotal()-1);
1488 docLineEndWrapping
= Platform::Minimum(docLineEndWrapping
, pdoc
->LinesTotal()-1);
1489 bool noWrap
= (docLastLineToWrap
== docLineLastWrapped
);
1490 if (docLineLastWrapped
> (docLineStartWrapping
- 1)) {
1491 docLineLastWrapped
= docLineStartWrapping
- 1;
1492 if (docLineLastWrapped
< -1)
1493 docLineLastWrapped
= -1;
1494 llc
.Invalidate(LineLayout::llPositions
);
1497 docLastLineToWrap
= docLineEndWrapping
;
1498 } else if (docLastLineToWrap
< docLineEndWrapping
) {
1499 docLastLineToWrap
= docLineEndWrapping
+ 1;
1501 if (docLastLineToWrap
< -1)
1502 docLastLineToWrap
= -1;
1503 if (docLastLineToWrap
>= pdoc
->LinesTotal())
1504 docLastLineToWrap
= pdoc
->LinesTotal()-1;
1505 // Wrap lines during idle.
1506 if ((wrapState
!= eWrapNone
) &&
1507 backgroundWrapEnabled
&&
1508 (docLastLineToWrap
!= docLineLastWrapped
)) {
1513 // Check if wrapping needed and perform any needed wrapping.
1514 // fullwrap: if true, all lines which need wrapping will be done,
1515 // in this single call.
1516 // priorityWrapLineStart: If greater than zero, all lines starting from
1517 // here to 100 lines past will be wrapped (even if there are
1518 // more lines under wrapping process in idle).
1519 // If it is neither fullwrap, nor priorityWrap, then 100 lines will be
1520 // wrapped, if there are any wrapping going on in idle. (Generally this
1521 // condition is called only from idler).
1522 // Return true if wrapping occurred.
1523 bool Editor::WrapLines(bool fullWrap
, int priorityWrapLineStart
) {
1524 // If there are any pending wraps, do them during idle if possible.
1525 if (wrapState
!= eWrapNone
) {
1526 if (docLineLastWrapped
< docLastLineToWrap
) {
1527 if (!(backgroundWrapEnabled
&& SetIdle(true))) {
1528 // Background wrapping is disabled, or idle processing
1529 // not supported. A full wrap is required.
1533 if (!fullWrap
&& priorityWrapLineStart
>= 0 &&
1534 // .. and if the paint window is outside pending wraps
1535 (((priorityWrapLineStart
+ 100) < docLineLastWrapped
) ||
1536 (priorityWrapLineStart
> docLastLineToWrap
))) {
1537 // No priority wrap pending
1541 int goodTopLine
= topLine
;
1542 bool wrapOccurred
= false;
1543 if (docLineLastWrapped
< pdoc
->LinesTotal()) {
1544 if (wrapState
== eWrapNone
) {
1545 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1546 wrapWidth
= LineLayout::wrapWidthInfinite
;
1547 for (int lineDoc
= 0; lineDoc
< pdoc
->LinesTotal(); lineDoc
++) {
1548 cs
.SetHeight(lineDoc
, 1);
1550 wrapOccurred
= true;
1552 docLineLastWrapped
= 0x7ffffff;
1555 int lineDocTop
= cs
.DocFromDisplay(topLine
);
1556 int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1557 PRectangle rcTextArea
= GetClientRectangle();
1558 rcTextArea
.left
= vs
.fixedColumnWidth
;
1559 rcTextArea
.right
-= vs
.rightMarginWidth
;
1560 wrapWidth
= rcTextArea
.Width();
1561 // Ensure all of the document is styled.
1562 pdoc
->EnsureStyledTo(pdoc
->Length());
1564 AutoSurface
surface(this);
1566 bool priorityWrap
= false;
1567 int lastLineToWrap
= docLastLineToWrap
;
1568 int firstLineToWrap
= docLineLastWrapped
;
1570 if (priorityWrapLineStart
>= 0) {
1571 // This is a priority wrap.
1572 firstLineToWrap
= priorityWrapLineStart
;
1573 lastLineToWrap
= firstLineToWrap
+ 100;
1574 priorityWrap
= true;
1576 // This is idle wrap.
1577 lastLineToWrap
= docLineLastWrapped
+ 100;
1579 if (lastLineToWrap
>= docLastLineToWrap
)
1580 lastLineToWrap
= docLastLineToWrap
;
1581 } // else do a fullWrap.
1583 // printf("Wraplines: full = %d, priorityStart = %d (wrapping: %d to %d)\n", fullWrap, priorityWrapLineStart, firstLineToWrap, lastLineToWrap);
1584 // printf("Pending wraps: %d to %d\n", docLineLastWrapped, docLastLineToWrap);
1585 while (firstLineToWrap
< lastLineToWrap
) {
1588 docLineLastWrapped
++;
1589 if (firstLineToWrap
< pdoc
->LinesTotal()) {
1590 AutoLineLayout
ll(llc
, RetrieveLineLayout(firstLineToWrap
));
1591 int linesWrapped
= 1;
1593 LayoutLine(firstLineToWrap
, surface
, vs
, ll
, wrapWidth
);
1594 linesWrapped
= ll
->lines
;
1596 if (cs
.SetHeight(firstLineToWrap
, linesWrapped
)) {
1597 wrapOccurred
= true;
1601 // If wrapping is done, bring it to resting position
1602 if (docLineLastWrapped
> docLastLineToWrap
) {
1603 docLineLastWrapped
= -1;
1604 docLastLineToWrap
= -1;
1607 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
);
1608 if (subLineTop
< cs
.GetHeight(lineDocTop
))
1609 goodTopLine
+= subLineTop
;
1611 goodTopLine
+= cs
.GetHeight(lineDocTop
);
1612 //double durWrap = et.Duration(true);
1613 //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap);
1618 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1619 SetVerticalScrollPos();
1621 return wrapOccurred
;
1624 void Editor::LinesJoin() {
1625 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1626 pdoc
->BeginUndoAction();
1627 bool prevNonWS
= true;
1628 for (int pos
= targetStart
; pos
< targetEnd
; pos
++) {
1629 if (IsEOLChar(pdoc
->CharAt(pos
))) {
1630 targetEnd
-= pdoc
->LenChar(pos
);
1633 // Ensure at least one space separating previous lines
1634 pdoc
->InsertChar(pos
, ' ');
1637 prevNonWS
= pdoc
->CharAt(pos
) != ' ';
1640 pdoc
->EndUndoAction();
1644 const char *StringFromEOLMode(int eolMode
) {
1645 if (eolMode
== SC_EOL_CRLF
) {
1647 } else if (eolMode
== SC_EOL_CR
) {
1654 void Editor::LinesSplit(int pixelWidth
) {
1655 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1656 if (pixelWidth
== 0) {
1657 PRectangle rcText
= GetTextRectangle();
1658 pixelWidth
= rcText
.Width();
1660 int lineStart
= pdoc
->LineFromPosition(targetStart
);
1661 int lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1662 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1663 pdoc
->BeginUndoAction();
1664 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
1665 AutoSurface
surface(this);
1666 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
1667 if (surface
&& ll
) {
1668 unsigned int posLineStart
= pdoc
->LineStart(line
);
1669 LayoutLine(line
, surface
, vs
, ll
, pixelWidth
);
1670 for (int subLine
= 1; subLine
< ll
->lines
; subLine
++) {
1671 pdoc
->InsertString(posLineStart
+ (subLine
- 1) * strlen(eol
) +
1672 ll
->LineStart(subLine
), eol
);
1673 targetEnd
+= static_cast<int>(strlen(eol
));
1677 pdoc
->EndUndoAction();
1681 int Editor::SubstituteMarkerIfEmpty(int markerCheck
, int markerDefault
) {
1682 if (vs
.markers
[markerCheck
].markType
== SC_MARK_EMPTY
)
1683 return markerDefault
;
1687 // Avoid 64 bit compiler warnings.
1688 // Scintilla does not support text buffers larger than 2**31
1689 static int istrlen(const char *s
) {
1690 return static_cast<int>(strlen(s
));
1693 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1694 if (vs
.fixedColumnWidth
== 0)
1697 PRectangle rcMargin
= GetClientRectangle();
1698 rcMargin
.right
= vs
.fixedColumnWidth
;
1700 if (!rc
.Intersects(rcMargin
))
1705 surface
= pixmapSelMargin
;
1707 surface
= surfWindow
;
1710 PRectangle rcSelMargin
= rcMargin
;
1711 rcSelMargin
.right
= rcMargin
.left
;
1713 for (int margin
= 0; margin
< vs
.margins
; margin
++) {
1714 if (vs
.ms
[margin
].width
> 0) {
1716 rcSelMargin
.left
= rcSelMargin
.right
;
1717 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
1719 if (vs
.ms
[margin
].symbol
) {
1720 /* alternate scheme:
1721 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
1722 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1724 // Required because of special way brush is created for selection margin
1725 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
1727 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
1728 // Required because of special way brush is created for selection margin
1729 surface
->FillRectangle(rcSelMargin
, *pixmapSelPattern
);
1731 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1733 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1736 int visibleLine
= topLine
;
1739 // Work out whether the top line is whitespace located after a
1740 // lessening of fold level which implies a 'fold tail' but which should not
1741 // be displayed until the last of a sequence of whitespace.
1742 bool needWhiteClosure
= false;
1743 int level
= pdoc
->GetLevel(cs
.DocFromDisplay(topLine
));
1744 if (level
& SC_FOLDLEVELWHITEFLAG
) {
1745 int lineBack
= cs
.DocFromDisplay(topLine
);
1746 int levelPrev
= level
;
1747 while ((lineBack
> 0) && (levelPrev
& SC_FOLDLEVELWHITEFLAG
)) {
1749 levelPrev
= pdoc
->GetLevel(lineBack
);
1751 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
1752 if ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelPrev
& SC_FOLDLEVELNUMBERMASK
))
1753 needWhiteClosure
= true;
1757 // Old code does not know about new markers needed to distinguish all cases
1758 int folderOpenMid
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID
,
1759 SC_MARKNUM_FOLDEROPEN
);
1760 int folderEnd
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND
,
1763 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
1765 PLATFORM_ASSERT(visibleLine
< cs
.LinesDisplayed());
1767 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
1768 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
1769 bool firstSubLine
= visibleLine
== cs
.DisplayFromDoc(lineDoc
);
1771 // Decide which fold indicator should be displayed
1772 level
= pdoc
->GetLevel(lineDoc
);
1773 int levelNext
= pdoc
->GetLevel(lineDoc
+ 1);
1774 int marks
= pdoc
->GetMark(lineDoc
);
1777 int levelNum
= level
& SC_FOLDLEVELNUMBERMASK
;
1778 int levelNextNum
= levelNext
& SC_FOLDLEVELNUMBERMASK
;
1779 if (level
& SC_FOLDLEVELHEADERFLAG
) {
1781 if (cs
.GetExpanded(lineDoc
)) {
1782 if (levelNum
== SC_FOLDLEVELBASE
)
1783 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
1785 marks
|= 1 << folderOpenMid
;
1787 if (levelNum
== SC_FOLDLEVELBASE
)
1788 marks
|= 1 << SC_MARKNUM_FOLDER
;
1790 marks
|= 1 << folderEnd
;
1793 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1795 needWhiteClosure
= false;
1796 } else if (level
& SC_FOLDLEVELWHITEFLAG
) {
1797 if (needWhiteClosure
) {
1798 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1799 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1800 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1801 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1802 needWhiteClosure
= false;
1804 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1805 needWhiteClosure
= false;
1807 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1808 if (levelNextNum
< levelNum
) {
1809 if (levelNextNum
> SC_FOLDLEVELBASE
) {
1810 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1812 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1815 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1818 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1819 if (levelNextNum
< levelNum
) {
1820 needWhiteClosure
= false;
1821 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1822 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1823 needWhiteClosure
= true;
1824 } else if (levelNextNum
> SC_FOLDLEVELBASE
) {
1825 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1827 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1830 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1834 marks
&= vs
.ms
[margin
].mask
;
1835 PRectangle rcMarker
= rcSelMargin
;
1836 rcMarker
.top
= yposScreen
;
1837 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
1838 if (!vs
.ms
[margin
].symbol
) {
1842 sprintf(number
, "%d", lineDoc
+ 1);
1843 if (foldFlags
& SC_FOLDFLAG_LEVELNUMBERS
) {
1844 int lev
= pdoc
->GetLevel(lineDoc
);
1845 sprintf(number
, "%c%c %03X %03X",
1846 (lev
& SC_FOLDLEVELHEADERFLAG
) ? 'H' : '_',
1847 (lev
& SC_FOLDLEVELWHITEFLAG
) ? 'W' : '_',
1848 lev
& SC_FOLDLEVELNUMBERMASK
,
1852 PRectangle rcNumber
= rcMarker
;
1854 int width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
1855 int xpos
= rcNumber
.right
- width
- 3;
1856 rcNumber
.left
= xpos
;
1857 surface
->DrawTextNoClip(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
1858 rcNumber
.top
+ vs
.maxAscent
, number
, istrlen(number
),
1859 vs
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
1860 vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1864 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1866 vs
.markers
[markBit
].Draw(surface
, rcMarker
, vs
.styles
[STYLE_LINENUMBER
].font
);
1873 yposScreen
+= vs
.lineHeight
;
1878 PRectangle rcBlankMargin
= rcMargin
;
1879 rcBlankMargin
.left
= rcSelMargin
.right
;
1880 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1883 surfWindow
->Copy(rcMargin
, Point(), *pixmapSelMargin
);
1887 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
1888 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
1889 int xhead
= rcTab
.right
- 1 - ydiff
;
1890 if (xhead
<= rcTab
.left
) {
1891 ydiff
-= rcTab
.left
- xhead
- 1;
1892 xhead
= rcTab
.left
- 1;
1894 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
1895 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
1897 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1898 surface
->LineTo(rcTab
.right
- 1, ymid
);
1899 surface
->LineTo(xhead
, ymid
- ydiff
);
1900 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1901 surface
->LineTo(xhead
, ymid
+ ydiff
);
1904 static bool IsSpaceOrTab(char ch
) {
1905 return ch
== ' ' || ch
== '\t';
1908 LineLayout
*Editor::RetrieveLineLayout(int lineNumber
) {
1909 int posLineStart
= pdoc
->LineStart(lineNumber
);
1910 int posLineEnd
= pdoc
->LineStart(lineNumber
+ 1);
1911 int lineCaret
= pdoc
->LineFromPosition(currentPos
);
1912 return llc
.Retrieve(lineNumber
, lineCaret
,
1913 posLineEnd
- posLineStart
, pdoc
->GetStyleClock(),
1914 LinesOnScreen() + 1, pdoc
->LinesTotal());
1918 * Fill in the LineLayout data for the given line.
1919 * Copy the given @a line and its styles from the document into local arrays.
1920 * Also determine the x position at which each character starts.
1922 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
*ll
, int width
) {
1925 PLATFORM_ASSERT(line
< pdoc
->LinesTotal());
1926 int posLineStart
= pdoc
->LineStart(line
);
1927 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1928 // If the line is very long, limit the treatment to a length that should fit in the viewport
1929 if (posLineEnd
> (posLineStart
+ ll
->maxLineLength
)) {
1930 posLineEnd
= posLineStart
+ ll
->maxLineLength
;
1932 if (ll
->validity
== LineLayout::llCheckTextAndStyle
) {
1933 int lineLength
= posLineEnd
- posLineStart
;
1934 if (!vstyle
.viewEOL
) {
1935 int cid
= posLineEnd
- 1;
1936 while ((cid
> posLineStart
) && IsEOLChar(pdoc
->CharAt(cid
))) {
1941 if (lineLength
== ll
->numCharsInLine
) {
1942 // See if chars, styles, indicators, are all the same
1943 bool allSame
= true;
1944 const int styleMask
= pdoc
->stylingBitsMask
;
1945 // Check base line layout
1947 int numCharsInLine
= 0;
1948 while (numCharsInLine
< lineLength
) {
1949 int charInDoc
= numCharsInLine
+ posLineStart
;
1950 char chDoc
= pdoc
->CharAt(charInDoc
);
1951 styleByte
= pdoc
->StyleAt(charInDoc
);
1952 allSame
= allSame
&&
1953 (ll
->styles
[numCharsInLine
] == static_cast<unsigned char>(styleByte
& styleMask
));
1954 allSame
= allSame
&&
1955 (ll
->indicators
[numCharsInLine
] == static_cast<char>(styleByte
& ~styleMask
));
1956 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseMixed
)
1957 allSame
= allSame
&&
1958 (ll
->chars
[numCharsInLine
] == chDoc
);
1959 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1960 allSame
= allSame
&&
1961 (ll
->chars
[numCharsInLine
] == static_cast<char>(tolower(chDoc
)));
1962 else // Style::caseUpper
1963 allSame
= allSame
&&
1964 (ll
->chars
[numCharsInLine
] == static_cast<char>(toupper(chDoc
)));
1967 allSame
= allSame
&& (ll
->styles
[numCharsInLine
] == styleByte
); // For eolFilled
1969 ll
->validity
= LineLayout::llPositions
;
1971 ll
->validity
= LineLayout::llInvalid
;
1974 ll
->validity
= LineLayout::llInvalid
;
1977 if (ll
->validity
== LineLayout::llInvalid
) {
1978 ll
->widthLine
= LineLayout::wrapWidthInfinite
;
1980 int numCharsInLine
= 0;
1981 if (vstyle
.edgeState
== EDGE_BACKGROUND
) {
1982 ll
->edgeColumn
= pdoc
->FindColumn(line
, theEdge
);
1983 if (ll
->edgeColumn
>= posLineStart
) {
1984 ll
->edgeColumn
-= posLineStart
;
1987 ll
->edgeColumn
= -1;
1991 int styleMask
= pdoc
->stylingBitsMask
;
1992 ll
->styleBitsSet
= 0;
1993 // Fill base line layout
1994 for (int charInDoc
= posLineStart
; charInDoc
< posLineEnd
; charInDoc
++) {
1995 char chDoc
= pdoc
->CharAt(charInDoc
);
1996 styleByte
= pdoc
->StyleAt(charInDoc
);
1997 ll
->styleBitsSet
|= styleByte
;
1998 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
1999 ll
->chars
[numCharsInLine
] = chDoc
;
2000 ll
->styles
[numCharsInLine
] = static_cast<char>(styleByte
& styleMask
);
2001 ll
->indicators
[numCharsInLine
] = static_cast<char>(styleByte
& ~styleMask
);
2002 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
2003 ll
->chars
[numCharsInLine
] = static_cast<char>(toupper(chDoc
));
2004 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
2005 ll
->chars
[numCharsInLine
] = static_cast<char>(tolower(chDoc
));
2009 ll
->xHighlightGuide
= 0;
2010 // Extra element at the end of the line to hold end x position and act as
2011 ll
->chars
[numCharsInLine
] = 0; // Also triggers processing in the loops as this is a control character
2012 ll
->styles
[numCharsInLine
] = styleByte
; // For eolFilled
2013 ll
->indicators
[numCharsInLine
] = 0;
2015 // Layout the line, determining the position of each character,
2016 // with an extra element at the end for the end of the line.
2017 int startseg
= 0; // Start of the current segment, in char. number
2018 int startsegx
= 0; // Start of the current segment, in pixels
2019 ll
->positions
[0] = 0;
2020 unsigned int tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
2021 bool lastSegItalics
= false;
2022 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
2024 int ctrlCharWidth
[32] = {0};
2025 bool isControlNext
= IsControlCharacter(ll
->chars
[0]);
2026 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
2027 bool isControl
= isControlNext
;
2028 isControlNext
= IsControlCharacter(ll
->chars
[charInLine
+ 1]);
2029 if ((ll
->styles
[charInLine
] != ll
->styles
[charInLine
+ 1]) ||
2030 isControl
|| isControlNext
) {
2031 ll
->positions
[startseg
] = 0;
2032 if (vstyle
.styles
[ll
->styles
[charInLine
]].visible
) {
2034 if (ll
->chars
[charInLine
] == '\t') {
2035 ll
->positions
[charInLine
+ 1] = ((((startsegx
+ 2) /
2036 tabWidth
) + 1) * tabWidth
) - startsegx
;
2037 } else if (controlCharSymbol
< 32) {
2038 if (ctrlCharWidth
[ll
->chars
[charInLine
]] == 0) {
2039 const char *ctrlChar
= ControlCharacterString(ll
->chars
[charInLine
]);
2040 // +3 For a blank on front and rounded edge each side:
2041 ctrlCharWidth
[ll
->chars
[charInLine
]] =
2042 surface
->WidthText(ctrlCharsFont
, ctrlChar
, istrlen(ctrlChar
)) + 3;
2044 ll
->positions
[charInLine
+ 1] = ctrlCharWidth
[ll
->chars
[charInLine
]];
2046 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
2047 surface
->MeasureWidths(ctrlCharsFont
, cc
, 1,
2048 ll
->positions
+ startseg
+ 1);
2050 lastSegItalics
= false;
2051 } else { // Regular character
2052 int lenSeg
= charInLine
- startseg
+ 1;
2053 if ((lenSeg
== 1) && (' ' == ll
->chars
[startseg
])) {
2054 lastSegItalics
= false;
2055 // Over half the segments are single characters and of these about half are space characters.
2056 ll
->positions
[charInLine
+ 1] = vstyle
.styles
[ll
->styles
[charInLine
]].spaceWidth
;
2058 lastSegItalics
= vstyle
.styles
[ll
->styles
[charInLine
]].italic
;
2059 surface
->MeasureWidths(vstyle
.styles
[ll
->styles
[charInLine
]].font
, ll
->chars
+ startseg
,
2060 lenSeg
, ll
->positions
+ startseg
+ 1);
2063 } else { // invisible
2064 for (int posToZero
= startseg
; posToZero
<= (charInLine
+ 1); posToZero
++) {
2065 ll
->positions
[posToZero
] = 0;
2068 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
2069 ll
->positions
[posToIncrease
] += startsegx
;
2071 startsegx
= ll
->positions
[charInLine
+ 1];
2072 startseg
= charInLine
+ 1;
2075 // Small hack to make lines that end with italics not cut off the edge of the last character
2076 if ((startseg
> 0) && lastSegItalics
) {
2077 ll
->positions
[startseg
] += 2;
2079 ll
->numCharsInLine
= numCharsInLine
;
2080 ll
->validity
= LineLayout::llPositions
;
2082 // Hard to cope when too narrow, so just assume there is space
2086 if ((ll
->validity
== LineLayout::llPositions
) || (ll
->widthLine
!= width
)) {
2087 ll
->widthLine
= width
;
2088 if (width
== LineLayout::wrapWidthInfinite
) {
2090 } else if (width
> ll
->positions
[ll
->numCharsInLine
]) {
2091 // Simple common case where line does not need wrapping.
2094 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_END
) {
2095 width
-= vstyle
.aveCharWidth
; // take into account the space for end wrap mark
2098 // Calculate line start positions based upon width.
2099 // For now this is simplistic - wraps on byte rather than character and
2100 // in the middle of words. Should search for spaces or style changes.
2101 int lastGoodBreak
= 0;
2102 int lastLineStart
= 0;
2103 int startOffset
= 0;
2105 while (p
< ll
->numCharsInLine
) {
2106 if ((ll
->positions
[p
+ 1] - startOffset
) >= width
) {
2107 if (lastGoodBreak
== lastLineStart
) {
2108 // Try moving to start of last character
2110 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
2113 if (lastGoodBreak
== lastLineStart
) {
2114 // Ensure at least one character on line.
2115 lastGoodBreak
= pdoc
->MovePositionOutsideChar(lastGoodBreak
+ posLineStart
+ 1, 1)
2119 lastLineStart
= lastGoodBreak
;
2121 ll
->SetLineStart(ll
->lines
, lastGoodBreak
);
2122 startOffset
= ll
->positions
[lastGoodBreak
];
2123 // take into account the space for start wrap mark and indent
2124 startOffset
-= actualWrapVisualStartIndent
* vstyle
.aveCharWidth
;
2125 p
= lastGoodBreak
+ 1;
2129 if (wrapState
== eWrapChar
){
2130 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
2132 p
= pdoc
->MovePositionOutsideChar(p
+ 1 + posLineStart
, 1) - posLineStart
;
2134 } else if (ll
->styles
[p
] != ll
->styles
[p
- 1]) {
2136 } else if (IsSpaceOrTab(ll
->chars
[p
- 1]) && !IsSpaceOrTab(ll
->chars
[p
])) {
2144 ll
->validity
= LineLayout::llLines
;
2148 ColourAllocated
Editor::TextBackground(ViewStyle
&vsDraw
, bool overrideBackground
,
2149 ColourAllocated background
, bool inSelection
, bool inHotspot
, int styleMain
, int i
, LineLayout
*ll
) {
2151 if (vsDraw
.selbackset
) {
2152 if (primarySelection
)
2153 return vsDraw
.selbackground
.allocated
;
2155 return vsDraw
.selbackground2
.allocated
;
2158 if ((vsDraw
.edgeState
== EDGE_BACKGROUND
) &&
2159 (i
>= ll
->edgeColumn
) &&
2160 !IsEOLChar(ll
->chars
[i
]))
2161 return vsDraw
.edgecolour
.allocated
;
2162 if (inHotspot
&& vsDraw
.hotspotBackgroundSet
)
2163 return vsDraw
.hotspotBackground
.allocated
;
2164 if (overrideBackground
)
2167 return vsDraw
.styles
[styleMain
].back
.allocated
;
2170 void Editor::DrawIndentGuide(Surface
*surface
, int lineVisible
, int lineHeight
, int start
, PRectangle rcSegment
, bool highlight
) {
2171 Point
from(0, ((lineVisible
& 1) && (lineHeight
& 1)) ? 1 : 0);
2172 PRectangle
rcCopyArea(start
+ 1, rcSegment
.top
, start
+ 2, rcSegment
.bottom
);
2173 surface
->Copy(rcCopyArea
, from
,
2174 highlight
? *pixmapIndentGuideHighlight
: *pixmapIndentGuide
);
2177 void Editor::DrawWrapMarker(Surface
*surface
, PRectangle rcPlace
,
2178 bool isEndMarker
, ColourAllocated wrapColour
) {
2179 surface
->PenColour(wrapColour
);
2181 enum { xa
= 1 }; // gap before start
2182 int w
= rcPlace
.right
- rcPlace
.left
- xa
- 1;
2184 bool xStraight
= isEndMarker
; // x-mirrored symbol for start marker
2185 bool yStraight
= true;
2186 //bool yStraight= isEndMarker; // comment in for start marker y-mirrowed
2188 int x0
= xStraight
? rcPlace
.left
: rcPlace
.right
- 1;
2189 int y0
= yStraight
? rcPlace
.top
: rcPlace
.bottom
- 1;
2191 int dy
= (rcPlace
.bottom
- rcPlace
.top
) / 5;
2192 int y
= (rcPlace
.bottom
- rcPlace
.top
) / 2 + dy
;
2200 void MoveTo(int xRelative
, int yRelative
) {
2201 surface
->MoveTo(xBase
+ xDir
* xRelative
, yBase
+ yDir
* yRelative
);
2203 void LineTo(int xRelative
, int yRelative
) {
2204 surface
->LineTo(xBase
+ xDir
* xRelative
, yBase
+ yDir
* yRelative
);
2207 Relative rel
= {surface
, x0
, xStraight
?1:-1, y0
, yStraight
?1:-1};
2211 rel
.LineTo(xa
+ 2*w
/ 3, y
- dy
);
2213 rel
.LineTo(xa
+ 2*w
/ 3, y
+ dy
);
2217 rel
.LineTo(xa
+ w
, y
);
2218 rel
.LineTo(xa
+ w
, y
- 2 * dy
);
2219 rel
.LineTo(xa
- 1, // on windows lineto is exclusive endpoint, perhaps GTK not...
2223 void Editor::DrawEOL(Surface
*surface
, ViewStyle
&vsDraw
, PRectangle rcLine
, LineLayout
*ll
,
2224 int line
, int lineEnd
, int xStart
, int subLine
, int subLineStart
,
2225 bool overrideBackground
, ColourAllocated background
,
2226 bool drawWrapMarkEnd
, ColourAllocated wrapColour
) {
2228 int styleMask
= pdoc
->stylingBitsMask
;
2229 PRectangle rcSegment
= rcLine
;
2231 // Fill in a PRectangle representing the end of line characters
2232 int xEol
= ll
->positions
[lineEnd
] - subLineStart
;
2233 rcSegment
.left
= xEol
+ xStart
;
2234 rcSegment
.right
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
2235 int posLineEnd
= pdoc
->LineStart(line
+ 1);
2236 bool eolInSelection
= (subLine
== (ll
->lines
- 1)) &&
2237 (posLineEnd
> ll
->selStart
) && (posLineEnd
<= ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2239 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1)) {
2240 if (primarySelection
)
2241 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground
.allocated
);
2243 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground2
.allocated
);
2244 } else if (overrideBackground
) {
2245 surface
->FillRectangle(rcSegment
, background
);
2247 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2250 rcSegment
.left
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
2251 rcSegment
.right
= rcLine
.right
;
2252 if (overrideBackground
) {
2253 surface
->FillRectangle(rcSegment
, background
);
2254 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
2255 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2257 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
2260 if (drawWrapMarkEnd
) {
2261 PRectangle rcPlace
= rcSegment
;
2263 if (wrapVisualFlagsLocation
& SC_WRAPVISUALFLAGLOC_END_BY_TEXT
) {
2264 rcPlace
.left
= xEol
+ xStart
;
2265 rcPlace
.right
= rcPlace
.left
+ vsDraw
.aveCharWidth
;
2267 // draw left of the right text margin, to avoid clipping by the current clip rect
2268 rcPlace
.right
= rcLine
.right
- vs
.rightMarginWidth
;
2269 rcPlace
.left
= rcPlace
.right
- vsDraw
.aveCharWidth
;
2271 DrawWrapMarker(surface
, rcPlace
, true, wrapColour
);
2275 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int lineVisible
, int xStart
,
2276 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
2278 PRectangle rcSegment
= rcLine
;
2280 // Using one font for all control characters so it can be controlled independently to ensure
2281 // the box goes around the characters tightly. Seems to be no way to work out what height
2282 // is taken by an individual character - internal leading gives varying results.
2283 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
2285 // See if something overrides the line background color: Either if caret is on the line
2286 // and background color is set for that, or if a marker is defined that forces its background
2287 // color onto the line, or if a marker is defined but has no selection margin in which to
2288 // display itself (as long as it's not an SC_MARK_EMPTY marker). These are checked in order
2289 // with the earlier taking precedence. When multiple markers cause background override,
2290 // the color for the highest numbered one is used.
2291 bool overrideBackground
= false;
2292 ColourAllocated background
;
2293 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& ll
->containsCaret
) {
2294 overrideBackground
= true;
2295 background
= vsDraw
.caretLineBackground
.allocated
;
2297 if (!overrideBackground
) {
2298 int marks
= pdoc
->GetMark(line
);
2299 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2300 if ((marks
& 1) && vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
) {
2301 background
= vsDraw
.markers
[markBit
].back
.allocated
;
2302 overrideBackground
= true;
2307 if (!overrideBackground
) {
2308 if (vsDraw
.maskInLine
) {
2309 int marks
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
2311 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2312 if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
!= SC_MARK_EMPTY
)) {
2313 overrideBackground
= true;
2314 background
= vsDraw
.markers
[markBit
].back
.allocated
;
2322 bool drawWhitespaceBackground
= (vsDraw
.viewWhitespace
!= wsInvisible
) &&
2323 (!overrideBackground
) && (vsDraw
.whitespaceBackgroundSet
);
2325 bool inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2326 int indentWidth
= pdoc
->IndentSize() * vsDraw
.spaceWidth
;
2328 int posLineStart
= pdoc
->LineStart(line
);
2330 int startseg
= ll
->LineStart(subLine
);
2331 int subLineStart
= ll
->positions
[startseg
];
2334 if (subLine
< ll
->lines
) {
2335 lineStart
= ll
->LineStart(subLine
);
2336 lineEnd
= ll
->LineStart(subLine
+ 1);
2339 bool drawWrapMarkEnd
= false;
2341 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_END
) {
2342 if (subLine
+ 1 < ll
->lines
) {
2343 drawWrapMarkEnd
= ll
->LineStart(subLine
+ 1) != 0;
2347 if (actualWrapVisualStartIndent
!= 0) {
2349 bool continuedWrapLine
= false;
2350 if (subLine
< ll
->lines
) {
2351 continuedWrapLine
= ll
->LineStart(subLine
) != 0;
2354 if (continuedWrapLine
) {
2355 // draw continuation rect
2356 PRectangle rcPlace
= rcSegment
;
2358 rcPlace
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2359 rcPlace
.right
= rcPlace
.left
+ actualWrapVisualStartIndent
* vsDraw
.aveCharWidth
;
2361 // default bgnd here..
2362 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
2364 // main line style would be below but this would be inconsistent with end markers
2365 // also would possibly not be the style at wrap point
2366 //int styleMain = ll->styles[lineStart];
2367 //surface->FillRectangle(rcPlace, vsDraw.styles[styleMain].back.allocated);
2369 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) {
2371 if (wrapVisualFlagsLocation
& SC_WRAPVISUALFLAGLOC_START_BY_TEXT
)
2372 rcPlace
.left
= rcPlace
.right
- vsDraw
.aveCharWidth
;
2374 rcPlace
.right
= rcPlace
.left
+ vsDraw
.aveCharWidth
;
2376 DrawWrapMarker(surface
, rcPlace
, false, vsDraw
.whitespaceForeground
.allocated
);
2379 xStart
+= actualWrapVisualStartIndent
* vsDraw
.aveCharWidth
;
2385 // Background drawing loop
2386 for (i
= lineStart
; twoPhaseDraw
&& (i
< lineEnd
); i
++) {
2388 int iDoc
= i
+ posLineStart
;
2389 // If there is the end of a style run for any reason
2390 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
2391 i
== (lineEnd
- 1) ||
2392 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
2393 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
2394 (i
== (ll
->edgeColumn
- 1))) {
2395 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2396 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2397 // Only try to draw if really visible - enhances performance by not calling environment to
2398 // draw strings that are completely past the right side of the window.
2399 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2400 int styleMain
= ll
->styles
[i
];
2401 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2402 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2403 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2404 if (ll
->chars
[i
] == '\t') {
2406 if (drawWhitespaceBackground
&&
2407 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2408 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2409 surface
->FillRectangle(rcSegment
, textBack
);
2410 } else if (IsControlCharacter(ll
->chars
[i
])) {
2411 // Control character display
2412 inIndentation
= false;
2413 surface
->FillRectangle(rcSegment
, textBack
);
2415 // Normal text display
2416 surface
->FillRectangle(rcSegment
, textBack
);
2417 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2418 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
2419 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2420 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2421 if (drawWhitespaceBackground
&&
2422 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2423 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
,
2424 ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2425 surface
->FillRectangle(rcSpace
, vsDraw
.whitespaceBackground
.allocated
);
2428 inIndentation
= false;
2433 } else if (rcSegment
.left
> rcLine
.right
) {
2441 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2442 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
2443 drawWrapMarkEnd
, vsDraw
.whitespaceForeground
.allocated
);
2446 inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2447 startseg
= ll
->LineStart(subLine
);
2448 // Foreground drawing loop
2449 for (i
= lineStart
; i
< lineEnd
; i
++) {
2451 int iDoc
= i
+ posLineStart
;
2452 // If there is the end of a style run for any reason
2453 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
2454 i
== (lineEnd
- 1) ||
2455 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
2456 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
2457 (i
== (ll
->edgeColumn
- 1))) {
2458 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2459 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2460 // Only try to draw if really visible - enhances performance by not calling environment to
2461 // draw strings that are completely past the right side of the window.
2462 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2463 int styleMain
= ll
->styles
[i
];
2464 ColourAllocated textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
2465 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
2466 //hotspot foreground
2467 if (ll
->hsStart
!= -1 && iDoc
>= ll
->hsStart
&& iDoc
< hsEnd
) {
2468 if (vsDraw
.hotspotForegroundSet
)
2469 textFore
= vsDraw
.hotspotForeground
.allocated
;
2471 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2472 if (inSelection
&& (vsDraw
.selforeset
)) {
2473 textFore
= vsDraw
.selforeground
.allocated
;
2475 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2476 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2477 if (ll
->chars
[i
] == '\t') {
2479 if (!twoPhaseDraw
) {
2480 if (drawWhitespaceBackground
&&
2481 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2482 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2483 surface
->FillRectangle(rcSegment
, textBack
);
2485 if ((vsDraw
.viewWhitespace
!= wsInvisible
) || ((inIndentation
&& vsDraw
.viewIndentationGuides
))) {
2486 if (vsDraw
.whitespaceForegroundSet
)
2487 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2488 surface
->PenColour(textFore
);
2490 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
2491 for (int xIG
= ll
->positions
[i
] / indentWidth
* indentWidth
; xIG
< ll
->positions
[i
+ 1]; xIG
+= indentWidth
) {
2492 if (xIG
>= ll
->positions
[i
] && xIG
> 0) {
2493 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIG
+ xStart
, rcSegment
,
2494 (ll
->xHighlightGuide
== xIG
));
2498 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2499 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2500 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
2501 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
2502 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
2505 } else if (IsControlCharacter(ll
->chars
[i
])) {
2506 // Control character display
2507 inIndentation
= false;
2508 if (controlCharSymbol
< 32) {
2509 // Draw the character
2510 const char *ctrlChar
= ControlCharacterString(ll
->chars
[i
]);
2511 if (!twoPhaseDraw
) {
2512 surface
->FillRectangle(rcSegment
, textBack
);
2514 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
2515 surface
->InternalLeading(ctrlCharsFont
);
2516 PRectangle rcCChar
= rcSegment
;
2517 rcCChar
.left
= rcCChar
.left
+ 1;
2518 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
2519 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
2520 PRectangle rcCentral
= rcCChar
;
2523 surface
->FillRectangle(rcCentral
, textFore
);
2524 PRectangle rcChar
= rcCChar
;
2527 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
2528 rcSegment
.top
+ vsDraw
.maxAscent
, ctrlChar
, istrlen(ctrlChar
),
2529 textBack
, textFore
);
2531 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
2532 surface
->DrawTextNoClip(rcSegment
, ctrlCharsFont
,
2533 rcSegment
.top
+ vsDraw
.maxAscent
,
2534 cc
, 1, textBack
, textFore
);
2537 // Normal text display
2538 if (vsDraw
.styles
[styleMain
].visible
) {
2540 surface
->DrawTextTransparent(rcSegment
, textFont
,
2541 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2542 i
- startseg
+ 1, textFore
);
2544 surface
->DrawTextNoClip(rcSegment
, textFont
,
2545 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2546 i
- startseg
+ 1, textFore
, textBack
);
2549 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2550 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
2551 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2552 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2553 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2554 if (vsDraw
.whitespaceForegroundSet
)
2555 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2556 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2557 int xmid
= (ll
->positions
[cpos
+ startseg
] + ll
->positions
[cpos
+ startseg
+ 1]) / 2;
2558 if (!twoPhaseDraw
&& drawWhitespaceBackground
&&
2559 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2560 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2561 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
, ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2562 surface
->FillRectangle(rcSpace
, textBack
);
2564 PRectangle
rcDot(xmid
+ xStart
- subLineStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
2565 rcDot
.right
= rcDot
.left
+ 1;
2566 rcDot
.bottom
= rcDot
.top
+ 1;
2567 surface
->FillRectangle(rcDot
, textFore
);
2570 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
2571 int startSpace
= ll
->positions
[cpos
+ startseg
];
2572 if (startSpace
> 0 && (startSpace
% indentWidth
== 0)) {
2573 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, startSpace
+ xStart
, rcSegment
,
2574 (ll
->xHighlightGuide
== ll
->positions
[cpos
+ startseg
]));
2578 inIndentation
= false;
2583 if (ll
->hsStart
!= -1 && vsDraw
.hotspotUnderline
&& iDoc
>= ll
->hsStart
&& iDoc
< ll
->hsEnd
) {
2584 PRectangle rcUL
= rcSegment
;
2585 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2586 rcUL
.bottom
= rcUL
.top
+ 1;
2587 if (vsDraw
.hotspotForegroundSet
)
2588 surface
->FillRectangle(rcUL
, vsDraw
.hotspotForeground
.allocated
);
2590 surface
->FillRectangle(rcUL
, textFore
);
2591 } else if (vsDraw
.styles
[styleMain
].underline
) {
2592 PRectangle rcUL
= rcSegment
;
2593 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2594 rcUL
.bottom
= rcUL
.top
+ 1;
2595 surface
->FillRectangle(rcUL
, textFore
);
2597 } else if (rcSegment
.left
> rcLine
.right
) {
2605 // foreach indicator...
2606 for (int indicnum
= 0, mask
= 1 << pdoc
->stylingBits
; mask
< 0x100; indicnum
++) {
2607 if (!(mask
& ll
->styleBitsSet
)) {
2612 // foreach style pos in line...
2613 for (int indicPos
= lineStart
; indicPos
<= lineEnd
; indicPos
++) {
2614 // look for starts...
2616 // NOT in indicator run, looking for START
2617 if (indicPos
< lineEnd
&& (ll
->indicators
[indicPos
] & mask
))
2618 startPos
= indicPos
;
2621 if (startPos
>= 0) {
2622 // IN indicator run, looking for END
2623 if (indicPos
>= lineEnd
|| !(ll
->indicators
[indicPos
] & mask
)) {
2624 // AT end of indicator run, DRAW it!
2626 ll
->positions
[startPos
] + xStart
- subLineStart
,
2627 rcLine
.top
+ vsDraw
.maxAscent
,
2628 ll
->positions
[indicPos
] + xStart
- subLineStart
,
2629 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
2630 vsDraw
.indicators
[indicnum
].Draw(surface
, rcIndic
, rcLine
);
2631 // RESET control var
2638 // End of the drawing of the current line
2639 if (!twoPhaseDraw
) {
2640 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2641 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
2642 drawWrapMarkEnd
, vsDraw
.whitespaceForeground
.allocated
);
2645 if (vsDraw
.edgeState
== EDGE_LINE
) {
2646 int edgeX
= theEdge
* vsDraw
.spaceWidth
;
2647 rcSegment
.left
= edgeX
+ xStart
;
2648 rcSegment
.right
= rcSegment
.left
+ 1;
2649 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
.allocated
);
2653 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
2654 if (!pixmapSelPattern
->Initialised()) {
2655 const int patternSize
= 8;
2656 pixmapSelPattern
->InitPixMap(patternSize
, patternSize
, surfaceWindow
, wMain
.GetID());
2657 // This complex procedure is to reproduce the checkerboard dithered pattern used by windows
2658 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
2659 // way between the chrome colour and the chrome highlight colour making a nice transition
2660 // between the window chrome and the content area. And it works in low colour depths.
2661 PRectangle
rcPattern(0, 0, patternSize
, patternSize
);
2663 // Initialize default colours based on the chrome colour scheme. Typically the highlight is white.
2664 ColourAllocated colourFMFill
= vs
.selbar
.allocated
;
2665 ColourAllocated colourFMStripes
= vs
.selbarlight
.allocated
;
2667 if (!(vs
.selbarlight
.desired
== ColourDesired(0xff, 0xff, 0xff))) {
2668 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
2669 // (Typically, the highlight colour is white.)
2670 colourFMFill
= vs
.selbarlight
.allocated
;
2673 if (vs
.foldmarginColourSet
) {
2674 // override default fold margin colour
2675 colourFMFill
= vs
.foldmarginColour
.allocated
;
2677 if (vs
.foldmarginHighlightColourSet
) {
2678 // override default fold margin highlight colour
2679 colourFMStripes
= vs
.foldmarginHighlightColour
.allocated
;
2682 pixmapSelPattern
->FillRectangle(rcPattern
, colourFMFill
);
2683 pixmapSelPattern
->PenColour(colourFMStripes
);
2684 for (int stripe
= 0; stripe
< patternSize
; stripe
++) {
2685 // Alternating 1 pixel stripes is same as checkerboard.
2686 pixmapSelPattern
->MoveTo(0, stripe
* 2);
2687 pixmapSelPattern
->LineTo(patternSize
, stripe
* 2 - patternSize
);
2691 if (!pixmapIndentGuide
->Initialised()) {
2692 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
2693 pixmapIndentGuide
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2694 pixmapIndentGuideHighlight
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2695 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
2696 pixmapIndentGuide
->FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
.allocated
);
2697 pixmapIndentGuide
->PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
2698 pixmapIndentGuideHighlight
->FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
.allocated
);
2699 pixmapIndentGuideHighlight
->PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
2700 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
2701 pixmapIndentGuide
->MoveTo(0, stripe
);
2702 pixmapIndentGuide
->LineTo(2, stripe
);
2703 pixmapIndentGuideHighlight
->MoveTo(0, stripe
);
2704 pixmapIndentGuideHighlight
->LineTo(2, stripe
);
2709 if (!pixmapLine
->Initialised()) {
2710 PRectangle rcClient
= GetClientRectangle();
2711 pixmapLine
->InitPixMap(rcClient
.Width(), vs
.lineHeight
,
2712 surfaceWindow
, wMain
.GetID());
2713 pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
2714 rcClient
.Height(), surfaceWindow
, wMain
.GetID());
2719 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
2720 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
2721 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
2725 RefreshPixMaps(surfaceWindow
);
2727 PRectangle rcClient
= GetClientRectangle();
2728 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
2729 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
2731 surfaceWindow
->SetPalette(&palette
, true);
2732 pixmapLine
->SetPalette(&palette
, !hasFocus
);
2734 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
2735 // The area to be painted plus one extra line is styled.
2736 // The extra line is to determine when a style change, such as starting a comment flows on to other lines.
2737 int lineStyleLast
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
2738 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
2739 int endPosPaint
= pdoc
->Length();
2740 if (lineStyleLast
< cs
.LinesDisplayed())
2741 endPosPaint
= pdoc
->LineStart(cs
.DocFromDisplay(lineStyleLast
+ 1));
2743 int xStart
= vs
.fixedColumnWidth
- xOffset
;
2746 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
2747 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
2749 // Ensure we are styled as far as we are painting.
2750 pdoc
->EnsureStyledTo(endPosPaint
);
2751 bool paintAbandonedByStyling
= paintState
== paintAbandoned
;
2754 needUpdateUI
= false;
2757 // Call priority lines wrap on a window of lines which are likely
2758 // to rendered with the following paint (that is wrap the visible
2760 int startLineToWrap
= cs
.DocFromDisplay(topLine
) - 5;
2761 if (startLineToWrap
< 0)
2762 startLineToWrap
= -1;
2763 if (WrapLines(false, startLineToWrap
)) {
2764 // The wrapping process has changed the height of some lines so
2765 // abandon this paint for a complete repaint.
2766 if (AbandonPaint()) {
2769 RefreshPixMaps(surfaceWindow
); // In case pixmaps invalidated by scrollbar change
2771 PLATFORM_ASSERT(pixmapSelPattern
->Initialised());
2773 PaintSelMargin(surfaceWindow
, rcArea
);
2775 PRectangle rcRightMargin
= rcClient
;
2776 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
2777 if (rcArea
.Intersects(rcRightMargin
)) {
2778 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2781 if (paintState
== paintAbandoned
) {
2782 // Either styling or NotifyUpdateUI noticed that painting is needed
2783 // outside the current painting rectangle
2784 //Platform::DebugPrintf("Abandoning paint\n");
2785 if (wrapState
!= eWrapNone
) {
2786 if (paintAbandonedByStyling
) {
2787 // Styling has spilled over a line end, such as occurs by starting a multiline
2788 // comment. The width of subsequent text may have changed, so rewrap.
2789 NeedWrapping(cs
.DocFromDisplay(topLine
));
2794 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
2797 if (rcArea
.right
> vs
.fixedColumnWidth
) {
2799 Surface
*surface
= surfaceWindow
;
2801 surface
= pixmapLine
;
2802 PLATFORM_ASSERT(pixmapLine
->Initialised());
2804 surface
->SetUnicodeMode(IsUnicodeMode());
2805 surface
->SetDBCSMode(CodePage());
2807 int visibleLine
= topLine
+ screenLinePaintFirst
;
2809 int posCaret
= currentPos
;
2812 int lineCaret
= pdoc
->LineFromPosition(posCaret
);
2814 // Remove selection margin from drawing area so text will not be drawn
2815 // on it in unbuffered mode.
2816 PRectangle rcTextArea
= rcClient
;
2817 rcTextArea
.left
= vs
.fixedColumnWidth
;
2818 rcTextArea
.right
-= vs
.rightMarginWidth
;
2819 surfaceWindow
->SetClip(rcTextArea
);
2821 // Loop on visible lines
2822 //double durLayout = 0.0;
2823 //double durPaint = 0.0;
2824 //double durCopy = 0.0;
2825 //ElapsedTime etWhole;
2826 int lineDocPrevious
= -1; // Used to avoid laying out one document line multiple times
2827 AutoLineLayout
ll(llc
, 0);
2828 SelectionLineIterator
lineIterator(this);
2829 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
2831 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
2832 // Only visible lines should be handled by the code within the loop
2833 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
2834 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
2835 int subLine
= visibleLine
- lineStartSet
;
2837 // Copy this line and its styles from the document into local arrays
2838 // and determine the x position at which each character starts.
2840 if (lineDoc
!= lineDocPrevious
) {
2842 // For rectangular selection this accesses the layout cache so should be after layout returned.
2843 lineIterator
.SetAt(lineDoc
);
2844 ll
.Set(RetrieveLineLayout(lineDoc
));
2845 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
2846 lineDocPrevious
= lineDoc
;
2848 //durLayout += et.Duration(true);
2851 if (selType
== selStream
) {
2852 ll
->selStart
= SelectionStart();
2853 ll
->selEnd
= SelectionEnd();
2855 ll
->selStart
= lineIterator
.startPos
;
2856 ll
->selEnd
= lineIterator
.endPos
;
2858 ll
->containsCaret
= lineDoc
== lineCaret
;
2859 if (hideSelection
) {
2862 ll
->containsCaret
= false;
2865 GetHotSpotRange(ll
->hsStart
, ll
->hsEnd
);
2867 PRectangle rcLine
= rcClient
;
2869 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
2871 Range
rangeLine(pdoc
->LineStart(lineDoc
), pdoc
->LineStart(lineDoc
+ 1));
2872 // Highlight the current braces if any
2873 ll
->SetBracesHighlight(rangeLine
, braces
, static_cast<char>(bracesMatchStyle
),
2874 highlightGuideColumn
* vs
.spaceWidth
);
2877 DrawLine(surface
, vs
, lineDoc
, visibleLine
, xStart
, rcLine
, ll
, subLine
);
2878 //durPaint += et.Duration(true);
2880 // Restore the previous styles for the brace highlights in case layout is in cache.
2881 ll
->RestoreBracesHighlight(rangeLine
, braces
);
2883 bool expanded
= cs
.GetExpanded(lineDoc
);
2884 if ((foldFlags
& SC_FOLDFLAG_BOX
) == 0) {
2885 // Paint the line above the fold
2886 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_EXPANDED
))
2888 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_CONTRACTED
))) {
2889 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2890 PRectangle rcFoldLine
= rcLine
;
2891 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2892 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2895 // Paint the line below the fold
2896 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_EXPANDED
))
2898 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2899 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2900 PRectangle rcFoldLine
= rcLine
;
2901 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2902 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2906 int FoldLevelCurr
= (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2907 int FoldLevelPrev
= (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2908 int FoldLevelFlags
= (pdoc
->GetLevel(lineDoc
) & ~SC_FOLDLEVELNUMBERMASK
) & ~(0xFFF0000);
2909 int indentationStep
= pdoc
->IndentSize();
2910 // Draw line above fold
2911 if ((FoldLevelPrev
< FoldLevelCurr
)
2913 (FoldLevelFlags
& SC_FOLDLEVELBOXHEADERFLAG
2915 (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELBOXFOOTERFLAG
) == 0)) {
2916 PRectangle rcFoldLine
= rcLine
;
2917 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2918 rcFoldLine
.left
+= xStart
+ FoldLevelCurr
* vs
.spaceWidth
* indentationStep
- 1;
2919 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2922 // Line below the fold (or below a contracted fold)
2923 if (FoldLevelFlags
& SC_FOLDLEVELBOXFOOTERFLAG
2925 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2926 PRectangle rcFoldLine
= rcLine
;
2927 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2928 rcFoldLine
.left
+= xStart
+ (FoldLevelCurr
) * vs
.spaceWidth
* indentationStep
- 1;
2929 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2932 PRectangle rcBoxLine
= rcLine
;
2933 // Draw vertical line for every fold level
2934 for (int i
= 0; i
<= FoldLevelCurr
; i
++) {
2935 rcBoxLine
.left
= xStart
+ i
* vs
.spaceWidth
* indentationStep
- 1;
2936 rcBoxLine
.right
= rcBoxLine
.left
+ 1;
2937 surface
->FillRectangle(rcBoxLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2942 if (lineDoc
== lineCaret
) {
2943 int offset
= Platform::Minimum(posCaret
- rangeLine
.start
, ll
->maxLineLength
);
2944 if ((offset
>= ll
->LineStart(subLine
)) &&
2945 ((offset
< ll
->LineStart(subLine
+ 1)) || offset
== ll
->numCharsInLine
)) {
2946 int xposCaret
= ll
->positions
[offset
] - ll
->positions
[ll
->LineStart(subLine
)] + xStart
;
2948 if (actualWrapVisualStartIndent
!= 0) {
2949 int lineStart
= ll
->LineStart(subLine
);
2950 if (lineStart
!= 0) // Wrapped
2951 xposCaret
+= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
2953 int widthOverstrikeCaret
;
2954 if (posCaret
== pdoc
->Length()) { // At end of document
2955 widthOverstrikeCaret
= vs
.aveCharWidth
;
2956 } else if ((posCaret
- rangeLine
.start
) >= ll
->numCharsInLine
) { // At end of line
2957 widthOverstrikeCaret
= vs
.aveCharWidth
;
2959 widthOverstrikeCaret
= ll
->positions
[offset
+ 1] - ll
->positions
[offset
];
2961 if (widthOverstrikeCaret
< 3) // Make sure its visible
2962 widthOverstrikeCaret
= 3;
2963 if (((caret
.active
&& caret
.on
) || (posDrag
>= 0)) && xposCaret
>= 0) {
2964 PRectangle rcCaret
= rcLine
;
2965 int caretWidthOffset
= 0;
2966 if ((offset
> 0) && (vs
.caretWidth
> 1))
2967 caretWidthOffset
= 1; // Move back so overlaps both character cells.
2969 rcCaret
.left
= xposCaret
- caretWidthOffset
;
2970 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
2973 rcCaret
.top
= rcCaret
.bottom
- 2;
2974 rcCaret
.left
= xposCaret
+ 1;
2975 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
2977 rcCaret
.left
= xposCaret
- caretWidthOffset
;
2978 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
2981 surface
->FillRectangle(rcCaret
, vs
.caretcolour
.allocated
);
2987 Point
from(vs
.fixedColumnWidth
, 0);
2988 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
2989 rcClient
.right
, yposScreen
+ vs
.lineHeight
);
2990 surfaceWindow
->Copy(rcCopyArea
, from
, *pixmapLine
);
2992 //durCopy += et.Duration(true);
2995 if (!bufferedDraw
) {
2996 ypos
+= vs
.lineHeight
;
2999 yposScreen
+= vs
.lineHeight
;
3004 //if (durPaint < 0.00000001)
3005 // durPaint = 0.00000001;
3007 // Right column limit indicator
3008 PRectangle rcBeyondEOF
= rcClient
;
3009 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
3010 rcBeyondEOF
.right
= rcBeyondEOF
.right
;
3011 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
3012 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
3013 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
3014 if (vs
.edgeState
== EDGE_LINE
) {
3015 int edgeX
= theEdge
* vs
.spaceWidth
;
3016 rcBeyondEOF
.left
= edgeX
+ xStart
;
3017 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
3018 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
.allocated
);
3021 //Platform::DebugPrintf(
3022 //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
3023 //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
3028 // Space (3 space characters) between line numbers and text when printing.
3029 #define lineNumberPrintSpace " "
3031 ColourDesired
InvertedLight(ColourDesired orig
) {
3032 unsigned int r
= orig
.GetRed();
3033 unsigned int g
= orig
.GetGreen();
3034 unsigned int b
= orig
.GetBlue();
3035 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
3036 unsigned int il
= 0xff - l
;
3038 return ColourDesired(0xff, 0xff, 0xff);
3042 return ColourDesired(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
3045 // This is mostly copied from the Paint method but with some things omitted
3046 // such as the margin markers, line numbers, selection and caret
3047 // Should be merged back into a combined Draw method.
3048 long Editor::FormatRange(bool draw
, RangeToFormat
*pfr
) {
3052 AutoSurface
surface(pfr
->hdc
, this);
3055 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this);
3056 if (!surfaceMeasure
) {
3060 ViewStyle
vsPrint(vs
);
3062 // Modify the view style for printing as do not normally want any of the transient features to be printed
3063 // Printing supports only the line number margin.
3064 int lineNumberIndex
= -1;
3065 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
3066 if ((!vsPrint
.ms
[margin
].symbol
) && (vsPrint
.ms
[margin
].width
> 0)) {
3067 lineNumberIndex
= margin
;
3069 vsPrint
.ms
[margin
].width
= 0;
3072 vsPrint
.showMarkedLines
= false;
3073 vsPrint
.fixedColumnWidth
= 0;
3074 vsPrint
.zoomLevel
= printMagnification
;
3075 vsPrint
.viewIndentationGuides
= false;
3076 // Don't show the selection when printing
3077 vsPrint
.selbackset
= false;
3078 vsPrint
.selforeset
= false;
3079 vsPrint
.whitespaceBackgroundSet
= false;
3080 vsPrint
.whitespaceForegroundSet
= false;
3081 vsPrint
.showCaretLineBackground
= false;
3083 // Set colours for printing according to users settings
3084 for (int sty
= 0;sty
<= STYLE_MAX
;sty
++) {
3085 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
3086 vsPrint
.styles
[sty
].fore
.desired
= InvertedLight(vsPrint
.styles
[sty
].fore
.desired
);
3087 vsPrint
.styles
[sty
].back
.desired
= InvertedLight(vsPrint
.styles
[sty
].back
.desired
);
3088 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
3089 vsPrint
.styles
[sty
].fore
.desired
= ColourDesired(0, 0, 0);
3090 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3091 } else if (printColourMode
== SC_PRINT_COLOURONWHITE
) {
3092 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3093 } else if (printColourMode
== SC_PRINT_COLOURONWHITEDEFAULTBG
) {
3094 if (sty
<= STYLE_DEFAULT
) {
3095 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3099 // White background for the line numbers
3100 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3102 vsPrint
.Refresh(*surfaceMeasure
);
3103 // Ensure colours are set up
3104 vsPrint
.RefreshColourPalette(palette
, true);
3105 vsPrint
.RefreshColourPalette(palette
, false);
3106 // Determining width must hapen after fonts have been realised in Refresh
3107 int lineNumberWidth
= 0;
3108 if (lineNumberIndex
>= 0) {
3109 lineNumberWidth
= surfaceMeasure
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3110 "99999" lineNumberPrintSpace
, 5 + istrlen(lineNumberPrintSpace
));
3111 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
3114 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
3115 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
3116 if (linePrintLast
< linePrintStart
)
3117 linePrintLast
= linePrintStart
;
3118 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
);
3119 if (linePrintLast
> linePrintMax
)
3120 linePrintLast
= linePrintMax
;
3121 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
3122 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
3123 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
3124 int endPosPrint
= pdoc
->Length();
3125 if (linePrintLast
< pdoc
->LinesTotal())
3126 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
3128 // Ensure we are styled to where we are formatting.
3129 pdoc
->EnsureStyledTo(endPosPrint
);
3131 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
+ lineNumberWidth
;
3132 int ypos
= pfr
->rc
.top
;
3134 int lineDoc
= linePrintStart
;
3136 int nPrintPos
= pfr
->chrg
.cpMin
;
3137 int visibleLine
= 0;
3138 int widthPrint
= pfr
->rc
.Width() - lineNumberWidth
;
3139 if (printWrapState
== eWrapNone
)
3140 widthPrint
= LineLayout::wrapWidthInfinite
;
3142 while (lineDoc
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
3144 // When printing, the hdc and hdcTarget may be the same, so
3145 // changing the state of surfaceMeasure may change the underlying
3146 // state of surface. Therefore, any cached state is discarded before
3147 // using each surface.
3148 surfaceMeasure
->FlushCachedState();
3150 // Copy this line and its styles from the document into local arrays
3151 // and determine the x position at which each character starts.
3152 LineLayout
ll(8000);
3153 LayoutLine(lineDoc
, surfaceMeasure
, vsPrint
, &ll
, widthPrint
);
3157 ll
.containsCaret
= false;
3160 rcLine
.left
= pfr
->rc
.left
+ lineNumberWidth
;
3162 rcLine
.right
= pfr
->rc
.right
- 1;
3163 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3165 // When document line is wrapped over multiple display lines, find where
3166 // to start printing from to ensure a particular position is on the first
3167 // line of the page.
3168 if (visibleLine
== 0) {
3169 int startWithinLine
= nPrintPos
- pdoc
->LineStart(lineDoc
);
3170 for (int iwl
= 0; iwl
< ll
.lines
- 1; iwl
++) {
3171 if (ll
.LineStart(iwl
) <= startWithinLine
&& ll
.LineStart(iwl
+ 1) >= startWithinLine
) {
3176 if (ll
.lines
> 1 && startWithinLine
>= ll
.LineStart(ll
.lines
- 1)) {
3177 visibleLine
= -(ll
.lines
- 1);
3181 if (draw
&& lineNumberWidth
&&
3182 (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) &&
3183 (visibleLine
>= 0)) {
3185 sprintf(number
, "%d" lineNumberPrintSpace
, lineDoc
+ 1);
3186 PRectangle rcNumber
= rcLine
;
3187 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
3189 rcNumber
.left
-= surfaceMeasure
->WidthText(
3190 vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
3191 surface
->FlushCachedState();
3192 surface
->DrawTextNoClip(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3193 ypos
+ vsPrint
.maxAscent
, number
, istrlen(number
),
3194 vsPrint
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
3195 vsPrint
.styles
[STYLE_LINENUMBER
].back
.allocated
);
3199 surface
->FlushCachedState();
3201 for (int iwl
= 0; iwl
< ll
.lines
; iwl
++) {
3202 if (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) {
3203 if (visibleLine
>= 0) {
3206 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3207 DrawLine(surface
, vsPrint
, lineDoc
, visibleLine
, xStart
, rcLine
, &ll
, iwl
);
3209 ypos
+= vsPrint
.lineHeight
;
3212 if (iwl
== ll
.lines
- 1)
3213 nPrintPos
= pdoc
->LineStart(lineDoc
+ 1);
3215 nPrintPos
+= ll
.LineStart(iwl
+ 1) - ll
.LineStart(iwl
);
3225 int Editor::TextWidth(int style
, const char *text
) {
3227 AutoSurface
surface(this);
3229 return surface
->WidthText(vs
.styles
[style
].font
, text
, istrlen(text
));
3235 // Empty method is overridden on GTK+ to show / hide scrollbars
3236 void Editor::ReconfigureScrollBars() {}
3238 void Editor::SetScrollBars() {
3241 int nMax
= MaxScrollPos();
3242 int nPage
= LinesOnScreen();
3243 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
3248 // TODO: ensure always showing as many lines as possible
3249 // May not be, if, for example, window made larger
3250 if (topLine
> MaxScrollPos()) {
3251 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
3252 SetVerticalScrollPos();
3256 if (!AbandonPaint())
3259 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
3262 void Editor::ChangeSize() {
3265 if (wrapState
!= eWrapNone
) {
3266 PRectangle rcTextArea
= GetClientRectangle();
3267 rcTextArea
.left
= vs
.fixedColumnWidth
;
3268 rcTextArea
.right
-= vs
.rightMarginWidth
;
3269 if (wrapWidth
!= rcTextArea
.Width()) {
3276 void Editor::AddChar(char ch
) {
3283 void Editor::AddCharUTF(char *s
, unsigned int len
, bool treatAsDBCS
) {
3284 bool wasSelection
= currentPos
!= anchor
;
3286 bool charReplaceAction
= false;
3287 if (inOverstrike
&& !wasSelection
&& !RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3288 if (currentPos
< (pdoc
->Length())) {
3289 if (!IsEOLChar(pdoc
->CharAt(currentPos
))) {
3290 charReplaceAction
= true;
3291 pdoc
->BeginUndoAction();
3292 pdoc
->DelChar(currentPos
);
3296 if (pdoc
->InsertString(currentPos
, s
, len
)) {
3297 SetEmptySelection(currentPos
+ len
);
3299 if (charReplaceAction
) {
3300 pdoc
->EndUndoAction();
3302 EnsureCaretVisible();
3303 // Avoid blinking during rapid typing:
3304 ShowCaretAtCurrentPosition();
3310 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
3311 static_cast<unsigned char>(s
[1]));
3313 int byte
= static_cast<unsigned char>(s
[0]);
3314 if ((byte
< 0xC0) || (1 == len
)) {
3315 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
3316 // characters when not in UTF-8 mode.
3317 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
3318 // characters representing themselves.
3320 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
3321 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
3322 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
3324 int byte2
= static_cast<unsigned char>(s
[1]);
3325 if ((byte2
& 0xC0) == 0x80) {
3326 // Two-byte-character lead-byte followed by a trail-byte.
3327 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
3329 // A two-byte-character lead-byte not followed by trail-byte
3330 // represents itself.
3331 } else if (byte
< 0xF0) {
3332 int byte2
= static_cast<unsigned char>(s
[1]);
3333 int byte3
= static_cast<unsigned char>(s
[2]);
3334 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
3335 // Three-byte-character lead byte followed by two trail bytes.
3336 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
3339 // A three-byte-character lead-byte not followed by two trail-bytes
3340 // represents itself.
3347 void Editor::ClearSelection() {
3348 if (!SelectionContainsProtected()) {
3349 int startPos
= SelectionStart();
3350 if (selType
== selStream
) {
3351 unsigned int chars
= SelectionEnd() - startPos
;
3353 pdoc
->BeginUndoAction();
3354 pdoc
->DeleteChars(startPos
, chars
);
3355 pdoc
->EndUndoAction();
3358 pdoc
->BeginUndoAction();
3359 SelectionLineIterator
lineIterator(this, false);
3360 while (lineIterator
.Iterate()) {
3361 startPos
= lineIterator
.startPos
;
3362 unsigned int chars
= lineIterator
.endPos
- startPos
;
3364 pdoc
->DeleteChars(startPos
, chars
);
3367 pdoc
->EndUndoAction();
3368 selType
= selStream
;
3370 SetEmptySelection(startPos
);
3374 void Editor::ClearAll() {
3375 pdoc
->BeginUndoAction();
3376 if (0 != pdoc
->Length()) {
3377 pdoc
->DeleteChars(0, pdoc
->Length());
3379 if (!pdoc
->IsReadOnly()) {
3382 pdoc
->EndUndoAction();
3386 SetVerticalScrollPos();
3387 InvalidateStyleRedraw();
3390 void Editor::ClearDocumentStyle() {
3391 pdoc
->StartStyling(0, '\377');
3392 pdoc
->SetStyleFor(pdoc
->Length(), 0);
3394 pdoc
->ClearLevels();
3397 void Editor::Cut() {
3398 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
3404 void Editor::PasteRectangular(int pos
, const char *ptr
, int len
) {
3405 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
3409 int xInsert
= XFromPosition(currentPos
);
3410 int line
= pdoc
->LineFromPosition(currentPos
);
3411 bool prevCr
= false;
3412 pdoc
->BeginUndoAction();
3413 for (int i
= 0; i
< len
; i
++) {
3414 if (IsEOLChar(ptr
[i
])) {
3415 if ((ptr
[i
] == '\r') || (!prevCr
))
3417 if (line
>= pdoc
->LinesTotal()) {
3418 if (pdoc
->eolMode
!= SC_EOL_LF
)
3419 pdoc
->InsertChar(pdoc
->Length(), '\r');
3420 if (pdoc
->eolMode
!= SC_EOL_CR
)
3421 pdoc
->InsertChar(pdoc
->Length(), '\n');
3423 // Pad the end of lines with spaces if required
3424 currentPos
= PositionFromLineX(line
, xInsert
);
3425 if ((XFromPosition(currentPos
) < xInsert
) && (i
+ 1 < len
)) {
3426 for (int i
= 0; i
< xInsert
- XFromPosition(currentPos
); i
++) {
3427 pdoc
->InsertChar(currentPos
, ' ');
3431 prevCr
= ptr
[i
] == '\r';
3433 pdoc
->InsertString(currentPos
, ptr
+ i
, 1);
3438 pdoc
->EndUndoAction();
3439 SetEmptySelection(pos
);
3442 bool Editor::CanPaste() {
3443 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
3446 void Editor::Clear() {
3447 if (currentPos
== anchor
) {
3448 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3454 SetEmptySelection(currentPos
);
3457 void Editor::SelectAll() {
3458 SetSelection(0, pdoc
->Length());
3462 void Editor::Undo() {
3463 if (pdoc
->CanUndo()) {
3465 int newPos
= pdoc
->Undo();
3467 SetEmptySelection(newPos
);
3468 EnsureCaretVisible();
3472 void Editor::Redo() {
3473 if (pdoc
->CanRedo()) {
3474 int newPos
= pdoc
->Redo();
3476 SetEmptySelection(newPos
);
3477 EnsureCaretVisible();
3481 void Editor::DelChar() {
3482 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3483 pdoc
->DelChar(currentPos
);
3485 // Avoid blinking during rapid typing:
3486 ShowCaretAtCurrentPosition();
3489 void Editor::DelCharBack(bool allowLineStartDeletion
) {
3490 if (currentPos
== anchor
) {
3491 if (!RangeContainsProtected(currentPos
- 1, currentPos
)) {
3492 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
3493 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != currentPos
)) {
3494 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3495 pdoc
->GetColumn(currentPos
) > 0 && pdoc
->backspaceUnindents
) {
3496 pdoc
->BeginUndoAction();
3497 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3498 int indentationStep
= pdoc
->IndentSize();
3499 if (indentation
% indentationStep
== 0) {
3500 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3502 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- (indentation
% indentationStep
));
3504 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
3505 pdoc
->EndUndoAction();
3507 pdoc
->DelCharBack(currentPos
);
3513 SetEmptySelection(currentPos
);
3515 // Avoid blinking during rapid typing:
3516 ShowCaretAtCurrentPosition();
3519 void Editor::NotifyFocus(bool) {}
3521 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
3522 SCNotification scn
= {0};
3523 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
3524 scn
.position
= endStyleNeeded
;
3528 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
3529 NotifyStyleToNeeded(endStyleNeeded
);
3532 void Editor::NotifyChar(int ch
) {
3533 SCNotification scn
= {0};
3534 scn
.nmhdr
.code
= SCN_CHARADDED
;
3537 if (recordingMacro
) {
3539 txt
[0] = static_cast<char>(ch
);
3541 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
3545 void Editor::NotifySavePoint(bool isSavePoint
) {
3546 SCNotification scn
= {0};
3548 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
3550 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
3555 void Editor::NotifyModifyAttempt() {
3556 SCNotification scn
= {0};
3557 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
3561 void Editor::NotifyDoubleClick(Point
, bool) {
3562 SCNotification scn
= {0};
3563 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
3567 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3568 SCNotification scn
= {0};
3569 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
3570 scn
.position
= position
;
3571 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3572 (alt
? SCI_ALT
: 0);
3576 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3577 SCNotification scn
= {0};
3578 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
3579 scn
.position
= position
;
3580 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3581 (alt
? SCI_ALT
: 0);
3585 void Editor::NotifyUpdateUI() {
3586 SCNotification scn
= {0};
3587 scn
.nmhdr
.code
= SCN_UPDATEUI
;
3591 void Editor::NotifyPainted() {
3592 SCNotification scn
= {0};
3593 scn
.nmhdr
.code
= SCN_PAINTED
;
3597 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
3598 int marginClicked
= -1;
3600 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
3601 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
3602 marginClicked
= margin
;
3603 x
+= vs
.ms
[margin
].width
;
3605 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
3606 SCNotification scn
= {0};
3607 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
3608 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3609 (alt
? SCI_ALT
: 0);
3610 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
3611 scn
.margin
= marginClicked
;
3619 void Editor::NotifyNeedShown(int pos
, int len
) {
3620 SCNotification scn
= {0};
3621 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
3627 void Editor::NotifyDwelling(Point pt
, bool state
) {
3628 SCNotification scn
= {0};
3629 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
3630 scn
.position
= PositionFromLocationClose(pt
);
3636 void Editor::NotifyZoom() {
3637 SCNotification scn
= {0};
3638 scn
.nmhdr
.code
= SCN_ZOOM
;
3642 // Notifications from document
3643 void Editor::NotifyModifyAttempt(Document
*, void *) {
3644 //Platform::DebugPrintf("** Modify Attempt\n");
3645 NotifyModifyAttempt();
3648 void Editor::NotifyMove(int position
) {
3649 SCNotification scn
= {0};
3650 scn
.nmhdr
.code
= SCN_POSCHANGED
;
3651 scn
.position
= position
;
3655 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
3656 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
3657 NotifySavePoint(atSavePoint
);
3660 void Editor::CheckModificationForWrap(DocModification mh
) {
3661 if (mh
.modificationType
& (SC_MOD_INSERTTEXT
|SC_MOD_DELETETEXT
)) {
3662 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
3663 if (wrapState
!= eWrapNone
) {
3664 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
3665 if (mh
.linesAdded
<= 0) {
3666 AutoSurface
surface(this);
3667 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
3668 if (surface
&& ll
) {
3669 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
3670 if (cs
.GetHeight(lineDoc
) != ll
->lines
) {
3671 NeedWrapping(lineDoc
- 1, lineDoc
+ 1);
3676 NeedWrapping(lineDoc
, lineDoc
+ 1 + mh
.linesAdded
);
3682 // Move a position so it is still after the same character as before the insertion.
3683 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
3684 if (position
> startInsertion
) {
3685 return position
+ length
;
3690 // Move a position so it is still after the same character as before the deletion if that
3691 // character is still present else after the previous surviving character.
3692 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
3693 if (position
> startDeletion
) {
3694 int endDeletion
= startDeletion
+ length
;
3695 if (position
> endDeletion
) {
3696 return position
- length
;
3698 return startDeletion
;
3705 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
3706 needUpdateUI
= true;
3707 if (paintState
== painting
) {
3708 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
3710 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
3711 pdoc
->IncrementStyleClock();
3712 if (paintState
== notPainting
) {
3713 if (mh
.position
< pdoc
->LineStart(topLine
)) {
3714 // Styling performed before this view
3717 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3721 // Move selection and brace highlights
3722 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
3723 currentPos
= MovePositionForInsertion(currentPos
, mh
.position
, mh
.length
);
3724 anchor
= MovePositionForInsertion(anchor
, mh
.position
, mh
.length
);
3725 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
3726 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
3727 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
3728 currentPos
= MovePositionForDeletion(currentPos
, mh
.position
, mh
.length
);
3729 anchor
= MovePositionForDeletion(anchor
, mh
.position
, mh
.length
);
3730 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
3731 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
3733 if (cs
.LinesDisplayed() < cs
.LinesInDoc()) {
3734 // Some lines are hidden so may need shown.
3735 // TODO: check if the modified area is hidden.
3736 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
3737 NotifyNeedShown(mh
.position
, 0);
3738 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
3739 NotifyNeedShown(mh
.position
, mh
.length
);
3742 if (mh
.linesAdded
!= 0) {
3743 // Update contraction state for inserted and removed lines
3744 // lineOfPos should be calculated in context of state before modification, shouldn't it
3745 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
3746 if (mh
.linesAdded
> 0) {
3747 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
3749 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
3752 CheckModificationForWrap(mh
);
3753 if (mh
.linesAdded
!= 0) {
3754 // Avoid scrolling of display if change before current display
3755 if (mh
.position
< posTopLine
&& !CanDeferToLastStep(mh
)) {
3756 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
3757 if (newTop
!= topLine
) {
3759 SetVerticalScrollPos();
3763 //Platform::DebugPrintf("** %x Doc Changed\n", this);
3764 // TODO: could invalidate from mh.startModification to end of screen
3765 //InvalidateRange(mh.position, mh.position + mh.length);
3766 if (paintState
== notPainting
&& !CanDeferToLastStep(mh
)) {
3770 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
3771 // mh.position, mh.position + mh.length);
3772 if (paintState
== notPainting
&& mh
.length
&& !CanEliminate(mh
)) {
3773 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3778 if (mh
.linesAdded
!= 0 && !CanDeferToLastStep(mh
)) {
3782 if (mh
.modificationType
& SC_MOD_CHANGEMARKER
) {
3783 if ((paintState
== notPainting
) || !PaintContainsMargin()) {
3784 if (mh
.modificationType
& SC_MOD_CHANGEFOLD
) {
3785 // Fold changes can affect the drawing of following lines so redraw whole margin
3788 RedrawSelMargin(mh
.line
);
3793 // NOW pay the piper WRT "deferred" visual updates
3794 if (IsLastStep(mh
)) {
3799 // If client wants to see this modification
3800 if (mh
.modificationType
& modEventMask
) {
3801 if ((mh
.modificationType
& SC_MOD_CHANGESTYLE
) == 0) {
3802 // Real modification made to text of document.
3803 NotifyChange(); // Send EN_CHANGE
3806 SCNotification scn
= {0};
3807 scn
.nmhdr
.code
= SCN_MODIFIED
;
3808 scn
.position
= mh
.position
;
3809 scn
.modificationType
= mh
.modificationType
;
3811 scn
.length
= mh
.length
;
3812 scn
.linesAdded
= mh
.linesAdded
;
3814 scn
.foldLevelNow
= mh
.foldLevelNow
;
3815 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
3820 void Editor::NotifyDeleted(Document
*, void *) {
3824 void Editor::NotifyMacroRecord(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
3826 // Enumerates all macroable messages
3832 case SCI_REPLACESEL
:
3834 case SCI_INSERTTEXT
:
3835 case SCI_APPENDTEXT
:
3840 case SCI_SEARCHANCHOR
:
3841 case SCI_SEARCHNEXT
:
3842 case SCI_SEARCHPREV
:
3844 case SCI_LINEDOWNEXTEND
:
3846 case SCI_PARADOWNEXTEND
:
3848 case SCI_LINEUPEXTEND
:
3850 case SCI_PARAUPEXTEND
:
3852 case SCI_CHARLEFTEXTEND
:
3854 case SCI_CHARRIGHTEXTEND
:
3856 case SCI_WORDLEFTEXTEND
:
3858 case SCI_WORDRIGHTEXTEND
:
3859 case SCI_WORDPARTLEFT
:
3860 case SCI_WORDPARTLEFTEXTEND
:
3861 case SCI_WORDPARTRIGHT
:
3862 case SCI_WORDPARTRIGHTEXTEND
:
3863 case SCI_WORDLEFTEND
:
3864 case SCI_WORDLEFTENDEXTEND
:
3865 case SCI_WORDRIGHTEND
:
3866 case SCI_WORDRIGHTENDEXTEND
:
3868 case SCI_HOMEEXTEND
:
3870 case SCI_LINEENDEXTEND
:
3872 case SCI_HOMEWRAPEXTEND
:
3873 case SCI_LINEENDWRAP
:
3874 case SCI_LINEENDWRAPEXTEND
:
3875 case SCI_DOCUMENTSTART
:
3876 case SCI_DOCUMENTSTARTEXTEND
:
3877 case SCI_DOCUMENTEND
:
3878 case SCI_DOCUMENTENDEXTEND
:
3879 case SCI_STUTTEREDPAGEUP
:
3880 case SCI_STUTTEREDPAGEUPEXTEND
:
3881 case SCI_STUTTEREDPAGEDOWN
:
3882 case SCI_STUTTEREDPAGEDOWNEXTEND
:
3884 case SCI_PAGEUPEXTEND
:
3886 case SCI_PAGEDOWNEXTEND
:
3887 case SCI_EDITTOGGLEOVERTYPE
:
3889 case SCI_DELETEBACK
:
3894 case SCI_VCHOMEEXTEND
:
3895 case SCI_VCHOMEWRAP
:
3896 case SCI_VCHOMEWRAPEXTEND
:
3897 case SCI_DELWORDLEFT
:
3898 case SCI_DELWORDRIGHT
:
3899 case SCI_DELLINELEFT
:
3900 case SCI_DELLINERIGHT
:
3903 case SCI_LINEDELETE
:
3904 case SCI_LINETRANSPOSE
:
3905 case SCI_LINEDUPLICATE
:
3908 case SCI_LINESCROLLDOWN
:
3909 case SCI_LINESCROLLUP
:
3910 case SCI_DELETEBACKNOTLINE
:
3911 case SCI_HOMEDISPLAY
:
3912 case SCI_HOMEDISPLAYEXTEND
:
3913 case SCI_LINEENDDISPLAY
:
3914 case SCI_LINEENDDISPLAYEXTEND
:
3915 case SCI_SETSELECTIONMODE
:
3916 case SCI_LINEDOWNRECTEXTEND
:
3917 case SCI_LINEUPRECTEXTEND
:
3918 case SCI_CHARLEFTRECTEXTEND
:
3919 case SCI_CHARRIGHTRECTEXTEND
:
3920 case SCI_HOMERECTEXTEND
:
3921 case SCI_VCHOMERECTEXTEND
:
3922 case SCI_LINEENDRECTEXTEND
:
3923 case SCI_PAGEUPRECTEXTEND
:
3924 case SCI_PAGEDOWNRECTEXTEND
:
3925 case SCI_SELECTIONDUPLICATE
:
3928 // Filter out all others like display changes. Also, newlines are redundant
3929 // with char insert messages.
3932 // printf("Filtered out %ld of macro recording\n", iMessage);
3936 // Send notification
3937 SCNotification scn
= {0};
3938 scn
.nmhdr
.code
= SCN_MACRORECORD
;
3939 scn
.message
= iMessage
;
3940 scn
.wParam
= wParam
;
3941 scn
.lParam
= lParam
;
3946 * Force scroll and keep position relative to top of window.
3948 * If stuttered = true and not already at first/last row, move to first/last row of window.
3949 * If stuttered = true and already at first/last row, scroll as normal.
3951 void Editor::PageMove(int direction
, selTypes sel
, bool stuttered
) {
3952 int topLineNew
, newPos
;
3954 // I consider only the caretYSlop, and ignore the caretYPolicy-- is that a problem?
3955 int currentLine
= pdoc
->LineFromPosition(currentPos
);
3956 int topStutterLine
= topLine
+ caretYSlop
;
3957 int bottomStutterLine
= topLine
+ LinesToScroll() - caretYSlop
;
3959 if (stuttered
&& (direction
< 0 && currentLine
> topStutterLine
)) {
3960 topLineNew
= topLine
;
3961 newPos
= PositionFromLocation(Point(lastXChosen
, vs
.lineHeight
* caretYSlop
));
3963 } else if (stuttered
&& (direction
> 0 && currentLine
< bottomStutterLine
)) {
3964 topLineNew
= topLine
;
3965 newPos
= PositionFromLocation(Point(lastXChosen
, vs
.lineHeight
* (LinesToScroll() - caretYSlop
)));
3968 Point pt
= LocationFromPosition(currentPos
);
3970 topLineNew
= Platform::Clamp(
3971 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
3972 newPos
= PositionFromLocation(
3973 Point(lastXChosen
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())));
3976 if (topLineNew
!= topLine
) {
3977 SetTopLine(topLineNew
);
3978 MovePositionTo(newPos
, sel
);
3980 SetVerticalScrollPos();
3982 MovePositionTo(newPos
, sel
);
3986 void Editor::ChangeCaseOfSelection(bool makeUpperCase
) {
3987 pdoc
->BeginUndoAction();
3988 int startCurrent
= currentPos
;
3989 int startAnchor
= anchor
;
3990 if (selType
== selStream
) {
3991 pdoc
->ChangeCase(Range(SelectionStart(), SelectionEnd()),
3993 SetSelection(startCurrent
, startAnchor
);
3995 SelectionLineIterator
lineIterator(this, false);
3996 while (lineIterator
.Iterate()) {
3998 Range(lineIterator
.startPos
, lineIterator
.endPos
),
4001 // Would be nicer to keep the rectangular selection but this is complex
4002 SetEmptySelection(startCurrent
);
4004 pdoc
->EndUndoAction();
4007 void Editor::LineTranspose() {
4008 int line
= pdoc
->LineFromPosition(currentPos
);
4010 int startPrev
= pdoc
->LineStart(line
- 1);
4011 int endPrev
= pdoc
->LineEnd(line
- 1);
4012 int start
= pdoc
->LineStart(line
);
4013 int end
= pdoc
->LineEnd(line
);
4014 int startNext
= pdoc
->LineStart(line
+ 1);
4015 if (end
< pdoc
->Length()) {
4017 char *thisLine
= CopyRange(start
, end
);
4018 pdoc
->DeleteChars(start
, end
- start
);
4019 if (pdoc
->InsertString(startPrev
, thisLine
, end
- start
)) {
4020 MovePositionTo(startPrev
+ end
- start
);
4024 // Last line so line has no line end
4025 char *thisLine
= CopyRange(start
, end
);
4026 char *prevEnd
= CopyRange(endPrev
, start
);
4027 pdoc
->DeleteChars(endPrev
, end
- endPrev
);
4028 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
4029 if (pdoc
->InsertString(startPrev
+ end
- start
, prevEnd
, start
- endPrev
)) {
4030 MovePositionTo(startPrev
+ end
- endPrev
);
4039 void Editor::Duplicate(bool forLine
) {
4040 int start
= SelectionStart();
4041 int end
= SelectionEnd();
4046 int line
= pdoc
->LineFromPosition(currentPos
);
4047 start
= pdoc
->LineStart(line
);
4048 end
= pdoc
->LineEnd(line
);
4050 char *text
= CopyRange(start
, end
);
4052 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
4053 pdoc
->InsertString(end
, eol
);
4054 pdoc
->InsertString(end
+ istrlen(eol
), text
, end
- start
);
4056 pdoc
->InsertString(end
, text
, end
- start
);
4061 void Editor::CancelModes() {
4062 moveExtendsSelection
= false;
4065 void Editor::NewLine() {
4067 const char *eol
= "\n";
4068 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
4070 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
4072 } // else SC_EOL_LF -> "\n" already set
4073 if (pdoc
->InsertString(currentPos
, eol
)) {
4074 SetEmptySelection(currentPos
+ istrlen(eol
));
4081 EnsureCaretVisible();
4082 // Avoid blinking during rapid typing:
4083 ShowCaretAtCurrentPosition();
4086 void Editor::CursorUpOrDown(int direction
, selTypes sel
) {
4087 Point pt
= LocationFromPosition(currentPos
);
4088 int posNew
= PositionFromLocation(
4089 Point(lastXChosen
, pt
.y
+ direction
* vs
.lineHeight
));
4090 if (direction
< 0) {
4091 // Line wrapping may lead to a location on the same line, so
4092 // seek back if that is the case.
4093 // There is an equivalent case when moving down which skips
4094 // over a line but as that does not trap the user it is fine.
4095 Point ptNew
= LocationFromPosition(posNew
);
4096 while ((posNew
> 0) && (pt
.y
== ptNew
.y
)) {
4098 ptNew
= LocationFromPosition(posNew
);
4101 MovePositionTo(posNew
, sel
);
4104 void Editor::ParaUpOrDown(int direction
, selTypes sel
) {
4105 int lineDoc
, savedPos
= currentPos
;
4107 MovePositionTo(direction
> 0 ? pdoc
->ParaDown(currentPos
) : pdoc
->ParaUp(currentPos
), sel
);
4108 lineDoc
= pdoc
->LineFromPosition(currentPos
);
4109 if (direction
> 0) {
4110 if (currentPos
>= pdoc
->Length() && !cs
.GetVisible(lineDoc
)) {
4112 MovePositionTo(pdoc
->LineEndPosition(savedPos
));
4117 } while (!cs
.GetVisible(lineDoc
));
4120 int Editor::StartEndDisplayLine(int pos
, bool start
) {
4122 int line
= pdoc
->LineFromPosition(pos
);
4123 AutoSurface
surface(this);
4124 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
4125 int posRet
= INVALID_POSITION
;
4126 if (surface
&& ll
) {
4127 unsigned int posLineStart
= pdoc
->LineStart(line
);
4128 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
4129 int posInLine
= pos
- posLineStart
;
4130 if (posInLine
<= ll
->maxLineLength
) {
4131 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
4132 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
4134 posRet
= ll
->LineStart(subLine
) + posLineStart
;
4136 if (subLine
== ll
->lines
- 1)
4137 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
;
4139 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
- 1;
4145 if (posRet
== INVALID_POSITION
) {
4152 int Editor::KeyCommand(unsigned int iMessage
) {
4157 case SCI_LINEDOWNEXTEND
:
4158 CursorUpOrDown(1, selStream
);
4160 case SCI_LINEDOWNRECTEXTEND
:
4161 CursorUpOrDown(1, selRectangle
);
4166 case SCI_PARADOWNEXTEND
:
4167 ParaUpOrDown(1, selStream
);
4169 case SCI_LINESCROLLDOWN
:
4170 ScrollTo(topLine
+ 1);
4171 MoveCaretInsideView(false);
4176 case SCI_LINEUPEXTEND
:
4177 CursorUpOrDown(-1, selStream
);
4179 case SCI_LINEUPRECTEXTEND
:
4180 CursorUpOrDown(-1, selRectangle
);
4185 case SCI_PARAUPEXTEND
:
4186 ParaUpOrDown(-1, selStream
);
4188 case SCI_LINESCROLLUP
:
4189 ScrollTo(topLine
- 1);
4190 MoveCaretInsideView(false);
4193 if (SelectionEmpty() || moveExtendsSelection
) {
4194 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1));
4196 MovePositionTo(SelectionStart());
4200 case SCI_CHARLEFTEXTEND
:
4201 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), selStream
);
4204 case SCI_CHARLEFTRECTEXTEND
:
4205 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), selRectangle
);
4209 if (SelectionEmpty() || moveExtendsSelection
) {
4210 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1));
4212 MovePositionTo(SelectionEnd());
4216 case SCI_CHARRIGHTEXTEND
:
4217 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), selStream
);
4220 case SCI_CHARRIGHTRECTEXTEND
:
4221 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), selRectangle
);
4225 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1));
4228 case SCI_WORDLEFTEXTEND
:
4229 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1), selStream
);
4233 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1));
4236 case SCI_WORDRIGHTEXTEND
:
4237 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1), selStream
);
4241 case SCI_WORDLEFTEND
:
4242 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, -1), -1));
4245 case SCI_WORDLEFTENDEXTEND
:
4246 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, -1), -1), selStream
);
4249 case SCI_WORDRIGHTEND
:
4250 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, 1), 1));
4253 case SCI_WORDRIGHTENDEXTEND
:
4254 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, 1), 1), selStream
);
4259 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)));
4262 case SCI_HOMEEXTEND
:
4263 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), selStream
);
4266 case SCI_HOMERECTEXTEND
:
4267 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), selRectangle
);
4271 MovePositionTo(pdoc
->LineEndPosition(currentPos
));
4274 case SCI_LINEENDEXTEND
:
4275 MovePositionTo(pdoc
->LineEndPosition(currentPos
), selStream
);
4278 case SCI_LINEENDRECTEXTEND
:
4279 MovePositionTo(pdoc
->LineEndPosition(currentPos
), selRectangle
);
4282 case SCI_HOMEWRAP
: {
4283 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4284 if (currentPos
<= homePos
)
4285 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
4286 MovePositionTo(homePos
);
4290 case SCI_HOMEWRAPEXTEND
: {
4291 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4292 if (currentPos
<= homePos
)
4293 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
4294 MovePositionTo(homePos
, selStream
);
4298 case SCI_LINEENDWRAP
: {
4299 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
4300 int realEndPos
= pdoc
->LineEndPosition(currentPos
);
4301 if (endPos
> realEndPos
// if moved past visible EOLs
4302 || currentPos
>= endPos
) // if at end of display line already
4303 endPos
= realEndPos
;
4304 MovePositionTo(endPos
);
4308 case SCI_LINEENDWRAPEXTEND
: {
4309 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
4310 int realEndPos
= pdoc
->LineEndPosition(currentPos
);
4311 if (endPos
> realEndPos
// if moved past visible EOLs
4312 || currentPos
>= endPos
) // if at end of display line already
4313 endPos
= realEndPos
;
4314 MovePositionTo(endPos
, selStream
);
4318 case SCI_DOCUMENTSTART
:
4322 case SCI_DOCUMENTSTARTEXTEND
:
4323 MovePositionTo(0, selStream
);
4326 case SCI_DOCUMENTEND
:
4327 MovePositionTo(pdoc
->Length());
4330 case SCI_DOCUMENTENDEXTEND
:
4331 MovePositionTo(pdoc
->Length(), selStream
);
4334 case SCI_STUTTEREDPAGEUP
:
4335 PageMove(-1, noSel
, true);
4337 case SCI_STUTTEREDPAGEUPEXTEND
:
4338 PageMove(-1, selStream
, true);
4340 case SCI_STUTTEREDPAGEDOWN
:
4341 PageMove(1, noSel
, true);
4343 case SCI_STUTTEREDPAGEDOWNEXTEND
:
4344 PageMove(1, selStream
, true);
4349 case SCI_PAGEUPEXTEND
:
4350 PageMove(-1, selStream
);
4352 case SCI_PAGEUPRECTEXTEND
:
4353 PageMove(-1, selRectangle
);
4358 case SCI_PAGEDOWNEXTEND
:
4359 PageMove(1, selStream
);
4361 case SCI_PAGEDOWNRECTEXTEND
:
4362 PageMove(1, selRectangle
);
4364 case SCI_EDITTOGGLEOVERTYPE
:
4365 inOverstrike
= !inOverstrike
;
4367 ShowCaretAtCurrentPosition();
4370 case SCI_CANCEL
: // Cancel any modes - handled in subclass
4371 // Also unselect text
4374 case SCI_DELETEBACK
:
4379 EnsureCaretVisible();
4381 case SCI_DELETEBACKNOTLINE
:
4386 EnsureCaretVisible();
4393 EnsureCaretVisible();
4400 EnsureCaretVisible();
4409 MovePositionTo(pdoc
->VCHomePosition(currentPos
));
4412 case SCI_VCHOMEEXTEND
:
4413 MovePositionTo(pdoc
->VCHomePosition(currentPos
), selStream
);
4416 case SCI_VCHOMERECTEXTEND
:
4417 MovePositionTo(pdoc
->VCHomePosition(currentPos
), selRectangle
);
4420 case SCI_VCHOMEWRAP
: {
4421 int homePos
= pdoc
->VCHomePosition(currentPos
);
4422 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4423 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
4424 homePos
= viewLineStart
;
4426 MovePositionTo(homePos
);
4430 case SCI_VCHOMEWRAPEXTEND
: {
4431 int homePos
= pdoc
->VCHomePosition(currentPos
);
4432 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4433 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
4434 homePos
= viewLineStart
;
4436 MovePositionTo(homePos
, selStream
);
4441 if (vs
.zoomLevel
< 20) {
4443 InvalidateStyleRedraw();
4448 if (vs
.zoomLevel
> -10) {
4450 InvalidateStyleRedraw();
4454 case SCI_DELWORDLEFT
: {
4455 int startWord
= pdoc
->NextWordStart(currentPos
, -1);
4456 pdoc
->DeleteChars(startWord
, currentPos
- startWord
);
4460 case SCI_DELWORDRIGHT
: {
4461 int endWord
= pdoc
->NextWordStart(currentPos
, 1);
4462 pdoc
->DeleteChars(currentPos
, endWord
- currentPos
);
4465 case SCI_DELLINELEFT
: {
4466 int line
= pdoc
->LineFromPosition(currentPos
);
4467 int start
= pdoc
->LineStart(line
);
4468 pdoc
->DeleteChars(start
, currentPos
- start
);
4472 case SCI_DELLINERIGHT
: {
4473 int line
= pdoc
->LineFromPosition(currentPos
);
4474 int end
= pdoc
->LineEnd(line
);
4475 pdoc
->DeleteChars(currentPos
, end
- currentPos
);
4478 case SCI_LINECOPY
: {
4479 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4480 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4481 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
4482 pdoc
->LineStart(lineEnd
+ 1));
4486 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4487 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4488 int start
= pdoc
->LineStart(lineStart
);
4489 int end
= pdoc
->LineStart(lineEnd
+ 1);
4490 SetSelection(start
, end
);
4495 case SCI_LINEDELETE
: {
4496 int line
= pdoc
->LineFromPosition(currentPos
);
4497 int start
= pdoc
->LineStart(line
);
4498 int end
= pdoc
->LineStart(line
+ 1);
4499 pdoc
->DeleteChars(start
, end
- start
);
4502 case SCI_LINETRANSPOSE
:
4505 case SCI_LINEDUPLICATE
:
4508 case SCI_SELECTIONDUPLICATE
:
4512 ChangeCaseOfSelection(false);
4515 ChangeCaseOfSelection(true);
4517 case SCI_WORDPARTLEFT
:
4518 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1));
4521 case SCI_WORDPARTLEFTEXTEND
:
4522 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1), selStream
);
4525 case SCI_WORDPARTRIGHT
:
4526 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1));
4529 case SCI_WORDPARTRIGHTEXTEND
:
4530 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1), selStream
);
4533 case SCI_HOMEDISPLAY
:
4534 MovePositionTo(MovePositionSoVisible(
4535 StartEndDisplayLine(currentPos
, true), -1));
4538 case SCI_HOMEDISPLAYEXTEND
:
4539 MovePositionTo(MovePositionSoVisible(
4540 StartEndDisplayLine(currentPos
, true), -1), selStream
);
4543 case SCI_LINEENDDISPLAY
:
4544 MovePositionTo(MovePositionSoVisible(
4545 StartEndDisplayLine(currentPos
, false), 1));
4548 case SCI_LINEENDDISPLAYEXTEND
:
4549 MovePositionTo(MovePositionSoVisible(
4550 StartEndDisplayLine(currentPos
, false), 1), selStream
);
4557 int Editor::KeyDefault(int, int) {
4561 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
4563 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4564 (alt
? SCI_ALT
: 0);
4565 int msg
= kmap
.Find(key
, modifiers
);
4569 return WndProc(msg
, 0, 0);
4573 return KeyDefault(key
, modifiers
);
4577 void Editor::SetWhitespaceVisible(int view
) {
4578 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(view
);
4581 int Editor::GetWhitespaceVisible() {
4582 return vs
.viewWhitespace
;
4585 void Editor::Indent(bool forwards
) {
4586 //Platform::DebugPrintf("INdent %d\n", forwards);
4587 int lineOfAnchor
= pdoc
->LineFromPosition(anchor
);
4588 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
4589 if (lineOfAnchor
== lineCurrentPos
) {
4591 pdoc
->BeginUndoAction();
4593 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
4595 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4596 int indentationStep
= pdoc
->IndentSize();
4597 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
+ indentationStep
- indentation
% indentationStep
);
4598 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4600 if (pdoc
->useTabs
) {
4601 pdoc
->InsertChar(currentPos
, '\t');
4602 SetEmptySelection(currentPos
+ 1);
4604 int numSpaces
= (pdoc
->tabInChars
) -
4605 (pdoc
->GetColumn(currentPos
) % (pdoc
->tabInChars
));
4607 numSpaces
= pdoc
->tabInChars
;
4608 for (int i
= 0; i
< numSpaces
; i
++) {
4609 pdoc
->InsertChar(currentPos
+ i
, ' ');
4611 SetEmptySelection(currentPos
+ numSpaces
);
4614 pdoc
->EndUndoAction();
4616 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
4618 pdoc
->BeginUndoAction();
4619 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4620 int indentationStep
= pdoc
->IndentSize();
4621 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
4622 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4623 pdoc
->EndUndoAction();
4625 int newColumn
= ((pdoc
->GetColumn(currentPos
) - 1) / pdoc
->tabInChars
) *
4629 int newPos
= currentPos
;
4630 while (pdoc
->GetColumn(newPos
) > newColumn
)
4632 SetEmptySelection(newPos
);
4636 int anchorPosOnLine
= anchor
- pdoc
->LineStart(lineOfAnchor
);
4637 int currentPosPosOnLine
= currentPos
- pdoc
->LineStart(lineCurrentPos
);
4638 // Multiple lines selected so indent / dedent
4639 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
4640 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
4641 if (pdoc
->LineStart(lineBottomSel
) == anchor
|| pdoc
->LineStart(lineBottomSel
) == currentPos
)
4642 lineBottomSel
--; // If not selecting any characters on a line, do not indent
4643 pdoc
->BeginUndoAction();
4644 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
4645 pdoc
->EndUndoAction();
4646 if (lineOfAnchor
< lineCurrentPos
) {
4647 if (currentPosPosOnLine
== 0)
4648 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4650 SetSelection(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
4652 if (anchorPosOnLine
== 0)
4653 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4655 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
4661 * Search of a text in the document, in the given range.
4662 * @return The position of the found text, -1 if not found.
4664 long Editor::FindText(
4665 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4666 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4667 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
4669 TextToFind
*ft
= reinterpret_cast<TextToFind
*>(lParam
);
4670 int lengthFound
= istrlen(ft
->lpstrText
);
4671 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
4672 (wParam
& SCFIND_MATCHCASE
) != 0,
4673 (wParam
& SCFIND_WHOLEWORD
) != 0,
4674 (wParam
& SCFIND_WORDSTART
) != 0,
4675 (wParam
& SCFIND_REGEXP
) != 0,
4676 (wParam
& SCFIND_POSIX
) != 0,
4679 ft
->chrgText
.cpMin
= pos
;
4680 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
4686 * Relocatable search support : Searches relative to current selection
4687 * point and sets the selection to the found text range with
4691 * Anchor following searches at current selection start: This allows
4692 * multiple incremental interactive searches to be macro recorded
4693 * while still setting the selection to found text so the find/select
4694 * operation is self-contained.
4696 void Editor::SearchAnchor() {
4697 searchAnchor
= SelectionStart();
4701 * Find text from current search anchor: Must call @c SearchAnchor first.
4702 * Used for next text and previous text requests.
4703 * @return The position of the found text, -1 if not found.
4705 long Editor::SearchText(
4706 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
4707 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4708 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4709 sptr_t lParam
) { ///< The text to search for.
4711 const char *txt
= reinterpret_cast<char *>(lParam
);
4713 int lengthFound
= istrlen(txt
);
4714 if (iMessage
== SCI_SEARCHNEXT
) {
4715 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
4716 (wParam
& SCFIND_MATCHCASE
) != 0,
4717 (wParam
& SCFIND_WHOLEWORD
) != 0,
4718 (wParam
& SCFIND_WORDSTART
) != 0,
4719 (wParam
& SCFIND_REGEXP
) != 0,
4720 (wParam
& SCFIND_POSIX
) != 0,
4723 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
4724 (wParam
& SCFIND_MATCHCASE
) != 0,
4725 (wParam
& SCFIND_WHOLEWORD
) != 0,
4726 (wParam
& SCFIND_WORDSTART
) != 0,
4727 (wParam
& SCFIND_REGEXP
) != 0,
4728 (wParam
& SCFIND_POSIX
) != 0,
4733 SetSelection(pos
, pos
+ lengthFound
);
4740 * Search for text in the target range of the document.
4741 * @return The position of the found text, -1 if not found.
4743 long Editor::SearchInTarget(const char *text
, int length
) {
4744 int lengthFound
= length
;
4745 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
4746 (searchFlags
& SCFIND_MATCHCASE
) != 0,
4747 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
4748 (searchFlags
& SCFIND_WORDSTART
) != 0,
4749 (searchFlags
& SCFIND_REGEXP
) != 0,
4750 (searchFlags
& SCFIND_POSIX
) != 0,
4754 targetEnd
= pos
+ lengthFound
;
4759 void Editor::GoToLine(int lineNo
) {
4760 if (lineNo
> pdoc
->LinesTotal())
4761 lineNo
= pdoc
->LinesTotal();
4764 SetEmptySelection(pdoc
->LineStart(lineNo
));
4765 ShowCaretAtCurrentPosition();
4766 EnsureCaretVisible();
4769 static bool Close(Point pt1
, Point pt2
) {
4770 if (abs(pt1
.x
- pt2
.x
) > 3)
4772 if (abs(pt1
.y
- pt2
.y
) > 3)
4777 char *Editor::CopyRange(int start
, int end
) {
4780 int len
= end
- start
;
4781 text
= new char[len
+ 1];
4783 for (int i
= 0; i
< len
; i
++) {
4784 text
[i
] = pdoc
->CharAt(start
+ i
);
4792 void Editor::CopySelectionFromRange(SelectionText
*ss
, int start
, int end
) {
4793 ss
->Set(CopyRange(start
, end
), end
- start
+ 1,
4794 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4797 void Editor::CopySelectionRange(SelectionText
*ss
) {
4798 if (selType
== selStream
) {
4799 CopySelectionFromRange(ss
, SelectionStart(), SelectionEnd());
4803 SelectionLineIterator
lineIterator(this);
4804 while (lineIterator
.Iterate()) {
4805 size
+= lineIterator
.endPos
- lineIterator
.startPos
;
4806 if (selType
!= selLines
) {
4808 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
4814 text
= new char[size
+ 1];
4817 lineIterator
.Reset();
4818 while (lineIterator
.Iterate()) {
4819 for (int i
= lineIterator
.startPos
;
4820 i
< lineIterator
.endPos
;
4822 text
[j
++] = pdoc
->CharAt(i
);
4824 if (selType
!= selLines
) {
4825 if (pdoc
->eolMode
!= SC_EOL_LF
) {
4828 if (pdoc
->eolMode
!= SC_EOL_CR
) {
4836 ss
->Set(text
, size
+ 1, pdoc
->dbcsCodePage
,
4837 vs
.styles
[STYLE_DEFAULT
].characterSet
, selType
== selRectangle
);
4841 void Editor::CopyRangeToClipboard(int start
, int end
) {
4842 start
= pdoc
->ClampPositionIntoDocument(start
);
4843 end
= pdoc
->ClampPositionIntoDocument(end
);
4844 SelectionText selectedText
;
4845 selectedText
.Set(CopyRange(start
, end
), end
- start
+ 1,
4846 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4847 CopyToClipboard(selectedText
);
4850 void Editor::CopyText(int length
, const char *text
) {
4851 SelectionText selectedText
;
4852 selectedText
.Copy(text
, length
,
4853 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4854 CopyToClipboard(selectedText
);
4857 void Editor::SetDragPosition(int newPos
) {
4859 newPos
= MovePositionOutsideChar(newPos
, 1);
4862 if (posDrag
!= newPos
) {
4871 void Editor::DisplayCursor(Window::Cursor c
) {
4872 if (cursorMode
== SC_CURSORNORMAL
)
4875 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
4878 void Editor::StartDrag() {
4879 // Always handled by subclasses
4880 //SetMouseCapture(true);
4881 //DisplayCursor(Window::cursorArrow);
4884 void Editor::DropAt(int position
, const char *value
, bool moving
, bool rectangular
) {
4885 //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
4887 dropWentOutside
= false;
4889 int positionWasInSelection
= PositionInSelection(position
);
4891 bool positionOnEdgeOfSelection
=
4892 (position
== SelectionStart()) || (position
== SelectionEnd());
4894 if ((!inDragDrop
) || !(0 == positionWasInSelection
) ||
4895 (positionOnEdgeOfSelection
&& !moving
)) {
4897 int selStart
= SelectionStart();
4898 int selEnd
= SelectionEnd();
4900 pdoc
->BeginUndoAction();
4902 int positionAfterDeletion
= position
;
4903 if (inDragDrop
&& moving
) {
4904 // Remove dragged out text
4905 if (rectangular
|| selType
== selLines
) {
4906 SelectionLineIterator
lineIterator(this);
4907 while (lineIterator
.Iterate()) {
4908 if (position
>= lineIterator
.startPos
) {
4909 if (position
> lineIterator
.endPos
) {
4910 positionAfterDeletion
-= lineIterator
.endPos
- lineIterator
.startPos
;
4912 positionAfterDeletion
-= position
- lineIterator
.startPos
;
4917 if (position
> selStart
) {
4918 positionAfterDeletion
-= selEnd
- selStart
;
4923 position
= positionAfterDeletion
;
4926 PasteRectangular(position
, value
, istrlen(value
));
4927 pdoc
->EndUndoAction();
4928 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
4929 SetEmptySelection(position
);
4931 position
= MovePositionOutsideChar(position
, currentPos
- position
);
4932 if (pdoc
->InsertString(position
, value
)) {
4933 SetSelection(position
+ istrlen(value
), position
);
4935 pdoc
->EndUndoAction();
4937 } else if (inDragDrop
) {
4938 SetEmptySelection(position
);
4943 * @return -1 if given position is before the selection,
4944 * 1 if position is after the selection,
4945 * 0 if position is inside the selection,
4947 int Editor::PositionInSelection(int pos
) {
4948 pos
= MovePositionOutsideChar(pos
, currentPos
- pos
);
4949 if (pos
< SelectionStart()) {
4952 if (pos
> SelectionEnd()) {
4955 if (selType
== selStream
) {
4958 SelectionLineIterator
lineIterator(this);
4959 lineIterator
.SetAt(pdoc
->LineFromPosition(pos
));
4960 if (pos
< lineIterator
.startPos
) {
4962 } else if (pos
> lineIterator
.endPos
) {
4970 bool Editor::PointInSelection(Point pt
) {
4971 int pos
= PositionFromLocation(pt
);
4972 if (0 == PositionInSelection(pos
)) {
4973 // Probably inside, but we must make a finer test
4974 int selStart
, selEnd
;
4975 if (selType
== selStream
) {
4976 selStart
= SelectionStart();
4977 selEnd
= SelectionEnd();
4979 SelectionLineIterator
lineIterator(this);
4980 lineIterator
.SetAt(pdoc
->LineFromPosition(pos
));
4981 selStart
= lineIterator
.startPos
;
4982 selEnd
= lineIterator
.endPos
;
4984 if (pos
== selStart
) {
4985 // see if just before selection
4986 Point locStart
= LocationFromPosition(pos
);
4987 if (pt
.x
< locStart
.x
) {
4991 if (pos
== selEnd
) {
4992 // see if just after selection
4993 Point locEnd
= LocationFromPosition(pos
);
4994 if (pt
.x
> locEnd
.x
) {
5003 bool Editor::PointInSelMargin(Point pt
) {
5004 // Really means: "Point in a margin"
5005 if (vs
.fixedColumnWidth
> 0) { // There is a margin
5006 PRectangle rcSelMargin
= GetClientRectangle();
5007 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
5008 return rcSelMargin
.Contains(pt
);
5014 void Editor::LineSelection(int lineCurrent_
, int lineAnchor_
) {
5015 if (lineAnchor_
< lineCurrent_
) {
5016 SetSelection(pdoc
->LineStart(lineCurrent_
+ 1),
5017 pdoc
->LineStart(lineAnchor_
));
5018 } else if (lineAnchor_
> lineCurrent_
) {
5019 SetSelection(pdoc
->LineStart(lineCurrent_
),
5020 pdoc
->LineStart(lineAnchor_
+ 1));
5021 } else { // Same line, select it
5022 SetSelection(pdoc
->LineStart(lineAnchor_
+ 1),
5023 pdoc
->LineStart(lineAnchor_
));
5027 void Editor::DwellEnd(bool mouseMoved
) {
5029 ticksToDwell
= dwellDelay
;
5031 ticksToDwell
= SC_TIME_FOREVER
;
5032 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
5034 NotifyDwelling(ptMouseLast
, dwelling
);
5038 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
5039 //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
5041 int newPos
= PositionFromLocation(pt
);
5042 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
5044 moveExtendsSelection
= false;
5046 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
5050 bool inSelMargin
= PointInSelMargin(pt
);
5051 if (shift
& !inSelMargin
) {
5052 SetSelection(newPos
);
5054 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
5055 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
5056 SetMouseCapture(true);
5057 SetEmptySelection(newPos
);
5058 bool doubleClick
= false;
5059 // Stop mouse button bounce changing selection type
5060 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
5061 if (selectionType
== selChar
) {
5062 selectionType
= selWord
;
5064 } else if (selectionType
== selWord
) {
5065 selectionType
= selLine
;
5067 selectionType
= selChar
;
5068 originalAnchorPos
= currentPos
;
5072 if (selectionType
== selWord
) {
5073 if (currentPos
>= originalAnchorPos
) { // Moved forward
5074 SetSelection(pdoc
->ExtendWordSelect(currentPos
, 1),
5075 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
5076 } else { // Moved backward
5077 SetSelection(pdoc
->ExtendWordSelect(currentPos
, -1),
5078 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
5080 } else if (selectionType
== selLine
) {
5081 lineAnchor
= LineFromLocation(pt
);
5082 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
5083 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
5085 SetEmptySelection(currentPos
);
5087 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
5089 NotifyDoubleClick(pt
, shift
);
5090 if (PositionIsHotspot(newPos
))
5091 NotifyHotSpotDoubleClicked(newPos
, shift
, ctrl
, alt
);
5093 } else { // Single click
5095 selType
= selStream
;
5098 lastClickTime
= curTime
;
5102 lineAnchor
= LineFromLocation(pt
);
5103 // Single click in margin: select whole line
5104 LineSelection(lineAnchor
, lineAnchor
);
5105 SetSelection(pdoc
->LineStart(lineAnchor
+ 1),
5106 pdoc
->LineStart(lineAnchor
));
5108 // Single shift+click in margin: select from line anchor to clicked line
5109 if (anchor
> currentPos
)
5110 lineAnchor
= pdoc
->LineFromPosition(anchor
- 1);
5112 lineAnchor
= pdoc
->LineFromPosition(anchor
);
5113 int lineStart
= LineFromLocation(pt
);
5114 LineSelection(lineStart
, lineAnchor
);
5115 //lineAnchor = lineStart; // Keep the same anchor for ButtonMove
5118 SetDragPosition(invalidPosition
);
5119 SetMouseCapture(true);
5120 selectionType
= selLine
;
5122 if (PointIsHotspot(pt
)) {
5123 NotifyHotSpotClicked(newPos
, shift
, ctrl
, alt
);
5126 inDragDrop
= PointInSelection(pt
) && !SelectionEmpty();
5129 SetMouseCapture(false);
5130 SetDragPosition(newPos
);
5131 CopySelectionRange(&drag
);
5134 SetDragPosition(invalidPosition
);
5135 SetMouseCapture(true);
5137 SetEmptySelection(newPos
);
5139 selType
= alt
? selRectangle
: selStream
;
5140 selectionType
= selChar
;
5141 originalAnchorPos
= currentPos
;
5142 SetRectangularRange();
5146 lastClickTime
= curTime
;
5148 ShowCaretAtCurrentPosition();
5151 bool Editor::PositionIsHotspot(int position
) {
5152 return vs
.styles
[pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
].hotspot
;
5155 bool Editor::PointIsHotspot(Point pt
) {
5156 int pos
= PositionFromLocationClose(pt
);
5157 if (pos
== INVALID_POSITION
)
5159 return PositionIsHotspot(pos
);
5162 void Editor::SetHotSpotRange(Point
*pt
) {
5164 int pos
= PositionFromLocation(*pt
);
5166 // If we don't limit this to word characters then the
5167 // range can encompass more than the run range and then
5168 // the underline will not be drawn properly.
5169 int hsStart_
= pdoc
->ExtendStyleRange(pos
, -1, vs
.hotspotSingleLine
);
5170 int hsEnd_
= pdoc
->ExtendStyleRange(pos
, 1, vs
.hotspotSingleLine
);
5172 // Only invalidate the range if the hotspot range has changed...
5173 if (hsStart_
!= hsStart
|| hsEnd_
!= hsEnd
) {
5174 if (hsStart
!= -1) {
5175 InvalidateRange(hsStart
, hsEnd
);
5179 InvalidateRange(hsStart
, hsEnd
);
5182 if (hsStart
!= -1) {
5183 int hsStart_
= hsStart
;
5187 InvalidateRange(hsStart_
, hsEnd_
);
5195 void Editor::GetHotSpotRange(int& hsStart_
, int& hsEnd_
) {
5200 void Editor::ButtonMove(Point pt
) {
5201 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
5205 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
5206 if (HaveMouseCapture()) {
5208 // Slow down autoscrolling/selection
5209 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
5210 if (autoScrollTimer
.ticksToWait
> 0)
5212 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
5215 int movePos
= PositionFromLocation(pt
);
5216 movePos
= MovePositionOutsideChar(movePos
, currentPos
- movePos
);
5218 SetDragPosition(movePos
);
5220 if (selectionType
== selChar
) {
5221 SetSelection(movePos
);
5222 } else if (selectionType
== selWord
) {
5223 // Continue selecting by word
5224 if (movePos
== originalAnchorPos
) { // Didn't move
5225 // No need to do anything. Previously this case was lumped
5226 // in with "Moved forward", but that can be harmful in this
5227 // case: a handler for the NotifyDoubleClick re-adjusts
5228 // the selection for a fancier definition of "word" (for
5229 // example, in Perl it is useful to include the leading
5230 // '$', '%' or '@' on variables for word selection). In this
5231 // the ButtonMove() called via Tick() for auto-scrolling
5232 // could result in the fancier word selection adjustment
5234 } else if (movePos
> originalAnchorPos
) { // Moved forward
5235 SetSelection(pdoc
->ExtendWordSelect(movePos
, 1),
5236 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
5237 } else { // Moved backward
5238 SetSelection(pdoc
->ExtendWordSelect(movePos
, -1),
5239 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
5242 // Continue selecting by line
5243 int lineMove
= LineFromLocation(pt
);
5244 LineSelection(lineMove
, lineAnchor
);
5247 // While dragging to make rectangular selection, we don't want the current
5248 // position to jump to the end of smaller or empty lines.
5249 //xEndSelect = pt.x - vs.fixedColumnWidth + xOffset;
5250 xEndSelect
= XFromPosition(movePos
);
5253 PRectangle rcClient
= GetClientRectangle();
5254 if (pt
.y
> rcClient
.bottom
) {
5255 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
5257 lineMove
= cs
.DisplayFromDoc(pdoc
->LinesTotal() - 1);
5259 ScrollTo(lineMove
- LinesOnScreen() + 5);
5261 } else if (pt
.y
< rcClient
.top
) {
5262 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
5263 ScrollTo(lineMove
- 5);
5266 EnsureCaretVisible(false, false, true);
5268 if (hsStart
!= -1 && !PositionIsHotspot(movePos
))
5269 SetHotSpotRange(NULL
);
5272 if (vs
.fixedColumnWidth
> 0) { // There is a margin
5273 if (PointInSelMargin(pt
)) {
5274 DisplayCursor(Window::cursorReverseArrow
);
5275 return; // No need to test for selection
5278 // Display regular (drag) cursor over selection
5279 if (PointInSelection(pt
) && !SelectionEmpty()) {
5280 DisplayCursor(Window::cursorArrow
);
5281 } else if (PointIsHotspot(pt
)) {
5282 DisplayCursor(Window::cursorHand
);
5283 SetHotSpotRange(&pt
);
5285 DisplayCursor(Window::cursorText
);
5286 SetHotSpotRange(NULL
);
5291 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
5292 //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
5293 if (HaveMouseCapture()) {
5294 if (PointInSelMargin(pt
)) {
5295 DisplayCursor(Window::cursorReverseArrow
);
5297 DisplayCursor(Window::cursorText
);
5298 SetHotSpotRange(NULL
);
5301 SetMouseCapture(false);
5302 int newPos
= PositionFromLocation(pt
);
5303 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
5305 int selStart
= SelectionStart();
5306 int selEnd
= SelectionEnd();
5307 if (selStart
< selEnd
) {
5310 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5311 SetSelection(newPos
, newPos
+ drag
.len
);
5313 } else if (newPos
< selStart
) {
5314 pdoc
->DeleteChars(selStart
, drag
.len
);
5315 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5316 SetSelection(newPos
, newPos
+ drag
.len
);
5318 } else if (newPos
> selEnd
) {
5319 pdoc
->DeleteChars(selStart
, drag
.len
);
5321 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5322 SetSelection(newPos
, newPos
+ drag
.len
);
5325 SetEmptySelection(newPos
);
5329 selectionType
= selChar
;
5332 if (selectionType
== selChar
) {
5333 SetSelection(newPos
);
5336 SetRectangularRange();
5337 lastClickTime
= curTime
;
5340 if (selType
== selStream
) {
5344 EnsureCaretVisible(false);
5348 // Called frequently to perform background UI including
5349 // caret blinking and automatic scrolling.
5350 void Editor::Tick() {
5351 if (HaveMouseCapture()) {
5353 ButtonMove(ptMouseLast
);
5355 if (caret
.period
> 0) {
5356 timer
.ticksToWait
-= timer
.tickSize
;
5357 if (timer
.ticksToWait
<= 0) {
5358 caret
.on
= !caret
.on
;
5359 timer
.ticksToWait
= caret
.period
;
5365 if ((dwellDelay
< SC_TIME_FOREVER
) &&
5366 (ticksToDwell
> 0) &&
5367 (!HaveMouseCapture())) {
5368 ticksToDwell
-= timer
.tickSize
;
5369 if (ticksToDwell
<= 0) {
5371 NotifyDwelling(ptMouseLast
, dwelling
);
5376 bool Editor::Idle() {
5380 bool wrappingDone
= (wrapState
== eWrapNone
) || (!backgroundWrapEnabled
);
5382 if (!wrappingDone
) {
5383 // Wrap lines during idle.
5384 WrapLines(false, -1);
5386 if (docLineLastWrapped
== docLastLineToWrap
)
5387 wrappingDone
= true;
5390 // Add more idle things to do here, but make sure idleDone is
5391 // set correctly before the function returns. returning
5392 // false will stop calling this idle funtion until SetIdle() is
5395 idleDone
= wrappingDone
; // && thatDone && theOtherThingDone...
5400 void Editor::SetFocusState(bool focusState
) {
5401 hasFocus
= focusState
;
5402 NotifyFocus(hasFocus
);
5404 ShowCaretAtCurrentPosition();
5411 bool Editor::PaintContains(PRectangle rc
) {
5412 return rcPaint
.Contains(rc
);
5415 bool Editor::PaintContainsMargin() {
5416 PRectangle rcSelMargin
= GetClientRectangle();
5417 rcSelMargin
.right
= vs
.fixedColumnWidth
;
5418 return PaintContains(rcSelMargin
);
5421 void Editor::CheckForChangeOutsidePaint(Range r
) {
5422 if (paintState
== painting
&& !paintingAllText
) {
5423 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
5427 PRectangle rcRange
= RectangleFromRange(r
.start
, r
.end
);
5428 PRectangle rcText
= GetTextRectangle();
5429 if (rcRange
.top
< rcText
.top
) {
5430 rcRange
.top
= rcText
.top
;
5432 if (rcRange
.bottom
> rcText
.bottom
) {
5433 rcRange
.bottom
= rcText
.bottom
;
5436 if (!PaintContains(rcRange
)) {
5442 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
5443 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
5444 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
5445 CheckForChangeOutsidePaint(Range(braces
[0]));
5446 CheckForChangeOutsidePaint(Range(pos0
));
5449 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
5450 CheckForChangeOutsidePaint(Range(braces
[1]));
5451 CheckForChangeOutsidePaint(Range(pos1
));
5454 bracesMatchStyle
= matchStyle
;
5455 if (paintState
== notPainting
) {
5461 void Editor::SetDocPointer(Document
*document
) {
5462 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
5463 pdoc
->RemoveWatcher(this, 0);
5465 if (document
== NULL
) {
5466 pdoc
= new Document();
5472 // Ensure all positions within document
5473 selType
= selStream
;
5479 braces
[0] = invalidPosition
;
5480 braces
[1] = invalidPosition
;
5482 // Reset the contraction state to fully shown.
5484 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
5488 pdoc
->AddWatcher(this, 0);
5494 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
5496 void Editor::Expand(int &line
, bool doExpand
) {
5497 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5499 while (line
<= lineMaxSubord
) {
5501 cs
.SetVisible(line
, line
, true);
5502 int level
= pdoc
->GetLevel(line
);
5503 if (level
& SC_FOLDLEVELHEADERFLAG
) {
5504 if (doExpand
&& cs
.GetExpanded(line
)) {
5507 Expand(line
, false);
5515 void Editor::ToggleContraction(int line
) {
5517 if ((pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) == 0) {
5518 line
= pdoc
->GetFoldParent(line
);
5523 if (cs
.GetExpanded(line
)) {
5524 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5525 cs
.SetExpanded(line
, 0);
5526 if (lineMaxSubord
> line
) {
5527 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
5529 int lineCurrent
= pdoc
->LineFromPosition(currentPos
);
5530 if (lineCurrent
> line
&& lineCurrent
<= lineMaxSubord
) {
5531 // This does not re-expand the fold
5532 EnsureCaretVisible();
5540 if (!(cs
.GetVisible(line
))) {
5541 EnsureLineVisible(line
, false);
5544 cs
.SetExpanded(line
, 1);
5553 * Recurse up from this line to find any folds that prevent this line from being visible
5554 * and unfold them all.
5556 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
5558 // In case in need of wrapping to ensure DisplayFromDoc works.
5559 WrapLines(true, -1);
5561 if (!cs
.GetVisible(lineDoc
)) {
5562 int lineParent
= pdoc
->GetFoldParent(lineDoc
);
5563 if (lineParent
>= 0) {
5564 if (lineDoc
!= lineParent
)
5565 EnsureLineVisible(lineParent
, enforcePolicy
);
5566 if (!cs
.GetExpanded(lineParent
)) {
5567 cs
.SetExpanded(lineParent
, 1);
5568 Expand(lineParent
, true);
5574 if (enforcePolicy
) {
5575 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
5576 if (visiblePolicy
& VISIBLE_SLOP
) {
5577 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
5578 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
5579 SetVerticalScrollPos();
5581 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
5582 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
5583 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
5584 SetVerticalScrollPos();
5588 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
5589 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
5590 SetVerticalScrollPos();
5597 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
5598 pdoc
->BeginUndoAction();
5600 length
= istrlen(text
);
5601 if (replacePatterns
) {
5602 text
= pdoc
->SubstituteByPosition(text
, &length
);
5606 if (targetStart
!= targetEnd
)
5607 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
5608 targetEnd
= targetStart
;
5609 pdoc
->InsertString(targetStart
, text
, length
);
5610 targetEnd
= targetStart
+ length
;
5611 pdoc
->EndUndoAction();
5615 bool Editor::IsUnicodeMode() const {
5616 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
5619 int Editor::CodePage() const {
5621 return pdoc
->dbcsCodePage
;
5626 int Editor::WrapCount(int line
) {
5627 AutoSurface
surface(this);
5628 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
5630 if (surface
&& ll
) {
5631 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
5638 static bool ValidMargin(unsigned long wParam
) {
5639 return wParam
< ViewStyle::margins
;
5642 static char *CharPtrFromSPtr(sptr_t lParam
) {
5643 return reinterpret_cast<char *>(lParam
);
5646 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5647 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
5649 // Optional macro recording hook
5651 NotifyMacroRecord(iMessage
, wParam
, lParam
);
5657 return pdoc
->Length() + 1;
5660 char *ptr
= CharPtrFromSPtr(lParam
);
5661 unsigned int iChar
= 0;
5662 for (; iChar
< wParam
- 1; iChar
++)
5663 ptr
[iChar
] = pdoc
->CharAt(iChar
);
5671 pdoc
->BeginUndoAction();
5672 pdoc
->DeleteChars(0, pdoc
->Length());
5673 SetEmptySelection(0);
5674 pdoc
->InsertString(0, CharPtrFromSPtr(lParam
));
5675 pdoc
->EndUndoAction();
5679 case SCI_GETTEXTLENGTH
:
5680 return pdoc
->Length();
5692 CopyRangeToClipboard(wParam
, lParam
);
5696 CopyText(wParam
, CharPtrFromSPtr(lParam
));
5704 EnsureCaretVisible();
5710 EnsureCaretVisible();
5719 return (pdoc
->CanUndo() && !pdoc
->IsReadOnly()) ? 1 : 0;
5721 case SCI_EMPTYUNDOBUFFER
:
5722 pdoc
->DeleteUndoHistory();
5725 case SCI_GETFIRSTVISIBLELINE
:
5728 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
5729 int lineStart
= pdoc
->LineStart(wParam
);
5730 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
5732 return lineEnd
- lineStart
;
5734 char *ptr
= CharPtrFromSPtr(lParam
);
5736 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
5737 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5742 case SCI_GETLINECOUNT
:
5743 if (pdoc
->LinesTotal() == 0)
5746 return pdoc
->LinesTotal();
5749 return !pdoc
->IsSavePoint();
5752 int nStart
= static_cast<int>(wParam
);
5753 int nEnd
= static_cast<int>(lParam
);
5755 nEnd
= pdoc
->Length();
5757 nStart
= nEnd
; // Remove selection
5758 selType
= selStream
;
5759 SetSelection(nEnd
, nStart
);
5760 EnsureCaretVisible();
5764 case SCI_GETSELTEXT
: {
5766 if (selType
== selStream
) {
5767 return 1 + SelectionEnd() - SelectionStart();
5769 // TODO: why is selLines handled the slow way?
5771 int extraCharsPerLine
= 0;
5772 if (selType
!= selLines
)
5773 extraCharsPerLine
= (pdoc
->eolMode
== SC_EOL_CRLF
) ? 2 : 1;
5774 SelectionLineIterator
lineIterator(this);
5775 while (lineIterator
.Iterate()) {
5776 size
+= lineIterator
.endPos
+ extraCharsPerLine
- lineIterator
.startPos
;
5782 SelectionText selectedText
;
5783 CopySelectionRange(&selectedText
);
5784 char *ptr
= CharPtrFromSPtr(lParam
);
5786 if (selectedText
.len
) {
5787 for (; iChar
< selectedText
.len
; iChar
++)
5788 ptr
[iChar
] = selectedText
.s
[iChar
];
5795 case SCI_LINEFROMPOSITION
:
5796 if (static_cast<int>(wParam
) < 0)
5798 return pdoc
->LineFromPosition(wParam
);
5800 case SCI_POSITIONFROMLINE
:
5801 if (static_cast<int>(wParam
) < 0)
5802 wParam
= pdoc
->LineFromPosition(SelectionStart());
5804 return 0; // Even if there is no text, there is a first line that starts at 0
5805 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
5807 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
5809 return pdoc
->LineStart(wParam
);
5811 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
5812 case SCI_LINELENGTH
:
5813 if ((static_cast<int>(wParam
) < 0) ||
5814 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
5816 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
5818 case SCI_REPLACESEL
: {
5821 pdoc
->BeginUndoAction();
5823 char *replacement
= CharPtrFromSPtr(lParam
);
5824 pdoc
->InsertString(currentPos
, replacement
);
5825 pdoc
->EndUndoAction();
5826 SetEmptySelection(currentPos
+ istrlen(replacement
));
5827 EnsureCaretVisible();
5831 case SCI_SETTARGETSTART
:
5832 targetStart
= wParam
;
5835 case SCI_GETTARGETSTART
:
5838 case SCI_SETTARGETEND
:
5842 case SCI_GETTARGETEND
:
5845 case SCI_TARGETFROMSELECTION
:
5846 if (currentPos
< anchor
) {
5847 targetStart
= currentPos
;
5850 targetStart
= anchor
;
5851 targetEnd
= currentPos
;
5855 case SCI_REPLACETARGET
:
5856 PLATFORM_ASSERT(lParam
);
5857 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), wParam
);
5859 case SCI_REPLACETARGETRE
:
5860 PLATFORM_ASSERT(lParam
);
5861 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), wParam
);
5863 case SCI_SEARCHINTARGET
:
5864 PLATFORM_ASSERT(lParam
);
5865 return SearchInTarget(CharPtrFromSPtr(lParam
), wParam
);
5867 case SCI_SETSEARCHFLAGS
:
5868 searchFlags
= wParam
;
5871 case SCI_GETSEARCHFLAGS
:
5874 case SCI_POSITIONBEFORE
:
5875 return pdoc
->MovePositionOutsideChar(wParam
-1, -1, true);
5877 case SCI_POSITIONAFTER
:
5878 return pdoc
->MovePositionOutsideChar(wParam
+1, 1, true);
5880 case SCI_LINESCROLL
:
5881 ScrollTo(topLine
+ lParam
);
5882 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
5885 case SCI_SETXOFFSET
:
5887 SetHorizontalScrollPos();
5891 case SCI_GETXOFFSET
:
5894 case SCI_CHOOSECARETX
:
5898 case SCI_SCROLLCARET
:
5899 EnsureCaretVisible();
5902 case SCI_SETREADONLY
:
5903 pdoc
->SetReadOnly(wParam
!= 0);
5906 case SCI_GETREADONLY
:
5907 return pdoc
->IsReadOnly();
5912 case SCI_POINTXFROMPOSITION
:
5916 Point pt
= LocationFromPosition(lParam
);
5920 case SCI_POINTYFROMPOSITION
:
5924 Point pt
= LocationFromPosition(lParam
);
5929 return FindText(wParam
, lParam
);
5931 case SCI_GETTEXTRANGE
: {
5934 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
5935 int cpMax
= tr
->chrg
.cpMax
;
5937 cpMax
= pdoc
->Length();
5938 PLATFORM_ASSERT(cpMax
<= pdoc
->Length());
5939 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
5940 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
5941 // Spec says copied text is terminated with a NUL
5942 tr
->lpstrText
[len
] = '\0';
5943 return len
; // Not including NUL
5946 case SCI_HIDESELECTION
:
5947 hideSelection
= wParam
!= 0;
5951 case SCI_FORMATRANGE
:
5952 return FormatRange(wParam
!= 0, reinterpret_cast<RangeToFormat
*>(lParam
));
5954 case SCI_GETMARGINLEFT
:
5955 return vs
.leftMarginWidth
;
5957 case SCI_GETMARGINRIGHT
:
5958 return vs
.rightMarginWidth
;
5960 case SCI_SETMARGINLEFT
:
5961 vs
.leftMarginWidth
= lParam
;
5962 InvalidateStyleRedraw();
5965 case SCI_SETMARGINRIGHT
:
5966 vs
.rightMarginWidth
= lParam
;
5967 InvalidateStyleRedraw();
5970 // Control specific mesages
5975 pdoc
->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam
), wParam
);
5976 SetEmptySelection(currentPos
+ wParam
);
5980 case SCI_ADDSTYLEDTEXT
: {
5983 pdoc
->InsertStyledString(CurrentPosition() * 2, CharPtrFromSPtr(lParam
), wParam
);
5984 SetEmptySelection(currentPos
+ wParam
/ 2);
5988 case SCI_INSERTTEXT
: {
5991 int insertPos
= wParam
;
5992 if (static_cast<int>(wParam
) == -1)
5993 insertPos
= CurrentPosition();
5994 int newCurrent
= CurrentPosition();
5995 char *sz
= CharPtrFromSPtr(lParam
);
5996 pdoc
->InsertString(insertPos
, sz
);
5997 if (newCurrent
> insertPos
)
5998 newCurrent
+= istrlen(sz
);
5999 SetEmptySelection(newCurrent
);
6003 case SCI_APPENDTEXT
:
6004 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), wParam
);
6011 case SCI_CLEARDOCUMENTSTYLE
:
6012 ClearDocumentStyle();
6015 case SCI_SETUNDOCOLLECTION
:
6016 pdoc
->SetUndoCollection(wParam
!= 0);
6019 case SCI_GETUNDOCOLLECTION
:
6020 return pdoc
->IsCollectingUndo();
6022 case SCI_BEGINUNDOACTION
:
6023 pdoc
->BeginUndoAction();
6026 case SCI_ENDUNDOACTION
:
6027 pdoc
->EndUndoAction();
6030 case SCI_GETCARETPERIOD
:
6031 return caret
.period
;
6033 case SCI_SETCARETPERIOD
:
6034 caret
.period
= wParam
;
6037 case SCI_SETWORDCHARS
: {
6038 pdoc
->SetDefaultCharClasses(false);
6041 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), Document::ccWord
);
6045 case SCI_SETWHITESPACECHARS
: {
6048 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), Document::ccSpace
);
6052 case SCI_SETCHARSDEFAULT
:
6053 pdoc
->SetDefaultCharClasses(true);
6057 return pdoc
->Length();
6060 pdoc
->Allocate(wParam
);
6064 return pdoc
->CharAt(wParam
);
6066 case SCI_SETCURRENTPOS
:
6067 SetSelection(wParam
, anchor
);
6070 case SCI_GETCURRENTPOS
:
6074 SetSelection(currentPos
, wParam
);
6080 case SCI_SETSELECTIONSTART
:
6081 SetSelection(Platform::Maximum(currentPos
, wParam
), wParam
);
6084 case SCI_GETSELECTIONSTART
:
6085 return Platform::Minimum(anchor
, currentPos
);
6087 case SCI_SETSELECTIONEND
:
6088 SetSelection(wParam
, Platform::Minimum(anchor
, wParam
));
6091 case SCI_GETSELECTIONEND
:
6092 return Platform::Maximum(anchor
, currentPos
);
6094 case SCI_SETPRINTMAGNIFICATION
:
6095 printMagnification
= wParam
;
6098 case SCI_GETPRINTMAGNIFICATION
:
6099 return printMagnification
;
6101 case SCI_SETPRINTCOLOURMODE
:
6102 printColourMode
= wParam
;
6105 case SCI_GETPRINTCOLOURMODE
:
6106 return printColourMode
;
6108 case SCI_SETPRINTWRAPMODE
:
6109 printWrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
6112 case SCI_GETPRINTWRAPMODE
:
6113 return printWrapState
;
6115 case SCI_GETSTYLEAT
:
6116 if (static_cast<int>(wParam
) >= pdoc
->Length())
6119 return pdoc
->StyleAt(wParam
);
6129 case SCI_SETSAVEPOINT
:
6130 pdoc
->SetSavePoint();
6133 case SCI_GETSTYLEDTEXT
: {
6136 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
6138 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
6139 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
6140 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
6142 tr
->lpstrText
[iPlace
] = '\0';
6143 tr
->lpstrText
[iPlace
+ 1] = '\0';
6148 return (pdoc
->CanRedo() && !pdoc
->IsReadOnly()) ? 1 : 0;
6150 case SCI_MARKERLINEFROMHANDLE
:
6151 return pdoc
->LineFromHandle(wParam
);
6153 case SCI_MARKERDELETEHANDLE
:
6154 pdoc
->DeleteMarkFromHandle(wParam
);
6158 return vs
.viewWhitespace
;
6161 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
6165 case SCI_POSITIONFROMPOINT
:
6166 return PositionFromLocation(Point(wParam
, lParam
));
6168 case SCI_POSITIONFROMPOINTCLOSE
:
6169 return PositionFromLocationClose(Point(wParam
, lParam
));
6176 SetEmptySelection(wParam
);
6177 EnsureCaretVisible();
6181 case SCI_GETCURLINE
: {
6182 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
6183 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
6184 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
6186 return 1 + lineEnd
- lineStart
;
6188 PLATFORM_ASSERT(wParam
> 0);
6189 char *ptr
= CharPtrFromSPtr(lParam
);
6190 unsigned int iPlace
= 0;
6191 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
6192 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
6195 return currentPos
- lineStart
;
6198 case SCI_GETENDSTYLED
:
6199 return pdoc
->GetEndStyled();
6201 case SCI_GETEOLMODE
:
6202 return pdoc
->eolMode
;
6204 case SCI_SETEOLMODE
:
6205 pdoc
->eolMode
= wParam
;
6208 case SCI_STARTSTYLING
:
6209 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
6212 case SCI_SETSTYLING
:
6213 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
6216 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
6219 pdoc
->SetStyles(wParam
, CharPtrFromSPtr(lParam
));
6222 case SCI_SETBUFFEREDDRAW
:
6223 bufferedDraw
= wParam
!= 0;
6226 case SCI_GETBUFFEREDDRAW
:
6227 return bufferedDraw
;
6229 case SCI_GETTWOPHASEDRAW
:
6230 return twoPhaseDraw
;
6232 case SCI_SETTWOPHASEDRAW
:
6233 twoPhaseDraw
= wParam
!= 0;
6234 InvalidateStyleRedraw();
6237 case SCI_SETTABWIDTH
:
6239 pdoc
->tabInChars
= wParam
;
6240 if (pdoc
->indentInChars
== 0)
6241 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6243 InvalidateStyleRedraw();
6246 case SCI_GETTABWIDTH
:
6247 return pdoc
->tabInChars
;
6250 pdoc
->indentInChars
= wParam
;
6251 if (pdoc
->indentInChars
!= 0)
6252 pdoc
->actualIndentInChars
= pdoc
->indentInChars
;
6254 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6255 InvalidateStyleRedraw();
6259 return pdoc
->indentInChars
;
6261 case SCI_SETUSETABS
:
6262 pdoc
->useTabs
= wParam
!= 0;
6263 InvalidateStyleRedraw();
6266 case SCI_GETUSETABS
:
6267 return pdoc
->useTabs
;
6269 case SCI_SETLINEINDENTATION
:
6270 pdoc
->SetLineIndentation(wParam
, lParam
);
6273 case SCI_GETLINEINDENTATION
:
6274 return pdoc
->GetLineIndentation(wParam
);
6276 case SCI_GETLINEINDENTPOSITION
:
6277 return pdoc
->GetLineIndentPosition(wParam
);
6279 case SCI_SETTABINDENTS
:
6280 pdoc
->tabIndents
= wParam
!= 0;
6283 case SCI_GETTABINDENTS
:
6284 return pdoc
->tabIndents
;
6286 case SCI_SETBACKSPACEUNINDENTS
:
6287 pdoc
->backspaceUnindents
= wParam
!= 0;
6290 case SCI_GETBACKSPACEUNINDENTS
:
6291 return pdoc
->backspaceUnindents
;
6293 case SCI_SETMOUSEDWELLTIME
:
6294 dwellDelay
= wParam
;
6295 ticksToDwell
= dwellDelay
;
6298 case SCI_GETMOUSEDWELLTIME
:
6301 case SCI_WORDSTARTPOSITION
:
6302 return pdoc
->ExtendWordSelect(wParam
, -1, lParam
!= 0);
6304 case SCI_WORDENDPOSITION
:
6305 return pdoc
->ExtendWordSelect(wParam
, 1, lParam
!= 0);
6307 case SCI_SETWRAPMODE
:
6310 wrapState
= eWrapWord
;
6313 wrapState
= eWrapChar
;
6316 wrapState
= eWrapNone
;
6320 InvalidateStyleRedraw();
6321 ReconfigureScrollBars();
6324 case SCI_GETWRAPMODE
:
6327 case SCI_SETWRAPVISUALFLAGS
:
6328 wrapVisualFlags
= wParam
;
6329 actualWrapVisualStartIndent
= wrapVisualStartIndent
;
6330 if ((wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) && (actualWrapVisualStartIndent
== 0))
6331 actualWrapVisualStartIndent
= 1; // must indent to show start visual
6332 InvalidateStyleRedraw();
6333 ReconfigureScrollBars();
6336 case SCI_GETWRAPVISUALFLAGS
:
6337 return wrapVisualFlags
;
6339 case SCI_SETWRAPVISUALFLAGSLOCATION
:
6340 wrapVisualFlagsLocation
= wParam
;
6341 InvalidateStyleRedraw();
6344 case SCI_GETWRAPVISUALFLAGSLOCATION
:
6345 return wrapVisualFlagsLocation
;
6347 case SCI_SETWRAPSTARTINDENT
:
6348 wrapVisualStartIndent
= wParam
;
6349 actualWrapVisualStartIndent
= wrapVisualStartIndent
;
6350 if ((wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) && (actualWrapVisualStartIndent
== 0))
6351 actualWrapVisualStartIndent
= 1; // must indent to show start visual
6352 InvalidateStyleRedraw();
6353 ReconfigureScrollBars();
6356 case SCI_GETWRAPSTARTINDENT
:
6357 return wrapVisualStartIndent
;
6359 case SCI_SETLAYOUTCACHE
:
6360 llc
.SetLevel(wParam
);
6363 case SCI_GETLAYOUTCACHE
:
6364 return llc
.GetLevel();
6366 case SCI_SETSCROLLWIDTH
:
6367 PLATFORM_ASSERT(wParam
> 0);
6368 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
6369 scrollWidth
= wParam
;
6374 case SCI_GETSCROLLWIDTH
:
6381 case SCI_LINESSPLIT
:
6386 PLATFORM_ASSERT(wParam
<= STYLE_MAX
);
6387 PLATFORM_ASSERT(lParam
);
6388 return TextWidth(wParam
, CharPtrFromSPtr(lParam
));
6390 case SCI_TEXTHEIGHT
:
6391 return vs
.lineHeight
;
6393 case SCI_SETENDATLASTLINE
:
6394 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
6395 if (endAtLastLine
!= (wParam
!= 0)) {
6396 endAtLastLine
= wParam
!= 0;
6401 case SCI_GETENDATLASTLINE
:
6402 return endAtLastLine
;
6404 case SCI_SETCARETSTICKY
:
6405 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
6406 if (caretSticky
!= (wParam
!= 0)) {
6407 caretSticky
= wParam
!= 0;
6411 case SCI_GETCARETSTICKY
:
6414 case SCI_TOGGLECARETSTICKY
:
6415 caretSticky
= !caretSticky
;
6419 return pdoc
->GetColumn(wParam
);
6421 case SCI_FINDCOLUMN
:
6422 return pdoc
->FindColumn(wParam
, lParam
);
6424 case SCI_SETHSCROLLBAR
:
6425 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
6426 horizontalScrollBarVisible
= wParam
!= 0;
6428 ReconfigureScrollBars();
6432 case SCI_GETHSCROLLBAR
:
6433 return horizontalScrollBarVisible
;
6435 case SCI_SETVSCROLLBAR
:
6436 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
6437 verticalScrollBarVisible
= wParam
!= 0;
6439 ReconfigureScrollBars();
6443 case SCI_GETVSCROLLBAR
:
6444 return verticalScrollBarVisible
;
6446 case SCI_SETINDENTATIONGUIDES
:
6447 vs
.viewIndentationGuides
= wParam
!= 0;
6451 case SCI_GETINDENTATIONGUIDES
:
6452 return vs
.viewIndentationGuides
;
6454 case SCI_SETHIGHLIGHTGUIDE
:
6455 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
6456 highlightGuideColumn
= wParam
;
6461 case SCI_GETHIGHLIGHTGUIDE
:
6462 return highlightGuideColumn
;
6464 case SCI_GETLINEENDPOSITION
:
6465 return pdoc
->LineEnd(wParam
);
6467 case SCI_SETCODEPAGE
:
6468 pdoc
->dbcsCodePage
= wParam
;
6469 InvalidateStyleRedraw();
6472 case SCI_GETCODEPAGE
:
6473 return pdoc
->dbcsCodePage
;
6475 case SCI_SETUSEPALETTE
:
6476 palette
.allowRealization
= wParam
!= 0;
6477 InvalidateStyleRedraw();
6480 case SCI_GETUSEPALETTE
:
6481 return palette
.allowRealization
;
6483 // Marker definition and setting
6484 case SCI_MARKERDEFINE
:
6485 if (wParam
<= MARKER_MAX
)
6486 vs
.markers
[wParam
].markType
= lParam
;
6487 InvalidateStyleData();
6490 case SCI_MARKERSETFORE
:
6491 if (wParam
<= MARKER_MAX
)
6492 vs
.markers
[wParam
].fore
.desired
= ColourDesired(lParam
);
6493 InvalidateStyleData();
6496 case SCI_MARKERSETBACK
:
6497 if (wParam
<= MARKER_MAX
)
6498 vs
.markers
[wParam
].back
.desired
= ColourDesired(lParam
);
6499 InvalidateStyleData();
6502 case SCI_MARKERADD
: {
6503 int markerID
= pdoc
->AddMark(wParam
, lParam
);
6506 case SCI_MARKERADDSET
:
6508 pdoc
->AddMarkSet(wParam
, lParam
);
6511 case SCI_MARKERDELETE
:
6512 pdoc
->DeleteMark(wParam
, lParam
);
6515 case SCI_MARKERDELETEALL
:
6516 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
6520 return pdoc
->GetMark(wParam
);
6522 case SCI_MARKERNEXT
: {
6523 int lt
= pdoc
->LinesTotal();
6524 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
6525 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6531 case SCI_MARKERPREVIOUS
: {
6532 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
6533 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6539 case SCI_MARKERDEFINEPIXMAP
:
6540 if (wParam
<= MARKER_MAX
) {
6541 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
6543 InvalidateStyleData();
6547 case SCI_SETMARGINTYPEN
:
6548 if (ValidMargin(wParam
)) {
6549 vs
.ms
[wParam
].symbol
= (lParam
== SC_MARGIN_SYMBOL
);
6550 InvalidateStyleRedraw();
6554 case SCI_GETMARGINTYPEN
:
6555 if (ValidMargin(wParam
))
6556 return vs
.ms
[wParam
].symbol
? SC_MARGIN_SYMBOL
: SC_MARGIN_NUMBER
;
6560 case SCI_SETMARGINWIDTHN
:
6561 if (ValidMargin(wParam
)) {
6562 // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
6563 if (vs
.ms
[wParam
].width
!= lParam
) {
6564 vs
.ms
[wParam
].width
= lParam
;
6565 InvalidateStyleRedraw();
6570 case SCI_GETMARGINWIDTHN
:
6571 if (ValidMargin(wParam
))
6572 return vs
.ms
[wParam
].width
;
6576 case SCI_SETMARGINMASKN
:
6577 if (ValidMargin(wParam
)) {
6578 vs
.ms
[wParam
].mask
= lParam
;
6579 InvalidateStyleRedraw();
6583 case SCI_GETMARGINMASKN
:
6584 if (ValidMargin(wParam
))
6585 return vs
.ms
[wParam
].mask
;
6589 case SCI_SETMARGINSENSITIVEN
:
6590 if (ValidMargin(wParam
)) {
6591 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
6592 InvalidateStyleRedraw();
6596 case SCI_GETMARGINSENSITIVEN
:
6597 if (ValidMargin(wParam
))
6598 return vs
.ms
[wParam
].sensitive
? 1 : 0;
6602 case SCI_STYLECLEARALL
:
6604 InvalidateStyleRedraw();
6607 case SCI_STYLESETFORE
:
6608 if (wParam
<= STYLE_MAX
) {
6609 vs
.styles
[wParam
].fore
.desired
= ColourDesired(lParam
);
6610 InvalidateStyleRedraw();
6613 case SCI_STYLESETBACK
:
6614 if (wParam
<= STYLE_MAX
) {
6615 vs
.styles
[wParam
].back
.desired
= ColourDesired(lParam
);
6616 InvalidateStyleRedraw();
6619 case SCI_STYLESETBOLD
:
6620 if (wParam
<= STYLE_MAX
) {
6621 vs
.styles
[wParam
].bold
= lParam
!= 0;
6622 InvalidateStyleRedraw();
6625 case SCI_STYLESETITALIC
:
6626 if (wParam
<= STYLE_MAX
) {
6627 vs
.styles
[wParam
].italic
= lParam
!= 0;
6628 InvalidateStyleRedraw();
6631 case SCI_STYLESETEOLFILLED
:
6632 if (wParam
<= STYLE_MAX
) {
6633 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
6634 InvalidateStyleRedraw();
6637 case SCI_STYLESETSIZE
:
6638 if (wParam
<= STYLE_MAX
) {
6639 vs
.styles
[wParam
].size
= lParam
;
6640 InvalidateStyleRedraw();
6643 case SCI_STYLESETFONT
:
6646 if (wParam
<= STYLE_MAX
) {
6647 vs
.SetStyleFontName(wParam
, CharPtrFromSPtr(lParam
));
6648 InvalidateStyleRedraw();
6651 case SCI_STYLESETUNDERLINE
:
6652 if (wParam
<= STYLE_MAX
) {
6653 vs
.styles
[wParam
].underline
= lParam
!= 0;
6654 InvalidateStyleRedraw();
6657 case SCI_STYLESETCASE
:
6658 if (wParam
<= STYLE_MAX
) {
6659 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
6660 InvalidateStyleRedraw();
6663 case SCI_STYLESETCHARACTERSET
:
6664 if (wParam
<= STYLE_MAX
) {
6665 vs
.styles
[wParam
].characterSet
= lParam
;
6666 InvalidateStyleRedraw();
6669 case SCI_STYLESETVISIBLE
:
6670 if (wParam
<= STYLE_MAX
) {
6671 vs
.styles
[wParam
].visible
= lParam
!= 0;
6672 InvalidateStyleRedraw();
6675 case SCI_STYLESETCHANGEABLE
:
6676 if (wParam
<= STYLE_MAX
) {
6677 vs
.styles
[wParam
].changeable
= lParam
!= 0;
6678 InvalidateStyleRedraw();
6681 case SCI_STYLESETHOTSPOT
:
6682 if (wParam
<= STYLE_MAX
) {
6683 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
6684 InvalidateStyleRedraw();
6688 case SCI_STYLERESETDEFAULT
:
6689 vs
.ResetDefaultStyle();
6690 InvalidateStyleRedraw();
6692 case SCI_SETSTYLEBITS
:
6693 pdoc
->SetStylingBits(wParam
);
6696 case SCI_GETSTYLEBITS
:
6697 return pdoc
->stylingBits
;
6699 case SCI_SETLINESTATE
:
6700 return pdoc
->SetLineState(wParam
, lParam
);
6702 case SCI_GETLINESTATE
:
6703 return pdoc
->GetLineState(wParam
);
6705 case SCI_GETMAXLINESTATE
:
6706 return pdoc
->GetMaxLineState();
6708 case SCI_GETCARETLINEVISIBLE
:
6709 return vs
.showCaretLineBackground
;
6710 case SCI_SETCARETLINEVISIBLE
:
6711 vs
.showCaretLineBackground
= wParam
!= 0;
6712 InvalidateStyleRedraw();
6714 case SCI_GETCARETLINEBACK
:
6715 return vs
.caretLineBackground
.desired
.AsLong();
6716 case SCI_SETCARETLINEBACK
:
6717 vs
.caretLineBackground
.desired
= wParam
;
6718 InvalidateStyleRedraw();
6723 case SCI_VISIBLEFROMDOCLINE
:
6724 return cs
.DisplayFromDoc(wParam
);
6726 case SCI_DOCLINEFROMVISIBLE
:
6727 return cs
.DocFromDisplay(wParam
);
6730 return WrapCount(wParam
);
6732 case SCI_SETFOLDLEVEL
: {
6733 int prev
= pdoc
->SetLevel(wParam
, lParam
);
6739 case SCI_GETFOLDLEVEL
:
6740 return pdoc
->GetLevel(wParam
);
6742 case SCI_GETLASTCHILD
:
6743 return pdoc
->GetLastChild(wParam
, lParam
);
6745 case SCI_GETFOLDPARENT
:
6746 return pdoc
->GetFoldParent(wParam
);
6749 cs
.SetVisible(wParam
, lParam
, true);
6755 cs
.SetVisible(wParam
, lParam
, false);
6760 case SCI_GETLINEVISIBLE
:
6761 return cs
.GetVisible(wParam
);
6763 case SCI_SETFOLDEXPANDED
:
6764 if (cs
.SetExpanded(wParam
, lParam
!= 0)) {
6769 case SCI_GETFOLDEXPANDED
:
6770 return cs
.GetExpanded(wParam
);
6772 case SCI_SETFOLDFLAGS
:
6777 case SCI_TOGGLEFOLD
:
6778 ToggleContraction(wParam
);
6781 case SCI_ENSUREVISIBLE
:
6782 EnsureLineVisible(wParam
, false);
6785 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
6786 EnsureLineVisible(wParam
, true);
6789 case SCI_SEARCHANCHOR
:
6793 case SCI_SEARCHNEXT
:
6794 case SCI_SEARCHPREV
:
6795 return SearchText(iMessage
, wParam
, lParam
);
6797 #ifdef INCLUDE_DEPRECATED_FEATURES
6798 case SCI_SETCARETPOLICY
: // Deprecated
6799 caretXPolicy
= caretYPolicy
= wParam
;
6800 caretXSlop
= caretYSlop
= lParam
;
6804 case SCI_SETXCARETPOLICY
:
6805 caretXPolicy
= wParam
;
6806 caretXSlop
= lParam
;
6809 case SCI_SETYCARETPOLICY
:
6810 caretYPolicy
= wParam
;
6811 caretYSlop
= lParam
;
6814 case SCI_SETVISIBLEPOLICY
:
6815 visiblePolicy
= wParam
;
6816 visibleSlop
= lParam
;
6819 case SCI_LINESONSCREEN
:
6820 return LinesOnScreen();
6822 case SCI_SETSELFORE
:
6823 vs
.selforeset
= wParam
!= 0;
6824 vs
.selforeground
.desired
= ColourDesired(lParam
);
6825 InvalidateStyleRedraw();
6828 case SCI_SETSELBACK
:
6829 vs
.selbackset
= wParam
!= 0;
6830 vs
.selbackground
.desired
= ColourDesired(lParam
);
6831 InvalidateStyleRedraw();
6834 case SCI_SETWHITESPACEFORE
:
6835 vs
.whitespaceForegroundSet
= wParam
!= 0;
6836 vs
.whitespaceForeground
.desired
= ColourDesired(lParam
);
6837 InvalidateStyleRedraw();
6840 case SCI_SETWHITESPACEBACK
:
6841 vs
.whitespaceBackgroundSet
= wParam
!= 0;
6842 vs
.whitespaceBackground
.desired
= ColourDesired(lParam
);
6843 InvalidateStyleRedraw();
6846 case SCI_SETCARETFORE
:
6847 vs
.caretcolour
.desired
= ColourDesired(wParam
);
6848 InvalidateStyleRedraw();
6851 case SCI_GETCARETFORE
:
6852 return vs
.caretcolour
.desired
.AsLong();
6854 case SCI_SETCARETWIDTH
:
6857 else if (wParam
>= 3)
6860 vs
.caretWidth
= wParam
;
6861 InvalidateStyleRedraw();
6864 case SCI_GETCARETWIDTH
:
6865 return vs
.caretWidth
;
6867 case SCI_ASSIGNCMDKEY
:
6868 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6869 Platform::HighShortFromLong(wParam
), lParam
);
6872 case SCI_CLEARCMDKEY
:
6873 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6874 Platform::HighShortFromLong(wParam
), SCI_NULL
);
6877 case SCI_CLEARALLCMDKEYS
:
6881 case SCI_INDICSETSTYLE
:
6882 if (wParam
<= INDIC_MAX
) {
6883 vs
.indicators
[wParam
].style
= lParam
;
6884 InvalidateStyleRedraw();
6888 case SCI_INDICGETSTYLE
:
6889 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
6891 case SCI_INDICSETFORE
:
6892 if (wParam
<= INDIC_MAX
) {
6893 vs
.indicators
[wParam
].fore
.desired
= ColourDesired(lParam
);
6894 InvalidateStyleRedraw();
6898 case SCI_INDICGETFORE
:
6899 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
6902 case SCI_LINEDOWNEXTEND
:
6904 case SCI_PARADOWNEXTEND
:
6906 case SCI_LINEUPEXTEND
:
6908 case SCI_PARAUPEXTEND
:
6910 case SCI_CHARLEFTEXTEND
:
6912 case SCI_CHARRIGHTEXTEND
:
6914 case SCI_WORDLEFTEXTEND
:
6916 case SCI_WORDRIGHTEXTEND
:
6917 case SCI_WORDLEFTEND
:
6918 case SCI_WORDLEFTENDEXTEND
:
6919 case SCI_WORDRIGHTEND
:
6920 case SCI_WORDRIGHTENDEXTEND
:
6922 case SCI_HOMEEXTEND
:
6924 case SCI_LINEENDEXTEND
:
6926 case SCI_HOMEWRAPEXTEND
:
6927 case SCI_LINEENDWRAP
:
6928 case SCI_LINEENDWRAPEXTEND
:
6929 case SCI_DOCUMENTSTART
:
6930 case SCI_DOCUMENTSTARTEXTEND
:
6931 case SCI_DOCUMENTEND
:
6932 case SCI_DOCUMENTENDEXTEND
:
6934 case SCI_STUTTEREDPAGEUP
:
6935 case SCI_STUTTEREDPAGEUPEXTEND
:
6936 case SCI_STUTTEREDPAGEDOWN
:
6937 case SCI_STUTTEREDPAGEDOWNEXTEND
:
6940 case SCI_PAGEUPEXTEND
:
6942 case SCI_PAGEDOWNEXTEND
:
6943 case SCI_EDITTOGGLEOVERTYPE
:
6945 case SCI_DELETEBACK
:
6951 case SCI_VCHOMEEXTEND
:
6952 case SCI_VCHOMEWRAP
:
6953 case SCI_VCHOMEWRAPEXTEND
:
6956 case SCI_DELWORDLEFT
:
6957 case SCI_DELWORDRIGHT
:
6958 case SCI_DELLINELEFT
:
6959 case SCI_DELLINERIGHT
:
6962 case SCI_LINEDELETE
:
6963 case SCI_LINETRANSPOSE
:
6964 case SCI_LINEDUPLICATE
:
6967 case SCI_LINESCROLLDOWN
:
6968 case SCI_LINESCROLLUP
:
6969 case SCI_WORDPARTLEFT
:
6970 case SCI_WORDPARTLEFTEXTEND
:
6971 case SCI_WORDPARTRIGHT
:
6972 case SCI_WORDPARTRIGHTEXTEND
:
6973 case SCI_DELETEBACKNOTLINE
:
6974 case SCI_HOMEDISPLAY
:
6975 case SCI_HOMEDISPLAYEXTEND
:
6976 case SCI_LINEENDDISPLAY
:
6977 case SCI_LINEENDDISPLAYEXTEND
:
6978 case SCI_LINEDOWNRECTEXTEND
:
6979 case SCI_LINEUPRECTEXTEND
:
6980 case SCI_CHARLEFTRECTEXTEND
:
6981 case SCI_CHARRIGHTRECTEXTEND
:
6982 case SCI_HOMERECTEXTEND
:
6983 case SCI_VCHOMERECTEXTEND
:
6984 case SCI_LINEENDRECTEXTEND
:
6985 case SCI_PAGEUPRECTEXTEND
:
6986 case SCI_PAGEDOWNRECTEXTEND
:
6987 case SCI_SELECTIONDUPLICATE
:
6988 return KeyCommand(iMessage
);
6990 case SCI_BRACEHIGHLIGHT
:
6991 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
6994 case SCI_BRACEBADLIGHT
:
6995 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
6998 case SCI_BRACEMATCH
:
6999 // wParam is position of char to find brace for,
7000 // lParam is maximum amount of text to restyle to find it
7001 return pdoc
->BraceMatch(wParam
, lParam
);
7003 case SCI_GETVIEWEOL
:
7006 case SCI_SETVIEWEOL
:
7007 vs
.viewEOL
= wParam
!= 0;
7008 InvalidateStyleRedraw();
7012 vs
.zoomLevel
= wParam
;
7013 InvalidateStyleRedraw();
7018 return vs
.zoomLevel
;
7020 case SCI_GETEDGECOLUMN
:
7023 case SCI_SETEDGECOLUMN
:
7025 InvalidateStyleRedraw();
7028 case SCI_GETEDGEMODE
:
7029 return vs
.edgeState
;
7031 case SCI_SETEDGEMODE
:
7032 vs
.edgeState
= wParam
;
7033 InvalidateStyleRedraw();
7036 case SCI_GETEDGECOLOUR
:
7037 return vs
.edgecolour
.desired
.AsLong();
7039 case SCI_SETEDGECOLOUR
:
7040 vs
.edgecolour
.desired
= ColourDesired(wParam
);
7041 InvalidateStyleRedraw();
7044 case SCI_GETDOCPOINTER
:
7045 return reinterpret_cast<sptr_t
>(pdoc
);
7047 case SCI_SETDOCPOINTER
:
7049 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
7052 case SCI_CREATEDOCUMENT
: {
7053 Document
*doc
= new Document();
7057 return reinterpret_cast<sptr_t
>(doc
);
7060 case SCI_ADDREFDOCUMENT
:
7061 (reinterpret_cast<Document
*>(lParam
))->AddRef();
7064 case SCI_RELEASEDOCUMENT
:
7065 (reinterpret_cast<Document
*>(lParam
))->Release();
7068 case SCI_SETMODEVENTMASK
:
7069 modEventMask
= wParam
;
7072 case SCI_GETMODEVENTMASK
:
7073 return modEventMask
;
7075 case SCI_CONVERTEOLS
:
7076 pdoc
->ConvertLineEnds(wParam
);
7077 SetSelection(currentPos
, anchor
); // Ensure selection inside document
7080 case SCI_SETLENGTHFORENCODE
:
7081 lengthForEncode
= wParam
;
7084 case SCI_SELECTIONISRECTANGLE
:
7085 return selType
== selRectangle
? 1 : 0;
7087 case SCI_SETSELECTIONMODE
: {
7090 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selStream
);
7091 selType
= selStream
;
7093 case SC_SEL_RECTANGLE
:
7094 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selRectangle
);
7095 selType
= selRectangle
;
7098 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selLines
);
7102 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selStream
);
7103 selType
= selStream
;
7105 InvalidateSelection(currentPos
, anchor
);
7107 case SCI_GETSELECTIONMODE
:
7110 return SC_SEL_STREAM
;
7112 return SC_SEL_RECTANGLE
;
7114 return SC_SEL_LINES
;
7116 return SC_SEL_STREAM
;
7118 case SCI_GETLINESELSTARTPOSITION
: {
7119 SelectionLineIterator
lineIterator(this);
7120 lineIterator
.SetAt(wParam
);
7121 return lineIterator
.startPos
;
7123 case SCI_GETLINESELENDPOSITION
: {
7124 SelectionLineIterator
lineIterator(this);
7125 lineIterator
.SetAt(wParam
);
7126 return lineIterator
.endPos
;
7129 case SCI_SETOVERTYPE
:
7130 inOverstrike
= wParam
!= 0;
7133 case SCI_GETOVERTYPE
:
7134 return inOverstrike
? 1 : 0;
7137 SetFocusState(wParam
!= 0);
7144 errorStatus
= wParam
;
7150 case SCI_SETMOUSEDOWNCAPTURES
:
7151 mouseDownCaptures
= wParam
!= 0;
7154 case SCI_GETMOUSEDOWNCAPTURES
:
7155 return mouseDownCaptures
;
7158 cursorMode
= wParam
;
7159 DisplayCursor(Window::cursorText
);
7165 case SCI_SETCONTROLCHARSYMBOL
:
7166 controlCharSymbol
= wParam
;
7169 case SCI_GETCONTROLCHARSYMBOL
:
7170 return controlCharSymbol
;
7172 case SCI_STARTRECORD
:
7173 recordingMacro
= true;
7176 case SCI_STOPRECORD
:
7177 recordingMacro
= false;
7180 case SCI_MOVECARETINSIDEVIEW
:
7181 MoveCaretInsideView();
7184 case SCI_SETFOLDMARGINCOLOUR
:
7185 vs
.foldmarginColourSet
= wParam
!= 0;
7186 vs
.foldmarginColour
.desired
= ColourDesired(lParam
);
7187 InvalidateStyleRedraw();
7190 case SCI_SETFOLDMARGINHICOLOUR
:
7191 vs
.foldmarginHighlightColourSet
= wParam
!= 0;
7192 vs
.foldmarginHighlightColour
.desired
= ColourDesired(lParam
);
7193 InvalidateStyleRedraw();
7196 case SCI_SETHOTSPOTACTIVEFORE
:
7197 vs
.hotspotForegroundSet
= wParam
!= 0;
7198 vs
.hotspotForeground
.desired
= ColourDesired(lParam
);
7199 InvalidateStyleRedraw();
7202 case SCI_SETHOTSPOTACTIVEBACK
:
7203 vs
.hotspotBackgroundSet
= wParam
!= 0;
7204 vs
.hotspotBackground
.desired
= ColourDesired(lParam
);
7205 InvalidateStyleRedraw();
7208 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
7209 vs
.hotspotUnderline
= wParam
!= 0;
7210 InvalidateStyleRedraw();
7213 case SCI_SETHOTSPOTSINGLELINE
:
7214 vs
.hotspotSingleLine
= wParam
!= 0;
7215 InvalidateStyleRedraw();
7218 case SCI_SETPASTECONVERTENDINGS
:
7219 convertPastes
= wParam
!= 0;
7222 case SCI_GETPASTECONVERTENDINGS
:
7223 return convertPastes
? 1 : 0;
7226 return DefWndProc(iMessage
, wParam
, lParam
);
7228 //Platform::DebugPrintf("end wnd proc\n");