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"
29 #include "CharClassify.h"
34 return whether this modification represents an operation that
35 may reasonably be deferred (not done now OR [possibly] at all)
37 static bool CanDeferToLastStep(const DocModification
& mh
) {
38 if (mh
.modificationType
& (SC_MOD_BEFOREINSERT
|SC_MOD_BEFOREDELETE
))
39 return true; // CAN skip
40 if (!(mh
.modificationType
& (SC_PERFORMED_UNDO
|SC_PERFORMED_REDO
)))
41 return false; // MUST do
42 if (mh
.modificationType
& SC_MULTISTEPUNDOREDO
)
43 return true; // CAN skip
44 return false; // PRESUMABLY must do
47 static bool CanEliminate(const DocModification
& mh
) {
49 (mh
.modificationType
& (SC_MOD_BEFOREINSERT
|SC_MOD_BEFOREDELETE
)) != 0;
53 return whether this modification represents the FINAL step
54 in a [possibly lengthy] multi-step Undo/Redo sequence
56 static bool IsLastStep(const DocModification
& mh
) {
58 (mh
.modificationType
& (SC_PERFORMED_UNDO
|SC_PERFORMED_REDO
)) != 0
59 && (mh
.modificationType
& SC_MULTISTEPUNDOREDO
) != 0
60 && (mh
.modificationType
& SC_LASTSTEPINUNDOREDO
) != 0
61 && (mh
.modificationType
& SC_MULTILINEUNDOREDO
) != 0;
65 active(false), on(false), period(500) {}
68 ticking(false), ticksToWait(0), tickerID(0) {}
71 state(false), idlerID(0) {}
73 LineLayout::LineLayout(int maxLineLength_
) :
94 widthLine(wrapWidthInfinite
),
96 Resize(maxLineLength_
);
99 LineLayout::~LineLayout() {
103 void LineLayout::Resize(int maxLineLength_
) {
104 if (maxLineLength_
> maxLineLength
) {
106 chars
= new char[maxLineLength_
+ 1];
107 styles
= new unsigned char[maxLineLength_
+ 1];
108 indicators
= new char[maxLineLength_
+ 1];
109 // Extra position allocated as sometimes the Windows
110 // GetTextExtentExPoint API writes an extra element.
111 positions
= new int[maxLineLength_
+ 1 + 1];
112 maxLineLength
= maxLineLength_
;
116 void LineLayout::Free() {
129 void LineLayout::Invalidate(validLevel validity_
) {
130 if (validity
> validity_
)
131 validity
= validity_
;
134 void LineLayout::SetLineStart(int line
, int start
) {
135 if ((line
>= lenLineStarts
) && (line
!= 0)) {
136 int newMaxLines
= line
+ 20;
137 int *newLineStarts
= new int[newMaxLines
];
140 for (int i
= 0; i
< newMaxLines
; i
++) {
141 if (i
< lenLineStarts
)
142 newLineStarts
[i
] = lineStarts
[i
];
144 newLineStarts
[i
] = 0;
147 lineStarts
= newLineStarts
;
148 lenLineStarts
= newMaxLines
;
150 lineStarts
[line
] = start
;
153 void LineLayout::SetBracesHighlight(Range rangeLine
, Position braces
[],
154 char bracesMatchStyle
, int xHighlight
) {
155 if (rangeLine
.ContainsCharacter(braces
[0])) {
156 int braceOffset
= braces
[0] - rangeLine
.start
;
157 if (braceOffset
< numCharsInLine
) {
158 bracePreviousStyles
[0] = styles
[braceOffset
];
159 styles
[braceOffset
] = bracesMatchStyle
;
162 if (rangeLine
.ContainsCharacter(braces
[1])) {
163 int braceOffset
= braces
[1] - rangeLine
.start
;
164 if (braceOffset
< numCharsInLine
) {
165 bracePreviousStyles
[1] = styles
[braceOffset
];
166 styles
[braceOffset
] = bracesMatchStyle
;
169 if ((braces
[0] >= rangeLine
.start
&& braces
[1] <= rangeLine
.end
) ||
170 (braces
[1] >= rangeLine
.start
&& braces
[0] <= rangeLine
.end
)) {
171 xHighlightGuide
= xHighlight
;
175 void LineLayout::RestoreBracesHighlight(Range rangeLine
, Position braces
[]) {
176 if (rangeLine
.ContainsCharacter(braces
[0])) {
177 int braceOffset
= braces
[0] - rangeLine
.start
;
178 if (braceOffset
< numCharsInLine
) {
179 styles
[braceOffset
] = bracePreviousStyles
[0];
182 if (rangeLine
.ContainsCharacter(braces
[1])) {
183 int braceOffset
= braces
[1] - rangeLine
.start
;
184 if (braceOffset
< numCharsInLine
) {
185 styles
[braceOffset
] = bracePreviousStyles
[1];
191 LineLayoutCache::LineLayoutCache() :
192 level(0), length(0), size(0), cache(0),
193 allInvalidated(false), styleClock(-1), useCount(0) {
197 LineLayoutCache::~LineLayoutCache() {
201 void LineLayoutCache::Allocate(int length_
) {
202 PLATFORM_ASSERT(cache
== NULL
);
203 allInvalidated
= false;
207 size
= (size
/ 16 + 1) * 16;
210 cache
= new LineLayout
* [size
];
212 for (int i
= 0; i
< size
; i
++)
216 void LineLayoutCache::AllocateForLevel(int linesOnScreen
, int linesInDoc
) {
217 PLATFORM_ASSERT(useCount
== 0);
218 int lengthForLevel
= 0;
219 if (level
== llcCaret
) {
221 } else if (level
== llcPage
) {
222 lengthForLevel
= linesOnScreen
+ 1;
223 } else if (level
== llcDocument
) {
224 lengthForLevel
= linesInDoc
;
226 if (lengthForLevel
> size
) {
228 Allocate(lengthForLevel
);
230 if (lengthForLevel
< length
) {
231 for (int i
= lengthForLevel
; i
< length
; i
++) {
236 length
= lengthForLevel
;
238 PLATFORM_ASSERT(length
== lengthForLevel
);
239 PLATFORM_ASSERT(cache
!= NULL
|| length
== 0);
242 void LineLayoutCache::Deallocate() {
243 PLATFORM_ASSERT(useCount
== 0);
244 for (int i
= 0; i
< length
; i
++)
252 void LineLayoutCache::Invalidate(LineLayout::validLevel validity_
) {
253 if (cache
&& !allInvalidated
) {
254 for (int i
= 0; i
< length
; i
++) {
256 cache
[i
]->Invalidate(validity_
);
259 if (validity_
== LineLayout::llInvalid
) {
260 allInvalidated
= true;
265 void LineLayoutCache::SetLevel(int level_
) {
266 allInvalidated
= false;
267 if ((level_
!= -1) && (level
!= level_
)) {
273 LineLayout
*LineLayoutCache::Retrieve(int lineNumber
, int lineCaret
, int maxChars
, int styleClock_
,
274 int linesOnScreen
, int linesInDoc
) {
275 AllocateForLevel(linesOnScreen
, linesInDoc
);
276 if (styleClock
!= styleClock_
) {
277 Invalidate(LineLayout::llCheckTextAndStyle
);
278 styleClock
= styleClock_
;
280 allInvalidated
= false;
283 if (level
== llcCaret
) {
285 } else if (level
== llcPage
) {
286 if (lineNumber
== lineCaret
) {
288 } else if (length
> 1) {
289 pos
= 1 + (lineNumber
% (length
- 1));
291 } else if (level
== llcDocument
) {
295 PLATFORM_ASSERT(useCount
== 0);
296 if (cache
&& (pos
< length
)) {
298 if ((cache
[pos
]->lineNumber
!= lineNumber
) ||
299 (cache
[pos
]->maxLineLength
< maxChars
)) {
305 cache
[pos
] = new LineLayout(maxChars
);
308 cache
[pos
]->lineNumber
= lineNumber
;
309 cache
[pos
]->inCache
= true;
317 ret
= new LineLayout(maxChars
);
318 ret
->lineNumber
= lineNumber
;
324 void LineLayoutCache::Dispose(LineLayout
*ll
) {
325 allInvalidated
= false;
340 printMagnification
= 0;
341 printColourMode
= SC_PRINT_NORMAL
;
342 printWrapState
= eWrapWord
;
343 cursorMode
= SC_CURSORNORMAL
;
344 controlCharSymbol
= 0; /* Draw the control characters */
347 hideSelection
= false;
348 inOverstrike
= false;
350 mouseDownCaptures
= true;
356 dwellDelay
= SC_TIME_FOREVER
;
357 ticksToDwell
= SC_TIME_FOREVER
;
362 dropWentOutside
= false;
363 posDrag
= invalidPosition
;
364 posDrop
= invalidPosition
;
365 selectionType
= selChar
;
369 originalAnchorPos
= 0;
372 moveExtendsSelection
= false;
375 primarySelection
= true;
377 caretXPolicy
= CARET_SLOP
| CARET_EVEN
;
380 caretYPolicy
= CARET_EVEN
;
387 horizontalScrollBarVisible
= true;
389 verticalScrollBarVisible
= true;
390 endAtLastLine
= true;
393 pixmapLine
= Surface::Allocate();
394 pixmapSelMargin
= Surface::Allocate();
395 pixmapSelPattern
= Surface::Allocate();
396 pixmapIndentGuide
= Surface::Allocate();
397 pixmapIndentGuideHighlight
= Surface::Allocate();
409 lengthForEncode
= -1;
412 braces
[0] = invalidPosition
;
413 braces
[1] = invalidPosition
;
414 bracesMatchStyle
= STYLE_BRACEBAD
;
415 highlightGuideColumn
= 0;
419 paintState
= notPainting
;
421 modEventMask
= SC_MODEVENTMASKALL
;
423 pdoc
= new Document();
425 pdoc
->AddWatcher(this, 0);
427 recordingMacro
= false;
430 wrapState
= eWrapNone
;
431 wrapWidth
= LineLayout::wrapWidthInfinite
;
432 wrapStart
= wrapLineLarge
;
433 wrapEnd
= wrapLineLarge
;
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);
813 if (pt
.x
< (ll
->positions
[lineEnd
] - subLineStart
)) {
814 return pdoc
->MovePositionOutsideChar(lineEnd
+ posLineStart
, 1);
819 return INVALID_POSITION
;
823 * Find the document position corresponding to an x coordinate on a particular document line.
824 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
826 int Editor::PositionFromLineX(int lineDoc
, int x
) {
828 if (lineDoc
>= pdoc
->LinesTotal())
829 return pdoc
->Length();
830 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
831 AutoSurface
surface(this);
832 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
835 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
836 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
837 retVal
= ll
->numCharsInLine
+ posLineStart
;
839 int lineStart
= ll
->LineStart(subLine
);
840 int lineEnd
= ll
->LineStart(subLine
+ 1);
841 int subLineStart
= ll
->positions
[lineStart
];
843 if (actualWrapVisualStartIndent
!= 0) {
844 if (lineStart
!= 0) // Wrapped
845 x
-= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
847 for (int i
= lineStart
; i
< lineEnd
; i
++) {
848 if (x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
849 IsEOLChar(ll
->chars
[i
])) {
850 retVal
= pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
859 * If painting then abandon the painting because a wider redraw is needed.
860 * @return true if calling code should stop drawing.
862 bool Editor::AbandonPaint() {
863 if ((paintState
== painting
) && !paintingAllText
) {
864 paintState
= paintAbandoned
;
866 return paintState
== paintAbandoned
;
869 void Editor::RedrawRect(PRectangle rc
) {
870 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
872 // Clip the redraw rectangle into the client area
873 PRectangle rcClient
= GetClientRectangle();
874 if (rc
.top
< rcClient
.top
)
875 rc
.top
= rcClient
.top
;
876 if (rc
.bottom
> rcClient
.bottom
)
877 rc
.bottom
= rcClient
.bottom
;
878 if (rc
.left
< rcClient
.left
)
879 rc
.left
= rcClient
.left
;
880 if (rc
.right
> rcClient
.right
)
881 rc
.right
= rcClient
.right
;
883 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
884 wMain
.InvalidateRectangle(rc
);
888 void Editor::Redraw() {
889 //Platform::DebugPrintf("Redraw all\n");
890 PRectangle rcClient
= GetClientRectangle();
891 wMain
.InvalidateRectangle(rcClient
);
892 //wMain.InvalidateAll();
895 void Editor::RedrawSelMargin(int line
) {
896 if (!AbandonPaint()) {
900 PRectangle rcSelMargin
= GetClientRectangle();
901 rcSelMargin
.right
= vs
.fixedColumnWidth
;
903 int position
= pdoc
->LineStart(line
);
904 PRectangle rcLine
= RectangleFromRange(position
, position
);
905 rcSelMargin
.top
= rcLine
.top
;
906 rcSelMargin
.bottom
= rcLine
.bottom
;
908 wMain
.InvalidateRectangle(rcSelMargin
);
913 PRectangle
Editor::RectangleFromRange(int start
, int end
) {
920 int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(minPos
));
921 int lineDocMax
= pdoc
->LineFromPosition(maxPos
);
922 int maxLine
= cs
.DisplayFromDoc(lineDocMax
) + cs
.GetHeight(lineDocMax
) - 1;
923 PRectangle rcClient
= GetTextRectangle();
925 rc
.left
= vs
.fixedColumnWidth
;
926 rc
.top
= (minLine
- topLine
) * vs
.lineHeight
;
929 rc
.right
= rcClient
.right
;
930 rc
.bottom
= (maxLine
- topLine
+ 1) * vs
.lineHeight
;
931 // Ensure PRectangle is within 16 bit space
932 rc
.top
= Platform::Clamp(rc
.top
, -32000, 32000);
933 rc
.bottom
= Platform::Clamp(rc
.bottom
, -32000, 32000);
938 void Editor::InvalidateRange(int start
, int end
) {
939 RedrawRect(RectangleFromRange(start
, end
));
942 int Editor::CurrentPosition() {
946 bool Editor::SelectionEmpty() {
947 return anchor
== currentPos
;
950 int Editor::SelectionStart() {
951 return Platform::Minimum(currentPos
, anchor
);
954 int Editor::SelectionEnd() {
955 return Platform::Maximum(currentPos
, anchor
);
958 void Editor::SetRectangularRange() {
959 if (selType
== selRectangle
) {
960 xStartSelect
= XFromPosition(anchor
);
961 xEndSelect
= XFromPosition(currentPos
);
965 void Editor::InvalidateSelection(int currentPos_
, int anchor_
) {
966 int firstAffected
= anchor
;
967 if (firstAffected
> currentPos
)
968 firstAffected
= currentPos
;
969 if (firstAffected
> anchor_
)
970 firstAffected
= anchor_
;
971 if (firstAffected
> currentPos_
)
972 firstAffected
= currentPos_
;
973 int lastAffected
= anchor
;
974 if (lastAffected
< currentPos
)
975 lastAffected
= currentPos
;
976 if (lastAffected
< anchor_
)
977 lastAffected
= anchor_
;
978 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
979 lastAffected
= (currentPos_
+ 1);
981 InvalidateRange(firstAffected
, lastAffected
);
984 void Editor::SetSelection(int currentPos_
, int anchor_
) {
985 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
986 anchor_
= pdoc
->ClampPositionIntoDocument(anchor_
);
987 if ((currentPos
!= currentPos_
) || (anchor
!= anchor_
)) {
988 InvalidateSelection(currentPos_
, anchor_
);
989 currentPos
= currentPos_
;
992 SetRectangularRange();
996 void Editor::SetSelection(int currentPos_
) {
997 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
998 if (currentPos
!= currentPos_
) {
999 InvalidateSelection(currentPos_
, currentPos_
);
1000 currentPos
= currentPos_
;
1002 SetRectangularRange();
1006 void Editor::SetEmptySelection(int currentPos_
) {
1007 selType
= selStream
;
1008 moveExtendsSelection
= false;
1009 SetSelection(currentPos_
, currentPos_
);
1012 bool Editor::RangeContainsProtected(int start
, int end
) const {
1013 if (vs
.ProtectionActive()) {
1019 int mask
= pdoc
->stylingBitsMask
;
1020 for (int pos
= start
; pos
< end
; pos
++) {
1021 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected())
1028 bool Editor::SelectionContainsProtected() {
1029 // DONE, but untested...: make support rectangular selection
1031 if (selType
== selStream
) {
1032 scp
= RangeContainsProtected(anchor
, currentPos
);
1034 SelectionLineIterator
lineIterator(this);
1035 while (lineIterator
.Iterate()) {
1036 if (RangeContainsProtected(lineIterator
.startPos
, lineIterator
.endPos
)) {
1046 * Asks document to find a good position and then moves out of any invisible positions.
1048 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) {
1049 pos
= pdoc
->MovePositionOutsideChar(pos
, moveDir
, checkLineEnd
);
1050 if (vs
.ProtectionActive()) {
1051 int mask
= pdoc
->stylingBitsMask
;
1053 if ((pos
> 0) && vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()) {
1054 while ((pos
< pdoc
->Length()) &&
1055 (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected()))
1058 } else if (moveDir
< 0) {
1059 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected()) {
1061 (vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()))
1069 int Editor::MovePositionTo(int newPos
, selTypes sel
, bool ensureVisible
) {
1070 int delta
= newPos
- currentPos
;
1071 newPos
= pdoc
->ClampPositionIntoDocument(newPos
);
1072 newPos
= MovePositionOutsideChar(newPos
, delta
);
1076 if (sel
!= noSel
|| moveExtendsSelection
) {
1077 SetSelection(newPos
);
1079 SetEmptySelection(newPos
);
1081 ShowCaretAtCurrentPosition();
1082 if (ensureVisible
) {
1083 EnsureCaretVisible();
1089 int Editor::MovePositionSoVisible(int pos
, int moveDir
) {
1090 pos
= pdoc
->ClampPositionIntoDocument(pos
);
1091 pos
= MovePositionOutsideChar(pos
, moveDir
);
1092 int lineDoc
= pdoc
->LineFromPosition(pos
);
1093 if (cs
.GetVisible(lineDoc
)) {
1096 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
1098 // lineDisplay is already line before fold as lines in fold use display line of line after fold
1099 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
1100 return pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
));
1102 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
1103 return pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
));
1109 * Choose the x position that the caret will try to stick to
1110 * as it moves up and down.
1112 void Editor::SetLastXChosen() {
1113 Point pt
= LocationFromPosition(currentPos
);
1117 void Editor::ScrollTo(int line
, bool moveThumb
) {
1118 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
1119 if (topLineNew
!= topLine
) {
1120 // Try to optimise small scrolls
1121 int linesToMove
= topLine
- topLineNew
;
1122 SetTopLine(topLineNew
);
1123 ShowCaretAtCurrentPosition();
1124 // Perform redraw rather than scroll if many lines would be redrawn anyway.
1126 if (abs(linesToMove
) <= 10) {
1127 ScrollText(linesToMove
);
1135 SetVerticalScrollPos();
1140 void Editor::ScrollText(int /* linesToMove */) {
1141 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
1145 void Editor::HorizontalScrollTo(int xPos
) {
1146 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
1149 if ((wrapState
== eWrapNone
) && (xOffset
!= xPos
)) {
1151 SetHorizontalScrollPos();
1152 RedrawRect(GetClientRectangle());
1156 void Editor::MoveCaretInsideView(bool ensureVisible
) {
1157 PRectangle rcClient
= GetTextRectangle();
1158 Point pt
= LocationFromPosition(currentPos
);
1159 if (pt
.y
< rcClient
.top
) {
1160 MovePositionTo(PositionFromLocation(
1161 Point(lastXChosen
, rcClient
.top
)),
1162 noSel
, ensureVisible
);
1163 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
1164 int yOfLastLineFullyDisplayed
= rcClient
.top
+ (LinesOnScreen() - 1) * vs
.lineHeight
;
1165 MovePositionTo(PositionFromLocation(
1166 Point(lastXChosen
, rcClient
.top
+ yOfLastLineFullyDisplayed
)),
1167 noSel
, ensureVisible
);
1171 int Editor::DisplayFromPosition(int pos
) {
1172 int lineDoc
= pdoc
->LineFromPosition(pos
);
1173 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
1174 AutoSurface
surface(this);
1175 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
1176 if (surface
&& ll
) {
1177 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
1178 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
1179 int posInLine
= pos
- posLineStart
;
1180 lineDisplay
--; // To make up for first increment ahead.
1181 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
1182 if (posInLine
>= ll
->LineStart(subLine
)) {
1191 * Ensure the caret is reasonably visible in context.
1193 Caret policy in SciTE
1195 If slop is set, we can define a slop value.
1196 This value defines an unwanted zone (UZ) where the caret is... unwanted.
1197 This zone is defined as a number of pixels near the vertical margins,
1198 and as a number of lines near the horizontal margins.
1199 By keeping the caret away from the edges, it is seen within its context,
1200 so it is likely that the identifier that the caret is on can be completely seen,
1201 and that the current line is seen with some of the lines following it which are
1202 often dependent on that line.
1204 If strict is set, the policy is enforced... strictly.
1205 The caret is centred on the display if slop is not set,
1206 and cannot go in the UZ if slop is set.
1208 If jumps is set, the display is moved more energetically
1209 so the caret can move in the same direction longer before the policy is applied again.
1210 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1212 If even is not set, instead of having symmetrical UZs,
1213 the left and bottom UZs are extended up to right and top UZs respectively.
1214 This way, we favour the displaying of useful information: the begining of lines,
1215 where most code reside, and the lines after the caret, eg. the body of a function.
1218 slop | strict | jumps | even | Caret can go to the margin | When reaching limitÝ(caret going out of
1219 | | | | | visibility or going into the UZ) display is...
1220 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1221 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1222 0 | 0 | 0 | 1 | Yes | moved by one position
1223 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1224 0 | 0 | 1 | 1 | Yes | centred on the caret
1225 0 | 1 | - | 0 | Caret is always on top/on right of display | -
1226 0 | 1 | - | 1 | No, caret is always centred | -
1227 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1228 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1229 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1230 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1231 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1232 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1233 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1235 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
1236 //Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " ");
1237 PRectangle rcClient
= GetTextRectangle();
1238 //int rcClientFullWidth = rcClient.Width();
1239 int posCaret
= currentPos
;
1243 Point pt
= LocationFromPosition(posCaret
);
1244 Point ptBottomCaret
= pt
;
1245 ptBottomCaret
.y
+= vs
.lineHeight
- 1;
1246 int lineCaret
= DisplayFromPosition(posCaret
);
1247 bool bSlop
, bStrict
, bJump
, bEven
;
1249 // Vertical positioning
1250 if (vert
&& (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
> rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1251 int linesOnScreen
= LinesOnScreen();
1252 int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1253 int newTopLine
= topLine
;
1254 bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1255 bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1256 bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1257 bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1259 // It should be possible to scroll the window to show the caret,
1260 // but this fails to remove the caret on GTK+
1261 if (bSlop
) { // A margin is defined
1264 int yMarginT
, yMarginB
;
1266 // In drag mode, avoid moves
1267 // otherwise, a double click will select several lines.
1268 yMarginT
= yMarginB
= 0;
1270 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1271 // a maximum of slightly less than half the heigth of the text area.
1272 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1274 yMarginB
= yMarginT
;
1276 yMarginB
= linesOnScreen
- yMarginT
- 1;
1282 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1286 yMoveB
= linesOnScreen
- yMoveT
- 1;
1288 if (lineCaret
< topLine
+ yMarginT
) {
1289 // Caret goes too high
1290 newTopLine
= lineCaret
- yMoveT
;
1291 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1292 // Caret goes too low
1293 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1295 } else { // Not strict
1296 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1297 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1301 yMoveB
= linesOnScreen
- yMoveT
- 1;
1303 if (lineCaret
< topLine
) {
1304 // Caret goes too high
1305 newTopLine
= lineCaret
- yMoveT
;
1306 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1307 // Caret goes too low
1308 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1312 if (!bStrict
&& !bJump
) {
1314 if (lineCaret
< topLine
) {
1315 // Caret goes too high
1316 newTopLine
= lineCaret
;
1317 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1318 // Caret goes too low
1320 newTopLine
= lineCaret
- linesOnScreen
+ 1;
1322 newTopLine
= lineCaret
;
1325 } else { // Strict or going out of display
1327 // Always center caret
1328 newTopLine
= lineCaret
- halfScreen
;
1330 // Always put caret on top of display
1331 newTopLine
= lineCaret
;
1335 newTopLine
= Platform::Clamp(newTopLine
, 0, MaxScrollPos());
1336 if (newTopLine
!= topLine
) {
1338 SetTopLine(newTopLine
);
1339 SetVerticalScrollPos();
1343 // Horizontal positioning
1344 if (horiz
&& (wrapState
== eWrapNone
)) {
1345 int halfScreen
= Platform::Maximum(rcClient
.Width() - 4, 4) / 2;
1346 int xOffsetNew
= xOffset
;
1347 bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1348 bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1349 bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1350 bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1352 if (bSlop
) { // A margin is defined
1355 int xMarginL
, xMarginR
;
1357 // In drag mode, avoid moves unless very near of the margin
1358 // otherwise, a simple click will select text.
1359 xMarginL
= xMarginR
= 2;
1361 // xMargin must equal to caretXSlop, with a minimum of 2 and
1362 // a maximum of slightly less than half the width of the text area.
1363 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1365 xMarginL
= xMarginR
;
1367 xMarginL
= rcClient
.Width() - xMarginR
- 4;
1370 if (bJump
&& bEven
) {
1371 // Jump is used only in even mode
1372 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1374 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1376 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1377 // Caret is on the left of the display
1378 if (bJump
&& bEven
) {
1379 xOffsetNew
-= xMoveL
;
1381 // Move just enough to allow to display the caret
1382 xOffsetNew
-= (rcClient
.left
+ xMarginL
) - pt
.x
;
1384 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1385 // Caret is on the right of the display
1386 if (bJump
&& bEven
) {
1387 xOffsetNew
+= xMoveR
;
1389 // Move just enough to allow to display the caret
1390 xOffsetNew
+= pt
.x
- (rcClient
.right
- xMarginR
) + 1;
1393 } else { // Not strict
1394 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1395 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1399 xMoveL
= rcClient
.Width() - xMoveR
- 4;
1401 if (pt
.x
< rcClient
.left
) {
1402 // Caret is on the left of the display
1403 xOffsetNew
-= xMoveL
;
1404 } else if (pt
.x
>= rcClient
.right
) {
1405 // Caret is on the right of the display
1406 xOffsetNew
+= xMoveR
;
1411 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1412 // Strict or going out of display
1415 xOffsetNew
+= pt
.x
- rcClient
.left
- halfScreen
;
1417 // Put caret on right
1418 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1421 // Move just enough to allow to display the caret
1422 if (pt
.x
< rcClient
.left
) {
1423 // Caret is on the left of the display
1425 xOffsetNew
-= rcClient
.left
- pt
.x
;
1427 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1429 } else if (pt
.x
>= rcClient
.right
) {
1430 // Caret is on the right of the display
1431 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1435 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1436 if (pt
.x
+ xOffset
< rcClient
.left
+ xOffsetNew
) {
1437 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.left
;
1438 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ xOffsetNew
) {
1439 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.right
+ 1;
1441 if (xOffsetNew
< 0) {
1444 if (xOffset
!= xOffsetNew
) {
1445 xOffset
= xOffsetNew
;
1446 if (xOffsetNew
> 0) {
1447 PRectangle rcText
= GetTextRectangle();
1448 if (horizontalScrollBarVisible
== true &&
1449 rcText
.Width() + xOffset
> scrollWidth
) {
1450 scrollWidth
= xOffset
+ rcText
.Width();
1454 SetHorizontalScrollPos();
1458 UpdateSystemCaret();
1461 void Editor::ShowCaretAtCurrentPosition() {
1463 caret
.active
= true;
1467 caret
.active
= false;
1473 void Editor::DropCaret() {
1474 caret
.active
= false;
1478 void Editor::InvalidateCaret() {
1480 InvalidateRange(posDrag
, posDrag
+ 1);
1482 InvalidateRange(currentPos
, currentPos
+ 1);
1483 UpdateSystemCaret();
1486 void Editor::UpdateSystemCaret() {
1489 void Editor::NeedWrapping(int docLineStart
, int docLineEnd
) {
1490 docLineStart
= Platform::Clamp(docLineStart
, 0, pdoc
->LinesTotal());
1491 if (wrapStart
> docLineStart
) {
1492 wrapStart
= docLineStart
;
1493 llc
.Invalidate(LineLayout::llPositions
);
1495 if (wrapEnd
< docLineEnd
) {
1496 wrapEnd
= docLineEnd
;
1498 wrapEnd
= Platform::Clamp(wrapEnd
, 0, pdoc
->LinesTotal());
1499 // Wrap lines during idle.
1500 if ((wrapState
!= eWrapNone
) && (wrapEnd
!= wrapStart
)) {
1505 // Check if wrapping needed and perform any needed wrapping.
1506 // fullwrap: if true, all lines which need wrapping will be done,
1507 // in this single call.
1508 // priorityWrapLineStart: If greater than zero, all lines starting from
1509 // here to 1 page + 100 lines past will be wrapped (even if there are
1510 // more lines under wrapping process in idle).
1511 // If it is neither fullwrap, nor priorityWrap, then 1 page + 100 lines will be
1512 // wrapped, if there are any wrapping going on in idle. (Generally this
1513 // condition is called only from idler).
1514 // Return true if wrapping occurred.
1515 bool Editor::WrapLines(bool fullWrap
, int priorityWrapLineStart
) {
1516 // If there are any pending wraps, do them during idle if possible.
1517 int linesInOneCall
= LinesOnScreen() + 100;
1518 if (wrapState
!= eWrapNone
) {
1519 if (wrapStart
< wrapEnd
) {
1520 if (!SetIdle(true)) {
1521 // Idle processing not supported so full wrap required.
1525 if (!fullWrap
&& priorityWrapLineStart
>= 0 &&
1526 // .. and if the paint window is outside pending wraps
1527 (((priorityWrapLineStart
+ linesInOneCall
) < wrapStart
) ||
1528 (priorityWrapLineStart
> wrapEnd
))) {
1529 // No priority wrap pending
1533 int goodTopLine
= topLine
;
1534 bool wrapOccurred
= false;
1535 if (wrapStart
<= pdoc
->LinesTotal()) {
1536 if (wrapState
== eWrapNone
) {
1537 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1538 wrapWidth
= LineLayout::wrapWidthInfinite
;
1539 for (int lineDoc
= 0; lineDoc
< pdoc
->LinesTotal(); lineDoc
++) {
1540 cs
.SetHeight(lineDoc
, 1);
1542 wrapOccurred
= true;
1544 wrapStart
= wrapLineLarge
;
1545 wrapEnd
= wrapLineLarge
;
1547 if (wrapEnd
>= pdoc
->LinesTotal())
1548 wrapEnd
= pdoc
->LinesTotal();
1550 int lineDocTop
= cs
.DocFromDisplay(topLine
);
1551 int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1552 PRectangle rcTextArea
= GetClientRectangle();
1553 rcTextArea
.left
= vs
.fixedColumnWidth
;
1554 rcTextArea
.right
-= vs
.rightMarginWidth
;
1555 wrapWidth
= rcTextArea
.Width();
1556 // Ensure all of the document is styled.
1557 pdoc
->EnsureStyledTo(pdoc
->Length());
1559 AutoSurface
surface(this);
1561 bool priorityWrap
= false;
1562 int lastLineToWrap
= wrapEnd
;
1563 int lineToWrap
= wrapStart
;
1565 if (priorityWrapLineStart
>= 0) {
1566 // This is a priority wrap.
1567 lineToWrap
= priorityWrapLineStart
;
1568 lastLineToWrap
= priorityWrapLineStart
+ linesInOneCall
;
1569 priorityWrap
= true;
1571 // This is idle wrap.
1572 lastLineToWrap
= wrapStart
+ linesInOneCall
;
1574 if (lastLineToWrap
>= wrapEnd
)
1575 lastLineToWrap
= wrapEnd
;
1576 } // else do a fullWrap.
1578 // Platform::DebugPrintf("Wraplines: full = %d, priorityStart = %d (wrapping: %d to %d)\n", fullWrap, priorityWrapLineStart, lineToWrap, lastLineToWrap);
1579 // Platform::DebugPrintf("Pending wraps: %d to %d\n", wrapStart, wrapEnd);
1580 while (lineToWrap
< lastLineToWrap
) {
1581 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineToWrap
));
1582 int linesWrapped
= 1;
1584 LayoutLine(lineToWrap
, surface
, vs
, ll
, wrapWidth
);
1585 linesWrapped
= ll
->lines
;
1587 if (cs
.SetHeight(lineToWrap
, linesWrapped
)) {
1588 wrapOccurred
= true;
1593 wrapStart
= lineToWrap
;
1594 // If wrapping is done, bring it to resting position
1595 if (wrapStart
>= wrapEnd
) {
1596 wrapStart
= wrapLineLarge
;
1597 wrapEnd
= wrapLineLarge
;
1600 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
);
1601 if (subLineTop
< cs
.GetHeight(lineDocTop
))
1602 goodTopLine
+= subLineTop
;
1604 goodTopLine
+= cs
.GetHeight(lineDocTop
);
1605 //double durWrap = et.Duration(true);
1606 //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap);
1611 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1612 SetVerticalScrollPos();
1614 return wrapOccurred
;
1617 void Editor::LinesJoin() {
1618 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1619 pdoc
->BeginUndoAction();
1620 bool prevNonWS
= true;
1621 for (int pos
= targetStart
; pos
< targetEnd
; pos
++) {
1622 if (IsEOLChar(pdoc
->CharAt(pos
))) {
1623 targetEnd
-= pdoc
->LenChar(pos
);
1626 // Ensure at least one space separating previous lines
1627 pdoc
->InsertChar(pos
, ' ');
1630 prevNonWS
= pdoc
->CharAt(pos
) != ' ';
1633 pdoc
->EndUndoAction();
1637 const char *StringFromEOLMode(int eolMode
) {
1638 if (eolMode
== SC_EOL_CRLF
) {
1640 } else if (eolMode
== SC_EOL_CR
) {
1647 void Editor::LinesSplit(int pixelWidth
) {
1648 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1649 if (pixelWidth
== 0) {
1650 PRectangle rcText
= GetTextRectangle();
1651 pixelWidth
= rcText
.Width();
1653 int lineStart
= pdoc
->LineFromPosition(targetStart
);
1654 int lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1655 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1656 pdoc
->BeginUndoAction();
1657 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
1658 AutoSurface
surface(this);
1659 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
1660 if (surface
&& ll
) {
1661 unsigned int posLineStart
= pdoc
->LineStart(line
);
1662 LayoutLine(line
, surface
, vs
, ll
, pixelWidth
);
1663 for (int subLine
= 1; subLine
< ll
->lines
; subLine
++) {
1664 pdoc
->InsertString(posLineStart
+ (subLine
- 1) * strlen(eol
) +
1665 ll
->LineStart(subLine
), eol
);
1666 targetEnd
+= static_cast<int>(strlen(eol
));
1669 lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1671 pdoc
->EndUndoAction();
1675 int Editor::SubstituteMarkerIfEmpty(int markerCheck
, int markerDefault
) {
1676 if (vs
.markers
[markerCheck
].markType
== SC_MARK_EMPTY
)
1677 return markerDefault
;
1681 // Avoid 64 bit compiler warnings.
1682 // Scintilla does not support text buffers larger than 2**31
1683 static int istrlen(const char *s
) {
1684 return static_cast<int>(strlen(s
));
1687 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1688 if (vs
.fixedColumnWidth
== 0)
1691 PRectangle rcMargin
= GetClientRectangle();
1692 rcMargin
.right
= vs
.fixedColumnWidth
;
1694 if (!rc
.Intersects(rcMargin
))
1699 surface
= pixmapSelMargin
;
1701 surface
= surfWindow
;
1704 PRectangle rcSelMargin
= rcMargin
;
1705 rcSelMargin
.right
= rcMargin
.left
;
1707 for (int margin
= 0; margin
< vs
.margins
; margin
++) {
1708 if (vs
.ms
[margin
].width
> 0) {
1710 rcSelMargin
.left
= rcSelMargin
.right
;
1711 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
1713 if (vs
.ms
[margin
].style
!= SC_MARGIN_NUMBER
) {
1714 /* alternate scheme:
1715 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
1716 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1718 // Required because of special way brush is created for selection margin
1719 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
1721 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
1722 // Required because of special way brush is created for selection margin
1723 surface
->FillRectangle(rcSelMargin
, *pixmapSelPattern
);
1725 ColourAllocated colour
;
1726 switch (vs
.ms
[margin
].style
) {
1727 case SC_MARGIN_BACK
:
1728 colour
= vs
.styles
[STYLE_DEFAULT
].back
.allocated
;
1730 case SC_MARGIN_FORE
:
1731 colour
= vs
.styles
[STYLE_DEFAULT
].fore
.allocated
;
1734 colour
= vs
.styles
[STYLE_LINENUMBER
].back
.allocated
;
1737 surface
->FillRectangle(rcSelMargin
, colour
);
1740 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1743 int visibleLine
= topLine
;
1746 // Work out whether the top line is whitespace located after a
1747 // lessening of fold level which implies a 'fold tail' but which should not
1748 // be displayed until the last of a sequence of whitespace.
1749 bool needWhiteClosure
= false;
1750 int level
= pdoc
->GetLevel(cs
.DocFromDisplay(topLine
));
1751 if (level
& SC_FOLDLEVELWHITEFLAG
) {
1752 int lineBack
= cs
.DocFromDisplay(topLine
);
1753 int levelPrev
= level
;
1754 while ((lineBack
> 0) && (levelPrev
& SC_FOLDLEVELWHITEFLAG
)) {
1756 levelPrev
= pdoc
->GetLevel(lineBack
);
1758 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
1759 if ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelPrev
& SC_FOLDLEVELNUMBERMASK
))
1760 needWhiteClosure
= true;
1764 // Old code does not know about new markers needed to distinguish all cases
1765 int folderOpenMid
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID
,
1766 SC_MARKNUM_FOLDEROPEN
);
1767 int folderEnd
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND
,
1770 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
1772 PLATFORM_ASSERT(visibleLine
< cs
.LinesDisplayed());
1774 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
1775 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
1776 bool firstSubLine
= visibleLine
== cs
.DisplayFromDoc(lineDoc
);
1778 // Decide which fold indicator should be displayed
1779 level
= pdoc
->GetLevel(lineDoc
);
1780 int levelNext
= pdoc
->GetLevel(lineDoc
+ 1);
1781 int marks
= pdoc
->GetMark(lineDoc
);
1784 int levelNum
= level
& SC_FOLDLEVELNUMBERMASK
;
1785 int levelNextNum
= levelNext
& SC_FOLDLEVELNUMBERMASK
;
1786 if (level
& SC_FOLDLEVELHEADERFLAG
) {
1788 if (cs
.GetExpanded(lineDoc
)) {
1789 if (levelNum
== SC_FOLDLEVELBASE
)
1790 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
1792 marks
|= 1 << folderOpenMid
;
1794 if (levelNum
== SC_FOLDLEVELBASE
)
1795 marks
|= 1 << SC_MARKNUM_FOLDER
;
1797 marks
|= 1 << folderEnd
;
1800 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1802 needWhiteClosure
= false;
1803 } else if (level
& SC_FOLDLEVELWHITEFLAG
) {
1804 if (needWhiteClosure
) {
1805 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1806 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1807 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1808 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1809 needWhiteClosure
= false;
1811 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1812 needWhiteClosure
= false;
1814 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1815 if (levelNextNum
< levelNum
) {
1816 if (levelNextNum
> SC_FOLDLEVELBASE
) {
1817 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1819 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1822 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1825 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1826 if (levelNextNum
< levelNum
) {
1827 needWhiteClosure
= false;
1828 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1829 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1830 needWhiteClosure
= true;
1831 } else if (levelNextNum
> SC_FOLDLEVELBASE
) {
1832 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1834 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1837 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1841 marks
&= vs
.ms
[margin
].mask
;
1842 PRectangle rcMarker
= rcSelMargin
;
1843 rcMarker
.top
= yposScreen
;
1844 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
1845 if (vs
.ms
[margin
].style
== SC_MARGIN_NUMBER
) {
1849 sprintf(number
, "%d", lineDoc
+ 1);
1850 if (foldFlags
& SC_FOLDFLAG_LEVELNUMBERS
) {
1851 int lev
= pdoc
->GetLevel(lineDoc
);
1852 sprintf(number
, "%c%c %03X %03X",
1853 (lev
& SC_FOLDLEVELHEADERFLAG
) ? 'H' : '_',
1854 (lev
& SC_FOLDLEVELWHITEFLAG
) ? 'W' : '_',
1855 lev
& SC_FOLDLEVELNUMBERMASK
,
1859 PRectangle rcNumber
= rcMarker
;
1861 int width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
1862 int xpos
= rcNumber
.right
- width
- 3;
1863 rcNumber
.left
= xpos
;
1864 surface
->DrawTextNoClip(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
1865 rcNumber
.top
+ vs
.maxAscent
, number
, istrlen(number
),
1866 vs
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
1867 vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1871 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1873 vs
.markers
[markBit
].Draw(surface
, rcMarker
, vs
.styles
[STYLE_LINENUMBER
].font
);
1880 yposScreen
+= vs
.lineHeight
;
1885 PRectangle rcBlankMargin
= rcMargin
;
1886 rcBlankMargin
.left
= rcSelMargin
.right
;
1887 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1890 surfWindow
->Copy(rcMargin
, Point(), *pixmapSelMargin
);
1894 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
1895 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
1896 int xhead
= rcTab
.right
- 1 - ydiff
;
1897 if (xhead
<= rcTab
.left
) {
1898 ydiff
-= rcTab
.left
- xhead
- 1;
1899 xhead
= rcTab
.left
- 1;
1901 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
1902 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
1904 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1905 surface
->LineTo(rcTab
.right
- 1, ymid
);
1906 surface
->LineTo(xhead
, ymid
- ydiff
);
1907 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1908 surface
->LineTo(xhead
, ymid
+ ydiff
);
1911 static bool IsSpaceOrTab(char ch
) {
1912 return ch
== ' ' || ch
== '\t';
1915 LineLayout
*Editor::RetrieveLineLayout(int lineNumber
) {
1916 int posLineStart
= pdoc
->LineStart(lineNumber
);
1917 int posLineEnd
= pdoc
->LineStart(lineNumber
+ 1);
1918 int lineCaret
= pdoc
->LineFromPosition(currentPos
);
1919 return llc
.Retrieve(lineNumber
, lineCaret
,
1920 posLineEnd
- posLineStart
, pdoc
->GetStyleClock(),
1921 LinesOnScreen() + 1, pdoc
->LinesTotal());
1925 * Fill in the LineLayout data for the given line.
1926 * Copy the given @a line and its styles from the document into local arrays.
1927 * Also determine the x position at which each character starts.
1929 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
*ll
, int width
) {
1932 PLATFORM_ASSERT(line
< pdoc
->LinesTotal());
1933 int posLineStart
= pdoc
->LineStart(line
);
1934 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1935 // If the line is very long, limit the treatment to a length that should fit in the viewport
1936 if (posLineEnd
> (posLineStart
+ ll
->maxLineLength
)) {
1937 posLineEnd
= posLineStart
+ ll
->maxLineLength
;
1939 if (ll
->validity
== LineLayout::llCheckTextAndStyle
) {
1940 int lineLength
= posLineEnd
- posLineStart
;
1941 if (!vstyle
.viewEOL
) {
1942 int cid
= posLineEnd
- 1;
1943 while ((cid
> posLineStart
) && IsEOLChar(pdoc
->CharAt(cid
))) {
1948 if (lineLength
== ll
->numCharsInLine
) {
1949 // See if chars, styles, indicators, are all the same
1950 bool allSame
= true;
1951 const int styleMask
= pdoc
->stylingBitsMask
;
1952 // Check base line layout
1954 int numCharsInLine
= 0;
1955 while (numCharsInLine
< lineLength
) {
1956 int charInDoc
= numCharsInLine
+ posLineStart
;
1957 char chDoc
= pdoc
->CharAt(charInDoc
);
1958 styleByte
= pdoc
->StyleAt(charInDoc
);
1959 allSame
= allSame
&&
1960 (ll
->styles
[numCharsInLine
] == static_cast<unsigned char>(styleByte
& styleMask
));
1961 allSame
= allSame
&&
1962 (ll
->indicators
[numCharsInLine
] == static_cast<char>(styleByte
& ~styleMask
));
1963 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseMixed
)
1964 allSame
= allSame
&&
1965 (ll
->chars
[numCharsInLine
] == chDoc
);
1966 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1967 allSame
= allSame
&&
1968 (ll
->chars
[numCharsInLine
] == static_cast<char>(tolower(chDoc
)));
1969 else // Style::caseUpper
1970 allSame
= allSame
&&
1971 (ll
->chars
[numCharsInLine
] == static_cast<char>(toupper(chDoc
)));
1974 allSame
= allSame
&& (ll
->styles
[numCharsInLine
] == styleByte
); // For eolFilled
1976 ll
->validity
= LineLayout::llPositions
;
1978 ll
->validity
= LineLayout::llInvalid
;
1981 ll
->validity
= LineLayout::llInvalid
;
1984 if (ll
->validity
== LineLayout::llInvalid
) {
1985 ll
->widthLine
= LineLayout::wrapWidthInfinite
;
1987 int numCharsInLine
= 0;
1988 if (vstyle
.edgeState
== EDGE_BACKGROUND
) {
1989 ll
->edgeColumn
= pdoc
->FindColumn(line
, theEdge
);
1990 if (ll
->edgeColumn
>= posLineStart
) {
1991 ll
->edgeColumn
-= posLineStart
;
1994 ll
->edgeColumn
= -1;
1998 int styleMask
= pdoc
->stylingBitsMask
;
1999 ll
->styleBitsSet
= 0;
2000 // Fill base line layout
2001 for (int charInDoc
= posLineStart
; charInDoc
< posLineEnd
; charInDoc
++) {
2002 char chDoc
= pdoc
->CharAt(charInDoc
);
2003 styleByte
= pdoc
->StyleAt(charInDoc
);
2004 ll
->styleBitsSet
|= styleByte
;
2005 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
2006 ll
->chars
[numCharsInLine
] = chDoc
;
2007 ll
->styles
[numCharsInLine
] = static_cast<char>(styleByte
& styleMask
);
2008 ll
->indicators
[numCharsInLine
] = static_cast<char>(styleByte
& ~styleMask
);
2009 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
2010 ll
->chars
[numCharsInLine
] = static_cast<char>(toupper(chDoc
));
2011 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
2012 ll
->chars
[numCharsInLine
] = static_cast<char>(tolower(chDoc
));
2016 ll
->xHighlightGuide
= 0;
2017 // Extra element at the end of the line to hold end x position and act as
2018 ll
->chars
[numCharsInLine
] = 0; // Also triggers processing in the loops as this is a control character
2019 ll
->styles
[numCharsInLine
] = styleByte
; // For eolFilled
2020 ll
->indicators
[numCharsInLine
] = 0;
2022 // Layout the line, determining the position of each character,
2023 // with an extra element at the end for the end of the line.
2024 int startseg
= 0; // Start of the current segment, in char. number
2025 int startsegx
= 0; // Start of the current segment, in pixels
2026 ll
->positions
[0] = 0;
2027 unsigned int tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
2028 bool lastSegItalics
= false;
2029 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
2031 int ctrlCharWidth
[32] = {0};
2032 bool isControlNext
= IsControlCharacter(ll
->chars
[0]);
2033 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
2034 bool isControl
= isControlNext
;
2035 isControlNext
= IsControlCharacter(ll
->chars
[charInLine
+ 1]);
2036 if ((ll
->styles
[charInLine
] != ll
->styles
[charInLine
+ 1]) ||
2037 isControl
|| isControlNext
) {
2038 ll
->positions
[startseg
] = 0;
2039 if (vstyle
.styles
[ll
->styles
[charInLine
]].visible
) {
2041 if (ll
->chars
[charInLine
] == '\t') {
2042 ll
->positions
[charInLine
+ 1] = ((((startsegx
+ 2) /
2043 tabWidth
) + 1) * tabWidth
) - startsegx
;
2044 } else if (controlCharSymbol
< 32) {
2045 if (ctrlCharWidth
[ll
->chars
[charInLine
]] == 0) {
2046 const char *ctrlChar
= ControlCharacterString(ll
->chars
[charInLine
]);
2047 // +3 For a blank on front and rounded edge each side:
2048 ctrlCharWidth
[ll
->chars
[charInLine
]] =
2049 surface
->WidthText(ctrlCharsFont
, ctrlChar
, istrlen(ctrlChar
)) + 3;
2051 ll
->positions
[charInLine
+ 1] = ctrlCharWidth
[ll
->chars
[charInLine
]];
2053 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
2054 surface
->MeasureWidths(ctrlCharsFont
, cc
, 1,
2055 ll
->positions
+ startseg
+ 1);
2057 lastSegItalics
= false;
2058 } else { // Regular character
2059 int lenSeg
= charInLine
- startseg
+ 1;
2060 if ((lenSeg
== 1) && (' ' == ll
->chars
[startseg
])) {
2061 lastSegItalics
= false;
2062 // Over half the segments are single characters and of these about half are space characters.
2063 ll
->positions
[charInLine
+ 1] = vstyle
.styles
[ll
->styles
[charInLine
]].spaceWidth
;
2065 lastSegItalics
= vstyle
.styles
[ll
->styles
[charInLine
]].italic
;
2066 surface
->MeasureWidths(vstyle
.styles
[ll
->styles
[charInLine
]].font
, ll
->chars
+ startseg
,
2067 lenSeg
, ll
->positions
+ startseg
+ 1);
2070 } else { // invisible
2071 for (int posToZero
= startseg
; posToZero
<= (charInLine
+ 1); posToZero
++) {
2072 ll
->positions
[posToZero
] = 0;
2075 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
2076 ll
->positions
[posToIncrease
] += startsegx
;
2078 startsegx
= ll
->positions
[charInLine
+ 1];
2079 startseg
= charInLine
+ 1;
2082 // Small hack to make lines that end with italics not cut off the edge of the last character
2083 if ((startseg
> 0) && lastSegItalics
) {
2084 ll
->positions
[startseg
] += 2;
2086 ll
->numCharsInLine
= numCharsInLine
;
2087 ll
->validity
= LineLayout::llPositions
;
2089 // Hard to cope when too narrow, so just assume there is space
2093 if ((ll
->validity
== LineLayout::llPositions
) || (ll
->widthLine
!= width
)) {
2094 ll
->widthLine
= width
;
2095 if (width
== LineLayout::wrapWidthInfinite
) {
2097 } else if (width
> ll
->positions
[ll
->numCharsInLine
]) {
2098 // Simple common case where line does not need wrapping.
2101 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_END
) {
2102 width
-= vstyle
.aveCharWidth
; // take into account the space for end wrap mark
2105 // Calculate line start positions based upon width.
2106 // For now this is simplistic - wraps on byte rather than character and
2107 // in the middle of words. Should search for spaces or style changes.
2108 int lastGoodBreak
= 0;
2109 int lastLineStart
= 0;
2110 int startOffset
= 0;
2112 while (p
< ll
->numCharsInLine
) {
2113 if ((ll
->positions
[p
+ 1] - startOffset
) >= width
) {
2114 if (lastGoodBreak
== lastLineStart
) {
2115 // Try moving to start of last character
2117 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
2120 if (lastGoodBreak
== lastLineStart
) {
2121 // Ensure at least one character on line.
2122 lastGoodBreak
= pdoc
->MovePositionOutsideChar(lastGoodBreak
+ posLineStart
+ 1, 1)
2126 lastLineStart
= lastGoodBreak
;
2128 ll
->SetLineStart(ll
->lines
, lastGoodBreak
);
2129 startOffset
= ll
->positions
[lastGoodBreak
];
2130 // take into account the space for start wrap mark and indent
2131 startOffset
-= actualWrapVisualStartIndent
* vstyle
.aveCharWidth
;
2132 p
= lastGoodBreak
+ 1;
2136 if (wrapState
== eWrapChar
) {
2137 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
2139 p
= pdoc
->MovePositionOutsideChar(p
+ 1 + posLineStart
, 1) - posLineStart
;
2141 } else if (ll
->styles
[p
] != ll
->styles
[p
- 1]) {
2143 } else if (IsSpaceOrTab(ll
->chars
[p
- 1]) && !IsSpaceOrTab(ll
->chars
[p
])) {
2151 ll
->validity
= LineLayout::llLines
;
2155 ColourAllocated
Editor::SelectionBackground(ViewStyle
&vsDraw
) {
2156 return primarySelection
? vsDraw
.selbackground
.allocated
: vsDraw
.selbackground2
.allocated
;
2159 ColourAllocated
Editor::TextBackground(ViewStyle
&vsDraw
, bool overrideBackground
,
2160 ColourAllocated background
, bool inSelection
, bool inHotspot
, int styleMain
, int i
, LineLayout
*ll
) {
2162 if (vsDraw
.selbackset
&& (vsDraw
.selAlpha
== SC_ALPHA_NOALPHA
)) {
2163 return SelectionBackground(vsDraw
);
2166 if ((vsDraw
.edgeState
== EDGE_BACKGROUND
) &&
2167 (i
>= ll
->edgeColumn
) &&
2168 !IsEOLChar(ll
->chars
[i
]))
2169 return vsDraw
.edgecolour
.allocated
;
2170 if (inHotspot
&& vsDraw
.hotspotBackgroundSet
)
2171 return vsDraw
.hotspotBackground
.allocated
;
2172 if (overrideBackground
)
2175 return vsDraw
.styles
[styleMain
].back
.allocated
;
2178 void Editor::DrawIndentGuide(Surface
*surface
, int lineVisible
, int lineHeight
, int start
, PRectangle rcSegment
, bool highlight
) {
2179 Point
from(0, ((lineVisible
& 1) && (lineHeight
& 1)) ? 1 : 0);
2180 PRectangle
rcCopyArea(start
+ 1, rcSegment
.top
, start
+ 2, rcSegment
.bottom
);
2181 surface
->Copy(rcCopyArea
, from
,
2182 highlight
? *pixmapIndentGuideHighlight
: *pixmapIndentGuide
);
2185 void Editor::DrawWrapMarker(Surface
*surface
, PRectangle rcPlace
,
2186 bool isEndMarker
, ColourAllocated wrapColour
) {
2187 surface
->PenColour(wrapColour
);
2189 enum { xa
= 1 }; // gap before start
2190 int w
= rcPlace
.right
- rcPlace
.left
- xa
- 1;
2192 bool xStraight
= isEndMarker
; // x-mirrored symbol for start marker
2193 bool yStraight
= true;
2194 //bool yStraight= isEndMarker; // comment in for start marker y-mirrowed
2196 int x0
= xStraight
? rcPlace
.left
: rcPlace
.right
- 1;
2197 int y0
= yStraight
? rcPlace
.top
: rcPlace
.bottom
- 1;
2199 int dy
= (rcPlace
.bottom
- rcPlace
.top
) / 5;
2200 int y
= (rcPlace
.bottom
- rcPlace
.top
) / 2 + dy
;
2208 void MoveTo(int xRelative
, int yRelative
) {
2209 surface
->MoveTo(xBase
+ xDir
* xRelative
, yBase
+ yDir
* yRelative
);
2211 void LineTo(int xRelative
, int yRelative
) {
2212 surface
->LineTo(xBase
+ xDir
* xRelative
, yBase
+ yDir
* yRelative
);
2215 Relative rel
= {surface
, x0
, xStraight
? 1 : -1, y0
, yStraight
? 1 : -1};
2219 rel
.LineTo(xa
+ 2*w
/ 3, y
- dy
);
2221 rel
.LineTo(xa
+ 2*w
/ 3, y
+ dy
);
2225 rel
.LineTo(xa
+ w
, y
);
2226 rel
.LineTo(xa
+ w
, y
- 2 * dy
);
2227 rel
.LineTo(xa
- 1, // on windows lineto is exclusive endpoint, perhaps GTK not...
2231 static void SimpleAlphaRectangle(Surface
*surface
, PRectangle rc
, ColourAllocated fill
, int alpha
) {
2232 if (alpha
!= SC_ALPHA_NOALPHA
) {
2233 surface
->AlphaRectangle(rc
, 0, fill
, alpha
, fill
, alpha
, 0);
2237 void Editor::DrawEOL(Surface
*surface
, ViewStyle
&vsDraw
, PRectangle rcLine
, LineLayout
*ll
,
2238 int line
, int lineEnd
, int xStart
, int subLine
, int subLineStart
,
2239 bool overrideBackground
, ColourAllocated background
,
2240 bool drawWrapMarkEnd
, ColourAllocated wrapColour
) {
2242 int styleMask
= pdoc
->stylingBitsMask
;
2243 PRectangle rcSegment
= rcLine
;
2245 // Fill in a PRectangle representing the end of line characters
2246 int xEol
= ll
->positions
[lineEnd
] - subLineStart
;
2247 rcSegment
.left
= xEol
+ xStart
;
2248 rcSegment
.right
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
2249 int posLineEnd
= pdoc
->LineStart(line
+ 1);
2250 bool eolInSelection
= (subLine
== (ll
->lines
- 1)) &&
2251 (posLineEnd
> ll
->selStart
) && (posLineEnd
<= ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2253 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (vsDraw
.selAlpha
== SC_ALPHA_NOALPHA
)) {
2254 surface
->FillRectangle(rcSegment
, SelectionBackground(vsDraw
));
2256 if (overrideBackground
) {
2257 surface
->FillRectangle(rcSegment
, background
);
2259 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2261 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (vsDraw
.selAlpha
!= SC_ALPHA_NOALPHA
)) {
2262 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
), vsDraw
.selAlpha
);
2266 rcSegment
.left
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
2267 rcSegment
.right
= rcLine
.right
;
2268 if (overrideBackground
) {
2269 surface
->FillRectangle(rcSegment
, background
);
2270 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
2271 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2273 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
2276 if (drawWrapMarkEnd
) {
2277 PRectangle rcPlace
= rcSegment
;
2279 if (wrapVisualFlagsLocation
& SC_WRAPVISUALFLAGLOC_END_BY_TEXT
) {
2280 rcPlace
.left
= xEol
+ xStart
;
2281 rcPlace
.right
= rcPlace
.left
+ vsDraw
.aveCharWidth
;
2283 // draw left of the right text margin, to avoid clipping by the current clip rect
2284 rcPlace
.right
= rcLine
.right
- vs
.rightMarginWidth
;
2285 rcPlace
.left
= rcPlace
.right
- vsDraw
.aveCharWidth
;
2287 DrawWrapMarker(surface
, rcPlace
, true, wrapColour
);
2291 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int lineVisible
, int xStart
,
2292 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
2294 PRectangle rcSegment
= rcLine
;
2296 // Using one font for all control characters so it can be controlled independently to ensure
2297 // the box goes around the characters tightly. Seems to be no way to work out what height
2298 // is taken by an individual character - internal leading gives varying results.
2299 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
2301 // See if something overrides the line background color: Either if caret is on the line
2302 // and background color is set for that, or if a marker is defined that forces its background
2303 // color onto the line, or if a marker is defined but has no selection margin in which to
2304 // display itself (as long as it's not an SC_MARK_EMPTY marker). These are checked in order
2305 // with the earlier taking precedence. When multiple markers cause background override,
2306 // the color for the highest numbered one is used.
2307 bool overrideBackground
= false;
2308 ColourAllocated background
;
2309 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& (vsDraw
.caretLineAlpha
== SC_ALPHA_NOALPHA
) && ll
->containsCaret
) {
2310 overrideBackground
= true;
2311 background
= vsDraw
.caretLineBackground
.allocated
;
2313 if (!overrideBackground
) {
2314 int marks
= pdoc
->GetMark(line
);
2315 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2316 if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
) &&
2317 (vsDraw
.markers
[markBit
].alpha
== SC_ALPHA_NOALPHA
)) {
2318 background
= vsDraw
.markers
[markBit
].back
.allocated
;
2319 overrideBackground
= true;
2324 if (!overrideBackground
) {
2325 if (vsDraw
.maskInLine
) {
2326 int marksMasked
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
2328 for (int markBit
= 0; (markBit
< 32) && marksMasked
; markBit
++) {
2329 if ((marksMasked
& 1) && (vsDraw
.markers
[markBit
].markType
!= SC_MARK_EMPTY
) &&
2330 (vsDraw
.markers
[markBit
].alpha
== SC_ALPHA_NOALPHA
)) {
2331 overrideBackground
= true;
2332 background
= vsDraw
.markers
[markBit
].back
.allocated
;
2340 bool drawWhitespaceBackground
= (vsDraw
.viewWhitespace
!= wsInvisible
) &&
2341 (!overrideBackground
) && (vsDraw
.whitespaceBackgroundSet
);
2343 bool inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2344 int indentWidth
= pdoc
->IndentSize() * vsDraw
.spaceWidth
;
2346 int posLineStart
= pdoc
->LineStart(line
);
2348 int startseg
= ll
->LineStart(subLine
);
2349 int subLineStart
= ll
->positions
[startseg
];
2352 if (subLine
< ll
->lines
) {
2353 lineStart
= ll
->LineStart(subLine
);
2354 lineEnd
= ll
->LineStart(subLine
+ 1);
2357 bool drawWrapMarkEnd
= false;
2359 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_END
) {
2360 if (subLine
+ 1 < ll
->lines
) {
2361 drawWrapMarkEnd
= ll
->LineStart(subLine
+ 1) != 0;
2365 if (actualWrapVisualStartIndent
!= 0) {
2367 bool continuedWrapLine
= false;
2368 if (subLine
< ll
->lines
) {
2369 continuedWrapLine
= ll
->LineStart(subLine
) != 0;
2372 if (continuedWrapLine
) {
2373 // draw continuation rect
2374 PRectangle rcPlace
= rcSegment
;
2376 rcPlace
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2377 rcPlace
.right
= rcPlace
.left
+ actualWrapVisualStartIndent
* vsDraw
.aveCharWidth
;
2379 // default bgnd here..
2380 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
2382 // main line style would be below but this would be inconsistent with end markers
2383 // also would possibly not be the style at wrap point
2384 //int styleMain = ll->styles[lineStart];
2385 //surface->FillRectangle(rcPlace, vsDraw.styles[styleMain].back.allocated);
2387 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) {
2389 if (wrapVisualFlagsLocation
& SC_WRAPVISUALFLAGLOC_START_BY_TEXT
)
2390 rcPlace
.left
= rcPlace
.right
- vsDraw
.aveCharWidth
;
2392 rcPlace
.right
= rcPlace
.left
+ vsDraw
.aveCharWidth
;
2394 DrawWrapMarker(surface
, rcPlace
, false, vsDraw
.whitespaceForeground
.allocated
);
2397 xStart
+= actualWrapVisualStartIndent
* vsDraw
.aveCharWidth
;
2403 // Background drawing loop
2404 for (i
= lineStart
; twoPhaseDraw
&& (i
< lineEnd
); i
++) {
2406 int iDoc
= i
+ posLineStart
;
2407 // If there is the end of a style run for any reason
2408 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
2409 i
== (lineEnd
- 1) ||
2410 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
2411 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
2412 (i
== (ll
->edgeColumn
- 1))) {
2413 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2414 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2415 // Only try to draw if really visible - enhances performance by not calling environment to
2416 // draw strings that are completely past the right side of the window.
2417 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2418 int styleMain
= ll
->styles
[i
];
2419 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2420 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2421 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2422 if (ll
->chars
[i
] == '\t') {
2424 if (drawWhitespaceBackground
&&
2425 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2426 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2427 surface
->FillRectangle(rcSegment
, textBack
);
2428 } else if (IsControlCharacter(ll
->chars
[i
])) {
2429 // Control character display
2430 inIndentation
= false;
2431 surface
->FillRectangle(rcSegment
, textBack
);
2433 // Normal text display
2434 surface
->FillRectangle(rcSegment
, textBack
);
2435 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2436 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
2437 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2438 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2439 if (drawWhitespaceBackground
&&
2440 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2441 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
,
2442 ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2443 surface
->FillRectangle(rcSpace
, vsDraw
.whitespaceBackground
.allocated
);
2446 inIndentation
= false;
2451 } else if (rcSegment
.left
> rcLine
.right
) {
2459 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2460 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
2461 drawWrapMarkEnd
, vsDraw
.whitespaceForeground
.allocated
);
2464 inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2465 startseg
= ll
->LineStart(subLine
);
2466 // Foreground drawing loop
2467 for (i
= lineStart
; i
< lineEnd
; i
++) {
2469 int iDoc
= i
+ posLineStart
;
2470 // If there is the end of a style run for any reason
2471 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
2472 i
== (lineEnd
- 1) ||
2473 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
2474 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
2475 (i
== (ll
->edgeColumn
- 1))) {
2476 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2477 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2478 // Only try to draw if really visible - enhances performance by not calling environment to
2479 // draw strings that are completely past the right side of the window.
2480 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2481 int styleMain
= ll
->styles
[i
];
2482 ColourAllocated textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
2483 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
2484 //hotspot foreground
2485 if (ll
->hsStart
!= -1 && iDoc
>= ll
->hsStart
&& iDoc
< hsEnd
) {
2486 if (vsDraw
.hotspotForegroundSet
)
2487 textFore
= vsDraw
.hotspotForeground
.allocated
;
2489 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2490 if (inSelection
&& (vsDraw
.selforeset
)) {
2491 textFore
= vsDraw
.selforeground
.allocated
;
2493 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2494 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2495 if (ll
->chars
[i
] == '\t') {
2497 if (!twoPhaseDraw
) {
2498 if (drawWhitespaceBackground
&&
2499 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2500 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2501 surface
->FillRectangle(rcSegment
, textBack
);
2503 if ((vsDraw
.viewWhitespace
!= wsInvisible
) || ((inIndentation
&& vsDraw
.viewIndentationGuides
))) {
2504 if (vsDraw
.whitespaceForegroundSet
)
2505 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2506 surface
->PenColour(textFore
);
2508 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
2509 for (int xIG
= ll
->positions
[i
] / indentWidth
* indentWidth
; xIG
< ll
->positions
[i
+ 1]; xIG
+= indentWidth
) {
2510 if (xIG
>= ll
->positions
[i
] && xIG
> 0) {
2511 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIG
+ xStart
, rcSegment
,
2512 (ll
->xHighlightGuide
== xIG
));
2516 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2517 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2518 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
2519 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
2520 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
2523 } else if (IsControlCharacter(ll
->chars
[i
])) {
2524 // Control character display
2525 inIndentation
= false;
2526 if (controlCharSymbol
< 32) {
2527 // Draw the character
2528 const char *ctrlChar
= ControlCharacterString(ll
->chars
[i
]);
2529 if (!twoPhaseDraw
) {
2530 surface
->FillRectangle(rcSegment
, textBack
);
2532 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
2533 surface
->InternalLeading(ctrlCharsFont
);
2534 PRectangle rcCChar
= rcSegment
;
2535 rcCChar
.left
= rcCChar
.left
+ 1;
2536 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
2537 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
2538 PRectangle rcCentral
= rcCChar
;
2541 surface
->FillRectangle(rcCentral
, textFore
);
2542 PRectangle rcChar
= rcCChar
;
2545 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
2546 rcSegment
.top
+ vsDraw
.maxAscent
, ctrlChar
, istrlen(ctrlChar
),
2547 textBack
, textFore
);
2549 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
2550 surface
->DrawTextNoClip(rcSegment
, ctrlCharsFont
,
2551 rcSegment
.top
+ vsDraw
.maxAscent
,
2552 cc
, 1, textBack
, textFore
);
2555 // Normal text display
2556 if (vsDraw
.styles
[styleMain
].visible
) {
2558 surface
->DrawTextTransparent(rcSegment
, textFont
,
2559 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2560 i
- startseg
+ 1, textFore
);
2562 surface
->DrawTextNoClip(rcSegment
, textFont
,
2563 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2564 i
- startseg
+ 1, textFore
, textBack
);
2567 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2568 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
2569 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2570 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2571 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2572 if (vsDraw
.whitespaceForegroundSet
)
2573 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2574 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2575 int xmid
= (ll
->positions
[cpos
+ startseg
] + ll
->positions
[cpos
+ startseg
+ 1]) / 2;
2576 if (!twoPhaseDraw
&& drawWhitespaceBackground
&&
2577 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2578 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2579 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
, ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2580 surface
->FillRectangle(rcSpace
, textBack
);
2582 PRectangle
rcDot(xmid
+ xStart
- subLineStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
2583 rcDot
.right
= rcDot
.left
+ 1;
2584 rcDot
.bottom
= rcDot
.top
+ 1;
2585 surface
->FillRectangle(rcDot
, textFore
);
2588 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
2589 int startSpace
= ll
->positions
[cpos
+ startseg
];
2590 if (startSpace
> 0 && (startSpace
% indentWidth
== 0)) {
2591 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, startSpace
+ xStart
, rcSegment
,
2592 (ll
->xHighlightGuide
== ll
->positions
[cpos
+ startseg
]));
2596 inIndentation
= false;
2601 if (ll
->hsStart
!= -1 && vsDraw
.hotspotUnderline
&& iDoc
>= ll
->hsStart
&& iDoc
< ll
->hsEnd
) {
2602 PRectangle rcUL
= rcSegment
;
2603 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2604 rcUL
.bottom
= rcUL
.top
+ 1;
2605 if (vsDraw
.hotspotForegroundSet
)
2606 surface
->FillRectangle(rcUL
, vsDraw
.hotspotForeground
.allocated
);
2608 surface
->FillRectangle(rcUL
, textFore
);
2609 } else if (vsDraw
.styles
[styleMain
].underline
) {
2610 PRectangle rcUL
= rcSegment
;
2611 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2612 rcUL
.bottom
= rcUL
.top
+ 1;
2613 surface
->FillRectangle(rcUL
, textFore
);
2615 } else if (rcSegment
.left
> rcLine
.right
) {
2623 // foreach indicator...
2624 for (int indicnum
= 0, mask
= 1 << pdoc
->stylingBits
; mask
< 0x100; indicnum
++) {
2625 if (!(mask
& ll
->styleBitsSet
)) {
2630 // foreach style pos in line...
2631 for (int indicPos
= lineStart
; indicPos
<= lineEnd
; indicPos
++) {
2632 // look for starts...
2634 // NOT in indicator run, looking for START
2635 if (indicPos
< lineEnd
&& (ll
->indicators
[indicPos
] & mask
))
2636 startPos
= indicPos
;
2639 if (startPos
>= 0) {
2640 // IN indicator run, looking for END
2641 if (indicPos
>= lineEnd
|| !(ll
->indicators
[indicPos
] & mask
)) {
2642 // AT end of indicator run, DRAW it!
2644 ll
->positions
[startPos
] + xStart
- subLineStart
,
2645 rcLine
.top
+ vsDraw
.maxAscent
,
2646 ll
->positions
[indicPos
] + xStart
- subLineStart
,
2647 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
2648 vsDraw
.indicators
[indicnum
].Draw(surface
, rcIndic
, rcLine
);
2649 // RESET control var
2656 // End of the drawing of the current line
2657 if (!twoPhaseDraw
) {
2658 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2659 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
2660 drawWrapMarkEnd
, vsDraw
.whitespaceForeground
.allocated
);
2662 if ((vsDraw
.selAlpha
!= SC_ALPHA_NOALPHA
) && (ll
->selStart
>= 0) && (ll
->selEnd
>= 0)) {
2663 int startPosSel
= (ll
->selStart
< posLineStart
) ? posLineStart
: ll
->selStart
;
2664 int endPosSel
= (ll
->selEnd
< (lineEnd
+ posLineStart
)) ? ll
->selEnd
: (lineEnd
+ posLineStart
);
2665 if (startPosSel
< endPosSel
) {
2666 rcSegment
.left
= xStart
+ ll
->positions
[startPosSel
- posLineStart
] - subLineStart
;
2667 rcSegment
.right
= xStart
+ ll
->positions
[endPosSel
- posLineStart
] - subLineStart
;
2668 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
), vsDraw
.selAlpha
);
2672 if (vsDraw
.edgeState
== EDGE_LINE
) {
2673 int edgeX
= theEdge
* vsDraw
.spaceWidth
;
2674 rcSegment
.left
= edgeX
+ xStart
;
2675 rcSegment
.right
= rcSegment
.left
+ 1;
2676 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
.allocated
);
2679 // Draw any translucent whole line states
2680 rcSegment
.left
= xStart
;
2681 rcSegment
.right
= rcLine
.right
- 1;
2682 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& ll
->containsCaret
) {
2683 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.caretLineBackground
.allocated
, vsDraw
.caretLineAlpha
);
2685 int marks
= pdoc
->GetMark(line
);
2686 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2687 if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
)) {
2688 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.markers
[markBit
].back
.allocated
, vsDraw
.markers
[markBit
].alpha
);
2692 if (vsDraw
.maskInLine
) {
2693 int marksMasked
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
2695 for (int markBit
= 0; (markBit
< 32) && marksMasked
; markBit
++) {
2696 if ((marksMasked
& 1) && (vsDraw
.markers
[markBit
].markType
!= SC_MARK_EMPTY
)) {
2697 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.markers
[markBit
].back
.allocated
, vsDraw
.markers
[markBit
].alpha
);
2705 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
2706 if (!pixmapSelPattern
->Initialised()) {
2707 const int patternSize
= 8;
2708 pixmapSelPattern
->InitPixMap(patternSize
, patternSize
, surfaceWindow
, wMain
.GetID());
2709 // This complex procedure is to reproduce the checkerboard dithered pattern used by windows
2710 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
2711 // way between the chrome colour and the chrome highlight colour making a nice transition
2712 // between the window chrome and the content area. And it works in low colour depths.
2713 PRectangle
rcPattern(0, 0, patternSize
, patternSize
);
2715 // Initialize default colours based on the chrome colour scheme. Typically the highlight is white.
2716 ColourAllocated colourFMFill
= vs
.selbar
.allocated
;
2717 ColourAllocated colourFMStripes
= vs
.selbarlight
.allocated
;
2719 if (!(vs
.selbarlight
.desired
== ColourDesired(0xff, 0xff, 0xff))) {
2720 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
2721 // (Typically, the highlight colour is white.)
2722 colourFMFill
= vs
.selbarlight
.allocated
;
2725 if (vs
.foldmarginColourSet
) {
2726 // override default fold margin colour
2727 colourFMFill
= vs
.foldmarginColour
.allocated
;
2729 if (vs
.foldmarginHighlightColourSet
) {
2730 // override default fold margin highlight colour
2731 colourFMStripes
= vs
.foldmarginHighlightColour
.allocated
;
2734 pixmapSelPattern
->FillRectangle(rcPattern
, colourFMFill
);
2735 pixmapSelPattern
->PenColour(colourFMStripes
);
2736 for (int stripe
= 0; stripe
< patternSize
; stripe
++) {
2737 // Alternating 1 pixel stripes is same as checkerboard.
2738 pixmapSelPattern
->MoveTo(0, stripe
* 2);
2739 pixmapSelPattern
->LineTo(patternSize
, stripe
* 2 - patternSize
);
2743 if (!pixmapIndentGuide
->Initialised()) {
2744 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
2745 pixmapIndentGuide
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2746 pixmapIndentGuideHighlight
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2747 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
2748 pixmapIndentGuide
->FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
.allocated
);
2749 pixmapIndentGuide
->PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
2750 pixmapIndentGuideHighlight
->FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
.allocated
);
2751 pixmapIndentGuideHighlight
->PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
2752 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
2753 pixmapIndentGuide
->MoveTo(0, stripe
);
2754 pixmapIndentGuide
->LineTo(2, stripe
);
2755 pixmapIndentGuideHighlight
->MoveTo(0, stripe
);
2756 pixmapIndentGuideHighlight
->LineTo(2, stripe
);
2761 if (!pixmapLine
->Initialised()) {
2762 PRectangle rcClient
= GetClientRectangle();
2763 pixmapLine
->InitPixMap(rcClient
.Width(), vs
.lineHeight
,
2764 surfaceWindow
, wMain
.GetID());
2765 pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
2766 rcClient
.Height(), surfaceWindow
, wMain
.GetID());
2771 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
2772 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
2773 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
2776 RefreshPixMaps(surfaceWindow
);
2778 PRectangle rcClient
= GetClientRectangle();
2779 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
2780 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
2782 surfaceWindow
->SetPalette(&palette
, true);
2783 pixmapLine
->SetPalette(&palette
, !hasFocus
);
2785 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
2786 // The area to be painted plus one extra line is styled.
2787 // The extra line is to determine when a style change, such as starting a comment flows on to other lines.
2788 int lineStyleLast
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
2789 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
2790 int endPosPaint
= pdoc
->Length();
2791 if (lineStyleLast
< cs
.LinesDisplayed())
2792 endPosPaint
= pdoc
->LineStart(cs
.DocFromDisplay(lineStyleLast
+ 1));
2794 int xStart
= vs
.fixedColumnWidth
- xOffset
;
2797 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
2798 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
2800 // Ensure we are styled as far as we are painting.
2801 pdoc
->EnsureStyledTo(endPosPaint
);
2802 bool paintAbandonedByStyling
= paintState
== paintAbandoned
;
2805 needUpdateUI
= false;
2807 RefreshPixMaps(surfaceWindow
);
2810 // Call priority lines wrap on a window of lines which are likely
2811 // to rendered with the following paint (that is wrap the visible
2813 int startLineToWrap
= cs
.DocFromDisplay(topLine
) - 5;
2814 if (startLineToWrap
< 0)
2815 startLineToWrap
= -1;
2816 if (WrapLines(false, startLineToWrap
)) {
2817 // The wrapping process has changed the height of some lines so
2818 // abandon this paint for a complete repaint.
2819 if (AbandonPaint()) {
2822 RefreshPixMaps(surfaceWindow
); // In case pixmaps invalidated by scrollbar change
2824 PLATFORM_ASSERT(pixmapSelPattern
->Initialised());
2826 PaintSelMargin(surfaceWindow
, rcArea
);
2828 PRectangle rcRightMargin
= rcClient
;
2829 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
2830 if (rcArea
.Intersects(rcRightMargin
)) {
2831 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2834 if (paintState
== paintAbandoned
) {
2835 // Either styling or NotifyUpdateUI noticed that painting is needed
2836 // outside the current painting rectangle
2837 //Platform::DebugPrintf("Abandoning paint\n");
2838 if (wrapState
!= eWrapNone
) {
2839 if (paintAbandonedByStyling
) {
2840 // Styling has spilled over a line end, such as occurs by starting a multiline
2841 // comment. The width of subsequent text may have changed, so rewrap.
2842 NeedWrapping(cs
.DocFromDisplay(topLine
));
2847 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
2850 if (rcArea
.right
> vs
.fixedColumnWidth
) {
2852 Surface
*surface
= surfaceWindow
;
2854 surface
= pixmapLine
;
2855 PLATFORM_ASSERT(pixmapLine
->Initialised());
2857 surface
->SetUnicodeMode(IsUnicodeMode());
2858 surface
->SetDBCSMode(CodePage());
2860 int visibleLine
= topLine
+ screenLinePaintFirst
;
2862 int posCaret
= currentPos
;
2865 int lineCaret
= pdoc
->LineFromPosition(posCaret
);
2867 // Remove selection margin from drawing area so text will not be drawn
2868 // on it in unbuffered mode.
2869 PRectangle rcTextArea
= rcClient
;
2870 rcTextArea
.left
= vs
.fixedColumnWidth
;
2871 rcTextArea
.right
-= vs
.rightMarginWidth
;
2872 surfaceWindow
->SetClip(rcTextArea
);
2874 // Loop on visible lines
2875 //double durLayout = 0.0;
2876 //double durPaint = 0.0;
2877 //double durCopy = 0.0;
2878 //ElapsedTime etWhole;
2879 int lineDocPrevious
= -1; // Used to avoid laying out one document line multiple times
2880 AutoLineLayout
ll(llc
, 0);
2881 SelectionLineIterator
lineIterator(this);
2882 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
2884 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
2885 // Only visible lines should be handled by the code within the loop
2886 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
2887 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
2888 int subLine
= visibleLine
- lineStartSet
;
2890 // Copy this line and its styles from the document into local arrays
2891 // and determine the x position at which each character starts.
2893 if (lineDoc
!= lineDocPrevious
) {
2895 // For rectangular selection this accesses the layout cache so should be after layout returned.
2896 lineIterator
.SetAt(lineDoc
);
2897 ll
.Set(RetrieveLineLayout(lineDoc
));
2898 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
2899 lineDocPrevious
= lineDoc
;
2901 //durLayout += et.Duration(true);
2904 if (selType
== selStream
) {
2905 ll
->selStart
= SelectionStart();
2906 ll
->selEnd
= SelectionEnd();
2908 ll
->selStart
= lineIterator
.startPos
;
2909 ll
->selEnd
= lineIterator
.endPos
;
2911 ll
->containsCaret
= lineDoc
== lineCaret
;
2912 if (hideSelection
) {
2915 ll
->containsCaret
= false;
2918 GetHotSpotRange(ll
->hsStart
, ll
->hsEnd
);
2920 PRectangle rcLine
= rcClient
;
2922 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
2924 Range
rangeLine(pdoc
->LineStart(lineDoc
), pdoc
->LineStart(lineDoc
+ 1));
2925 // Highlight the current braces if any
2926 ll
->SetBracesHighlight(rangeLine
, braces
, static_cast<char>(bracesMatchStyle
),
2927 highlightGuideColumn
* vs
.spaceWidth
);
2930 DrawLine(surface
, vs
, lineDoc
, visibleLine
, xStart
, rcLine
, ll
, subLine
);
2931 //durPaint += et.Duration(true);
2933 // Restore the previous styles for the brace highlights in case layout is in cache.
2934 ll
->RestoreBracesHighlight(rangeLine
, braces
);
2936 bool expanded
= cs
.GetExpanded(lineDoc
);
2937 if ((foldFlags
& SC_FOLDFLAG_BOX
) == 0) {
2938 // Paint the line above the fold
2939 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_EXPANDED
))
2941 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_CONTRACTED
))) {
2942 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2943 PRectangle rcFoldLine
= rcLine
;
2944 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2945 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2948 // Paint the line below the fold
2949 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_EXPANDED
))
2951 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2952 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2953 PRectangle rcFoldLine
= rcLine
;
2954 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2955 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2959 int FoldLevelCurr
= (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2960 int FoldLevelPrev
= (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2961 int FoldLevelFlags
= (pdoc
->GetLevel(lineDoc
) & ~SC_FOLDLEVELNUMBERMASK
) & ~(0xFFF0000);
2962 int indentationStep
= pdoc
->IndentSize();
2963 // Draw line above fold
2964 if ((FoldLevelPrev
< FoldLevelCurr
)
2966 (FoldLevelFlags
& SC_FOLDLEVELBOXHEADERFLAG
2968 (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELBOXFOOTERFLAG
) == 0)) {
2969 PRectangle rcFoldLine
= rcLine
;
2970 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2971 rcFoldLine
.left
+= xStart
+ FoldLevelCurr
* vs
.spaceWidth
* indentationStep
- 1;
2972 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2975 // Line below the fold (or below a contracted fold)
2976 if (FoldLevelFlags
& SC_FOLDLEVELBOXFOOTERFLAG
2978 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2979 PRectangle rcFoldLine
= rcLine
;
2980 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2981 rcFoldLine
.left
+= xStart
+ (FoldLevelCurr
) * vs
.spaceWidth
* indentationStep
- 1;
2982 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2985 PRectangle rcBoxLine
= rcLine
;
2986 // Draw vertical line for every fold level
2987 for (int i
= 0; i
<= FoldLevelCurr
; i
++) {
2988 rcBoxLine
.left
= xStart
+ i
* vs
.spaceWidth
* indentationStep
- 1;
2989 rcBoxLine
.right
= rcBoxLine
.left
+ 1;
2990 surface
->FillRectangle(rcBoxLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2995 if (lineDoc
== lineCaret
) {
2996 int offset
= Platform::Minimum(posCaret
- rangeLine
.start
, ll
->maxLineLength
);
2997 if ((offset
>= ll
->LineStart(subLine
)) &&
2998 ((offset
< ll
->LineStart(subLine
+ 1)) || offset
== ll
->numCharsInLine
)) {
2999 int xposCaret
= ll
->positions
[offset
] - ll
->positions
[ll
->LineStart(subLine
)] + xStart
;
3001 if (actualWrapVisualStartIndent
!= 0) {
3002 int lineStart
= ll
->LineStart(subLine
);
3003 if (lineStart
!= 0) // Wrapped
3004 xposCaret
+= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
3006 int widthOverstrikeCaret
;
3007 if (posCaret
== pdoc
->Length()) { // At end of document
3008 widthOverstrikeCaret
= vs
.aveCharWidth
;
3009 } else if ((posCaret
- rangeLine
.start
) >= ll
->numCharsInLine
) { // At end of line
3010 widthOverstrikeCaret
= vs
.aveCharWidth
;
3012 widthOverstrikeCaret
= ll
->positions
[offset
+ 1] - ll
->positions
[offset
];
3014 if (widthOverstrikeCaret
< 3) // Make sure its visible
3015 widthOverstrikeCaret
= 3;
3016 if (((caret
.active
&& caret
.on
) || (posDrag
>= 0)) && xposCaret
>= 0) {
3017 PRectangle rcCaret
= rcLine
;
3018 int caretWidthOffset
= 0;
3019 if ((offset
> 0) && (vs
.caretWidth
> 1))
3020 caretWidthOffset
= 1; // Move back so overlaps both character cells.
3022 rcCaret
.left
= xposCaret
- caretWidthOffset
;
3023 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
3026 rcCaret
.top
= rcCaret
.bottom
- 2;
3027 rcCaret
.left
= xposCaret
+ 1;
3028 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
3030 rcCaret
.left
= xposCaret
- caretWidthOffset
;
3031 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
3034 surface
->FillRectangle(rcCaret
, vs
.caretcolour
.allocated
);
3040 Point
from(vs
.fixedColumnWidth
, 0);
3041 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
3042 rcClient
.right
, yposScreen
+ vs
.lineHeight
);
3043 surfaceWindow
->Copy(rcCopyArea
, from
, *pixmapLine
);
3045 //durCopy += et.Duration(true);
3048 if (!bufferedDraw
) {
3049 ypos
+= vs
.lineHeight
;
3052 yposScreen
+= vs
.lineHeight
;
3057 //if (durPaint < 0.00000001)
3058 // durPaint = 0.00000001;
3060 // Right column limit indicator
3061 PRectangle rcBeyondEOF
= rcClient
;
3062 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
3063 rcBeyondEOF
.right
= rcBeyondEOF
.right
;
3064 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
3065 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
3066 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
3067 if (vs
.edgeState
== EDGE_LINE
) {
3068 int edgeX
= theEdge
* vs
.spaceWidth
;
3069 rcBeyondEOF
.left
= edgeX
+ xStart
;
3070 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
3071 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
.allocated
);
3074 //Platform::DebugPrintf(
3075 //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
3076 //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
3081 // Space (3 space characters) between line numbers and text when printing.
3082 #define lineNumberPrintSpace " "
3084 ColourDesired
InvertedLight(ColourDesired orig
) {
3085 unsigned int r
= orig
.GetRed();
3086 unsigned int g
= orig
.GetGreen();
3087 unsigned int b
= orig
.GetBlue();
3088 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
3089 unsigned int il
= 0xff - l
;
3091 return ColourDesired(0xff, 0xff, 0xff);
3095 return ColourDesired(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
3098 // This is mostly copied from the Paint method but with some things omitted
3099 // such as the margin markers, line numbers, selection and caret
3100 // Should be merged back into a combined Draw method.
3101 long Editor::FormatRange(bool draw
, RangeToFormat
*pfr
) {
3105 AutoSurface
surface(pfr
->hdc
, this);
3108 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this);
3109 if (!surfaceMeasure
) {
3113 ViewStyle
vsPrint(vs
);
3115 // Modify the view style for printing as do not normally want any of the transient features to be printed
3116 // Printing supports only the line number margin.
3117 int lineNumberIndex
= -1;
3118 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
3119 if ((vsPrint
.ms
[margin
].style
== SC_MARGIN_NUMBER
) && (vsPrint
.ms
[margin
].width
> 0)) {
3120 lineNumberIndex
= margin
;
3122 vsPrint
.ms
[margin
].width
= 0;
3125 vsPrint
.showMarkedLines
= false;
3126 vsPrint
.fixedColumnWidth
= 0;
3127 vsPrint
.zoomLevel
= printMagnification
;
3128 vsPrint
.viewIndentationGuides
= false;
3129 // Don't show the selection when printing
3130 vsPrint
.selbackset
= false;
3131 vsPrint
.selforeset
= false;
3132 vsPrint
.selAlpha
= SC_ALPHA_NOALPHA
;
3133 vsPrint
.whitespaceBackgroundSet
= false;
3134 vsPrint
.whitespaceForegroundSet
= false;
3135 vsPrint
.showCaretLineBackground
= false;
3137 // Set colours for printing according to users settings
3138 for (int sty
= 0;sty
<= STYLE_MAX
;sty
++) {
3139 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
3140 vsPrint
.styles
[sty
].fore
.desired
= InvertedLight(vsPrint
.styles
[sty
].fore
.desired
);
3141 vsPrint
.styles
[sty
].back
.desired
= InvertedLight(vsPrint
.styles
[sty
].back
.desired
);
3142 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
3143 vsPrint
.styles
[sty
].fore
.desired
= ColourDesired(0, 0, 0);
3144 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3145 } else if (printColourMode
== SC_PRINT_COLOURONWHITE
) {
3146 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3147 } else if (printColourMode
== SC_PRINT_COLOURONWHITEDEFAULTBG
) {
3148 if (sty
<= STYLE_DEFAULT
) {
3149 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3153 // White background for the line numbers
3154 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3156 vsPrint
.Refresh(*surfaceMeasure
);
3157 // Ensure colours are set up
3158 vsPrint
.RefreshColourPalette(palette
, true);
3159 vsPrint
.RefreshColourPalette(palette
, false);
3160 // Determining width must hapen after fonts have been realised in Refresh
3161 int lineNumberWidth
= 0;
3162 if (lineNumberIndex
>= 0) {
3163 lineNumberWidth
= surfaceMeasure
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3164 "99999" lineNumberPrintSpace
, 5 + istrlen(lineNumberPrintSpace
));
3165 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
3168 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
3169 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
3170 if (linePrintLast
< linePrintStart
)
3171 linePrintLast
= linePrintStart
;
3172 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
);
3173 if (linePrintLast
> linePrintMax
)
3174 linePrintLast
= linePrintMax
;
3175 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
3176 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
3177 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
3178 int endPosPrint
= pdoc
->Length();
3179 if (linePrintLast
< pdoc
->LinesTotal())
3180 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
3182 // Ensure we are styled to where we are formatting.
3183 pdoc
->EnsureStyledTo(endPosPrint
);
3185 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
+ lineNumberWidth
;
3186 int ypos
= pfr
->rc
.top
;
3188 int lineDoc
= linePrintStart
;
3190 int nPrintPos
= pfr
->chrg
.cpMin
;
3191 int visibleLine
= 0;
3192 int widthPrint
= pfr
->rc
.Width() - lineNumberWidth
;
3193 if (printWrapState
== eWrapNone
)
3194 widthPrint
= LineLayout::wrapWidthInfinite
;
3196 while (lineDoc
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
3198 // When printing, the hdc and hdcTarget may be the same, so
3199 // changing the state of surfaceMeasure may change the underlying
3200 // state of surface. Therefore, any cached state is discarded before
3201 // using each surface.
3202 surfaceMeasure
->FlushCachedState();
3204 // Copy this line and its styles from the document into local arrays
3205 // and determine the x position at which each character starts.
3206 LineLayout
ll(8000);
3207 LayoutLine(lineDoc
, surfaceMeasure
, vsPrint
, &ll
, widthPrint
);
3211 ll
.containsCaret
= false;
3214 rcLine
.left
= pfr
->rc
.left
+ lineNumberWidth
;
3216 rcLine
.right
= pfr
->rc
.right
- 1;
3217 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3219 // When document line is wrapped over multiple display lines, find where
3220 // to start printing from to ensure a particular position is on the first
3221 // line of the page.
3222 if (visibleLine
== 0) {
3223 int startWithinLine
= nPrintPos
- pdoc
->LineStart(lineDoc
);
3224 for (int iwl
= 0; iwl
< ll
.lines
- 1; iwl
++) {
3225 if (ll
.LineStart(iwl
) <= startWithinLine
&& ll
.LineStart(iwl
+ 1) >= startWithinLine
) {
3230 if (ll
.lines
> 1 && startWithinLine
>= ll
.LineStart(ll
.lines
- 1)) {
3231 visibleLine
= -(ll
.lines
- 1);
3235 if (draw
&& lineNumberWidth
&&
3236 (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) &&
3237 (visibleLine
>= 0)) {
3239 sprintf(number
, "%d" lineNumberPrintSpace
, lineDoc
+ 1);
3240 PRectangle rcNumber
= rcLine
;
3241 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
3243 rcNumber
.left
-= surfaceMeasure
->WidthText(
3244 vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
3245 surface
->FlushCachedState();
3246 surface
->DrawTextNoClip(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3247 ypos
+ vsPrint
.maxAscent
, number
, istrlen(number
),
3248 vsPrint
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
3249 vsPrint
.styles
[STYLE_LINENUMBER
].back
.allocated
);
3253 surface
->FlushCachedState();
3255 for (int iwl
= 0; iwl
< ll
.lines
; iwl
++) {
3256 if (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) {
3257 if (visibleLine
>= 0) {
3260 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3261 DrawLine(surface
, vsPrint
, lineDoc
, visibleLine
, xStart
, rcLine
, &ll
, iwl
);
3263 ypos
+= vsPrint
.lineHeight
;
3266 if (iwl
== ll
.lines
- 1)
3267 nPrintPos
= pdoc
->LineStart(lineDoc
+ 1);
3269 nPrintPos
+= ll
.LineStart(iwl
+ 1) - ll
.LineStart(iwl
);
3279 int Editor::TextWidth(int style
, const char *text
) {
3281 AutoSurface
surface(this);
3283 return surface
->WidthText(vs
.styles
[style
].font
, text
, istrlen(text
));
3289 // Empty method is overridden on GTK+ to show / hide scrollbars
3290 void Editor::ReconfigureScrollBars() {}
3292 void Editor::SetScrollBars() {
3295 int nMax
= MaxScrollPos();
3296 int nPage
= LinesOnScreen();
3297 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
3302 // TODO: ensure always showing as many lines as possible
3303 // May not be, if, for example, window made larger
3304 if (topLine
> MaxScrollPos()) {
3305 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
3306 SetVerticalScrollPos();
3310 if (!AbandonPaint())
3313 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
3316 void Editor::ChangeSize() {
3319 if (wrapState
!= eWrapNone
) {
3320 PRectangle rcTextArea
= GetClientRectangle();
3321 rcTextArea
.left
= vs
.fixedColumnWidth
;
3322 rcTextArea
.right
-= vs
.rightMarginWidth
;
3323 if (wrapWidth
!= rcTextArea
.Width()) {
3330 void Editor::AddChar(char ch
) {
3337 void Editor::AddCharUTF(char *s
, unsigned int len
, bool treatAsDBCS
) {
3338 bool wasSelection
= currentPos
!= anchor
;
3340 bool charReplaceAction
= false;
3341 if (inOverstrike
&& !wasSelection
&& !RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3342 if (currentPos
< (pdoc
->Length())) {
3343 if (!IsEOLChar(pdoc
->CharAt(currentPos
))) {
3344 charReplaceAction
= true;
3345 pdoc
->BeginUndoAction();
3346 pdoc
->DelChar(currentPos
);
3350 if (pdoc
->InsertString(currentPos
, s
, len
)) {
3351 SetEmptySelection(currentPos
+ len
);
3353 if (charReplaceAction
) {
3354 pdoc
->EndUndoAction();
3356 EnsureCaretVisible();
3357 // Avoid blinking during rapid typing:
3358 ShowCaretAtCurrentPosition();
3364 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
3365 static_cast<unsigned char>(s
[1]));
3367 int byte
= static_cast<unsigned char>(s
[0]);
3368 if ((byte
< 0xC0) || (1 == len
)) {
3369 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
3370 // characters when not in UTF-8 mode.
3371 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
3372 // characters representing themselves.
3374 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
3375 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
3376 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
3378 int byte2
= static_cast<unsigned char>(s
[1]);
3379 if ((byte2
& 0xC0) == 0x80) {
3380 // Two-byte-character lead-byte followed by a trail-byte.
3381 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
3383 // A two-byte-character lead-byte not followed by trail-byte
3384 // represents itself.
3385 } else if (byte
< 0xF0) {
3386 int byte2
= static_cast<unsigned char>(s
[1]);
3387 int byte3
= static_cast<unsigned char>(s
[2]);
3388 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
3389 // Three-byte-character lead byte followed by two trail bytes.
3390 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
3393 // A three-byte-character lead-byte not followed by two trail-bytes
3394 // represents itself.
3401 void Editor::ClearSelection() {
3402 if (!SelectionContainsProtected()) {
3403 int startPos
= SelectionStart();
3404 if (selType
== selStream
) {
3405 unsigned int chars
= SelectionEnd() - startPos
;
3407 pdoc
->BeginUndoAction();
3408 pdoc
->DeleteChars(startPos
, chars
);
3409 pdoc
->EndUndoAction();
3412 pdoc
->BeginUndoAction();
3413 SelectionLineIterator
lineIterator(this, false);
3414 while (lineIterator
.Iterate()) {
3415 startPos
= lineIterator
.startPos
;
3416 unsigned int chars
= lineIterator
.endPos
- startPos
;
3418 pdoc
->DeleteChars(startPos
, chars
);
3421 pdoc
->EndUndoAction();
3422 selType
= selStream
;
3424 SetEmptySelection(startPos
);
3428 void Editor::ClearAll() {
3429 pdoc
->BeginUndoAction();
3430 if (0 != pdoc
->Length()) {
3431 pdoc
->DeleteChars(0, pdoc
->Length());
3433 if (!pdoc
->IsReadOnly()) {
3436 pdoc
->EndUndoAction();
3440 SetVerticalScrollPos();
3441 InvalidateStyleRedraw();
3444 void Editor::ClearDocumentStyle() {
3445 pdoc
->StartStyling(0, '\377');
3446 pdoc
->SetStyleFor(pdoc
->Length(), 0);
3448 pdoc
->ClearLevels();
3451 void Editor::Cut() {
3452 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
3458 void Editor::PasteRectangular(int pos
, const char *ptr
, int len
) {
3459 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
3463 int xInsert
= XFromPosition(currentPos
);
3464 int line
= pdoc
->LineFromPosition(currentPos
);
3465 bool prevCr
= false;
3466 pdoc
->BeginUndoAction();
3467 for (int i
= 0; i
< len
; i
++) {
3468 if (IsEOLChar(ptr
[i
])) {
3469 if ((ptr
[i
] == '\r') || (!prevCr
))
3471 if (line
>= pdoc
->LinesTotal()) {
3472 if (pdoc
->eolMode
!= SC_EOL_LF
)
3473 pdoc
->InsertChar(pdoc
->Length(), '\r');
3474 if (pdoc
->eolMode
!= SC_EOL_CR
)
3475 pdoc
->InsertChar(pdoc
->Length(), '\n');
3477 // Pad the end of lines with spaces if required
3478 currentPos
= PositionFromLineX(line
, xInsert
);
3479 if ((XFromPosition(currentPos
) < xInsert
) && (i
+ 1 < len
)) {
3480 for (int i
= 0; i
< xInsert
- XFromPosition(currentPos
); i
++) {
3481 pdoc
->InsertChar(currentPos
, ' ');
3485 prevCr
= ptr
[i
] == '\r';
3487 pdoc
->InsertString(currentPos
, ptr
+ i
, 1);
3492 pdoc
->EndUndoAction();
3493 SetEmptySelection(pos
);
3496 bool Editor::CanPaste() {
3497 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
3500 void Editor::Clear() {
3501 if (currentPos
== anchor
) {
3502 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3508 SetEmptySelection(currentPos
);
3511 void Editor::SelectAll() {
3512 SetSelection(0, pdoc
->Length());
3516 void Editor::Undo() {
3517 if (pdoc
->CanUndo()) {
3519 int newPos
= pdoc
->Undo();
3521 SetEmptySelection(newPos
);
3522 EnsureCaretVisible();
3526 void Editor::Redo() {
3527 if (pdoc
->CanRedo()) {
3528 int newPos
= pdoc
->Redo();
3530 SetEmptySelection(newPos
);
3531 EnsureCaretVisible();
3535 void Editor::DelChar() {
3536 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3537 pdoc
->DelChar(currentPos
);
3539 // Avoid blinking during rapid typing:
3540 ShowCaretAtCurrentPosition();
3543 void Editor::DelCharBack(bool allowLineStartDeletion
) {
3544 if (currentPos
== anchor
) {
3545 if (!RangeContainsProtected(currentPos
- 1, currentPos
)) {
3546 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
3547 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != currentPos
)) {
3548 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3549 pdoc
->GetColumn(currentPos
) > 0 && pdoc
->backspaceUnindents
) {
3550 pdoc
->BeginUndoAction();
3551 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3552 int indentationStep
= pdoc
->IndentSize();
3553 if (indentation
% indentationStep
== 0) {
3554 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3556 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- (indentation
% indentationStep
));
3558 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
3559 pdoc
->EndUndoAction();
3561 pdoc
->DelCharBack(currentPos
);
3567 SetEmptySelection(currentPos
);
3569 // Avoid blinking during rapid typing:
3570 ShowCaretAtCurrentPosition();
3573 void Editor::NotifyFocus(bool) {}
3575 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
3576 SCNotification scn
= {0};
3577 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
3578 scn
.position
= endStyleNeeded
;
3582 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
3583 NotifyStyleToNeeded(endStyleNeeded
);
3586 void Editor::NotifyChar(int ch
) {
3587 SCNotification scn
= {0};
3588 scn
.nmhdr
.code
= SCN_CHARADDED
;
3591 if (recordingMacro
) {
3593 txt
[0] = static_cast<char>(ch
);
3595 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
3599 void Editor::NotifySavePoint(bool isSavePoint
) {
3600 SCNotification scn
= {0};
3602 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
3604 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
3609 void Editor::NotifyModifyAttempt() {
3610 SCNotification scn
= {0};
3611 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
3615 void Editor::NotifyDoubleClick(Point
, bool) {
3616 SCNotification scn
= {0};
3617 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
3621 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3622 SCNotification scn
= {0};
3623 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
3624 scn
.position
= position
;
3625 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3626 (alt
? SCI_ALT
: 0);
3630 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3631 SCNotification scn
= {0};
3632 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
3633 scn
.position
= position
;
3634 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3635 (alt
? SCI_ALT
: 0);
3639 void Editor::NotifyUpdateUI() {
3640 SCNotification scn
= {0};
3641 scn
.nmhdr
.code
= SCN_UPDATEUI
;
3645 void Editor::NotifyPainted() {
3646 SCNotification scn
= {0};
3647 scn
.nmhdr
.code
= SCN_PAINTED
;
3651 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
3652 int marginClicked
= -1;
3654 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
3655 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
3656 marginClicked
= margin
;
3657 x
+= vs
.ms
[margin
].width
;
3659 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
3660 SCNotification scn
= {0};
3661 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
3662 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3663 (alt
? SCI_ALT
: 0);
3664 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
3665 scn
.margin
= marginClicked
;
3673 void Editor::NotifyNeedShown(int pos
, int len
) {
3674 SCNotification scn
= {0};
3675 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
3681 void Editor::NotifyDwelling(Point pt
, bool state
) {
3682 SCNotification scn
= {0};
3683 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
3684 scn
.position
= PositionFromLocationClose(pt
);
3690 void Editor::NotifyZoom() {
3691 SCNotification scn
= {0};
3692 scn
.nmhdr
.code
= SCN_ZOOM
;
3696 // Notifications from document
3697 void Editor::NotifyModifyAttempt(Document
*, void *) {
3698 //Platform::DebugPrintf("** Modify Attempt\n");
3699 NotifyModifyAttempt();
3702 void Editor::NotifyMove(int position
) {
3703 SCNotification scn
= {0};
3704 scn
.nmhdr
.code
= SCN_POSCHANGED
;
3705 scn
.position
= position
;
3709 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
3710 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
3711 NotifySavePoint(atSavePoint
);
3714 void Editor::CheckModificationForWrap(DocModification mh
) {
3715 if (mh
.modificationType
& (SC_MOD_INSERTTEXT
|SC_MOD_DELETETEXT
)) {
3716 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
3717 if (wrapState
!= eWrapNone
) {
3718 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
3719 int lines
= Platform::Maximum(0, mh
.linesAdded
);
3720 NeedWrapping(lineDoc
, lineDoc
+ lines
+ 1);
3725 // Move a position so it is still after the same character as before the insertion.
3726 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
3727 if (position
> startInsertion
) {
3728 return position
+ length
;
3733 // Move a position so it is still after the same character as before the deletion if that
3734 // character is still present else after the previous surviving character.
3735 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
3736 if (position
> startDeletion
) {
3737 int endDeletion
= startDeletion
+ length
;
3738 if (position
> endDeletion
) {
3739 return position
- length
;
3741 return startDeletion
;
3748 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
3749 needUpdateUI
= true;
3750 if (paintState
== painting
) {
3751 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
3753 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
3754 pdoc
->IncrementStyleClock();
3755 if (paintState
== notPainting
) {
3756 if (mh
.position
< pdoc
->LineStart(topLine
)) {
3757 // Styling performed before this view
3760 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3763 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
3765 // Move selection and brace highlights
3766 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
3767 currentPos
= MovePositionForInsertion(currentPos
, mh
.position
, mh
.length
);
3768 anchor
= MovePositionForInsertion(anchor
, mh
.position
, mh
.length
);
3769 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
3770 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
3771 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
3772 currentPos
= MovePositionForDeletion(currentPos
, mh
.position
, mh
.length
);
3773 anchor
= MovePositionForDeletion(anchor
, mh
.position
, mh
.length
);
3774 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
3775 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
3777 if (cs
.LinesDisplayed() < cs
.LinesInDoc()) {
3778 // Some lines are hidden so may need shown.
3779 // TODO: check if the modified area is hidden.
3780 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
3781 NotifyNeedShown(mh
.position
, 0);
3782 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
3783 NotifyNeedShown(mh
.position
, mh
.length
);
3786 if (mh
.linesAdded
!= 0) {
3787 // Update contraction state for inserted and removed lines
3788 // lineOfPos should be calculated in context of state before modification, shouldn't it
3789 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
3790 if (mh
.linesAdded
> 0) {
3791 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
3793 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
3796 CheckModificationForWrap(mh
);
3797 if (mh
.linesAdded
!= 0) {
3798 // Avoid scrolling of display if change before current display
3799 if (mh
.position
< posTopLine
&& !CanDeferToLastStep(mh
)) {
3800 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
3801 if (newTop
!= topLine
) {
3803 SetVerticalScrollPos();
3807 //Platform::DebugPrintf("** %x Doc Changed\n", this);
3808 // TODO: could invalidate from mh.startModification to end of screen
3809 //InvalidateRange(mh.position, mh.position + mh.length);
3810 if (paintState
== notPainting
&& !CanDeferToLastStep(mh
)) {
3814 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
3815 // mh.position, mh.position + mh.length);
3816 if (paintState
== notPainting
&& mh
.length
&& !CanEliminate(mh
)) {
3817 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3822 if (mh
.linesAdded
!= 0 && !CanDeferToLastStep(mh
)) {
3826 if (mh
.modificationType
& SC_MOD_CHANGEMARKER
) {
3827 if ((paintState
== notPainting
) || !PaintContainsMargin()) {
3828 if (mh
.modificationType
& SC_MOD_CHANGEFOLD
) {
3829 // Fold changes can affect the drawing of following lines so redraw whole margin
3832 RedrawSelMargin(mh
.line
);
3837 // NOW pay the piper WRT "deferred" visual updates
3838 if (IsLastStep(mh
)) {
3843 // If client wants to see this modification
3844 if (mh
.modificationType
& modEventMask
) {
3845 if ((mh
.modificationType
& SC_MOD_CHANGESTYLE
) == 0) {
3846 // Real modification made to text of document.
3847 NotifyChange(); // Send EN_CHANGE
3850 SCNotification scn
= {0};
3851 scn
.nmhdr
.code
= SCN_MODIFIED
;
3852 scn
.position
= mh
.position
;
3853 scn
.modificationType
= mh
.modificationType
;
3855 scn
.length
= mh
.length
;
3856 scn
.linesAdded
= mh
.linesAdded
;
3858 scn
.foldLevelNow
= mh
.foldLevelNow
;
3859 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
3864 void Editor::NotifyDeleted(Document
*, void *) {
3868 void Editor::NotifyMacroRecord(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
3870 // Enumerates all macroable messages
3876 case SCI_REPLACESEL
:
3878 case SCI_INSERTTEXT
:
3879 case SCI_APPENDTEXT
:
3884 case SCI_SEARCHANCHOR
:
3885 case SCI_SEARCHNEXT
:
3886 case SCI_SEARCHPREV
:
3888 case SCI_LINEDOWNEXTEND
:
3890 case SCI_PARADOWNEXTEND
:
3892 case SCI_LINEUPEXTEND
:
3894 case SCI_PARAUPEXTEND
:
3896 case SCI_CHARLEFTEXTEND
:
3898 case SCI_CHARRIGHTEXTEND
:
3900 case SCI_WORDLEFTEXTEND
:
3902 case SCI_WORDRIGHTEXTEND
:
3903 case SCI_WORDPARTLEFT
:
3904 case SCI_WORDPARTLEFTEXTEND
:
3905 case SCI_WORDPARTRIGHT
:
3906 case SCI_WORDPARTRIGHTEXTEND
:
3907 case SCI_WORDLEFTEND
:
3908 case SCI_WORDLEFTENDEXTEND
:
3909 case SCI_WORDRIGHTEND
:
3910 case SCI_WORDRIGHTENDEXTEND
:
3912 case SCI_HOMEEXTEND
:
3914 case SCI_LINEENDEXTEND
:
3916 case SCI_HOMEWRAPEXTEND
:
3917 case SCI_LINEENDWRAP
:
3918 case SCI_LINEENDWRAPEXTEND
:
3919 case SCI_DOCUMENTSTART
:
3920 case SCI_DOCUMENTSTARTEXTEND
:
3921 case SCI_DOCUMENTEND
:
3922 case SCI_DOCUMENTENDEXTEND
:
3923 case SCI_STUTTEREDPAGEUP
:
3924 case SCI_STUTTEREDPAGEUPEXTEND
:
3925 case SCI_STUTTEREDPAGEDOWN
:
3926 case SCI_STUTTEREDPAGEDOWNEXTEND
:
3928 case SCI_PAGEUPEXTEND
:
3930 case SCI_PAGEDOWNEXTEND
:
3931 case SCI_EDITTOGGLEOVERTYPE
:
3933 case SCI_DELETEBACK
:
3938 case SCI_VCHOMEEXTEND
:
3939 case SCI_VCHOMEWRAP
:
3940 case SCI_VCHOMEWRAPEXTEND
:
3941 case SCI_DELWORDLEFT
:
3942 case SCI_DELWORDRIGHT
:
3943 case SCI_DELLINELEFT
:
3944 case SCI_DELLINERIGHT
:
3947 case SCI_LINEDELETE
:
3948 case SCI_LINETRANSPOSE
:
3949 case SCI_LINEDUPLICATE
:
3952 case SCI_LINESCROLLDOWN
:
3953 case SCI_LINESCROLLUP
:
3954 case SCI_DELETEBACKNOTLINE
:
3955 case SCI_HOMEDISPLAY
:
3956 case SCI_HOMEDISPLAYEXTEND
:
3957 case SCI_LINEENDDISPLAY
:
3958 case SCI_LINEENDDISPLAYEXTEND
:
3959 case SCI_SETSELECTIONMODE
:
3960 case SCI_LINEDOWNRECTEXTEND
:
3961 case SCI_LINEUPRECTEXTEND
:
3962 case SCI_CHARLEFTRECTEXTEND
:
3963 case SCI_CHARRIGHTRECTEXTEND
:
3964 case SCI_HOMERECTEXTEND
:
3965 case SCI_VCHOMERECTEXTEND
:
3966 case SCI_LINEENDRECTEXTEND
:
3967 case SCI_PAGEUPRECTEXTEND
:
3968 case SCI_PAGEDOWNRECTEXTEND
:
3969 case SCI_SELECTIONDUPLICATE
:
3972 // Filter out all others like display changes. Also, newlines are redundant
3973 // with char insert messages.
3976 // printf("Filtered out %ld of macro recording\n", iMessage);
3980 // Send notification
3981 SCNotification scn
= {0};
3982 scn
.nmhdr
.code
= SCN_MACRORECORD
;
3983 scn
.message
= iMessage
;
3984 scn
.wParam
= wParam
;
3985 scn
.lParam
= lParam
;
3990 * Force scroll and keep position relative to top of window.
3992 * If stuttered = true and not already at first/last row, move to first/last row of window.
3993 * If stuttered = true and already at first/last row, scroll as normal.
3995 void Editor::PageMove(int direction
, selTypes sel
, bool stuttered
) {
3996 int topLineNew
, newPos
;
3998 // I consider only the caretYSlop, and ignore the caretYPolicy-- is that a problem?
3999 int currentLine
= pdoc
->LineFromPosition(currentPos
);
4000 int topStutterLine
= topLine
+ caretYSlop
;
4001 int bottomStutterLine
= topLine
+ LinesToScroll() - caretYSlop
;
4003 if (stuttered
&& (direction
< 0 && currentLine
> topStutterLine
)) {
4004 topLineNew
= topLine
;
4005 newPos
= PositionFromLocation(Point(lastXChosen
, vs
.lineHeight
* caretYSlop
));
4007 } else if (stuttered
&& (direction
> 0 && currentLine
< bottomStutterLine
)) {
4008 topLineNew
= topLine
;
4009 newPos
= PositionFromLocation(Point(lastXChosen
, vs
.lineHeight
* (LinesToScroll() - caretYSlop
)));
4012 Point pt
= LocationFromPosition(currentPos
);
4014 topLineNew
= Platform::Clamp(
4015 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
4016 newPos
= PositionFromLocation(
4017 Point(lastXChosen
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())));
4020 if (topLineNew
!= topLine
) {
4021 SetTopLine(topLineNew
);
4022 MovePositionTo(newPos
, sel
);
4024 SetVerticalScrollPos();
4026 MovePositionTo(newPos
, sel
);
4030 void Editor::ChangeCaseOfSelection(bool makeUpperCase
) {
4031 pdoc
->BeginUndoAction();
4032 int startCurrent
= currentPos
;
4033 int startAnchor
= anchor
;
4034 if (selType
== selStream
) {
4035 pdoc
->ChangeCase(Range(SelectionStart(), SelectionEnd()),
4037 SetSelection(startCurrent
, startAnchor
);
4039 SelectionLineIterator
lineIterator(this, false);
4040 while (lineIterator
.Iterate()) {
4042 Range(lineIterator
.startPos
, lineIterator
.endPos
),
4045 // Would be nicer to keep the rectangular selection but this is complex
4046 SetEmptySelection(startCurrent
);
4048 pdoc
->EndUndoAction();
4051 void Editor::LineTranspose() {
4052 int line
= pdoc
->LineFromPosition(currentPos
);
4054 int startPrev
= pdoc
->LineStart(line
- 1);
4055 int endPrev
= pdoc
->LineEnd(line
- 1);
4056 int start
= pdoc
->LineStart(line
);
4057 int end
= pdoc
->LineEnd(line
);
4058 int startNext
= pdoc
->LineStart(line
+ 1);
4059 if (end
< pdoc
->Length()) {
4061 char *thisLine
= CopyRange(start
, end
);
4062 pdoc
->DeleteChars(start
, end
- start
);
4063 if (pdoc
->InsertString(startPrev
, thisLine
, end
- start
)) {
4064 MovePositionTo(startPrev
+ end
- start
);
4068 // Last line so line has no line end
4069 char *thisLine
= CopyRange(start
, end
);
4070 char *prevEnd
= CopyRange(endPrev
, start
);
4071 pdoc
->DeleteChars(endPrev
, end
- endPrev
);
4072 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
4073 if (pdoc
->InsertString(startPrev
+ end
- start
, prevEnd
, start
- endPrev
)) {
4074 MovePositionTo(startPrev
+ end
- endPrev
);
4083 void Editor::Duplicate(bool forLine
) {
4084 int start
= SelectionStart();
4085 int end
= SelectionEnd();
4090 int line
= pdoc
->LineFromPosition(currentPos
);
4091 start
= pdoc
->LineStart(line
);
4092 end
= pdoc
->LineEnd(line
);
4094 char *text
= CopyRange(start
, end
);
4096 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
4097 pdoc
->InsertString(end
, eol
);
4098 pdoc
->InsertString(end
+ istrlen(eol
), text
, end
- start
);
4100 pdoc
->InsertString(end
, text
, end
- start
);
4105 void Editor::CancelModes() {
4106 moveExtendsSelection
= false;
4109 void Editor::NewLine() {
4111 const char *eol
= "\n";
4112 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
4114 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
4116 } // else SC_EOL_LF -> "\n" already set
4117 if (pdoc
->InsertString(currentPos
, eol
)) {
4118 SetEmptySelection(currentPos
+ istrlen(eol
));
4125 EnsureCaretVisible();
4126 // Avoid blinking during rapid typing:
4127 ShowCaretAtCurrentPosition();
4130 void Editor::CursorUpOrDown(int direction
, selTypes sel
) {
4131 Point pt
= LocationFromPosition(currentPos
);
4132 int posNew
= PositionFromLocation(
4133 Point(lastXChosen
, pt
.y
+ direction
* vs
.lineHeight
));
4134 if (direction
< 0) {
4135 // Line wrapping may lead to a location on the same line, so
4136 // seek back if that is the case.
4137 // There is an equivalent case when moving down which skips
4138 // over a line but as that does not trap the user it is fine.
4139 Point ptNew
= LocationFromPosition(posNew
);
4140 while ((posNew
> 0) && (pt
.y
== ptNew
.y
)) {
4142 ptNew
= LocationFromPosition(posNew
);
4145 MovePositionTo(posNew
, sel
);
4148 void Editor::ParaUpOrDown(int direction
, selTypes sel
) {
4149 int lineDoc
, savedPos
= currentPos
;
4151 MovePositionTo(direction
> 0 ? pdoc
->ParaDown(currentPos
) : pdoc
->ParaUp(currentPos
), sel
);
4152 lineDoc
= pdoc
->LineFromPosition(currentPos
);
4153 if (direction
> 0) {
4154 if (currentPos
>= pdoc
->Length() && !cs
.GetVisible(lineDoc
)) {
4156 MovePositionTo(pdoc
->LineEndPosition(savedPos
));
4161 } while (!cs
.GetVisible(lineDoc
));
4164 int Editor::StartEndDisplayLine(int pos
, bool start
) {
4166 int line
= pdoc
->LineFromPosition(pos
);
4167 AutoSurface
surface(this);
4168 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
4169 int posRet
= INVALID_POSITION
;
4170 if (surface
&& ll
) {
4171 unsigned int posLineStart
= pdoc
->LineStart(line
);
4172 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
4173 int posInLine
= pos
- posLineStart
;
4174 if (posInLine
<= ll
->maxLineLength
) {
4175 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
4176 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
4178 posRet
= ll
->LineStart(subLine
) + posLineStart
;
4180 if (subLine
== ll
->lines
- 1)
4181 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
;
4183 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
- 1;
4189 if (posRet
== INVALID_POSITION
) {
4196 int Editor::KeyCommand(unsigned int iMessage
) {
4201 case SCI_LINEDOWNEXTEND
:
4202 CursorUpOrDown(1, selStream
);
4204 case SCI_LINEDOWNRECTEXTEND
:
4205 CursorUpOrDown(1, selRectangle
);
4210 case SCI_PARADOWNEXTEND
:
4211 ParaUpOrDown(1, selStream
);
4213 case SCI_LINESCROLLDOWN
:
4214 ScrollTo(topLine
+ 1);
4215 MoveCaretInsideView(false);
4220 case SCI_LINEUPEXTEND
:
4221 CursorUpOrDown(-1, selStream
);
4223 case SCI_LINEUPRECTEXTEND
:
4224 CursorUpOrDown(-1, selRectangle
);
4229 case SCI_PARAUPEXTEND
:
4230 ParaUpOrDown(-1, selStream
);
4232 case SCI_LINESCROLLUP
:
4233 ScrollTo(topLine
- 1);
4234 MoveCaretInsideView(false);
4237 if (SelectionEmpty() || moveExtendsSelection
) {
4238 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1));
4240 MovePositionTo(SelectionStart());
4244 case SCI_CHARLEFTEXTEND
:
4245 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), selStream
);
4248 case SCI_CHARLEFTRECTEXTEND
:
4249 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), selRectangle
);
4253 if (SelectionEmpty() || moveExtendsSelection
) {
4254 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1));
4256 MovePositionTo(SelectionEnd());
4260 case SCI_CHARRIGHTEXTEND
:
4261 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), selStream
);
4264 case SCI_CHARRIGHTRECTEXTEND
:
4265 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), selRectangle
);
4269 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1));
4272 case SCI_WORDLEFTEXTEND
:
4273 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1), selStream
);
4277 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1));
4280 case SCI_WORDRIGHTEXTEND
:
4281 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1), selStream
);
4285 case SCI_WORDLEFTEND
:
4286 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, -1), -1));
4289 case SCI_WORDLEFTENDEXTEND
:
4290 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, -1), -1), selStream
);
4293 case SCI_WORDRIGHTEND
:
4294 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, 1), 1));
4297 case SCI_WORDRIGHTENDEXTEND
:
4298 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, 1), 1), selStream
);
4303 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)));
4306 case SCI_HOMEEXTEND
:
4307 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), selStream
);
4310 case SCI_HOMERECTEXTEND
:
4311 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), selRectangle
);
4315 MovePositionTo(pdoc
->LineEndPosition(currentPos
));
4318 case SCI_LINEENDEXTEND
:
4319 MovePositionTo(pdoc
->LineEndPosition(currentPos
), selStream
);
4322 case SCI_LINEENDRECTEXTEND
:
4323 MovePositionTo(pdoc
->LineEndPosition(currentPos
), selRectangle
);
4326 case SCI_HOMEWRAP
: {
4327 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4328 if (currentPos
<= homePos
)
4329 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
4330 MovePositionTo(homePos
);
4334 case SCI_HOMEWRAPEXTEND
: {
4335 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4336 if (currentPos
<= homePos
)
4337 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
4338 MovePositionTo(homePos
, selStream
);
4342 case SCI_LINEENDWRAP
: {
4343 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
4344 int realEndPos
= pdoc
->LineEndPosition(currentPos
);
4345 if (endPos
> realEndPos
// if moved past visible EOLs
4346 || currentPos
>= endPos
) // if at end of display line already
4347 endPos
= realEndPos
;
4348 MovePositionTo(endPos
);
4352 case SCI_LINEENDWRAPEXTEND
: {
4353 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
4354 int realEndPos
= pdoc
->LineEndPosition(currentPos
);
4355 if (endPos
> realEndPos
// if moved past visible EOLs
4356 || currentPos
>= endPos
) // if at end of display line already
4357 endPos
= realEndPos
;
4358 MovePositionTo(endPos
, selStream
);
4362 case SCI_DOCUMENTSTART
:
4366 case SCI_DOCUMENTSTARTEXTEND
:
4367 MovePositionTo(0, selStream
);
4370 case SCI_DOCUMENTEND
:
4371 MovePositionTo(pdoc
->Length());
4374 case SCI_DOCUMENTENDEXTEND
:
4375 MovePositionTo(pdoc
->Length(), selStream
);
4378 case SCI_STUTTEREDPAGEUP
:
4379 PageMove(-1, noSel
, true);
4381 case SCI_STUTTEREDPAGEUPEXTEND
:
4382 PageMove(-1, selStream
, true);
4384 case SCI_STUTTEREDPAGEDOWN
:
4385 PageMove(1, noSel
, true);
4387 case SCI_STUTTEREDPAGEDOWNEXTEND
:
4388 PageMove(1, selStream
, true);
4393 case SCI_PAGEUPEXTEND
:
4394 PageMove(-1, selStream
);
4396 case SCI_PAGEUPRECTEXTEND
:
4397 PageMove(-1, selRectangle
);
4402 case SCI_PAGEDOWNEXTEND
:
4403 PageMove(1, selStream
);
4405 case SCI_PAGEDOWNRECTEXTEND
:
4406 PageMove(1, selRectangle
);
4408 case SCI_EDITTOGGLEOVERTYPE
:
4409 inOverstrike
= !inOverstrike
;
4411 ShowCaretAtCurrentPosition();
4414 case SCI_CANCEL
: // Cancel any modes - handled in subclass
4415 // Also unselect text
4418 case SCI_DELETEBACK
:
4423 EnsureCaretVisible();
4425 case SCI_DELETEBACKNOTLINE
:
4430 EnsureCaretVisible();
4437 EnsureCaretVisible();
4444 EnsureCaretVisible();
4453 MovePositionTo(pdoc
->VCHomePosition(currentPos
));
4456 case SCI_VCHOMEEXTEND
:
4457 MovePositionTo(pdoc
->VCHomePosition(currentPos
), selStream
);
4460 case SCI_VCHOMERECTEXTEND
:
4461 MovePositionTo(pdoc
->VCHomePosition(currentPos
), selRectangle
);
4464 case SCI_VCHOMEWRAP
: {
4465 int homePos
= pdoc
->VCHomePosition(currentPos
);
4466 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4467 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
4468 homePos
= viewLineStart
;
4470 MovePositionTo(homePos
);
4474 case SCI_VCHOMEWRAPEXTEND
: {
4475 int homePos
= pdoc
->VCHomePosition(currentPos
);
4476 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4477 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
4478 homePos
= viewLineStart
;
4480 MovePositionTo(homePos
, selStream
);
4485 if (vs
.zoomLevel
< 20) {
4487 InvalidateStyleRedraw();
4492 if (vs
.zoomLevel
> -10) {
4494 InvalidateStyleRedraw();
4498 case SCI_DELWORDLEFT
: {
4499 int startWord
= pdoc
->NextWordStart(currentPos
, -1);
4500 pdoc
->DeleteChars(startWord
, currentPos
- startWord
);
4504 case SCI_DELWORDRIGHT
: {
4505 int endWord
= pdoc
->NextWordStart(currentPos
, 1);
4506 pdoc
->DeleteChars(currentPos
, endWord
- currentPos
);
4509 case SCI_DELLINELEFT
: {
4510 int line
= pdoc
->LineFromPosition(currentPos
);
4511 int start
= pdoc
->LineStart(line
);
4512 pdoc
->DeleteChars(start
, currentPos
- start
);
4516 case SCI_DELLINERIGHT
: {
4517 int line
= pdoc
->LineFromPosition(currentPos
);
4518 int end
= pdoc
->LineEnd(line
);
4519 pdoc
->DeleteChars(currentPos
, end
- currentPos
);
4522 case SCI_LINECOPY
: {
4523 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4524 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4525 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
4526 pdoc
->LineStart(lineEnd
+ 1));
4530 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4531 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4532 int start
= pdoc
->LineStart(lineStart
);
4533 int end
= pdoc
->LineStart(lineEnd
+ 1);
4534 SetSelection(start
, end
);
4539 case SCI_LINEDELETE
: {
4540 int line
= pdoc
->LineFromPosition(currentPos
);
4541 int start
= pdoc
->LineStart(line
);
4542 int end
= pdoc
->LineStart(line
+ 1);
4543 pdoc
->DeleteChars(start
, end
- start
);
4546 case SCI_LINETRANSPOSE
:
4549 case SCI_LINEDUPLICATE
:
4552 case SCI_SELECTIONDUPLICATE
:
4556 ChangeCaseOfSelection(false);
4559 ChangeCaseOfSelection(true);
4561 case SCI_WORDPARTLEFT
:
4562 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1));
4565 case SCI_WORDPARTLEFTEXTEND
:
4566 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1), selStream
);
4569 case SCI_WORDPARTRIGHT
:
4570 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1));
4573 case SCI_WORDPARTRIGHTEXTEND
:
4574 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1), selStream
);
4577 case SCI_HOMEDISPLAY
:
4578 MovePositionTo(MovePositionSoVisible(
4579 StartEndDisplayLine(currentPos
, true), -1));
4582 case SCI_HOMEDISPLAYEXTEND
:
4583 MovePositionTo(MovePositionSoVisible(
4584 StartEndDisplayLine(currentPos
, true), -1), selStream
);
4587 case SCI_LINEENDDISPLAY
:
4588 MovePositionTo(MovePositionSoVisible(
4589 StartEndDisplayLine(currentPos
, false), 1));
4592 case SCI_LINEENDDISPLAYEXTEND
:
4593 MovePositionTo(MovePositionSoVisible(
4594 StartEndDisplayLine(currentPos
, false), 1), selStream
);
4601 int Editor::KeyDefault(int, int) {
4605 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
4607 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4608 (alt
? SCI_ALT
: 0);
4609 int msg
= kmap
.Find(key
, modifiers
);
4613 return WndProc(msg
, 0, 0);
4617 return KeyDefault(key
, modifiers
);
4621 void Editor::SetWhitespaceVisible(int view
) {
4622 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(view
);
4625 int Editor::GetWhitespaceVisible() {
4626 return vs
.viewWhitespace
;
4629 void Editor::Indent(bool forwards
) {
4630 //Platform::DebugPrintf("INdent %d\n", forwards);
4631 int lineOfAnchor
= pdoc
->LineFromPosition(anchor
);
4632 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
4633 if (lineOfAnchor
== lineCurrentPos
) {
4635 pdoc
->BeginUndoAction();
4637 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
4639 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4640 int indentationStep
= pdoc
->IndentSize();
4641 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
+ indentationStep
- indentation
% indentationStep
);
4642 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4644 if (pdoc
->useTabs
) {
4645 pdoc
->InsertChar(currentPos
, '\t');
4646 SetEmptySelection(currentPos
+ 1);
4648 int numSpaces
= (pdoc
->tabInChars
) -
4649 (pdoc
->GetColumn(currentPos
) % (pdoc
->tabInChars
));
4651 numSpaces
= pdoc
->tabInChars
;
4652 for (int i
= 0; i
< numSpaces
; i
++) {
4653 pdoc
->InsertChar(currentPos
+ i
, ' ');
4655 SetEmptySelection(currentPos
+ numSpaces
);
4658 pdoc
->EndUndoAction();
4660 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
4662 pdoc
->BeginUndoAction();
4663 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4664 int indentationStep
= pdoc
->IndentSize();
4665 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
4666 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4667 pdoc
->EndUndoAction();
4669 int newColumn
= ((pdoc
->GetColumn(currentPos
) - 1) / pdoc
->tabInChars
) *
4673 int newPos
= currentPos
;
4674 while (pdoc
->GetColumn(newPos
) > newColumn
)
4676 SetEmptySelection(newPos
);
4680 int anchorPosOnLine
= anchor
- pdoc
->LineStart(lineOfAnchor
);
4681 int currentPosPosOnLine
= currentPos
- pdoc
->LineStart(lineCurrentPos
);
4682 // Multiple lines selected so indent / dedent
4683 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
4684 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
4685 if (pdoc
->LineStart(lineBottomSel
) == anchor
|| pdoc
->LineStart(lineBottomSel
) == currentPos
)
4686 lineBottomSel
--; // If not selecting any characters on a line, do not indent
4687 pdoc
->BeginUndoAction();
4688 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
4689 pdoc
->EndUndoAction();
4690 if (lineOfAnchor
< lineCurrentPos
) {
4691 if (currentPosPosOnLine
== 0)
4692 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4694 SetSelection(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
4696 if (anchorPosOnLine
== 0)
4697 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4699 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
4705 * Search of a text in the document, in the given range.
4706 * @return The position of the found text, -1 if not found.
4708 long Editor::FindText(
4709 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4710 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4711 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
4713 TextToFind
*ft
= reinterpret_cast<TextToFind
*>(lParam
);
4714 int lengthFound
= istrlen(ft
->lpstrText
);
4715 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
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 ft
->chrgText
.cpMin
= pos
;
4724 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
4730 * Relocatable search support : Searches relative to current selection
4731 * point and sets the selection to the found text range with
4735 * Anchor following searches at current selection start: This allows
4736 * multiple incremental interactive searches to be macro recorded
4737 * while still setting the selection to found text so the find/select
4738 * operation is self-contained.
4740 void Editor::SearchAnchor() {
4741 searchAnchor
= SelectionStart();
4745 * Find text from current search anchor: Must call @c SearchAnchor first.
4746 * Used for next text and previous text requests.
4747 * @return The position of the found text, -1 if not found.
4749 long Editor::SearchText(
4750 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
4751 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4752 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4753 sptr_t lParam
) { ///< The text to search for.
4755 const char *txt
= reinterpret_cast<char *>(lParam
);
4757 int lengthFound
= istrlen(txt
);
4758 if (iMessage
== SCI_SEARCHNEXT
) {
4759 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
4760 (wParam
& SCFIND_MATCHCASE
) != 0,
4761 (wParam
& SCFIND_WHOLEWORD
) != 0,
4762 (wParam
& SCFIND_WORDSTART
) != 0,
4763 (wParam
& SCFIND_REGEXP
) != 0,
4764 (wParam
& SCFIND_POSIX
) != 0,
4767 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
4768 (wParam
& SCFIND_MATCHCASE
) != 0,
4769 (wParam
& SCFIND_WHOLEWORD
) != 0,
4770 (wParam
& SCFIND_WORDSTART
) != 0,
4771 (wParam
& SCFIND_REGEXP
) != 0,
4772 (wParam
& SCFIND_POSIX
) != 0,
4777 SetSelection(pos
, pos
+ lengthFound
);
4784 * Search for text in the target range of the document.
4785 * @return The position of the found text, -1 if not found.
4787 long Editor::SearchInTarget(const char *text
, int length
) {
4788 int lengthFound
= length
;
4789 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
4790 (searchFlags
& SCFIND_MATCHCASE
) != 0,
4791 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
4792 (searchFlags
& SCFIND_WORDSTART
) != 0,
4793 (searchFlags
& SCFIND_REGEXP
) != 0,
4794 (searchFlags
& SCFIND_POSIX
) != 0,
4798 targetEnd
= pos
+ lengthFound
;
4803 void Editor::GoToLine(int lineNo
) {
4804 if (lineNo
> pdoc
->LinesTotal())
4805 lineNo
= pdoc
->LinesTotal();
4808 SetEmptySelection(pdoc
->LineStart(lineNo
));
4809 ShowCaretAtCurrentPosition();
4810 EnsureCaretVisible();
4813 static bool Close(Point pt1
, Point pt2
) {
4814 if (abs(pt1
.x
- pt2
.x
) > 3)
4816 if (abs(pt1
.y
- pt2
.y
) > 3)
4821 char *Editor::CopyRange(int start
, int end
) {
4824 int len
= end
- start
;
4825 text
= new char[len
+ 1];
4827 for (int i
= 0; i
< len
; i
++) {
4828 text
[i
] = pdoc
->CharAt(start
+ i
);
4836 void Editor::CopySelectionFromRange(SelectionText
*ss
, int start
, int end
) {
4837 ss
->Set(CopyRange(start
, end
), end
- start
+ 1,
4838 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4841 void Editor::CopySelectionRange(SelectionText
*ss
) {
4842 if (selType
== selStream
) {
4843 CopySelectionFromRange(ss
, SelectionStart(), SelectionEnd());
4847 SelectionLineIterator
lineIterator(this);
4848 while (lineIterator
.Iterate()) {
4849 size
+= lineIterator
.endPos
- lineIterator
.startPos
;
4850 if (selType
!= selLines
) {
4852 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
4858 text
= new char[size
+ 1];
4861 lineIterator
.Reset();
4862 while (lineIterator
.Iterate()) {
4863 for (int i
= lineIterator
.startPos
;
4864 i
< lineIterator
.endPos
;
4866 text
[j
++] = pdoc
->CharAt(i
);
4868 if (selType
!= selLines
) {
4869 if (pdoc
->eolMode
!= SC_EOL_LF
) {
4872 if (pdoc
->eolMode
!= SC_EOL_CR
) {
4880 ss
->Set(text
, size
+ 1, pdoc
->dbcsCodePage
,
4881 vs
.styles
[STYLE_DEFAULT
].characterSet
, selType
== selRectangle
);
4885 void Editor::CopyRangeToClipboard(int start
, int end
) {
4886 start
= pdoc
->ClampPositionIntoDocument(start
);
4887 end
= pdoc
->ClampPositionIntoDocument(end
);
4888 SelectionText selectedText
;
4889 selectedText
.Set(CopyRange(start
, end
), end
- start
+ 1,
4890 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4891 CopyToClipboard(selectedText
);
4894 void Editor::CopyText(int length
, const char *text
) {
4895 SelectionText selectedText
;
4896 selectedText
.Copy(text
, length
+ 1,
4897 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4898 CopyToClipboard(selectedText
);
4901 void Editor::SetDragPosition(int newPos
) {
4903 newPos
= MovePositionOutsideChar(newPos
, 1);
4906 if (posDrag
!= newPos
) {
4915 void Editor::DisplayCursor(Window::Cursor c
) {
4916 if (cursorMode
== SC_CURSORNORMAL
)
4919 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
4922 void Editor::StartDrag() {
4923 // Always handled by subclasses
4924 //SetMouseCapture(true);
4925 //DisplayCursor(Window::cursorArrow);
4928 void Editor::DropAt(int position
, const char *value
, bool moving
, bool rectangular
) {
4929 //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
4931 dropWentOutside
= false;
4933 int positionWasInSelection
= PositionInSelection(position
);
4935 bool positionOnEdgeOfSelection
=
4936 (position
== SelectionStart()) || (position
== SelectionEnd());
4938 if ((!inDragDrop
) || !(0 == positionWasInSelection
) ||
4939 (positionOnEdgeOfSelection
&& !moving
)) {
4941 int selStart
= SelectionStart();
4942 int selEnd
= SelectionEnd();
4944 pdoc
->BeginUndoAction();
4946 int positionAfterDeletion
= position
;
4947 if (inDragDrop
&& moving
) {
4948 // Remove dragged out text
4949 if (rectangular
|| selType
== selLines
) {
4950 SelectionLineIterator
lineIterator(this);
4951 while (lineIterator
.Iterate()) {
4952 if (position
>= lineIterator
.startPos
) {
4953 if (position
> lineIterator
.endPos
) {
4954 positionAfterDeletion
-= lineIterator
.endPos
- lineIterator
.startPos
;
4956 positionAfterDeletion
-= position
- lineIterator
.startPos
;
4961 if (position
> selStart
) {
4962 positionAfterDeletion
-= selEnd
- selStart
;
4967 position
= positionAfterDeletion
;
4970 PasteRectangular(position
, value
, istrlen(value
));
4971 pdoc
->EndUndoAction();
4972 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
4973 SetEmptySelection(position
);
4975 position
= MovePositionOutsideChar(position
, currentPos
- position
);
4976 if (pdoc
->InsertString(position
, value
)) {
4977 SetSelection(position
+ istrlen(value
), position
);
4979 pdoc
->EndUndoAction();
4981 } else if (inDragDrop
) {
4982 SetEmptySelection(position
);
4987 * @return -1 if given position is before the selection,
4988 * 1 if position is after the selection,
4989 * 0 if position is inside the selection,
4991 int Editor::PositionInSelection(int pos
) {
4992 pos
= MovePositionOutsideChar(pos
, currentPos
- pos
);
4993 if (pos
< SelectionStart()) {
4996 if (pos
> SelectionEnd()) {
4999 if (selType
== selStream
) {
5002 SelectionLineIterator
lineIterator(this);
5003 lineIterator
.SetAt(pdoc
->LineFromPosition(pos
));
5004 if (pos
< lineIterator
.startPos
) {
5006 } else if (pos
> lineIterator
.endPos
) {
5014 bool Editor::PointInSelection(Point pt
) {
5015 int pos
= PositionFromLocation(pt
);
5016 if (0 == PositionInSelection(pos
)) {
5017 // Probably inside, but we must make a finer test
5018 int selStart
, selEnd
;
5019 if (selType
== selStream
) {
5020 selStart
= SelectionStart();
5021 selEnd
= SelectionEnd();
5023 SelectionLineIterator
lineIterator(this);
5024 lineIterator
.SetAt(pdoc
->LineFromPosition(pos
));
5025 selStart
= lineIterator
.startPos
;
5026 selEnd
= lineIterator
.endPos
;
5028 if (pos
== selStart
) {
5029 // see if just before selection
5030 Point locStart
= LocationFromPosition(pos
);
5031 if (pt
.x
< locStart
.x
) {
5035 if (pos
== selEnd
) {
5036 // see if just after selection
5037 Point locEnd
= LocationFromPosition(pos
);
5038 if (pt
.x
> locEnd
.x
) {
5047 bool Editor::PointInSelMargin(Point pt
) {
5048 // Really means: "Point in a margin"
5049 if (vs
.fixedColumnWidth
> 0) { // There is a margin
5050 PRectangle rcSelMargin
= GetClientRectangle();
5051 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
5052 return rcSelMargin
.Contains(pt
);
5058 void Editor::LineSelection(int lineCurrent_
, int lineAnchor_
) {
5059 if (lineAnchor_
< lineCurrent_
) {
5060 SetSelection(pdoc
->LineStart(lineCurrent_
+ 1),
5061 pdoc
->LineStart(lineAnchor_
));
5062 } else if (lineAnchor_
> lineCurrent_
) {
5063 SetSelection(pdoc
->LineStart(lineCurrent_
),
5064 pdoc
->LineStart(lineAnchor_
+ 1));
5065 } else { // Same line, select it
5066 SetSelection(pdoc
->LineStart(lineAnchor_
+ 1),
5067 pdoc
->LineStart(lineAnchor_
));
5071 void Editor::DwellEnd(bool mouseMoved
) {
5073 ticksToDwell
= dwellDelay
;
5075 ticksToDwell
= SC_TIME_FOREVER
;
5076 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
5078 NotifyDwelling(ptMouseLast
, dwelling
);
5082 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
5083 //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
5085 int newPos
= PositionFromLocation(pt
);
5086 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
5088 moveExtendsSelection
= false;
5090 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
5094 bool inSelMargin
= PointInSelMargin(pt
);
5095 if (shift
& !inSelMargin
) {
5096 SetSelection(newPos
);
5098 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
5099 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
5100 SetMouseCapture(true);
5101 SetEmptySelection(newPos
);
5102 bool doubleClick
= false;
5103 // Stop mouse button bounce changing selection type
5104 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
5105 if (selectionType
== selChar
) {
5106 selectionType
= selWord
;
5108 } else if (selectionType
== selWord
) {
5109 selectionType
= selLine
;
5111 selectionType
= selChar
;
5112 originalAnchorPos
= currentPos
;
5116 if (selectionType
== selWord
) {
5117 if (currentPos
>= originalAnchorPos
) { // Moved forward
5118 SetSelection(pdoc
->ExtendWordSelect(currentPos
, 1),
5119 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
5120 } else { // Moved backward
5121 SetSelection(pdoc
->ExtendWordSelect(currentPos
, -1),
5122 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
5124 } else if (selectionType
== selLine
) {
5125 lineAnchor
= LineFromLocation(pt
);
5126 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
5127 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
5129 SetEmptySelection(currentPos
);
5131 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
5133 NotifyDoubleClick(pt
, shift
);
5134 if (PositionIsHotspot(newPos
))
5135 NotifyHotSpotDoubleClicked(newPos
, shift
, ctrl
, alt
);
5137 } else { // Single click
5139 selType
= selStream
;
5142 lastClickTime
= curTime
;
5146 lineAnchor
= LineFromLocation(pt
);
5147 // Single click in margin: select whole line
5148 LineSelection(lineAnchor
, lineAnchor
);
5149 SetSelection(pdoc
->LineStart(lineAnchor
+ 1),
5150 pdoc
->LineStart(lineAnchor
));
5152 // Single shift+click in margin: select from line anchor to clicked line
5153 if (anchor
> currentPos
)
5154 lineAnchor
= pdoc
->LineFromPosition(anchor
- 1);
5156 lineAnchor
= pdoc
->LineFromPosition(anchor
);
5157 int lineStart
= LineFromLocation(pt
);
5158 LineSelection(lineStart
, lineAnchor
);
5159 //lineAnchor = lineStart; // Keep the same anchor for ButtonMove
5162 SetDragPosition(invalidPosition
);
5163 SetMouseCapture(true);
5164 selectionType
= selLine
;
5166 if (PointIsHotspot(pt
)) {
5167 NotifyHotSpotClicked(newPos
, shift
, ctrl
, alt
);
5170 inDragDrop
= PointInSelection(pt
) && !SelectionEmpty();
5173 SetMouseCapture(false);
5174 SetDragPosition(newPos
);
5175 CopySelectionRange(&drag
);
5178 SetDragPosition(invalidPosition
);
5179 SetMouseCapture(true);
5181 SetEmptySelection(newPos
);
5183 selType
= alt
? selRectangle
: selStream
;
5184 selectionType
= selChar
;
5185 originalAnchorPos
= currentPos
;
5186 SetRectangularRange();
5190 lastClickTime
= curTime
;
5192 ShowCaretAtCurrentPosition();
5195 bool Editor::PositionIsHotspot(int position
) {
5196 return vs
.styles
[pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
].hotspot
;
5199 bool Editor::PointIsHotspot(Point pt
) {
5200 int pos
= PositionFromLocationClose(pt
);
5201 if (pos
== INVALID_POSITION
)
5203 return PositionIsHotspot(pos
);
5206 void Editor::SetHotSpotRange(Point
*pt
) {
5208 int pos
= PositionFromLocation(*pt
);
5210 // If we don't limit this to word characters then the
5211 // range can encompass more than the run range and then
5212 // the underline will not be drawn properly.
5213 int hsStart_
= pdoc
->ExtendStyleRange(pos
, -1, vs
.hotspotSingleLine
);
5214 int hsEnd_
= pdoc
->ExtendStyleRange(pos
, 1, vs
.hotspotSingleLine
);
5216 // Only invalidate the range if the hotspot range has changed...
5217 if (hsStart_
!= hsStart
|| hsEnd_
!= hsEnd
) {
5218 if (hsStart
!= -1) {
5219 InvalidateRange(hsStart
, hsEnd
);
5223 InvalidateRange(hsStart
, hsEnd
);
5226 if (hsStart
!= -1) {
5227 int hsStart_
= hsStart
;
5231 InvalidateRange(hsStart_
, hsEnd_
);
5239 void Editor::GetHotSpotRange(int& hsStart_
, int& hsEnd_
) {
5244 void Editor::ButtonMove(Point pt
) {
5245 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
5249 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
5250 if (HaveMouseCapture()) {
5252 // Slow down autoscrolling/selection
5253 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
5254 if (autoScrollTimer
.ticksToWait
> 0)
5256 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
5259 int movePos
= PositionFromLocation(pt
);
5260 movePos
= MovePositionOutsideChar(movePos
, currentPos
- movePos
);
5262 SetDragPosition(movePos
);
5264 if (selectionType
== selChar
) {
5265 SetSelection(movePos
);
5266 } else if (selectionType
== selWord
) {
5267 // Continue selecting by word
5268 if (movePos
== originalAnchorPos
) { // Didn't move
5269 // No need to do anything. Previously this case was lumped
5270 // in with "Moved forward", but that can be harmful in this
5271 // case: a handler for the NotifyDoubleClick re-adjusts
5272 // the selection for a fancier definition of "word" (for
5273 // example, in Perl it is useful to include the leading
5274 // '$', '%' or '@' on variables for word selection). In this
5275 // the ButtonMove() called via Tick() for auto-scrolling
5276 // could result in the fancier word selection adjustment
5278 } else if (movePos
> originalAnchorPos
) { // Moved forward
5279 SetSelection(pdoc
->ExtendWordSelect(movePos
, 1),
5280 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
5281 } else { // Moved backward
5282 SetSelection(pdoc
->ExtendWordSelect(movePos
, -1),
5283 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
5286 // Continue selecting by line
5287 int lineMove
= LineFromLocation(pt
);
5288 LineSelection(lineMove
, lineAnchor
);
5291 // While dragging to make rectangular selection, we don't want the current
5292 // position to jump to the end of smaller or empty lines.
5293 //xEndSelect = pt.x - vs.fixedColumnWidth + xOffset;
5294 xEndSelect
= XFromPosition(movePos
);
5297 PRectangle rcClient
= GetClientRectangle();
5298 if (pt
.y
> rcClient
.bottom
) {
5299 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
5301 lineMove
= cs
.DisplayFromDoc(pdoc
->LinesTotal() - 1);
5303 ScrollTo(lineMove
- LinesOnScreen() + 5);
5305 } else if (pt
.y
< rcClient
.top
) {
5306 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
5307 ScrollTo(lineMove
- 5);
5310 EnsureCaretVisible(false, false, true);
5312 if (hsStart
!= -1 && !PositionIsHotspot(movePos
))
5313 SetHotSpotRange(NULL
);
5316 if (vs
.fixedColumnWidth
> 0) { // There is a margin
5317 if (PointInSelMargin(pt
)) {
5318 DisplayCursor(Window::cursorReverseArrow
);
5319 return; // No need to test for selection
5322 // Display regular (drag) cursor over selection
5323 if (PointInSelection(pt
) && !SelectionEmpty()) {
5324 DisplayCursor(Window::cursorArrow
);
5325 } else if (PointIsHotspot(pt
)) {
5326 DisplayCursor(Window::cursorHand
);
5327 SetHotSpotRange(&pt
);
5329 DisplayCursor(Window::cursorText
);
5330 SetHotSpotRange(NULL
);
5335 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
5336 //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
5337 if (HaveMouseCapture()) {
5338 if (PointInSelMargin(pt
)) {
5339 DisplayCursor(Window::cursorReverseArrow
);
5341 DisplayCursor(Window::cursorText
);
5342 SetHotSpotRange(NULL
);
5345 SetMouseCapture(false);
5346 int newPos
= PositionFromLocation(pt
);
5347 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
5349 int selStart
= SelectionStart();
5350 int selEnd
= SelectionEnd();
5351 if (selStart
< selEnd
) {
5354 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5355 SetSelection(newPos
, newPos
+ drag
.len
);
5357 } else if (newPos
< selStart
) {
5358 pdoc
->DeleteChars(selStart
, drag
.len
);
5359 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5360 SetSelection(newPos
, newPos
+ drag
.len
);
5362 } else if (newPos
> selEnd
) {
5363 pdoc
->DeleteChars(selStart
, drag
.len
);
5365 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5366 SetSelection(newPos
, newPos
+ drag
.len
);
5369 SetEmptySelection(newPos
);
5373 selectionType
= selChar
;
5376 if (selectionType
== selChar
) {
5377 SetSelection(newPos
);
5380 SetRectangularRange();
5381 lastClickTime
= curTime
;
5384 if (selType
== selStream
) {
5388 EnsureCaretVisible(false);
5392 // Called frequently to perform background UI including
5393 // caret blinking and automatic scrolling.
5394 void Editor::Tick() {
5395 if (HaveMouseCapture()) {
5397 ButtonMove(ptMouseLast
);
5399 if (caret
.period
> 0) {
5400 timer
.ticksToWait
-= timer
.tickSize
;
5401 if (timer
.ticksToWait
<= 0) {
5402 caret
.on
= !caret
.on
;
5403 timer
.ticksToWait
= caret
.period
;
5409 if ((dwellDelay
< SC_TIME_FOREVER
) &&
5410 (ticksToDwell
> 0) &&
5411 (!HaveMouseCapture())) {
5412 ticksToDwell
-= timer
.tickSize
;
5413 if (ticksToDwell
<= 0) {
5415 NotifyDwelling(ptMouseLast
, dwelling
);
5420 bool Editor::Idle() {
5424 bool wrappingDone
= wrapState
== eWrapNone
;
5426 if (!wrappingDone
) {
5427 // Wrap lines during idle.
5428 WrapLines(false, -1);
5430 if (wrapStart
== wrapEnd
)
5431 wrappingDone
= true;
5434 // Add more idle things to do here, but make sure idleDone is
5435 // set correctly before the function returns. returning
5436 // false will stop calling this idle funtion until SetIdle() is
5439 idleDone
= wrappingDone
; // && thatDone && theOtherThingDone...
5444 void Editor::SetFocusState(bool focusState
) {
5445 hasFocus
= focusState
;
5446 NotifyFocus(hasFocus
);
5448 ShowCaretAtCurrentPosition();
5455 bool Editor::PaintContains(PRectangle rc
) {
5456 return rcPaint
.Contains(rc
);
5459 bool Editor::PaintContainsMargin() {
5460 PRectangle rcSelMargin
= GetClientRectangle();
5461 rcSelMargin
.right
= vs
.fixedColumnWidth
;
5462 return PaintContains(rcSelMargin
);
5465 void Editor::CheckForChangeOutsidePaint(Range r
) {
5466 if (paintState
== painting
&& !paintingAllText
) {
5467 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
5471 PRectangle rcRange
= RectangleFromRange(r
.start
, r
.end
);
5472 PRectangle rcText
= GetTextRectangle();
5473 if (rcRange
.top
< rcText
.top
) {
5474 rcRange
.top
= rcText
.top
;
5476 if (rcRange
.bottom
> rcText
.bottom
) {
5477 rcRange
.bottom
= rcText
.bottom
;
5480 if (!PaintContains(rcRange
)) {
5486 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
5487 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
5488 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
5489 CheckForChangeOutsidePaint(Range(braces
[0]));
5490 CheckForChangeOutsidePaint(Range(pos0
));
5493 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
5494 CheckForChangeOutsidePaint(Range(braces
[1]));
5495 CheckForChangeOutsidePaint(Range(pos1
));
5498 bracesMatchStyle
= matchStyle
;
5499 if (paintState
== notPainting
) {
5505 void Editor::SetDocPointer(Document
*document
) {
5506 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
5507 pdoc
->RemoveWatcher(this, 0);
5509 if (document
== NULL
) {
5510 pdoc
= new Document();
5516 // Ensure all positions within document
5517 selType
= selStream
;
5523 braces
[0] = invalidPosition
;
5524 braces
[1] = invalidPosition
;
5526 // Reset the contraction state to fully shown.
5528 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
5532 pdoc
->AddWatcher(this, 0);
5538 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
5540 void Editor::Expand(int &line
, bool doExpand
) {
5541 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5543 while (line
<= lineMaxSubord
) {
5545 cs
.SetVisible(line
, line
, true);
5546 int level
= pdoc
->GetLevel(line
);
5547 if (level
& SC_FOLDLEVELHEADERFLAG
) {
5548 if (doExpand
&& cs
.GetExpanded(line
)) {
5551 Expand(line
, false);
5559 void Editor::ToggleContraction(int line
) {
5561 if ((pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) == 0) {
5562 line
= pdoc
->GetFoldParent(line
);
5567 if (cs
.GetExpanded(line
)) {
5568 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5569 cs
.SetExpanded(line
, 0);
5570 if (lineMaxSubord
> line
) {
5571 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
5573 int lineCurrent
= pdoc
->LineFromPosition(currentPos
);
5574 if (lineCurrent
> line
&& lineCurrent
<= lineMaxSubord
) {
5575 // This does not re-expand the fold
5576 EnsureCaretVisible();
5584 if (!(cs
.GetVisible(line
))) {
5585 EnsureLineVisible(line
, false);
5588 cs
.SetExpanded(line
, 1);
5597 * Recurse up from this line to find any folds that prevent this line from being visible
5598 * and unfold them all.
5600 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
5602 // In case in need of wrapping to ensure DisplayFromDoc works.
5603 WrapLines(true, -1);
5605 if (!cs
.GetVisible(lineDoc
)) {
5606 int lineParent
= pdoc
->GetFoldParent(lineDoc
);
5607 if (lineParent
>= 0) {
5608 if (lineDoc
!= lineParent
)
5609 EnsureLineVisible(lineParent
, enforcePolicy
);
5610 if (!cs
.GetExpanded(lineParent
)) {
5611 cs
.SetExpanded(lineParent
, 1);
5612 Expand(lineParent
, true);
5618 if (enforcePolicy
) {
5619 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
5620 if (visiblePolicy
& VISIBLE_SLOP
) {
5621 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
5622 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
5623 SetVerticalScrollPos();
5625 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
5626 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
5627 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
5628 SetVerticalScrollPos();
5632 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
5633 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
5634 SetVerticalScrollPos();
5641 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
5642 pdoc
->BeginUndoAction();
5644 length
= istrlen(text
);
5645 if (replacePatterns
) {
5646 text
= pdoc
->SubstituteByPosition(text
, &length
);
5650 if (targetStart
!= targetEnd
)
5651 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
5652 targetEnd
= targetStart
;
5653 pdoc
->InsertString(targetStart
, text
, length
);
5654 targetEnd
= targetStart
+ length
;
5655 pdoc
->EndUndoAction();
5659 bool Editor::IsUnicodeMode() const {
5660 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
5663 int Editor::CodePage() const {
5665 return pdoc
->dbcsCodePage
;
5670 int Editor::WrapCount(int line
) {
5671 AutoSurface
surface(this);
5672 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
5674 if (surface
&& ll
) {
5675 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
5682 static bool ValidMargin(unsigned long wParam
) {
5683 return wParam
< ViewStyle::margins
;
5686 static char *CharPtrFromSPtr(sptr_t lParam
) {
5687 return reinterpret_cast<char *>(lParam
);
5690 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5691 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
5693 // Optional macro recording hook
5695 NotifyMacroRecord(iMessage
, wParam
, lParam
);
5701 return pdoc
->Length() + 1;
5704 char *ptr
= CharPtrFromSPtr(lParam
);
5705 unsigned int iChar
= 0;
5706 for (; iChar
< wParam
- 1; iChar
++)
5707 ptr
[iChar
] = pdoc
->CharAt(iChar
);
5715 pdoc
->BeginUndoAction();
5716 pdoc
->DeleteChars(0, pdoc
->Length());
5717 SetEmptySelection(0);
5718 pdoc
->InsertString(0, CharPtrFromSPtr(lParam
));
5719 pdoc
->EndUndoAction();
5723 case SCI_GETTEXTLENGTH
:
5724 return pdoc
->Length();
5736 CopyRangeToClipboard(wParam
, lParam
);
5740 CopyText(wParam
, CharPtrFromSPtr(lParam
));
5748 EnsureCaretVisible();
5754 EnsureCaretVisible();
5763 return (pdoc
->CanUndo() && !pdoc
->IsReadOnly()) ? 1 : 0;
5765 case SCI_EMPTYUNDOBUFFER
:
5766 pdoc
->DeleteUndoHistory();
5769 case SCI_GETFIRSTVISIBLELINE
:
5772 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
5773 int lineStart
= pdoc
->LineStart(wParam
);
5774 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
5776 return lineEnd
- lineStart
;
5778 char *ptr
= CharPtrFromSPtr(lParam
);
5780 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
5781 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5786 case SCI_GETLINECOUNT
:
5787 if (pdoc
->LinesTotal() == 0)
5790 return pdoc
->LinesTotal();
5793 return !pdoc
->IsSavePoint();
5796 int nStart
= static_cast<int>(wParam
);
5797 int nEnd
= static_cast<int>(lParam
);
5799 nEnd
= pdoc
->Length();
5801 nStart
= nEnd
; // Remove selection
5802 selType
= selStream
;
5803 SetSelection(nEnd
, nStart
);
5804 EnsureCaretVisible();
5808 case SCI_GETSELTEXT
: {
5810 if (selType
== selStream
) {
5811 return 1 + SelectionEnd() - SelectionStart();
5813 // TODO: why is selLines handled the slow way?
5815 int extraCharsPerLine
= 0;
5816 if (selType
!= selLines
)
5817 extraCharsPerLine
= (pdoc
->eolMode
== SC_EOL_CRLF
) ? 2 : 1;
5818 SelectionLineIterator
lineIterator(this);
5819 while (lineIterator
.Iterate()) {
5820 size
+= lineIterator
.endPos
+ extraCharsPerLine
- lineIterator
.startPos
;
5826 SelectionText selectedText
;
5827 CopySelectionRange(&selectedText
);
5828 char *ptr
= CharPtrFromSPtr(lParam
);
5830 if (selectedText
.len
) {
5831 for (; iChar
< selectedText
.len
; iChar
++)
5832 ptr
[iChar
] = selectedText
.s
[iChar
];
5839 case SCI_LINEFROMPOSITION
:
5840 if (static_cast<int>(wParam
) < 0)
5842 return pdoc
->LineFromPosition(wParam
);
5844 case SCI_POSITIONFROMLINE
:
5845 if (static_cast<int>(wParam
) < 0)
5846 wParam
= pdoc
->LineFromPosition(SelectionStart());
5848 return 0; // Even if there is no text, there is a first line that starts at 0
5849 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
5851 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
5853 return pdoc
->LineStart(wParam
);
5855 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
5856 case SCI_LINELENGTH
:
5857 if ((static_cast<int>(wParam
) < 0) ||
5858 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
5860 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
5862 case SCI_REPLACESEL
: {
5865 pdoc
->BeginUndoAction();
5867 char *replacement
= CharPtrFromSPtr(lParam
);
5868 pdoc
->InsertString(currentPos
, replacement
);
5869 pdoc
->EndUndoAction();
5870 SetEmptySelection(currentPos
+ istrlen(replacement
));
5871 EnsureCaretVisible();
5875 case SCI_SETTARGETSTART
:
5876 targetStart
= wParam
;
5879 case SCI_GETTARGETSTART
:
5882 case SCI_SETTARGETEND
:
5886 case SCI_GETTARGETEND
:
5889 case SCI_TARGETFROMSELECTION
:
5890 if (currentPos
< anchor
) {
5891 targetStart
= currentPos
;
5894 targetStart
= anchor
;
5895 targetEnd
= currentPos
;
5899 case SCI_REPLACETARGET
:
5900 PLATFORM_ASSERT(lParam
);
5901 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), wParam
);
5903 case SCI_REPLACETARGETRE
:
5904 PLATFORM_ASSERT(lParam
);
5905 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), wParam
);
5907 case SCI_SEARCHINTARGET
:
5908 PLATFORM_ASSERT(lParam
);
5909 return SearchInTarget(CharPtrFromSPtr(lParam
), wParam
);
5911 case SCI_SETSEARCHFLAGS
:
5912 searchFlags
= wParam
;
5915 case SCI_GETSEARCHFLAGS
:
5918 case SCI_POSITIONBEFORE
:
5919 return pdoc
->MovePositionOutsideChar(wParam
-1, -1, true);
5921 case SCI_POSITIONAFTER
:
5922 return pdoc
->MovePositionOutsideChar(wParam
+1, 1, true);
5924 case SCI_LINESCROLL
:
5925 ScrollTo(topLine
+ lParam
);
5926 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
5929 case SCI_SETXOFFSET
:
5931 SetHorizontalScrollPos();
5935 case SCI_GETXOFFSET
:
5938 case SCI_CHOOSECARETX
:
5942 case SCI_SCROLLCARET
:
5943 EnsureCaretVisible();
5946 case SCI_SETREADONLY
:
5947 pdoc
->SetReadOnly(wParam
!= 0);
5950 case SCI_GETREADONLY
:
5951 return pdoc
->IsReadOnly();
5956 case SCI_POINTXFROMPOSITION
:
5960 Point pt
= LocationFromPosition(lParam
);
5964 case SCI_POINTYFROMPOSITION
:
5968 Point pt
= LocationFromPosition(lParam
);
5973 return FindText(wParam
, lParam
);
5975 case SCI_GETTEXTRANGE
: {
5978 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
5979 int cpMax
= tr
->chrg
.cpMax
;
5981 cpMax
= pdoc
->Length();
5982 PLATFORM_ASSERT(cpMax
<= pdoc
->Length());
5983 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
5984 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
5985 // Spec says copied text is terminated with a NUL
5986 tr
->lpstrText
[len
] = '\0';
5987 return len
; // Not including NUL
5990 case SCI_HIDESELECTION
:
5991 hideSelection
= wParam
!= 0;
5995 case SCI_FORMATRANGE
:
5996 return FormatRange(wParam
!= 0, reinterpret_cast<RangeToFormat
*>(lParam
));
5998 case SCI_GETMARGINLEFT
:
5999 return vs
.leftMarginWidth
;
6001 case SCI_GETMARGINRIGHT
:
6002 return vs
.rightMarginWidth
;
6004 case SCI_SETMARGINLEFT
:
6005 vs
.leftMarginWidth
= lParam
;
6006 InvalidateStyleRedraw();
6009 case SCI_SETMARGINRIGHT
:
6010 vs
.rightMarginWidth
= lParam
;
6011 InvalidateStyleRedraw();
6014 // Control specific mesages
6019 pdoc
->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam
), wParam
);
6020 SetEmptySelection(currentPos
+ wParam
);
6024 case SCI_ADDSTYLEDTEXT
: {
6027 pdoc
->InsertStyledString(CurrentPosition() * 2, CharPtrFromSPtr(lParam
), wParam
);
6028 SetEmptySelection(currentPos
+ wParam
/ 2);
6032 case SCI_INSERTTEXT
: {
6035 int insertPos
= wParam
;
6036 if (static_cast<int>(wParam
) == -1)
6037 insertPos
= CurrentPosition();
6038 int newCurrent
= CurrentPosition();
6039 char *sz
= CharPtrFromSPtr(lParam
);
6040 pdoc
->InsertString(insertPos
, sz
);
6041 if (newCurrent
> insertPos
)
6042 newCurrent
+= istrlen(sz
);
6043 SetEmptySelection(newCurrent
);
6047 case SCI_APPENDTEXT
:
6048 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), wParam
);
6055 case SCI_CLEARDOCUMENTSTYLE
:
6056 ClearDocumentStyle();
6059 case SCI_SETUNDOCOLLECTION
:
6060 pdoc
->SetUndoCollection(wParam
!= 0);
6063 case SCI_GETUNDOCOLLECTION
:
6064 return pdoc
->IsCollectingUndo();
6066 case SCI_BEGINUNDOACTION
:
6067 pdoc
->BeginUndoAction();
6070 case SCI_ENDUNDOACTION
:
6071 pdoc
->EndUndoAction();
6074 case SCI_GETCARETPERIOD
:
6075 return caret
.period
;
6077 case SCI_SETCARETPERIOD
:
6078 caret
.period
= wParam
;
6081 case SCI_SETWORDCHARS
: {
6082 pdoc
->SetDefaultCharClasses(false);
6085 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccWord
);
6089 case SCI_SETWHITESPACECHARS
: {
6092 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccSpace
);
6096 case SCI_SETCHARSDEFAULT
:
6097 pdoc
->SetDefaultCharClasses(true);
6101 return pdoc
->Length();
6104 pdoc
->Allocate(wParam
);
6108 return pdoc
->CharAt(wParam
);
6110 case SCI_SETCURRENTPOS
:
6111 SetSelection(wParam
, anchor
);
6114 case SCI_GETCURRENTPOS
:
6118 SetSelection(currentPos
, wParam
);
6124 case SCI_SETSELECTIONSTART
:
6125 SetSelection(Platform::Maximum(currentPos
, wParam
), wParam
);
6128 case SCI_GETSELECTIONSTART
:
6129 return Platform::Minimum(anchor
, currentPos
);
6131 case SCI_SETSELECTIONEND
:
6132 SetSelection(wParam
, Platform::Minimum(anchor
, wParam
));
6135 case SCI_GETSELECTIONEND
:
6136 return Platform::Maximum(anchor
, currentPos
);
6138 case SCI_SETPRINTMAGNIFICATION
:
6139 printMagnification
= wParam
;
6142 case SCI_GETPRINTMAGNIFICATION
:
6143 return printMagnification
;
6145 case SCI_SETPRINTCOLOURMODE
:
6146 printColourMode
= wParam
;
6149 case SCI_GETPRINTCOLOURMODE
:
6150 return printColourMode
;
6152 case SCI_SETPRINTWRAPMODE
:
6153 printWrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
6156 case SCI_GETPRINTWRAPMODE
:
6157 return printWrapState
;
6159 case SCI_GETSTYLEAT
:
6160 if (static_cast<int>(wParam
) >= pdoc
->Length())
6163 return pdoc
->StyleAt(wParam
);
6173 case SCI_SETSAVEPOINT
:
6174 pdoc
->SetSavePoint();
6177 case SCI_GETSTYLEDTEXT
: {
6180 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
6182 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
6183 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
6184 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
6186 tr
->lpstrText
[iPlace
] = '\0';
6187 tr
->lpstrText
[iPlace
+ 1] = '\0';
6192 return (pdoc
->CanRedo() && !pdoc
->IsReadOnly()) ? 1 : 0;
6194 case SCI_MARKERLINEFROMHANDLE
:
6195 return pdoc
->LineFromHandle(wParam
);
6197 case SCI_MARKERDELETEHANDLE
:
6198 pdoc
->DeleteMarkFromHandle(wParam
);
6202 return vs
.viewWhitespace
;
6205 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
6209 case SCI_POSITIONFROMPOINT
:
6210 return PositionFromLocation(Point(wParam
, lParam
));
6212 case SCI_POSITIONFROMPOINTCLOSE
:
6213 return PositionFromLocationClose(Point(wParam
, lParam
));
6220 SetEmptySelection(wParam
);
6221 EnsureCaretVisible();
6225 case SCI_GETCURLINE
: {
6226 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
6227 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
6228 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
6230 return 1 + lineEnd
- lineStart
;
6232 PLATFORM_ASSERT(wParam
> 0);
6233 char *ptr
= CharPtrFromSPtr(lParam
);
6234 unsigned int iPlace
= 0;
6235 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
6236 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
6239 return currentPos
- lineStart
;
6242 case SCI_GETENDSTYLED
:
6243 return pdoc
->GetEndStyled();
6245 case SCI_GETEOLMODE
:
6246 return pdoc
->eolMode
;
6248 case SCI_SETEOLMODE
:
6249 pdoc
->eolMode
= wParam
;
6252 case SCI_STARTSTYLING
:
6253 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
6256 case SCI_SETSTYLING
:
6257 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
6260 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
6263 pdoc
->SetStyles(wParam
, CharPtrFromSPtr(lParam
));
6266 case SCI_SETBUFFEREDDRAW
:
6267 bufferedDraw
= wParam
!= 0;
6270 case SCI_GETBUFFEREDDRAW
:
6271 return bufferedDraw
;
6273 case SCI_GETTWOPHASEDRAW
:
6274 return twoPhaseDraw
;
6276 case SCI_SETTWOPHASEDRAW
:
6277 twoPhaseDraw
= wParam
!= 0;
6278 InvalidateStyleRedraw();
6281 case SCI_SETTABWIDTH
:
6283 pdoc
->tabInChars
= wParam
;
6284 if (pdoc
->indentInChars
== 0)
6285 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6287 InvalidateStyleRedraw();
6290 case SCI_GETTABWIDTH
:
6291 return pdoc
->tabInChars
;
6294 pdoc
->indentInChars
= wParam
;
6295 if (pdoc
->indentInChars
!= 0)
6296 pdoc
->actualIndentInChars
= pdoc
->indentInChars
;
6298 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6299 InvalidateStyleRedraw();
6303 return pdoc
->indentInChars
;
6305 case SCI_SETUSETABS
:
6306 pdoc
->useTabs
= wParam
!= 0;
6307 InvalidateStyleRedraw();
6310 case SCI_GETUSETABS
:
6311 return pdoc
->useTabs
;
6313 case SCI_SETLINEINDENTATION
:
6314 pdoc
->SetLineIndentation(wParam
, lParam
);
6317 case SCI_GETLINEINDENTATION
:
6318 return pdoc
->GetLineIndentation(wParam
);
6320 case SCI_GETLINEINDENTPOSITION
:
6321 return pdoc
->GetLineIndentPosition(wParam
);
6323 case SCI_SETTABINDENTS
:
6324 pdoc
->tabIndents
= wParam
!= 0;
6327 case SCI_GETTABINDENTS
:
6328 return pdoc
->tabIndents
;
6330 case SCI_SETBACKSPACEUNINDENTS
:
6331 pdoc
->backspaceUnindents
= wParam
!= 0;
6334 case SCI_GETBACKSPACEUNINDENTS
:
6335 return pdoc
->backspaceUnindents
;
6337 case SCI_SETMOUSEDWELLTIME
:
6338 dwellDelay
= wParam
;
6339 ticksToDwell
= dwellDelay
;
6342 case SCI_GETMOUSEDWELLTIME
:
6345 case SCI_WORDSTARTPOSITION
:
6346 return pdoc
->ExtendWordSelect(wParam
, -1, lParam
!= 0);
6348 case SCI_WORDENDPOSITION
:
6349 return pdoc
->ExtendWordSelect(wParam
, 1, lParam
!= 0);
6351 case SCI_SETWRAPMODE
:
6354 wrapState
= eWrapWord
;
6357 wrapState
= eWrapChar
;
6360 wrapState
= eWrapNone
;
6364 InvalidateStyleRedraw();
6365 ReconfigureScrollBars();
6368 case SCI_GETWRAPMODE
:
6371 case SCI_SETWRAPVISUALFLAGS
:
6372 wrapVisualFlags
= wParam
;
6373 actualWrapVisualStartIndent
= wrapVisualStartIndent
;
6374 if ((wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) && (actualWrapVisualStartIndent
== 0))
6375 actualWrapVisualStartIndent
= 1; // must indent to show start visual
6376 InvalidateStyleRedraw();
6377 ReconfigureScrollBars();
6380 case SCI_GETWRAPVISUALFLAGS
:
6381 return wrapVisualFlags
;
6383 case SCI_SETWRAPVISUALFLAGSLOCATION
:
6384 wrapVisualFlagsLocation
= wParam
;
6385 InvalidateStyleRedraw();
6388 case SCI_GETWRAPVISUALFLAGSLOCATION
:
6389 return wrapVisualFlagsLocation
;
6391 case SCI_SETWRAPSTARTINDENT
:
6392 wrapVisualStartIndent
= wParam
;
6393 actualWrapVisualStartIndent
= wrapVisualStartIndent
;
6394 if ((wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) && (actualWrapVisualStartIndent
== 0))
6395 actualWrapVisualStartIndent
= 1; // must indent to show start visual
6396 InvalidateStyleRedraw();
6397 ReconfigureScrollBars();
6400 case SCI_GETWRAPSTARTINDENT
:
6401 return wrapVisualStartIndent
;
6403 case SCI_SETLAYOUTCACHE
:
6404 llc
.SetLevel(wParam
);
6407 case SCI_GETLAYOUTCACHE
:
6408 return llc
.GetLevel();
6410 case SCI_SETSCROLLWIDTH
:
6411 PLATFORM_ASSERT(wParam
> 0);
6412 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
6413 scrollWidth
= wParam
;
6418 case SCI_GETSCROLLWIDTH
:
6425 case SCI_LINESSPLIT
:
6430 PLATFORM_ASSERT(wParam
<= STYLE_MAX
);
6431 PLATFORM_ASSERT(lParam
);
6432 return TextWidth(wParam
, CharPtrFromSPtr(lParam
));
6434 case SCI_TEXTHEIGHT
:
6435 return vs
.lineHeight
;
6437 case SCI_SETENDATLASTLINE
:
6438 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
6439 if (endAtLastLine
!= (wParam
!= 0)) {
6440 endAtLastLine
= wParam
!= 0;
6445 case SCI_GETENDATLASTLINE
:
6446 return endAtLastLine
;
6448 case SCI_SETCARETSTICKY
:
6449 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
6450 if (caretSticky
!= (wParam
!= 0)) {
6451 caretSticky
= wParam
!= 0;
6455 case SCI_GETCARETSTICKY
:
6458 case SCI_TOGGLECARETSTICKY
:
6459 caretSticky
= !caretSticky
;
6463 return pdoc
->GetColumn(wParam
);
6465 case SCI_FINDCOLUMN
:
6466 return pdoc
->FindColumn(wParam
, lParam
);
6468 case SCI_SETHSCROLLBAR
:
6469 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
6470 horizontalScrollBarVisible
= wParam
!= 0;
6472 ReconfigureScrollBars();
6476 case SCI_GETHSCROLLBAR
:
6477 return horizontalScrollBarVisible
;
6479 case SCI_SETVSCROLLBAR
:
6480 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
6481 verticalScrollBarVisible
= wParam
!= 0;
6483 ReconfigureScrollBars();
6487 case SCI_GETVSCROLLBAR
:
6488 return verticalScrollBarVisible
;
6490 case SCI_SETINDENTATIONGUIDES
:
6491 vs
.viewIndentationGuides
= wParam
!= 0;
6495 case SCI_GETINDENTATIONGUIDES
:
6496 return vs
.viewIndentationGuides
;
6498 case SCI_SETHIGHLIGHTGUIDE
:
6499 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
6500 highlightGuideColumn
= wParam
;
6505 case SCI_GETHIGHLIGHTGUIDE
:
6506 return highlightGuideColumn
;
6508 case SCI_GETLINEENDPOSITION
:
6509 return pdoc
->LineEnd(wParam
);
6511 case SCI_SETCODEPAGE
:
6512 if (ValidCodePage(wParam
)) {
6513 pdoc
->dbcsCodePage
= wParam
;
6514 InvalidateStyleRedraw();
6518 case SCI_GETCODEPAGE
:
6519 return pdoc
->dbcsCodePage
;
6521 case SCI_SETUSEPALETTE
:
6522 palette
.allowRealization
= wParam
!= 0;
6523 InvalidateStyleRedraw();
6526 case SCI_GETUSEPALETTE
:
6527 return palette
.allowRealization
;
6529 // Marker definition and setting
6530 case SCI_MARKERDEFINE
:
6531 if (wParam
<= MARKER_MAX
)
6532 vs
.markers
[wParam
].markType
= lParam
;
6533 InvalidateStyleData();
6536 case SCI_MARKERSETFORE
:
6537 if (wParam
<= MARKER_MAX
)
6538 vs
.markers
[wParam
].fore
.desired
= ColourDesired(lParam
);
6539 InvalidateStyleData();
6542 case SCI_MARKERSETBACK
:
6543 if (wParam
<= MARKER_MAX
)
6544 vs
.markers
[wParam
].back
.desired
= ColourDesired(lParam
);
6545 InvalidateStyleData();
6548 case SCI_MARKERSETALPHA
:
6549 if (wParam
<= MARKER_MAX
)
6550 vs
.markers
[wParam
].alpha
= lParam
;
6551 InvalidateStyleRedraw();
6553 case SCI_MARKERADD
: {
6554 int markerID
= pdoc
->AddMark(wParam
, lParam
);
6557 case SCI_MARKERADDSET
:
6559 pdoc
->AddMarkSet(wParam
, lParam
);
6562 case SCI_MARKERDELETE
:
6563 pdoc
->DeleteMark(wParam
, lParam
);
6566 case SCI_MARKERDELETEALL
:
6567 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
6571 return pdoc
->GetMark(wParam
);
6573 case SCI_MARKERNEXT
: {
6574 int lt
= pdoc
->LinesTotal();
6575 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
6576 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6582 case SCI_MARKERPREVIOUS
: {
6583 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
6584 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6590 case SCI_MARKERDEFINEPIXMAP
:
6591 if (wParam
<= MARKER_MAX
) {
6592 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
6594 InvalidateStyleData();
6598 case SCI_SETMARGINTYPEN
:
6599 if (ValidMargin(wParam
)) {
6600 vs
.ms
[wParam
].style
= lParam
;
6601 InvalidateStyleRedraw();
6605 case SCI_GETMARGINTYPEN
:
6606 if (ValidMargin(wParam
))
6607 return vs
.ms
[wParam
].style
;
6611 case SCI_SETMARGINWIDTHN
:
6612 if (ValidMargin(wParam
)) {
6613 // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
6614 if (vs
.ms
[wParam
].width
!= lParam
) {
6615 vs
.ms
[wParam
].width
= lParam
;
6616 InvalidateStyleRedraw();
6621 case SCI_GETMARGINWIDTHN
:
6622 if (ValidMargin(wParam
))
6623 return vs
.ms
[wParam
].width
;
6627 case SCI_SETMARGINMASKN
:
6628 if (ValidMargin(wParam
)) {
6629 vs
.ms
[wParam
].mask
= lParam
;
6630 InvalidateStyleRedraw();
6634 case SCI_GETMARGINMASKN
:
6635 if (ValidMargin(wParam
))
6636 return vs
.ms
[wParam
].mask
;
6640 case SCI_SETMARGINSENSITIVEN
:
6641 if (ValidMargin(wParam
)) {
6642 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
6643 InvalidateStyleRedraw();
6647 case SCI_GETMARGINSENSITIVEN
:
6648 if (ValidMargin(wParam
))
6649 return vs
.ms
[wParam
].sensitive
? 1 : 0;
6653 case SCI_STYLECLEARALL
:
6655 InvalidateStyleRedraw();
6658 case SCI_STYLESETFORE
:
6659 if (wParam
<= STYLE_MAX
) {
6660 vs
.styles
[wParam
].fore
.desired
= ColourDesired(lParam
);
6661 InvalidateStyleRedraw();
6664 case SCI_STYLESETBACK
:
6665 if (wParam
<= STYLE_MAX
) {
6666 vs
.styles
[wParam
].back
.desired
= ColourDesired(lParam
);
6667 InvalidateStyleRedraw();
6670 case SCI_STYLESETBOLD
:
6671 if (wParam
<= STYLE_MAX
) {
6672 vs
.styles
[wParam
].bold
= lParam
!= 0;
6673 InvalidateStyleRedraw();
6676 case SCI_STYLESETITALIC
:
6677 if (wParam
<= STYLE_MAX
) {
6678 vs
.styles
[wParam
].italic
= lParam
!= 0;
6679 InvalidateStyleRedraw();
6682 case SCI_STYLESETEOLFILLED
:
6683 if (wParam
<= STYLE_MAX
) {
6684 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
6685 InvalidateStyleRedraw();
6688 case SCI_STYLESETSIZE
:
6689 if (wParam
<= STYLE_MAX
) {
6690 vs
.styles
[wParam
].size
= lParam
;
6691 InvalidateStyleRedraw();
6694 case SCI_STYLESETFONT
:
6697 if (wParam
<= STYLE_MAX
) {
6698 vs
.SetStyleFontName(wParam
, CharPtrFromSPtr(lParam
));
6699 InvalidateStyleRedraw();
6702 case SCI_STYLESETUNDERLINE
:
6703 if (wParam
<= STYLE_MAX
) {
6704 vs
.styles
[wParam
].underline
= lParam
!= 0;
6705 InvalidateStyleRedraw();
6708 case SCI_STYLESETCASE
:
6709 if (wParam
<= STYLE_MAX
) {
6710 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
6711 InvalidateStyleRedraw();
6714 case SCI_STYLESETCHARACTERSET
:
6715 if (wParam
<= STYLE_MAX
) {
6716 vs
.styles
[wParam
].characterSet
= lParam
;
6717 InvalidateStyleRedraw();
6720 case SCI_STYLESETVISIBLE
:
6721 if (wParam
<= STYLE_MAX
) {
6722 vs
.styles
[wParam
].visible
= lParam
!= 0;
6723 InvalidateStyleRedraw();
6726 case SCI_STYLESETCHANGEABLE
:
6727 if (wParam
<= STYLE_MAX
) {
6728 vs
.styles
[wParam
].changeable
= lParam
!= 0;
6729 InvalidateStyleRedraw();
6732 case SCI_STYLESETHOTSPOT
:
6733 if (wParam
<= STYLE_MAX
) {
6734 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
6735 InvalidateStyleRedraw();
6739 case SCI_STYLERESETDEFAULT
:
6740 vs
.ResetDefaultStyle();
6741 InvalidateStyleRedraw();
6743 case SCI_SETSTYLEBITS
:
6744 pdoc
->SetStylingBits(wParam
);
6747 case SCI_GETSTYLEBITS
:
6748 return pdoc
->stylingBits
;
6750 case SCI_SETLINESTATE
:
6751 return pdoc
->SetLineState(wParam
, lParam
);
6753 case SCI_GETLINESTATE
:
6754 return pdoc
->GetLineState(wParam
);
6756 case SCI_GETMAXLINESTATE
:
6757 return pdoc
->GetMaxLineState();
6759 case SCI_GETCARETLINEVISIBLE
:
6760 return vs
.showCaretLineBackground
;
6761 case SCI_SETCARETLINEVISIBLE
:
6762 vs
.showCaretLineBackground
= wParam
!= 0;
6763 InvalidateStyleRedraw();
6765 case SCI_GETCARETLINEBACK
:
6766 return vs
.caretLineBackground
.desired
.AsLong();
6767 case SCI_SETCARETLINEBACK
:
6768 vs
.caretLineBackground
.desired
= wParam
;
6769 InvalidateStyleRedraw();
6771 case SCI_GETCARETLINEBACKALPHA
:
6772 return vs
.caretLineAlpha
;
6773 case SCI_SETCARETLINEBACKALPHA
:
6774 vs
.caretLineAlpha
= wParam
;
6775 InvalidateStyleRedraw();
6780 case SCI_VISIBLEFROMDOCLINE
:
6781 return cs
.DisplayFromDoc(wParam
);
6783 case SCI_DOCLINEFROMVISIBLE
:
6784 return cs
.DocFromDisplay(wParam
);
6787 return WrapCount(wParam
);
6789 case SCI_SETFOLDLEVEL
: {
6790 int prev
= pdoc
->SetLevel(wParam
, lParam
);
6796 case SCI_GETFOLDLEVEL
:
6797 return pdoc
->GetLevel(wParam
);
6799 case SCI_GETLASTCHILD
:
6800 return pdoc
->GetLastChild(wParam
, lParam
);
6802 case SCI_GETFOLDPARENT
:
6803 return pdoc
->GetFoldParent(wParam
);
6806 cs
.SetVisible(wParam
, lParam
, true);
6812 cs
.SetVisible(wParam
, lParam
, false);
6817 case SCI_GETLINEVISIBLE
:
6818 return cs
.GetVisible(wParam
);
6820 case SCI_SETFOLDEXPANDED
:
6821 if (cs
.SetExpanded(wParam
, lParam
!= 0)) {
6826 case SCI_GETFOLDEXPANDED
:
6827 return cs
.GetExpanded(wParam
);
6829 case SCI_SETFOLDFLAGS
:
6834 case SCI_TOGGLEFOLD
:
6835 ToggleContraction(wParam
);
6838 case SCI_ENSUREVISIBLE
:
6839 EnsureLineVisible(wParam
, false);
6842 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
6843 EnsureLineVisible(wParam
, true);
6846 case SCI_SEARCHANCHOR
:
6850 case SCI_SEARCHNEXT
:
6851 case SCI_SEARCHPREV
:
6852 return SearchText(iMessage
, wParam
, lParam
);
6854 #ifdef INCLUDE_DEPRECATED_FEATURES
6855 case SCI_SETCARETPOLICY
: // Deprecated
6856 caretXPolicy
= caretYPolicy
= wParam
;
6857 caretXSlop
= caretYSlop
= lParam
;
6861 case SCI_SETXCARETPOLICY
:
6862 caretXPolicy
= wParam
;
6863 caretXSlop
= lParam
;
6866 case SCI_SETYCARETPOLICY
:
6867 caretYPolicy
= wParam
;
6868 caretYSlop
= lParam
;
6871 case SCI_SETVISIBLEPOLICY
:
6872 visiblePolicy
= wParam
;
6873 visibleSlop
= lParam
;
6876 case SCI_LINESONSCREEN
:
6877 return LinesOnScreen();
6879 case SCI_SETSELFORE
:
6880 vs
.selforeset
= wParam
!= 0;
6881 vs
.selforeground
.desired
= ColourDesired(lParam
);
6882 InvalidateStyleRedraw();
6885 case SCI_SETSELBACK
:
6886 vs
.selbackset
= wParam
!= 0;
6887 vs
.selbackground
.desired
= ColourDesired(lParam
);
6888 InvalidateStyleRedraw();
6891 case SCI_SETSELALPHA
:
6892 vs
.selAlpha
= wParam
;
6893 InvalidateStyleRedraw();
6896 case SCI_GETSELALPHA
:
6899 case SCI_SETWHITESPACEFORE
:
6900 vs
.whitespaceForegroundSet
= wParam
!= 0;
6901 vs
.whitespaceForeground
.desired
= ColourDesired(lParam
);
6902 InvalidateStyleRedraw();
6905 case SCI_SETWHITESPACEBACK
:
6906 vs
.whitespaceBackgroundSet
= wParam
!= 0;
6907 vs
.whitespaceBackground
.desired
= ColourDesired(lParam
);
6908 InvalidateStyleRedraw();
6911 case SCI_SETCARETFORE
:
6912 vs
.caretcolour
.desired
= ColourDesired(wParam
);
6913 InvalidateStyleRedraw();
6916 case SCI_GETCARETFORE
:
6917 return vs
.caretcolour
.desired
.AsLong();
6919 case SCI_SETCARETWIDTH
:
6922 else if (wParam
>= 3)
6925 vs
.caretWidth
= wParam
;
6926 InvalidateStyleRedraw();
6929 case SCI_GETCARETWIDTH
:
6930 return vs
.caretWidth
;
6932 case SCI_ASSIGNCMDKEY
:
6933 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6934 Platform::HighShortFromLong(wParam
), lParam
);
6937 case SCI_CLEARCMDKEY
:
6938 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6939 Platform::HighShortFromLong(wParam
), SCI_NULL
);
6942 case SCI_CLEARALLCMDKEYS
:
6946 case SCI_INDICSETSTYLE
:
6947 if (wParam
<= INDIC_MAX
) {
6948 vs
.indicators
[wParam
].style
= lParam
;
6949 InvalidateStyleRedraw();
6953 case SCI_INDICGETSTYLE
:
6954 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
6956 case SCI_INDICSETFORE
:
6957 if (wParam
<= INDIC_MAX
) {
6958 vs
.indicators
[wParam
].fore
.desired
= ColourDesired(lParam
);
6959 InvalidateStyleRedraw();
6963 case SCI_INDICGETFORE
:
6964 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
6967 case SCI_LINEDOWNEXTEND
:
6969 case SCI_PARADOWNEXTEND
:
6971 case SCI_LINEUPEXTEND
:
6973 case SCI_PARAUPEXTEND
:
6975 case SCI_CHARLEFTEXTEND
:
6977 case SCI_CHARRIGHTEXTEND
:
6979 case SCI_WORDLEFTEXTEND
:
6981 case SCI_WORDRIGHTEXTEND
:
6982 case SCI_WORDLEFTEND
:
6983 case SCI_WORDLEFTENDEXTEND
:
6984 case SCI_WORDRIGHTEND
:
6985 case SCI_WORDRIGHTENDEXTEND
:
6987 case SCI_HOMEEXTEND
:
6989 case SCI_LINEENDEXTEND
:
6991 case SCI_HOMEWRAPEXTEND
:
6992 case SCI_LINEENDWRAP
:
6993 case SCI_LINEENDWRAPEXTEND
:
6994 case SCI_DOCUMENTSTART
:
6995 case SCI_DOCUMENTSTARTEXTEND
:
6996 case SCI_DOCUMENTEND
:
6997 case SCI_DOCUMENTENDEXTEND
:
6999 case SCI_STUTTEREDPAGEUP
:
7000 case SCI_STUTTEREDPAGEUPEXTEND
:
7001 case SCI_STUTTEREDPAGEDOWN
:
7002 case SCI_STUTTEREDPAGEDOWNEXTEND
:
7005 case SCI_PAGEUPEXTEND
:
7007 case SCI_PAGEDOWNEXTEND
:
7008 case SCI_EDITTOGGLEOVERTYPE
:
7010 case SCI_DELETEBACK
:
7016 case SCI_VCHOMEEXTEND
:
7017 case SCI_VCHOMEWRAP
:
7018 case SCI_VCHOMEWRAPEXTEND
:
7021 case SCI_DELWORDLEFT
:
7022 case SCI_DELWORDRIGHT
:
7023 case SCI_DELLINELEFT
:
7024 case SCI_DELLINERIGHT
:
7027 case SCI_LINEDELETE
:
7028 case SCI_LINETRANSPOSE
:
7029 case SCI_LINEDUPLICATE
:
7032 case SCI_LINESCROLLDOWN
:
7033 case SCI_LINESCROLLUP
:
7034 case SCI_WORDPARTLEFT
:
7035 case SCI_WORDPARTLEFTEXTEND
:
7036 case SCI_WORDPARTRIGHT
:
7037 case SCI_WORDPARTRIGHTEXTEND
:
7038 case SCI_DELETEBACKNOTLINE
:
7039 case SCI_HOMEDISPLAY
:
7040 case SCI_HOMEDISPLAYEXTEND
:
7041 case SCI_LINEENDDISPLAY
:
7042 case SCI_LINEENDDISPLAYEXTEND
:
7043 case SCI_LINEDOWNRECTEXTEND
:
7044 case SCI_LINEUPRECTEXTEND
:
7045 case SCI_CHARLEFTRECTEXTEND
:
7046 case SCI_CHARRIGHTRECTEXTEND
:
7047 case SCI_HOMERECTEXTEND
:
7048 case SCI_VCHOMERECTEXTEND
:
7049 case SCI_LINEENDRECTEXTEND
:
7050 case SCI_PAGEUPRECTEXTEND
:
7051 case SCI_PAGEDOWNRECTEXTEND
:
7052 case SCI_SELECTIONDUPLICATE
:
7053 return KeyCommand(iMessage
);
7055 case SCI_BRACEHIGHLIGHT
:
7056 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
7059 case SCI_BRACEBADLIGHT
:
7060 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
7063 case SCI_BRACEMATCH
:
7064 // wParam is position of char to find brace for,
7065 // lParam is maximum amount of text to restyle to find it
7066 return pdoc
->BraceMatch(wParam
, lParam
);
7068 case SCI_GETVIEWEOL
:
7071 case SCI_SETVIEWEOL
:
7072 vs
.viewEOL
= wParam
!= 0;
7073 InvalidateStyleRedraw();
7077 vs
.zoomLevel
= wParam
;
7078 InvalidateStyleRedraw();
7083 return vs
.zoomLevel
;
7085 case SCI_GETEDGECOLUMN
:
7088 case SCI_SETEDGECOLUMN
:
7090 InvalidateStyleRedraw();
7093 case SCI_GETEDGEMODE
:
7094 return vs
.edgeState
;
7096 case SCI_SETEDGEMODE
:
7097 vs
.edgeState
= wParam
;
7098 InvalidateStyleRedraw();
7101 case SCI_GETEDGECOLOUR
:
7102 return vs
.edgecolour
.desired
.AsLong();
7104 case SCI_SETEDGECOLOUR
:
7105 vs
.edgecolour
.desired
= ColourDesired(wParam
);
7106 InvalidateStyleRedraw();
7109 case SCI_GETDOCPOINTER
:
7110 return reinterpret_cast<sptr_t
>(pdoc
);
7112 case SCI_SETDOCPOINTER
:
7114 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
7117 case SCI_CREATEDOCUMENT
: {
7118 Document
*doc
= new Document();
7122 return reinterpret_cast<sptr_t
>(doc
);
7125 case SCI_ADDREFDOCUMENT
:
7126 (reinterpret_cast<Document
*>(lParam
))->AddRef();
7129 case SCI_RELEASEDOCUMENT
:
7130 (reinterpret_cast<Document
*>(lParam
))->Release();
7133 case SCI_SETMODEVENTMASK
:
7134 modEventMask
= wParam
;
7137 case SCI_GETMODEVENTMASK
:
7138 return modEventMask
;
7140 case SCI_CONVERTEOLS
:
7141 pdoc
->ConvertLineEnds(wParam
);
7142 SetSelection(currentPos
, anchor
); // Ensure selection inside document
7145 case SCI_SETLENGTHFORENCODE
:
7146 lengthForEncode
= wParam
;
7149 case SCI_SELECTIONISRECTANGLE
:
7150 return selType
== selRectangle
? 1 : 0;
7152 case SCI_SETSELECTIONMODE
: {
7155 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selStream
);
7156 selType
= selStream
;
7158 case SC_SEL_RECTANGLE
:
7159 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selRectangle
);
7160 selType
= selRectangle
;
7163 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selLines
);
7167 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selStream
);
7168 selType
= selStream
;
7170 InvalidateSelection(currentPos
, anchor
);
7172 case SCI_GETSELECTIONMODE
:
7175 return SC_SEL_STREAM
;
7177 return SC_SEL_RECTANGLE
;
7179 return SC_SEL_LINES
;
7181 return SC_SEL_STREAM
;
7183 case SCI_GETLINESELSTARTPOSITION
: {
7184 SelectionLineIterator
lineIterator(this);
7185 lineIterator
.SetAt(wParam
);
7186 return lineIterator
.startPos
;
7188 case SCI_GETLINESELENDPOSITION
: {
7189 SelectionLineIterator
lineIterator(this);
7190 lineIterator
.SetAt(wParam
);
7191 return lineIterator
.endPos
;
7194 case SCI_SETOVERTYPE
:
7195 inOverstrike
= wParam
!= 0;
7198 case SCI_GETOVERTYPE
:
7199 return inOverstrike
? 1 : 0;
7202 SetFocusState(wParam
!= 0);
7209 errorStatus
= wParam
;
7215 case SCI_SETMOUSEDOWNCAPTURES
:
7216 mouseDownCaptures
= wParam
!= 0;
7219 case SCI_GETMOUSEDOWNCAPTURES
:
7220 return mouseDownCaptures
;
7223 cursorMode
= wParam
;
7224 DisplayCursor(Window::cursorText
);
7230 case SCI_SETCONTROLCHARSYMBOL
:
7231 controlCharSymbol
= wParam
;
7234 case SCI_GETCONTROLCHARSYMBOL
:
7235 return controlCharSymbol
;
7237 case SCI_STARTRECORD
:
7238 recordingMacro
= true;
7241 case SCI_STOPRECORD
:
7242 recordingMacro
= false;
7245 case SCI_MOVECARETINSIDEVIEW
:
7246 MoveCaretInsideView();
7249 case SCI_SETFOLDMARGINCOLOUR
:
7250 vs
.foldmarginColourSet
= wParam
!= 0;
7251 vs
.foldmarginColour
.desired
= ColourDesired(lParam
);
7252 InvalidateStyleRedraw();
7255 case SCI_SETFOLDMARGINHICOLOUR
:
7256 vs
.foldmarginHighlightColourSet
= wParam
!= 0;
7257 vs
.foldmarginHighlightColour
.desired
= ColourDesired(lParam
);
7258 InvalidateStyleRedraw();
7261 case SCI_SETHOTSPOTACTIVEFORE
:
7262 vs
.hotspotForegroundSet
= wParam
!= 0;
7263 vs
.hotspotForeground
.desired
= ColourDesired(lParam
);
7264 InvalidateStyleRedraw();
7267 case SCI_SETHOTSPOTACTIVEBACK
:
7268 vs
.hotspotBackgroundSet
= wParam
!= 0;
7269 vs
.hotspotBackground
.desired
= ColourDesired(lParam
);
7270 InvalidateStyleRedraw();
7273 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
7274 vs
.hotspotUnderline
= wParam
!= 0;
7275 InvalidateStyleRedraw();
7278 case SCI_SETHOTSPOTSINGLELINE
:
7279 vs
.hotspotSingleLine
= wParam
!= 0;
7280 InvalidateStyleRedraw();
7283 case SCI_SETPASTECONVERTENDINGS
:
7284 convertPastes
= wParam
!= 0;
7287 case SCI_GETPASTECONVERTENDINGS
:
7288 return convertPastes
? 1 : 0;
7291 return DefWndProc(iMessage
, wParam
, lParam
);
7293 //Platform::DebugPrintf("end wnd proc\n");