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 int n
= htClient
/ vs
.lineHeight
;
528 int Editor::LinesToScroll() {
529 int retVal
= LinesOnScreen() - 1;
536 int Editor::MaxScrollPos() {
537 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
538 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
539 int retVal
= cs
.LinesDisplayed();
541 retVal
-= LinesOnScreen();
552 static inline bool IsControlCharacter(int ch
) {
553 // iscntrl returns true for lots of chars > 127 which are displayable
554 return ch
>= 0 && ch
< ' ';
557 const char *ControlCharacterString(unsigned char ch
) {
558 const char *reps
[] = {
559 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
560 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
561 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
562 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
564 if (ch
< (sizeof(reps
) / sizeof(reps
[0]))) {
572 * Convenience class to ensure LineLayout objects are always disposed.
574 class AutoLineLayout
{
575 LineLayoutCache
&llc
;
577 AutoLineLayout
&operator=(const AutoLineLayout
&) { return * this; }
579 AutoLineLayout(LineLayoutCache
&llc_
, LineLayout
*ll_
) : llc(llc_
), ll(ll_
) {}
584 LineLayout
*operator->() const {
587 operator LineLayout
*() const {
590 void Set(LineLayout
*ll_
) {
597 * Allows to iterate through the lines of a selection.
598 * Althought it can be called for a stream selection, in most cases
599 * it is inefficient and it should be used only for
600 * a rectangular or a line selection.
602 class SelectionLineIterator
{
605 int line
; ///< Current line within the iteration.
606 bool forward
; ///< True if iterating by increasing line number, false otherwise.
607 int selStart
, selEnd
; ///< Positions of the start and end of the selection relative to the start of the document.
608 int minX
, maxX
; ///< Left and right of selection rectangle.
611 int lineStart
, lineEnd
; ///< Line numbers, first and last lines of the selection.
612 int startPos
, endPos
; ///< Positions of the beginning and end of the selection on the current line.
622 SelectionLineIterator(Editor
*ed_
, bool forward_
= true) : line(0), startPos(0), endPos(0) {
625 selStart
= ed
->SelectionStart();
626 selEnd
= ed
->SelectionEnd();
627 lineStart
= ed
->pdoc
->LineFromPosition(selStart
);
628 lineEnd
= ed
->pdoc
->LineFromPosition(selEnd
);
630 minX
= Platform::Minimum(ed
->xStartSelect
, ed
->xEndSelect
);
631 // Right of rectangle
632 maxX
= Platform::Maximum(ed
->xStartSelect
, ed
->xEndSelect
);
635 ~SelectionLineIterator() {}
637 void SetAt(int line
) {
638 if (line
< lineStart
|| line
> lineEnd
) {
639 startPos
= endPos
= INVALID_POSITION
;
641 if (ed
->selType
== ed
->selRectangle
) {
642 // Measure line and return character closest to minX
643 startPos
= ed
->PositionFromLineX(line
, minX
);
644 // Measure line and return character closest to maxX
645 endPos
= ed
->PositionFromLineX(line
, maxX
);
646 } else if (ed
->selType
== ed
->selLines
) {
647 startPos
= ed
->pdoc
->LineStart(line
);
648 endPos
= ed
->pdoc
->LineStart(line
+ 1);
649 } else { // Stream selection, here only for completion
650 if (line
== lineStart
) {
653 startPos
= ed
->pdoc
->LineStart(line
);
655 if (line
== lineEnd
) {
658 endPos
= ed
->pdoc
->LineStart(line
+ 1);
670 return startPos
!= INVALID_POSITION
;
674 Point
Editor::LocationFromPosition(int pos
) {
677 if (pos
== INVALID_POSITION
)
679 int line
= pdoc
->LineFromPosition(pos
);
680 int lineVisible
= cs
.DisplayFromDoc(line
);
681 //Platform::DebugPrintf("line=%d\n", line);
682 AutoSurface
surface(this);
683 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
685 // -1 because of adding in for visible lines in following loop.
686 pt
.y
= (lineVisible
- topLine
- 1) * vs
.lineHeight
;
688 unsigned int posLineStart
= pdoc
->LineStart(line
);
689 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
690 int posInLine
= pos
- posLineStart
;
691 // In case of very long line put x at arbitrary large position
692 if (posInLine
> ll
->maxLineLength
) {
693 pt
.x
= ll
->positions
[ll
->maxLineLength
] - ll
->positions
[ll
->LineStart(ll
->lines
)];
696 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
697 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
698 pt
.x
= ll
->positions
[posInLine
] - ll
->positions
[ll
->LineStart(subLine
)];
699 if (actualWrapVisualStartIndent
!= 0) {
700 int lineStart
= ll
->LineStart(subLine
);
701 if (lineStart
!= 0) // Wrapped
702 pt
.x
+= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
705 if (posInLine
>= ll
->LineStart(subLine
)) {
706 pt
.y
+= vs
.lineHeight
;
709 pt
.x
+= vs
.fixedColumnWidth
- xOffset
;
714 int Editor::XFromPosition(int pos
) {
715 Point pt
= LocationFromPosition(pos
);
716 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
719 int Editor::LineFromLocation(Point pt
) {
720 return cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
723 void Editor::SetTopLine(int topLineNew
) {
724 topLine
= topLineNew
;
725 posTopLine
= pdoc
->LineStart(cs
.DocFromDisplay(topLine
));
728 static inline bool IsEOLChar(char ch
) {
729 return (ch
== '\r') || (ch
== '\n');
732 int Editor::PositionFromLocation(Point pt
) {
734 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
735 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
736 if (pt
.y
< 0) { // Division rounds towards 0
737 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
741 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
742 if (lineDoc
>= pdoc
->LinesTotal())
743 return pdoc
->Length();
744 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
745 int retVal
= posLineStart
;
746 AutoSurface
surface(this);
747 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
749 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
750 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
751 int subLine
= visibleLine
- lineStartSet
;
752 if (subLine
< ll
->lines
) {
753 int lineStart
= ll
->LineStart(subLine
);
754 int lineEnd
= ll
->LineStart(subLine
+ 1);
755 int subLineStart
= ll
->positions
[lineStart
];
757 if (actualWrapVisualStartIndent
!= 0) {
758 if (lineStart
!= 0) // Wrapped
759 pt
.x
-= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
761 for (int i
= lineStart
; i
< lineEnd
; i
++) {
762 if (pt
.x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
763 IsEOLChar(ll
->chars
[i
])) {
764 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
767 return lineEnd
+ posLineStart
;
769 retVal
= ll
->numCharsInLine
+ posLineStart
;
774 // Like PositionFromLocation but INVALID_POSITION returned when not near any text.
775 int Editor::PositionFromLocationClose(Point pt
) {
777 PRectangle rcClient
= GetTextRectangle();
778 if (!rcClient
.Contains(pt
))
779 return INVALID_POSITION
;
780 if (pt
.x
< vs
.fixedColumnWidth
)
781 return INVALID_POSITION
;
783 return INVALID_POSITION
;
784 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
785 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
786 if (pt
.y
< 0) { // Division rounds towards 0
787 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
789 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
791 return INVALID_POSITION
;
792 if (lineDoc
>= pdoc
->LinesTotal())
793 return INVALID_POSITION
;
794 AutoSurface
surface(this);
795 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
797 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
798 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
799 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
800 int subLine
= visibleLine
- lineStartSet
;
801 if (subLine
< ll
->lines
) {
802 int lineStart
= ll
->LineStart(subLine
);
803 int lineEnd
= ll
->LineStart(subLine
+ 1);
804 int subLineStart
= ll
->positions
[lineStart
];
806 if (actualWrapVisualStartIndent
!= 0) {
807 if (lineStart
!= 0) // Wrapped
808 pt
.x
-= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
810 for (int i
= lineStart
; i
< lineEnd
; i
++) {
811 if (pt
.x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
812 IsEOLChar(ll
->chars
[i
])) {
813 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
816 if (pt
.x
< (ll
->positions
[lineEnd
] - subLineStart
)) {
817 return pdoc
->MovePositionOutsideChar(lineEnd
+ posLineStart
, 1);
822 return INVALID_POSITION
;
826 * Find the document position corresponding to an x coordinate on a particular document line.
827 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
829 int Editor::PositionFromLineX(int lineDoc
, int x
) {
831 if (lineDoc
>= pdoc
->LinesTotal())
832 return pdoc
->Length();
833 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
834 AutoSurface
surface(this);
835 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
838 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
839 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
840 retVal
= ll
->numCharsInLine
+ posLineStart
;
842 int lineStart
= ll
->LineStart(subLine
);
843 int lineEnd
= ll
->LineStart(subLine
+ 1);
844 int subLineStart
= ll
->positions
[lineStart
];
846 if (actualWrapVisualStartIndent
!= 0) {
847 if (lineStart
!= 0) // Wrapped
848 x
-= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
850 for (int i
= lineStart
; i
< lineEnd
; i
++) {
851 if (x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
852 IsEOLChar(ll
->chars
[i
])) {
853 retVal
= pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
862 * If painting then abandon the painting because a wider redraw is needed.
863 * @return true if calling code should stop drawing.
865 bool Editor::AbandonPaint() {
866 if ((paintState
== painting
) && !paintingAllText
) {
867 paintState
= paintAbandoned
;
869 return paintState
== paintAbandoned
;
872 void Editor::RedrawRect(PRectangle rc
) {
873 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
875 // Clip the redraw rectangle into the client area
876 PRectangle rcClient
= GetClientRectangle();
877 if (rc
.top
< rcClient
.top
)
878 rc
.top
= rcClient
.top
;
879 if (rc
.bottom
> rcClient
.bottom
)
880 rc
.bottom
= rcClient
.bottom
;
881 if (rc
.left
< rcClient
.left
)
882 rc
.left
= rcClient
.left
;
883 if (rc
.right
> rcClient
.right
)
884 rc
.right
= rcClient
.right
;
886 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
887 wMain
.InvalidateRectangle(rc
);
891 void Editor::Redraw() {
892 //Platform::DebugPrintf("Redraw all\n");
893 PRectangle rcClient
= GetClientRectangle();
894 wMain
.InvalidateRectangle(rcClient
);
895 //wMain.InvalidateAll();
898 void Editor::RedrawSelMargin(int line
) {
899 if (!AbandonPaint()) {
903 PRectangle rcSelMargin
= GetClientRectangle();
904 rcSelMargin
.right
= vs
.fixedColumnWidth
;
906 int position
= pdoc
->LineStart(line
);
907 PRectangle rcLine
= RectangleFromRange(position
, position
);
908 rcSelMargin
.top
= rcLine
.top
;
909 rcSelMargin
.bottom
= rcLine
.bottom
;
911 wMain
.InvalidateRectangle(rcSelMargin
);
916 PRectangle
Editor::RectangleFromRange(int start
, int end
) {
923 int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(minPos
));
924 int lineDocMax
= pdoc
->LineFromPosition(maxPos
);
925 int maxLine
= cs
.DisplayFromDoc(lineDocMax
) + cs
.GetHeight(lineDocMax
) - 1;
926 PRectangle rcClient
= GetTextRectangle();
928 rc
.left
= vs
.fixedColumnWidth
;
929 rc
.top
= (minLine
- topLine
) * vs
.lineHeight
;
932 rc
.right
= rcClient
.right
;
933 rc
.bottom
= (maxLine
- topLine
+ 1) * vs
.lineHeight
;
934 // Ensure PRectangle is within 16 bit space
935 rc
.top
= Platform::Clamp(rc
.top
, -32000, 32000);
936 rc
.bottom
= Platform::Clamp(rc
.bottom
, -32000, 32000);
941 void Editor::InvalidateRange(int start
, int end
) {
942 RedrawRect(RectangleFromRange(start
, end
));
945 int Editor::CurrentPosition() {
949 bool Editor::SelectionEmpty() {
950 return anchor
== currentPos
;
953 int Editor::SelectionStart() {
954 return Platform::Minimum(currentPos
, anchor
);
957 int Editor::SelectionEnd() {
958 return Platform::Maximum(currentPos
, anchor
);
961 void Editor::SetRectangularRange() {
962 if (selType
== selRectangle
) {
963 xStartSelect
= XFromPosition(anchor
);
964 xEndSelect
= XFromPosition(currentPos
);
968 void Editor::InvalidateSelection(int currentPos_
, int anchor_
) {
969 int firstAffected
= anchor
;
970 if (firstAffected
> currentPos
)
971 firstAffected
= currentPos
;
972 if (firstAffected
> anchor_
)
973 firstAffected
= anchor_
;
974 if (firstAffected
> currentPos_
)
975 firstAffected
= currentPos_
;
976 int lastAffected
= anchor
;
977 if (lastAffected
< currentPos
)
978 lastAffected
= currentPos
;
979 if (lastAffected
< anchor_
)
980 lastAffected
= anchor_
;
981 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
982 lastAffected
= (currentPos_
+ 1);
984 InvalidateRange(firstAffected
, lastAffected
);
987 void Editor::SetSelection(int currentPos_
, int anchor_
) {
988 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
989 anchor_
= pdoc
->ClampPositionIntoDocument(anchor_
);
990 if ((currentPos
!= currentPos_
) || (anchor
!= anchor_
)) {
991 InvalidateSelection(currentPos_
, anchor_
);
992 currentPos
= currentPos_
;
995 SetRectangularRange();
999 void Editor::SetSelection(int currentPos_
) {
1000 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
1001 if (currentPos
!= currentPos_
) {
1002 InvalidateSelection(currentPos_
, currentPos_
);
1003 currentPos
= currentPos_
;
1005 SetRectangularRange();
1009 void Editor::SetEmptySelection(int currentPos_
) {
1010 selType
= selStream
;
1011 moveExtendsSelection
= false;
1012 SetSelection(currentPos_
, currentPos_
);
1015 bool Editor::RangeContainsProtected(int start
, int end
) const {
1016 if (vs
.ProtectionActive()) {
1022 int mask
= pdoc
->stylingBitsMask
;
1023 for (int pos
= start
; pos
< end
; pos
++) {
1024 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected())
1031 bool Editor::SelectionContainsProtected() {
1032 // DONE, but untested...: make support rectangular selection
1034 if (selType
== selStream
) {
1035 scp
= RangeContainsProtected(anchor
, currentPos
);
1037 SelectionLineIterator
lineIterator(this);
1038 while (lineIterator
.Iterate()) {
1039 if (RangeContainsProtected(lineIterator
.startPos
, lineIterator
.endPos
)) {
1049 * Asks document to find a good position and then moves out of any invisible positions.
1051 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) {
1052 pos
= pdoc
->MovePositionOutsideChar(pos
, moveDir
, checkLineEnd
);
1053 if (vs
.ProtectionActive()) {
1054 int mask
= pdoc
->stylingBitsMask
;
1056 if ((pos
> 0) && vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()) {
1057 while ((pos
< pdoc
->Length()) &&
1058 (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected()))
1061 } else if (moveDir
< 0) {
1062 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected()) {
1064 (vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()))
1072 int Editor::MovePositionTo(int newPos
, selTypes sel
, bool ensureVisible
) {
1073 int delta
= newPos
- currentPos
;
1074 newPos
= pdoc
->ClampPositionIntoDocument(newPos
);
1075 newPos
= MovePositionOutsideChar(newPos
, delta
);
1079 if (sel
!= noSel
|| moveExtendsSelection
) {
1080 SetSelection(newPos
);
1082 SetEmptySelection(newPos
);
1084 ShowCaretAtCurrentPosition();
1085 if (ensureVisible
) {
1086 EnsureCaretVisible();
1092 int Editor::MovePositionSoVisible(int pos
, int moveDir
) {
1093 pos
= pdoc
->ClampPositionIntoDocument(pos
);
1094 pos
= MovePositionOutsideChar(pos
, moveDir
);
1095 int lineDoc
= pdoc
->LineFromPosition(pos
);
1096 if (cs
.GetVisible(lineDoc
)) {
1099 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
1101 // lineDisplay is already line before fold as lines in fold use display line of line after fold
1102 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
1103 return pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
));
1105 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
1106 return pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
));
1112 * Choose the x position that the caret will try to stick to
1113 * as it moves up and down.
1115 void Editor::SetLastXChosen() {
1116 Point pt
= LocationFromPosition(currentPos
);
1120 void Editor::ScrollTo(int line
, bool moveThumb
) {
1121 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
1122 if (topLineNew
!= topLine
) {
1123 // Try to optimise small scrolls
1124 int linesToMove
= topLine
- topLineNew
;
1125 SetTopLine(topLineNew
);
1126 ShowCaretAtCurrentPosition();
1127 // Perform redraw rather than scroll if many lines would be redrawn anyway.
1129 if (abs(linesToMove
) <= 10) {
1130 ScrollText(linesToMove
);
1138 SetVerticalScrollPos();
1143 void Editor::ScrollText(int /* linesToMove */) {
1144 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
1148 void Editor::HorizontalScrollTo(int xPos
) {
1149 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
1152 if ((wrapState
== eWrapNone
) && (xOffset
!= xPos
)) {
1154 SetHorizontalScrollPos();
1155 RedrawRect(GetClientRectangle());
1159 void Editor::MoveCaretInsideView(bool ensureVisible
) {
1160 PRectangle rcClient
= GetTextRectangle();
1161 Point pt
= LocationFromPosition(currentPos
);
1162 if (pt
.y
< rcClient
.top
) {
1163 MovePositionTo(PositionFromLocation(
1164 Point(lastXChosen
, rcClient
.top
)),
1165 noSel
, ensureVisible
);
1166 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
1167 int yOfLastLineFullyDisplayed
= rcClient
.top
+ (LinesOnScreen() - 1) * vs
.lineHeight
;
1168 MovePositionTo(PositionFromLocation(
1169 Point(lastXChosen
, rcClient
.top
+ yOfLastLineFullyDisplayed
)),
1170 noSel
, ensureVisible
);
1174 int Editor::DisplayFromPosition(int pos
) {
1175 int lineDoc
= pdoc
->LineFromPosition(pos
);
1176 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
1177 AutoSurface
surface(this);
1178 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
1179 if (surface
&& ll
) {
1180 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
1181 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
1182 int posInLine
= pos
- posLineStart
;
1183 lineDisplay
--; // To make up for first increment ahead.
1184 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
1185 if (posInLine
>= ll
->LineStart(subLine
)) {
1194 * Ensure the caret is reasonably visible in context.
1196 Caret policy in SciTE
1198 If slop is set, we can define a slop value.
1199 This value defines an unwanted zone (UZ) where the caret is... unwanted.
1200 This zone is defined as a number of pixels near the vertical margins,
1201 and as a number of lines near the horizontal margins.
1202 By keeping the caret away from the edges, it is seen within its context,
1203 so it is likely that the identifier that the caret is on can be completely seen,
1204 and that the current line is seen with some of the lines following it which are
1205 often dependent on that line.
1207 If strict is set, the policy is enforced... strictly.
1208 The caret is centred on the display if slop is not set,
1209 and cannot go in the UZ if slop is set.
1211 If jumps is set, the display is moved more energetically
1212 so the caret can move in the same direction longer before the policy is applied again.
1213 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1215 If even is not set, instead of having symmetrical UZs,
1216 the left and bottom UZs are extended up to right and top UZs respectively.
1217 This way, we favour the displaying of useful information: the begining of lines,
1218 where most code reside, and the lines after the caret, eg. the body of a function.
1221 slop | strict | jumps | even | Caret can go to the margin | When reaching limitÝ(caret going out of
1222 | | | | | visibility or going into the UZ) display is...
1223 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1224 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1225 0 | 0 | 0 | 1 | Yes | moved by one position
1226 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1227 0 | 0 | 1 | 1 | Yes | centred on the caret
1228 0 | 1 | - | 0 | Caret is always on top/on right of display | -
1229 0 | 1 | - | 1 | No, caret is always centred | -
1230 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1231 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1232 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1233 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1234 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1235 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1236 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1238 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
1239 //Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " ");
1240 PRectangle rcClient
= GetTextRectangle();
1241 //int rcClientFullWidth = rcClient.Width();
1242 int posCaret
= currentPos
;
1246 Point pt
= LocationFromPosition(posCaret
);
1247 Point ptBottomCaret
= pt
;
1248 ptBottomCaret
.y
+= vs
.lineHeight
- 1;
1249 int lineCaret
= DisplayFromPosition(posCaret
);
1250 bool bSlop
, bStrict
, bJump
, bEven
;
1252 // Vertical positioning
1253 if (vert
&& (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
> rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1254 int linesOnScreen
= LinesOnScreen();
1255 int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1256 int newTopLine
= topLine
;
1257 bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1258 bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1259 bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1260 bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1262 // It should be possible to scroll the window to show the caret,
1263 // but this fails to remove the caret on GTK+
1264 if (bSlop
) { // A margin is defined
1267 int yMarginT
, yMarginB
;
1269 // In drag mode, avoid moves
1270 // otherwise, a double click will select several lines.
1271 yMarginT
= yMarginB
= 0;
1273 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1274 // a maximum of slightly less than half the heigth of the text area.
1275 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1277 yMarginB
= yMarginT
;
1279 yMarginB
= linesOnScreen
- yMarginT
- 1;
1285 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1289 yMoveB
= linesOnScreen
- yMoveT
- 1;
1291 if (lineCaret
< topLine
+ yMarginT
) {
1292 // Caret goes too high
1293 newTopLine
= lineCaret
- yMoveT
;
1294 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1295 // Caret goes too low
1296 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1298 } else { // Not strict
1299 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1300 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1304 yMoveB
= linesOnScreen
- yMoveT
- 1;
1306 if (lineCaret
< topLine
) {
1307 // Caret goes too high
1308 newTopLine
= lineCaret
- yMoveT
;
1309 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1310 // Caret goes too low
1311 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1315 if (!bStrict
&& !bJump
) {
1317 if (lineCaret
< topLine
) {
1318 // Caret goes too high
1319 newTopLine
= lineCaret
;
1320 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1321 // Caret goes too low
1323 newTopLine
= lineCaret
- linesOnScreen
+ 1;
1325 newTopLine
= lineCaret
;
1328 } else { // Strict or going out of display
1330 // Always center caret
1331 newTopLine
= lineCaret
- halfScreen
;
1333 // Always put caret on top of display
1334 newTopLine
= lineCaret
;
1338 newTopLine
= Platform::Clamp(newTopLine
, 0, MaxScrollPos());
1339 if (newTopLine
!= topLine
) {
1341 SetTopLine(newTopLine
);
1342 SetVerticalScrollPos();
1346 // Horizontal positioning
1347 if (horiz
&& (wrapState
== eWrapNone
)) {
1348 int halfScreen
= Platform::Maximum(rcClient
.Width() - 4, 4) / 2;
1349 int xOffsetNew
= xOffset
;
1350 bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1351 bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1352 bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1353 bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1355 if (bSlop
) { // A margin is defined
1358 int xMarginL
, xMarginR
;
1360 // In drag mode, avoid moves unless very near of the margin
1361 // otherwise, a simple click will select text.
1362 xMarginL
= xMarginR
= 2;
1364 // xMargin must equal to caretXSlop, with a minimum of 2 and
1365 // a maximum of slightly less than half the width of the text area.
1366 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1368 xMarginL
= xMarginR
;
1370 xMarginL
= rcClient
.Width() - xMarginR
- 4;
1373 if (bJump
&& bEven
) {
1374 // Jump is used only in even mode
1375 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1377 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1379 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1380 // Caret is on the left of the display
1381 if (bJump
&& bEven
) {
1382 xOffsetNew
-= xMoveL
;
1384 // Move just enough to allow to display the caret
1385 xOffsetNew
-= (rcClient
.left
+ xMarginL
) - pt
.x
;
1387 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1388 // Caret is on the right of the display
1389 if (bJump
&& bEven
) {
1390 xOffsetNew
+= xMoveR
;
1392 // Move just enough to allow to display the caret
1393 xOffsetNew
+= pt
.x
- (rcClient
.right
- xMarginR
) + 1;
1396 } else { // Not strict
1397 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1398 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1402 xMoveL
= rcClient
.Width() - xMoveR
- 4;
1404 if (pt
.x
< rcClient
.left
) {
1405 // Caret is on the left of the display
1406 xOffsetNew
-= xMoveL
;
1407 } else if (pt
.x
>= rcClient
.right
) {
1408 // Caret is on the right of the display
1409 xOffsetNew
+= xMoveR
;
1414 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1415 // Strict or going out of display
1418 xOffsetNew
+= pt
.x
- rcClient
.left
- halfScreen
;
1420 // Put caret on right
1421 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1424 // Move just enough to allow to display the caret
1425 if (pt
.x
< rcClient
.left
) {
1426 // Caret is on the left of the display
1428 xOffsetNew
-= rcClient
.left
- pt
.x
;
1430 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1432 } else if (pt
.x
>= rcClient
.right
) {
1433 // Caret is on the right of the display
1434 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1438 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1439 if (pt
.x
+ xOffset
< rcClient
.left
+ xOffsetNew
) {
1440 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.left
;
1441 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ xOffsetNew
) {
1442 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.right
+ 1;
1444 if (xOffsetNew
< 0) {
1447 if (xOffset
!= xOffsetNew
) {
1448 xOffset
= xOffsetNew
;
1449 if (xOffsetNew
> 0) {
1450 PRectangle rcText
= GetTextRectangle();
1451 if (horizontalScrollBarVisible
== true &&
1452 rcText
.Width() + xOffset
> scrollWidth
) {
1453 scrollWidth
= xOffset
+ rcText
.Width();
1457 SetHorizontalScrollPos();
1461 UpdateSystemCaret();
1464 void Editor::ShowCaretAtCurrentPosition() {
1466 caret
.active
= true;
1470 caret
.active
= false;
1476 void Editor::DropCaret() {
1477 caret
.active
= false;
1481 void Editor::InvalidateCaret() {
1483 InvalidateRange(posDrag
, posDrag
+ 1);
1485 InvalidateRange(currentPos
, currentPos
+ 1);
1486 UpdateSystemCaret();
1489 void Editor::UpdateSystemCaret() {
1492 void Editor::NeedWrapping(int docLineStart
, int docLineEnd
) {
1493 docLineStart
= Platform::Clamp(docLineStart
, 0, pdoc
->LinesTotal());
1494 if (wrapStart
> docLineStart
) {
1495 wrapStart
= docLineStart
;
1496 llc
.Invalidate(LineLayout::llPositions
);
1498 if (wrapEnd
< docLineEnd
) {
1499 wrapEnd
= docLineEnd
;
1501 wrapEnd
= Platform::Clamp(wrapEnd
, 0, pdoc
->LinesTotal());
1502 // Wrap lines during idle.
1503 if ((wrapState
!= eWrapNone
) && (wrapEnd
!= wrapStart
)) {
1508 // Check if wrapping needed and perform any needed wrapping.
1509 // fullwrap: if true, all lines which need wrapping will be done,
1510 // in this single call.
1511 // priorityWrapLineStart: If greater than zero, all lines starting from
1512 // here to 1 page + 100 lines past will be wrapped (even if there are
1513 // more lines under wrapping process in idle).
1514 // If it is neither fullwrap, nor priorityWrap, then 1 page + 100 lines will be
1515 // wrapped, if there are any wrapping going on in idle. (Generally this
1516 // condition is called only from idler).
1517 // Return true if wrapping occurred.
1518 bool Editor::WrapLines(bool fullWrap
, int priorityWrapLineStart
) {
1519 // If there are any pending wraps, do them during idle if possible.
1520 int linesInOneCall
= LinesOnScreen() + 100;
1521 if (wrapState
!= eWrapNone
) {
1522 if (wrapStart
< wrapEnd
) {
1523 if (!SetIdle(true)) {
1524 // Idle processing not supported so full wrap required.
1528 if (!fullWrap
&& priorityWrapLineStart
>= 0 &&
1529 // .. and if the paint window is outside pending wraps
1530 (((priorityWrapLineStart
+ linesInOneCall
) < wrapStart
) ||
1531 (priorityWrapLineStart
> wrapEnd
))) {
1532 // No priority wrap pending
1536 int goodTopLine
= topLine
;
1537 bool wrapOccurred
= false;
1538 if (wrapStart
<= pdoc
->LinesTotal()) {
1539 if (wrapState
== eWrapNone
) {
1540 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1541 wrapWidth
= LineLayout::wrapWidthInfinite
;
1542 for (int lineDoc
= 0; lineDoc
< pdoc
->LinesTotal(); lineDoc
++) {
1543 cs
.SetHeight(lineDoc
, 1);
1545 wrapOccurred
= true;
1547 wrapStart
= wrapLineLarge
;
1548 wrapEnd
= wrapLineLarge
;
1550 if (wrapEnd
>= pdoc
->LinesTotal())
1551 wrapEnd
= pdoc
->LinesTotal();
1553 int lineDocTop
= cs
.DocFromDisplay(topLine
);
1554 int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1555 PRectangle rcTextArea
= GetClientRectangle();
1556 rcTextArea
.left
= vs
.fixedColumnWidth
;
1557 rcTextArea
.right
-= vs
.rightMarginWidth
;
1558 wrapWidth
= rcTextArea
.Width();
1559 // Ensure all of the document is styled.
1560 pdoc
->EnsureStyledTo(pdoc
->Length());
1562 AutoSurface
surface(this);
1564 bool priorityWrap
= false;
1565 int lastLineToWrap
= wrapEnd
;
1566 int lineToWrap
= wrapStart
;
1568 if (priorityWrapLineStart
>= 0) {
1569 // This is a priority wrap.
1570 lineToWrap
= priorityWrapLineStart
;
1571 lastLineToWrap
= priorityWrapLineStart
+ linesInOneCall
;
1572 priorityWrap
= true;
1574 // This is idle wrap.
1575 lastLineToWrap
= wrapStart
+ linesInOneCall
;
1577 if (lastLineToWrap
>= wrapEnd
)
1578 lastLineToWrap
= wrapEnd
;
1579 } // else do a fullWrap.
1581 // Platform::DebugPrintf("Wraplines: full = %d, priorityStart = %d (wrapping: %d to %d)\n", fullWrap, priorityWrapLineStart, lineToWrap, lastLineToWrap);
1582 // Platform::DebugPrintf("Pending wraps: %d to %d\n", wrapStart, wrapEnd);
1583 while (lineToWrap
< lastLineToWrap
) {
1584 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineToWrap
));
1585 int linesWrapped
= 1;
1587 LayoutLine(lineToWrap
, surface
, vs
, ll
, wrapWidth
);
1588 linesWrapped
= ll
->lines
;
1590 if (cs
.SetHeight(lineToWrap
, linesWrapped
)) {
1591 wrapOccurred
= true;
1596 wrapStart
= lineToWrap
;
1597 // If wrapping is done, bring it to resting position
1598 if (wrapStart
>= wrapEnd
) {
1599 wrapStart
= wrapLineLarge
;
1600 wrapEnd
= wrapLineLarge
;
1603 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
);
1604 if (subLineTop
< cs
.GetHeight(lineDocTop
))
1605 goodTopLine
+= subLineTop
;
1607 goodTopLine
+= cs
.GetHeight(lineDocTop
);
1608 //double durWrap = et.Duration(true);
1609 //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap);
1614 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1615 SetVerticalScrollPos();
1617 return wrapOccurred
;
1620 void Editor::LinesJoin() {
1621 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1622 pdoc
->BeginUndoAction();
1623 bool prevNonWS
= true;
1624 for (int pos
= targetStart
; pos
< targetEnd
; pos
++) {
1625 if (IsEOLChar(pdoc
->CharAt(pos
))) {
1626 targetEnd
-= pdoc
->LenChar(pos
);
1629 // Ensure at least one space separating previous lines
1630 pdoc
->InsertChar(pos
, ' ');
1633 prevNonWS
= pdoc
->CharAt(pos
) != ' ';
1636 pdoc
->EndUndoAction();
1640 const char *StringFromEOLMode(int eolMode
) {
1641 if (eolMode
== SC_EOL_CRLF
) {
1643 } else if (eolMode
== SC_EOL_CR
) {
1650 void Editor::LinesSplit(int pixelWidth
) {
1651 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1652 if (pixelWidth
== 0) {
1653 PRectangle rcText
= GetTextRectangle();
1654 pixelWidth
= rcText
.Width();
1656 int lineStart
= pdoc
->LineFromPosition(targetStart
);
1657 int lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1658 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1659 pdoc
->BeginUndoAction();
1660 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
1661 AutoSurface
surface(this);
1662 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
1663 if (surface
&& ll
) {
1664 unsigned int posLineStart
= pdoc
->LineStart(line
);
1665 LayoutLine(line
, surface
, vs
, ll
, pixelWidth
);
1666 for (int subLine
= 1; subLine
< ll
->lines
; subLine
++) {
1667 pdoc
->InsertString(posLineStart
+ (subLine
- 1) * strlen(eol
) +
1668 ll
->LineStart(subLine
), eol
);
1669 targetEnd
+= static_cast<int>(strlen(eol
));
1672 lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1674 pdoc
->EndUndoAction();
1678 int Editor::SubstituteMarkerIfEmpty(int markerCheck
, int markerDefault
) {
1679 if (vs
.markers
[markerCheck
].markType
== SC_MARK_EMPTY
)
1680 return markerDefault
;
1684 // Avoid 64 bit compiler warnings.
1685 // Scintilla does not support text buffers larger than 2**31
1686 static int istrlen(const char *s
) {
1687 return static_cast<int>(strlen(s
));
1690 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1691 if (vs
.fixedColumnWidth
== 0)
1694 PRectangle rcMargin
= GetClientRectangle();
1695 rcMargin
.right
= vs
.fixedColumnWidth
;
1697 if (!rc
.Intersects(rcMargin
))
1702 surface
= pixmapSelMargin
;
1704 surface
= surfWindow
;
1707 PRectangle rcSelMargin
= rcMargin
;
1708 rcSelMargin
.right
= rcMargin
.left
;
1710 for (int margin
= 0; margin
< vs
.margins
; margin
++) {
1711 if (vs
.ms
[margin
].width
> 0) {
1713 rcSelMargin
.left
= rcSelMargin
.right
;
1714 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
1716 if (vs
.ms
[margin
].style
!= SC_MARGIN_NUMBER
) {
1717 /* alternate scheme:
1718 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
1719 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1721 // Required because of special way brush is created for selection margin
1722 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
1724 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
1725 // Required because of special way brush is created for selection margin
1726 surface
->FillRectangle(rcSelMargin
, *pixmapSelPattern
);
1728 ColourAllocated colour
;
1729 switch (vs
.ms
[margin
].style
) {
1730 case SC_MARGIN_BACK
:
1731 colour
= vs
.styles
[STYLE_DEFAULT
].back
.allocated
;
1733 case SC_MARGIN_FORE
:
1734 colour
= vs
.styles
[STYLE_DEFAULT
].fore
.allocated
;
1737 colour
= vs
.styles
[STYLE_LINENUMBER
].back
.allocated
;
1740 surface
->FillRectangle(rcSelMargin
, colour
);
1743 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1746 int visibleLine
= topLine
;
1749 // Work out whether the top line is whitespace located after a
1750 // lessening of fold level which implies a 'fold tail' but which should not
1751 // be displayed until the last of a sequence of whitespace.
1752 bool needWhiteClosure
= false;
1753 int level
= pdoc
->GetLevel(cs
.DocFromDisplay(topLine
));
1754 if (level
& SC_FOLDLEVELWHITEFLAG
) {
1755 int lineBack
= cs
.DocFromDisplay(topLine
);
1756 int levelPrev
= level
;
1757 while ((lineBack
> 0) && (levelPrev
& SC_FOLDLEVELWHITEFLAG
)) {
1759 levelPrev
= pdoc
->GetLevel(lineBack
);
1761 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
1762 if ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelPrev
& SC_FOLDLEVELNUMBERMASK
))
1763 needWhiteClosure
= true;
1767 // Old code does not know about new markers needed to distinguish all cases
1768 int folderOpenMid
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID
,
1769 SC_MARKNUM_FOLDEROPEN
);
1770 int folderEnd
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND
,
1773 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
1775 PLATFORM_ASSERT(visibleLine
< cs
.LinesDisplayed());
1777 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
1778 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
1779 bool firstSubLine
= visibleLine
== cs
.DisplayFromDoc(lineDoc
);
1781 // Decide which fold indicator should be displayed
1782 level
= pdoc
->GetLevel(lineDoc
);
1783 int levelNext
= pdoc
->GetLevel(lineDoc
+ 1);
1784 int marks
= pdoc
->GetMark(lineDoc
);
1787 int levelNum
= level
& SC_FOLDLEVELNUMBERMASK
;
1788 int levelNextNum
= levelNext
& SC_FOLDLEVELNUMBERMASK
;
1789 if (level
& SC_FOLDLEVELHEADERFLAG
) {
1791 if (cs
.GetExpanded(lineDoc
)) {
1792 if (levelNum
== SC_FOLDLEVELBASE
)
1793 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
1795 marks
|= 1 << folderOpenMid
;
1797 if (levelNum
== SC_FOLDLEVELBASE
)
1798 marks
|= 1 << SC_MARKNUM_FOLDER
;
1800 marks
|= 1 << folderEnd
;
1803 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1805 needWhiteClosure
= false;
1806 } else if (level
& SC_FOLDLEVELWHITEFLAG
) {
1807 if (needWhiteClosure
) {
1808 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1809 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1810 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1811 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1812 needWhiteClosure
= false;
1814 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1815 needWhiteClosure
= false;
1817 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1818 if (levelNextNum
< levelNum
) {
1819 if (levelNextNum
> SC_FOLDLEVELBASE
) {
1820 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1822 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1825 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1828 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1829 if (levelNextNum
< levelNum
) {
1830 needWhiteClosure
= false;
1831 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1832 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1833 needWhiteClosure
= true;
1834 } else if (levelNextNum
> SC_FOLDLEVELBASE
) {
1835 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1837 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1840 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1844 marks
&= vs
.ms
[margin
].mask
;
1845 PRectangle rcMarker
= rcSelMargin
;
1846 rcMarker
.top
= yposScreen
;
1847 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
1848 if (vs
.ms
[margin
].style
== SC_MARGIN_NUMBER
) {
1852 sprintf(number
, "%d", lineDoc
+ 1);
1853 if (foldFlags
& SC_FOLDFLAG_LEVELNUMBERS
) {
1854 int lev
= pdoc
->GetLevel(lineDoc
);
1855 sprintf(number
, "%c%c %03X %03X",
1856 (lev
& SC_FOLDLEVELHEADERFLAG
) ? 'H' : '_',
1857 (lev
& SC_FOLDLEVELWHITEFLAG
) ? 'W' : '_',
1858 lev
& SC_FOLDLEVELNUMBERMASK
,
1862 PRectangle rcNumber
= rcMarker
;
1864 int width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
1865 int xpos
= rcNumber
.right
- width
- 3;
1866 rcNumber
.left
= xpos
;
1867 surface
->DrawTextNoClip(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
1868 rcNumber
.top
+ vs
.maxAscent
, number
, istrlen(number
),
1869 vs
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
1870 vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1874 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1876 vs
.markers
[markBit
].Draw(surface
, rcMarker
, vs
.styles
[STYLE_LINENUMBER
].font
);
1883 yposScreen
+= vs
.lineHeight
;
1888 PRectangle rcBlankMargin
= rcMargin
;
1889 rcBlankMargin
.left
= rcSelMargin
.right
;
1890 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1893 surfWindow
->Copy(rcMargin
, Point(), *pixmapSelMargin
);
1897 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
1898 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
1899 int xhead
= rcTab
.right
- 1 - ydiff
;
1900 if (xhead
<= rcTab
.left
) {
1901 ydiff
-= rcTab
.left
- xhead
- 1;
1902 xhead
= rcTab
.left
- 1;
1904 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
1905 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
1907 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1908 surface
->LineTo(rcTab
.right
- 1, ymid
);
1909 surface
->LineTo(xhead
, ymid
- ydiff
);
1910 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1911 surface
->LineTo(xhead
, ymid
+ ydiff
);
1914 static bool IsSpaceOrTab(char ch
) {
1915 return ch
== ' ' || ch
== '\t';
1918 LineLayout
*Editor::RetrieveLineLayout(int lineNumber
) {
1919 int posLineStart
= pdoc
->LineStart(lineNumber
);
1920 int posLineEnd
= pdoc
->LineStart(lineNumber
+ 1);
1921 int lineCaret
= pdoc
->LineFromPosition(currentPos
);
1922 return llc
.Retrieve(lineNumber
, lineCaret
,
1923 posLineEnd
- posLineStart
, pdoc
->GetStyleClock(),
1924 LinesOnScreen() + 1, pdoc
->LinesTotal());
1928 * Fill in the LineLayout data for the given line.
1929 * Copy the given @a line and its styles from the document into local arrays.
1930 * Also determine the x position at which each character starts.
1932 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
*ll
, int width
) {
1935 PLATFORM_ASSERT(line
< pdoc
->LinesTotal());
1936 int posLineStart
= pdoc
->LineStart(line
);
1937 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1938 // If the line is very long, limit the treatment to a length that should fit in the viewport
1939 if (posLineEnd
> (posLineStart
+ ll
->maxLineLength
)) {
1940 posLineEnd
= posLineStart
+ ll
->maxLineLength
;
1942 if (ll
->validity
== LineLayout::llCheckTextAndStyle
) {
1943 int lineLength
= posLineEnd
- posLineStart
;
1944 if (!vstyle
.viewEOL
) {
1945 int cid
= posLineEnd
- 1;
1946 while ((cid
> posLineStart
) && IsEOLChar(pdoc
->CharAt(cid
))) {
1951 if (lineLength
== ll
->numCharsInLine
) {
1952 // See if chars, styles, indicators, are all the same
1953 bool allSame
= true;
1954 const int styleMask
= pdoc
->stylingBitsMask
;
1955 // Check base line layout
1957 int numCharsInLine
= 0;
1958 while (numCharsInLine
< lineLength
) {
1959 int charInDoc
= numCharsInLine
+ posLineStart
;
1960 char chDoc
= pdoc
->CharAt(charInDoc
);
1961 styleByte
= pdoc
->StyleAt(charInDoc
);
1962 allSame
= allSame
&&
1963 (ll
->styles
[numCharsInLine
] == static_cast<unsigned char>(styleByte
& styleMask
));
1964 allSame
= allSame
&&
1965 (ll
->indicators
[numCharsInLine
] == static_cast<char>(styleByte
& ~styleMask
));
1966 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseMixed
)
1967 allSame
= allSame
&&
1968 (ll
->chars
[numCharsInLine
] == chDoc
);
1969 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1970 allSame
= allSame
&&
1971 (ll
->chars
[numCharsInLine
] == static_cast<char>(tolower(chDoc
)));
1972 else // Style::caseUpper
1973 allSame
= allSame
&&
1974 (ll
->chars
[numCharsInLine
] == static_cast<char>(toupper(chDoc
)));
1977 allSame
= allSame
&& (ll
->styles
[numCharsInLine
] == styleByte
); // For eolFilled
1979 ll
->validity
= LineLayout::llPositions
;
1981 ll
->validity
= LineLayout::llInvalid
;
1984 ll
->validity
= LineLayout::llInvalid
;
1987 if (ll
->validity
== LineLayout::llInvalid
) {
1988 ll
->widthLine
= LineLayout::wrapWidthInfinite
;
1990 int numCharsInLine
= 0;
1991 if (vstyle
.edgeState
== EDGE_BACKGROUND
) {
1992 ll
->edgeColumn
= pdoc
->FindColumn(line
, theEdge
);
1993 if (ll
->edgeColumn
>= posLineStart
) {
1994 ll
->edgeColumn
-= posLineStart
;
1997 ll
->edgeColumn
= -1;
2001 int styleMask
= pdoc
->stylingBitsMask
;
2002 ll
->styleBitsSet
= 0;
2003 // Fill base line layout
2004 for (int charInDoc
= posLineStart
; charInDoc
< posLineEnd
; charInDoc
++) {
2005 char chDoc
= pdoc
->CharAt(charInDoc
);
2006 styleByte
= pdoc
->StyleAt(charInDoc
);
2007 ll
->styleBitsSet
|= styleByte
;
2008 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
2009 ll
->chars
[numCharsInLine
] = chDoc
;
2010 ll
->styles
[numCharsInLine
] = static_cast<char>(styleByte
& styleMask
);
2011 ll
->indicators
[numCharsInLine
] = static_cast<char>(styleByte
& ~styleMask
);
2012 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
2013 ll
->chars
[numCharsInLine
] = static_cast<char>(toupper(chDoc
));
2014 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
2015 ll
->chars
[numCharsInLine
] = static_cast<char>(tolower(chDoc
));
2019 ll
->xHighlightGuide
= 0;
2020 // Extra element at the end of the line to hold end x position and act as
2021 ll
->chars
[numCharsInLine
] = 0; // Also triggers processing in the loops as this is a control character
2022 ll
->styles
[numCharsInLine
] = styleByte
; // For eolFilled
2023 ll
->indicators
[numCharsInLine
] = 0;
2025 // Layout the line, determining the position of each character,
2026 // with an extra element at the end for the end of the line.
2027 int startseg
= 0; // Start of the current segment, in char. number
2028 int startsegx
= 0; // Start of the current segment, in pixels
2029 ll
->positions
[0] = 0;
2030 unsigned int tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
2031 bool lastSegItalics
= false;
2032 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
2034 int ctrlCharWidth
[32] = {0};
2035 bool isControlNext
= IsControlCharacter(ll
->chars
[0]);
2036 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
2037 bool isControl
= isControlNext
;
2038 isControlNext
= IsControlCharacter(ll
->chars
[charInLine
+ 1]);
2039 if ((ll
->styles
[charInLine
] != ll
->styles
[charInLine
+ 1]) ||
2040 isControl
|| isControlNext
) {
2041 ll
->positions
[startseg
] = 0;
2042 if (vstyle
.styles
[ll
->styles
[charInLine
]].visible
) {
2044 if (ll
->chars
[charInLine
] == '\t') {
2045 ll
->positions
[charInLine
+ 1] = ((((startsegx
+ 2) /
2046 tabWidth
) + 1) * tabWidth
) - startsegx
;
2047 } else if (controlCharSymbol
< 32) {
2048 if (ctrlCharWidth
[ll
->chars
[charInLine
]] == 0) {
2049 const char *ctrlChar
= ControlCharacterString(ll
->chars
[charInLine
]);
2050 // +3 For a blank on front and rounded edge each side:
2051 ctrlCharWidth
[ll
->chars
[charInLine
]] =
2052 surface
->WidthText(ctrlCharsFont
, ctrlChar
, istrlen(ctrlChar
)) + 3;
2054 ll
->positions
[charInLine
+ 1] = ctrlCharWidth
[ll
->chars
[charInLine
]];
2056 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
2057 surface
->MeasureWidths(ctrlCharsFont
, cc
, 1,
2058 ll
->positions
+ startseg
+ 1);
2060 lastSegItalics
= false;
2061 } else { // Regular character
2062 int lenSeg
= charInLine
- startseg
+ 1;
2063 if ((lenSeg
== 1) && (' ' == ll
->chars
[startseg
])) {
2064 lastSegItalics
= false;
2065 // Over half the segments are single characters and of these about half are space characters.
2066 ll
->positions
[charInLine
+ 1] = vstyle
.styles
[ll
->styles
[charInLine
]].spaceWidth
;
2068 lastSegItalics
= vstyle
.styles
[ll
->styles
[charInLine
]].italic
;
2069 surface
->MeasureWidths(vstyle
.styles
[ll
->styles
[charInLine
]].font
, ll
->chars
+ startseg
,
2070 lenSeg
, ll
->positions
+ startseg
+ 1);
2073 } else { // invisible
2074 for (int posToZero
= startseg
; posToZero
<= (charInLine
+ 1); posToZero
++) {
2075 ll
->positions
[posToZero
] = 0;
2078 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
2079 ll
->positions
[posToIncrease
] += startsegx
;
2081 startsegx
= ll
->positions
[charInLine
+ 1];
2082 startseg
= charInLine
+ 1;
2085 // Small hack to make lines that end with italics not cut off the edge of the last character
2086 if ((startseg
> 0) && lastSegItalics
) {
2087 ll
->positions
[startseg
] += 2;
2089 ll
->numCharsInLine
= numCharsInLine
;
2090 ll
->validity
= LineLayout::llPositions
;
2092 // Hard to cope when too narrow, so just assume there is space
2096 if ((ll
->validity
== LineLayout::llPositions
) || (ll
->widthLine
!= width
)) {
2097 ll
->widthLine
= width
;
2098 if (width
== LineLayout::wrapWidthInfinite
) {
2100 } else if (width
> ll
->positions
[ll
->numCharsInLine
]) {
2101 // Simple common case where line does not need wrapping.
2104 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_END
) {
2105 width
-= vstyle
.aveCharWidth
; // take into account the space for end wrap mark
2108 // Calculate line start positions based upon width.
2109 // For now this is simplistic - wraps on byte rather than character and
2110 // in the middle of words. Should search for spaces or style changes.
2111 int lastGoodBreak
= 0;
2112 int lastLineStart
= 0;
2113 int startOffset
= 0;
2115 while (p
< ll
->numCharsInLine
) {
2116 if ((ll
->positions
[p
+ 1] - startOffset
) >= width
) {
2117 if (lastGoodBreak
== lastLineStart
) {
2118 // Try moving to start of last character
2120 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
2123 if (lastGoodBreak
== lastLineStart
) {
2124 // Ensure at least one character on line.
2125 lastGoodBreak
= pdoc
->MovePositionOutsideChar(lastGoodBreak
+ posLineStart
+ 1, 1)
2129 lastLineStart
= lastGoodBreak
;
2131 ll
->SetLineStart(ll
->lines
, lastGoodBreak
);
2132 startOffset
= ll
->positions
[lastGoodBreak
];
2133 // take into account the space for start wrap mark and indent
2134 startOffset
-= actualWrapVisualStartIndent
* vstyle
.aveCharWidth
;
2135 p
= lastGoodBreak
+ 1;
2139 if (wrapState
== eWrapChar
) {
2140 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
2142 p
= pdoc
->MovePositionOutsideChar(p
+ 1 + posLineStart
, 1) - posLineStart
;
2144 } else if (ll
->styles
[p
] != ll
->styles
[p
- 1]) {
2146 } else if (IsSpaceOrTab(ll
->chars
[p
- 1]) && !IsSpaceOrTab(ll
->chars
[p
])) {
2154 ll
->validity
= LineLayout::llLines
;
2158 ColourAllocated
Editor::SelectionBackground(ViewStyle
&vsDraw
) {
2159 return primarySelection
? vsDraw
.selbackground
.allocated
: vsDraw
.selbackground2
.allocated
;
2162 ColourAllocated
Editor::TextBackground(ViewStyle
&vsDraw
, bool overrideBackground
,
2163 ColourAllocated background
, bool inSelection
, bool inHotspot
, int styleMain
, int i
, LineLayout
*ll
) {
2165 if (vsDraw
.selbackset
&& (vsDraw
.selAlpha
== SC_ALPHA_NOALPHA
)) {
2166 return SelectionBackground(vsDraw
);
2169 if ((vsDraw
.edgeState
== EDGE_BACKGROUND
) &&
2170 (i
>= ll
->edgeColumn
) &&
2171 !IsEOLChar(ll
->chars
[i
]))
2172 return vsDraw
.edgecolour
.allocated
;
2173 if (inHotspot
&& vsDraw
.hotspotBackgroundSet
)
2174 return vsDraw
.hotspotBackground
.allocated
;
2175 if (overrideBackground
)
2178 return vsDraw
.styles
[styleMain
].back
.allocated
;
2181 void Editor::DrawIndentGuide(Surface
*surface
, int lineVisible
, int lineHeight
, int start
, PRectangle rcSegment
, bool highlight
) {
2182 Point
from(0, ((lineVisible
& 1) && (lineHeight
& 1)) ? 1 : 0);
2183 PRectangle
rcCopyArea(start
+ 1, rcSegment
.top
, start
+ 2, rcSegment
.bottom
);
2184 surface
->Copy(rcCopyArea
, from
,
2185 highlight
? *pixmapIndentGuideHighlight
: *pixmapIndentGuide
);
2188 void Editor::DrawWrapMarker(Surface
*surface
, PRectangle rcPlace
,
2189 bool isEndMarker
, ColourAllocated wrapColour
) {
2190 surface
->PenColour(wrapColour
);
2192 enum { xa
= 1 }; // gap before start
2193 int w
= rcPlace
.right
- rcPlace
.left
- xa
- 1;
2195 bool xStraight
= isEndMarker
; // x-mirrored symbol for start marker
2196 bool yStraight
= true;
2197 //bool yStraight= isEndMarker; // comment in for start marker y-mirrowed
2199 int x0
= xStraight
? rcPlace
.left
: rcPlace
.right
- 1;
2200 int y0
= yStraight
? rcPlace
.top
: rcPlace
.bottom
- 1;
2202 int dy
= (rcPlace
.bottom
- rcPlace
.top
) / 5;
2203 int y
= (rcPlace
.bottom
- rcPlace
.top
) / 2 + dy
;
2211 void MoveTo(int xRelative
, int yRelative
) {
2212 surface
->MoveTo(xBase
+ xDir
* xRelative
, yBase
+ yDir
* yRelative
);
2214 void LineTo(int xRelative
, int yRelative
) {
2215 surface
->LineTo(xBase
+ xDir
* xRelative
, yBase
+ yDir
* yRelative
);
2218 Relative rel
= {surface
, x0
, xStraight
? 1 : -1, y0
, yStraight
? 1 : -1};
2222 rel
.LineTo(xa
+ 2*w
/ 3, y
- dy
);
2224 rel
.LineTo(xa
+ 2*w
/ 3, y
+ dy
);
2228 rel
.LineTo(xa
+ w
, y
);
2229 rel
.LineTo(xa
+ w
, y
- 2 * dy
);
2230 rel
.LineTo(xa
- 1, // on windows lineto is exclusive endpoint, perhaps GTK not...
2234 static void SimpleAlphaRectangle(Surface
*surface
, PRectangle rc
, ColourAllocated fill
, int alpha
) {
2235 if (alpha
!= SC_ALPHA_NOALPHA
) {
2236 surface
->AlphaRectangle(rc
, 0, fill
, alpha
, fill
, alpha
, 0);
2240 void Editor::DrawEOL(Surface
*surface
, ViewStyle
&vsDraw
, PRectangle rcLine
, LineLayout
*ll
,
2241 int line
, int lineEnd
, int xStart
, int subLine
, int subLineStart
,
2242 bool overrideBackground
, ColourAllocated background
,
2243 bool drawWrapMarkEnd
, ColourAllocated wrapColour
) {
2245 int styleMask
= pdoc
->stylingBitsMask
;
2246 PRectangle rcSegment
= rcLine
;
2248 // Fill in a PRectangle representing the end of line characters
2249 int xEol
= ll
->positions
[lineEnd
] - subLineStart
;
2250 rcSegment
.left
= xEol
+ xStart
;
2251 rcSegment
.right
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
2252 int posLineEnd
= pdoc
->LineStart(line
+ 1);
2253 bool eolInSelection
= (subLine
== (ll
->lines
- 1)) &&
2254 (posLineEnd
> ll
->selStart
) && (posLineEnd
<= ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2256 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (vsDraw
.selAlpha
== SC_ALPHA_NOALPHA
)) {
2257 surface
->FillRectangle(rcSegment
, SelectionBackground(vsDraw
));
2259 if (overrideBackground
) {
2260 surface
->FillRectangle(rcSegment
, background
);
2262 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2264 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (vsDraw
.selAlpha
!= SC_ALPHA_NOALPHA
)) {
2265 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
), vsDraw
.selAlpha
);
2269 rcSegment
.left
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
2270 rcSegment
.right
= rcLine
.right
;
2271 if (overrideBackground
) {
2272 surface
->FillRectangle(rcSegment
, background
);
2273 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
2274 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2276 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
2279 if (drawWrapMarkEnd
) {
2280 PRectangle rcPlace
= rcSegment
;
2282 if (wrapVisualFlagsLocation
& SC_WRAPVISUALFLAGLOC_END_BY_TEXT
) {
2283 rcPlace
.left
= xEol
+ xStart
;
2284 rcPlace
.right
= rcPlace
.left
+ vsDraw
.aveCharWidth
;
2286 // draw left of the right text margin, to avoid clipping by the current clip rect
2287 rcPlace
.right
= rcLine
.right
- vs
.rightMarginWidth
;
2288 rcPlace
.left
= rcPlace
.right
- vsDraw
.aveCharWidth
;
2290 DrawWrapMarker(surface
, rcPlace
, true, wrapColour
);
2294 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int lineVisible
, int xStart
,
2295 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
2297 PRectangle rcSegment
= rcLine
;
2299 // Using one font for all control characters so it can be controlled independently to ensure
2300 // the box goes around the characters tightly. Seems to be no way to work out what height
2301 // is taken by an individual character - internal leading gives varying results.
2302 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
2304 // See if something overrides the line background color: Either if caret is on the line
2305 // and background color is set for that, or if a marker is defined that forces its background
2306 // color onto the line, or if a marker is defined but has no selection margin in which to
2307 // display itself (as long as it's not an SC_MARK_EMPTY marker). These are checked in order
2308 // with the earlier taking precedence. When multiple markers cause background override,
2309 // the color for the highest numbered one is used.
2310 bool overrideBackground
= false;
2311 ColourAllocated background
;
2312 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& (vsDraw
.caretLineAlpha
== SC_ALPHA_NOALPHA
) && ll
->containsCaret
) {
2313 overrideBackground
= true;
2314 background
= vsDraw
.caretLineBackground
.allocated
;
2316 if (!overrideBackground
) {
2317 int marks
= pdoc
->GetMark(line
);
2318 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2319 if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
) &&
2320 (vsDraw
.markers
[markBit
].alpha
== SC_ALPHA_NOALPHA
)) {
2321 background
= vsDraw
.markers
[markBit
].back
.allocated
;
2322 overrideBackground
= true;
2327 if (!overrideBackground
) {
2328 if (vsDraw
.maskInLine
) {
2329 int marksMasked
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
2331 for (int markBit
= 0; (markBit
< 32) && marksMasked
; markBit
++) {
2332 if ((marksMasked
& 1) && (vsDraw
.markers
[markBit
].markType
!= SC_MARK_EMPTY
) &&
2333 (vsDraw
.markers
[markBit
].alpha
== SC_ALPHA_NOALPHA
)) {
2334 overrideBackground
= true;
2335 background
= vsDraw
.markers
[markBit
].back
.allocated
;
2343 bool drawWhitespaceBackground
= (vsDraw
.viewWhitespace
!= wsInvisible
) &&
2344 (!overrideBackground
) && (vsDraw
.whitespaceBackgroundSet
);
2346 bool inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2347 int indentWidth
= pdoc
->IndentSize() * vsDraw
.spaceWidth
;
2349 int posLineStart
= pdoc
->LineStart(line
);
2351 int startseg
= ll
->LineStart(subLine
);
2352 int subLineStart
= ll
->positions
[startseg
];
2355 if (subLine
< ll
->lines
) {
2356 lineStart
= ll
->LineStart(subLine
);
2357 lineEnd
= ll
->LineStart(subLine
+ 1);
2360 bool drawWrapMarkEnd
= false;
2362 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_END
) {
2363 if (subLine
+ 1 < ll
->lines
) {
2364 drawWrapMarkEnd
= ll
->LineStart(subLine
+ 1) != 0;
2368 if (actualWrapVisualStartIndent
!= 0) {
2370 bool continuedWrapLine
= false;
2371 if (subLine
< ll
->lines
) {
2372 continuedWrapLine
= ll
->LineStart(subLine
) != 0;
2375 if (continuedWrapLine
) {
2376 // draw continuation rect
2377 PRectangle rcPlace
= rcSegment
;
2379 rcPlace
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2380 rcPlace
.right
= rcPlace
.left
+ actualWrapVisualStartIndent
* vsDraw
.aveCharWidth
;
2382 // default bgnd here..
2383 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
2385 // main line style would be below but this would be inconsistent with end markers
2386 // also would possibly not be the style at wrap point
2387 //int styleMain = ll->styles[lineStart];
2388 //surface->FillRectangle(rcPlace, vsDraw.styles[styleMain].back.allocated);
2390 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) {
2392 if (wrapVisualFlagsLocation
& SC_WRAPVISUALFLAGLOC_START_BY_TEXT
)
2393 rcPlace
.left
= rcPlace
.right
- vsDraw
.aveCharWidth
;
2395 rcPlace
.right
= rcPlace
.left
+ vsDraw
.aveCharWidth
;
2397 DrawWrapMarker(surface
, rcPlace
, false, vsDraw
.whitespaceForeground
.allocated
);
2400 xStart
+= actualWrapVisualStartIndent
* vsDraw
.aveCharWidth
;
2406 // Background drawing loop
2407 for (i
= lineStart
; twoPhaseDraw
&& (i
< lineEnd
); i
++) {
2409 int iDoc
= i
+ posLineStart
;
2410 // If there is the end of a style run for any reason
2411 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
2412 i
== (lineEnd
- 1) ||
2413 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
2414 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
2415 (i
== (ll
->edgeColumn
- 1))) {
2416 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2417 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2418 // Only try to draw if really visible - enhances performance by not calling environment to
2419 // draw strings that are completely past the right side of the window.
2420 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2421 int styleMain
= ll
->styles
[i
];
2422 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2423 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2424 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2425 if (ll
->chars
[i
] == '\t') {
2427 if (drawWhitespaceBackground
&&
2428 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2429 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2430 surface
->FillRectangle(rcSegment
, textBack
);
2431 } else if (IsControlCharacter(ll
->chars
[i
])) {
2432 // Control character display
2433 inIndentation
= false;
2434 surface
->FillRectangle(rcSegment
, textBack
);
2436 // Normal text display
2437 surface
->FillRectangle(rcSegment
, textBack
);
2438 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2439 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
2440 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2441 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2442 if (drawWhitespaceBackground
&&
2443 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2444 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
,
2445 ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2446 surface
->FillRectangle(rcSpace
, vsDraw
.whitespaceBackground
.allocated
);
2449 inIndentation
= false;
2454 } else if (rcSegment
.left
> rcLine
.right
) {
2462 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2463 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
2464 drawWrapMarkEnd
, vsDraw
.whitespaceForeground
.allocated
);
2467 inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2468 startseg
= ll
->LineStart(subLine
);
2469 // Foreground drawing loop
2470 for (i
= lineStart
; i
< lineEnd
; i
++) {
2472 int iDoc
= i
+ posLineStart
;
2473 // If there is the end of a style run for any reason
2474 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
2475 i
== (lineEnd
- 1) ||
2476 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
2477 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
2478 (i
== (ll
->edgeColumn
- 1))) {
2479 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2480 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2481 // Only try to draw if really visible - enhances performance by not calling environment to
2482 // draw strings that are completely past the right side of the window.
2483 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2484 int styleMain
= ll
->styles
[i
];
2485 ColourAllocated textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
2486 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
2487 //hotspot foreground
2488 if (ll
->hsStart
!= -1 && iDoc
>= ll
->hsStart
&& iDoc
< hsEnd
) {
2489 if (vsDraw
.hotspotForegroundSet
)
2490 textFore
= vsDraw
.hotspotForeground
.allocated
;
2492 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2493 if (inSelection
&& (vsDraw
.selforeset
)) {
2494 textFore
= vsDraw
.selforeground
.allocated
;
2496 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2497 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2498 if (ll
->chars
[i
] == '\t') {
2500 if (!twoPhaseDraw
) {
2501 if (drawWhitespaceBackground
&&
2502 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2503 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2504 surface
->FillRectangle(rcSegment
, textBack
);
2506 if ((vsDraw
.viewWhitespace
!= wsInvisible
) || ((inIndentation
&& vsDraw
.viewIndentationGuides
))) {
2507 if (vsDraw
.whitespaceForegroundSet
)
2508 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2509 surface
->PenColour(textFore
);
2511 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
2512 for (int xIG
= ll
->positions
[i
] / indentWidth
* indentWidth
; xIG
< ll
->positions
[i
+ 1]; xIG
+= indentWidth
) {
2513 if (xIG
>= ll
->positions
[i
] && xIG
> 0) {
2514 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIG
+ xStart
, rcSegment
,
2515 (ll
->xHighlightGuide
== xIG
));
2519 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2520 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2521 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
2522 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
2523 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
2526 } else if (IsControlCharacter(ll
->chars
[i
])) {
2527 // Control character display
2528 inIndentation
= false;
2529 if (controlCharSymbol
< 32) {
2530 // Draw the character
2531 const char *ctrlChar
= ControlCharacterString(ll
->chars
[i
]);
2532 if (!twoPhaseDraw
) {
2533 surface
->FillRectangle(rcSegment
, textBack
);
2535 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
2536 surface
->InternalLeading(ctrlCharsFont
);
2537 PRectangle rcCChar
= rcSegment
;
2538 rcCChar
.left
= rcCChar
.left
+ 1;
2539 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
2540 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
2541 PRectangle rcCentral
= rcCChar
;
2544 surface
->FillRectangle(rcCentral
, textFore
);
2545 PRectangle rcChar
= rcCChar
;
2548 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
2549 rcSegment
.top
+ vsDraw
.maxAscent
, ctrlChar
, istrlen(ctrlChar
),
2550 textBack
, textFore
);
2552 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
2553 surface
->DrawTextNoClip(rcSegment
, ctrlCharsFont
,
2554 rcSegment
.top
+ vsDraw
.maxAscent
,
2555 cc
, 1, textBack
, textFore
);
2558 // Normal text display
2559 if (vsDraw
.styles
[styleMain
].visible
) {
2561 surface
->DrawTextTransparent(rcSegment
, textFont
,
2562 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2563 i
- startseg
+ 1, textFore
);
2565 surface
->DrawTextNoClip(rcSegment
, textFont
,
2566 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2567 i
- startseg
+ 1, textFore
, textBack
);
2570 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2571 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
2572 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2573 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2574 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2575 if (vsDraw
.whitespaceForegroundSet
)
2576 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2577 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2578 int xmid
= (ll
->positions
[cpos
+ startseg
] + ll
->positions
[cpos
+ startseg
+ 1]) / 2;
2579 if (!twoPhaseDraw
&& drawWhitespaceBackground
&&
2580 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2581 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2582 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
, ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2583 surface
->FillRectangle(rcSpace
, textBack
);
2585 PRectangle
rcDot(xmid
+ xStart
- subLineStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
2586 rcDot
.right
= rcDot
.left
+ 1;
2587 rcDot
.bottom
= rcDot
.top
+ 1;
2588 surface
->FillRectangle(rcDot
, textFore
);
2591 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
2592 int startSpace
= ll
->positions
[cpos
+ startseg
];
2593 if (startSpace
> 0 && (startSpace
% indentWidth
== 0)) {
2594 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, startSpace
+ xStart
, rcSegment
,
2595 (ll
->xHighlightGuide
== ll
->positions
[cpos
+ startseg
]));
2599 inIndentation
= false;
2604 if (ll
->hsStart
!= -1 && vsDraw
.hotspotUnderline
&& iDoc
>= ll
->hsStart
&& iDoc
< ll
->hsEnd
) {
2605 PRectangle rcUL
= rcSegment
;
2606 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2607 rcUL
.bottom
= rcUL
.top
+ 1;
2608 if (vsDraw
.hotspotForegroundSet
)
2609 surface
->FillRectangle(rcUL
, vsDraw
.hotspotForeground
.allocated
);
2611 surface
->FillRectangle(rcUL
, textFore
);
2612 } else if (vsDraw
.styles
[styleMain
].underline
) {
2613 PRectangle rcUL
= rcSegment
;
2614 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2615 rcUL
.bottom
= rcUL
.top
+ 1;
2616 surface
->FillRectangle(rcUL
, textFore
);
2618 } else if (rcSegment
.left
> rcLine
.right
) {
2626 // foreach indicator...
2627 for (int indicnum
= 0, mask
= 1 << pdoc
->stylingBits
; mask
< 0x100; indicnum
++) {
2628 if (!(mask
& ll
->styleBitsSet
)) {
2633 // foreach style pos in line...
2634 for (int indicPos
= lineStart
; indicPos
<= lineEnd
; indicPos
++) {
2635 // look for starts...
2637 // NOT in indicator run, looking for START
2638 if (indicPos
< lineEnd
&& (ll
->indicators
[indicPos
] & mask
))
2639 startPos
= indicPos
;
2642 if (startPos
>= 0) {
2643 // IN indicator run, looking for END
2644 if (indicPos
>= lineEnd
|| !(ll
->indicators
[indicPos
] & mask
)) {
2645 // AT end of indicator run, DRAW it!
2647 ll
->positions
[startPos
] + xStart
- subLineStart
,
2648 rcLine
.top
+ vsDraw
.maxAscent
,
2649 ll
->positions
[indicPos
] + xStart
- subLineStart
,
2650 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
2651 vsDraw
.indicators
[indicnum
].Draw(surface
, rcIndic
, rcLine
);
2652 // RESET control var
2659 // End of the drawing of the current line
2660 if (!twoPhaseDraw
) {
2661 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2662 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
2663 drawWrapMarkEnd
, vsDraw
.whitespaceForeground
.allocated
);
2665 if ((vsDraw
.selAlpha
!= SC_ALPHA_NOALPHA
) && (ll
->selStart
>= 0) && (ll
->selEnd
>= 0)) {
2666 int startPosSel
= (ll
->selStart
< posLineStart
) ? posLineStart
: ll
->selStart
;
2667 int endPosSel
= (ll
->selEnd
< (lineEnd
+ posLineStart
)) ? ll
->selEnd
: (lineEnd
+ posLineStart
);
2668 if (startPosSel
< endPosSel
) {
2669 rcSegment
.left
= xStart
+ ll
->positions
[startPosSel
- posLineStart
] - subLineStart
;
2670 rcSegment
.right
= xStart
+ ll
->positions
[endPosSel
- posLineStart
] - subLineStart
;
2671 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
), vsDraw
.selAlpha
);
2675 if (vsDraw
.edgeState
== EDGE_LINE
) {
2676 int edgeX
= theEdge
* vsDraw
.spaceWidth
;
2677 rcSegment
.left
= edgeX
+ xStart
;
2678 rcSegment
.right
= rcSegment
.left
+ 1;
2679 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
.allocated
);
2682 // Draw any translucent whole line states
2683 rcSegment
.left
= xStart
;
2684 rcSegment
.right
= rcLine
.right
- 1;
2685 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& ll
->containsCaret
) {
2686 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.caretLineBackground
.allocated
, vsDraw
.caretLineAlpha
);
2688 int marks
= pdoc
->GetMark(line
);
2689 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2690 if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
)) {
2691 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.markers
[markBit
].back
.allocated
, vsDraw
.markers
[markBit
].alpha
);
2695 if (vsDraw
.maskInLine
) {
2696 int marksMasked
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
2698 for (int markBit
= 0; (markBit
< 32) && marksMasked
; markBit
++) {
2699 if ((marksMasked
& 1) && (vsDraw
.markers
[markBit
].markType
!= SC_MARK_EMPTY
)) {
2700 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.markers
[markBit
].back
.allocated
, vsDraw
.markers
[markBit
].alpha
);
2708 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
2709 if (!pixmapSelPattern
->Initialised()) {
2710 const int patternSize
= 8;
2711 pixmapSelPattern
->InitPixMap(patternSize
, patternSize
, surfaceWindow
, wMain
.GetID());
2712 // This complex procedure is to reproduce the checkerboard dithered pattern used by windows
2713 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
2714 // way between the chrome colour and the chrome highlight colour making a nice transition
2715 // between the window chrome and the content area. And it works in low colour depths.
2716 PRectangle
rcPattern(0, 0, patternSize
, patternSize
);
2718 // Initialize default colours based on the chrome colour scheme. Typically the highlight is white.
2719 ColourAllocated colourFMFill
= vs
.selbar
.allocated
;
2720 ColourAllocated colourFMStripes
= vs
.selbarlight
.allocated
;
2722 if (!(vs
.selbarlight
.desired
== ColourDesired(0xff, 0xff, 0xff))) {
2723 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
2724 // (Typically, the highlight colour is white.)
2725 colourFMFill
= vs
.selbarlight
.allocated
;
2728 if (vs
.foldmarginColourSet
) {
2729 // override default fold margin colour
2730 colourFMFill
= vs
.foldmarginColour
.allocated
;
2732 if (vs
.foldmarginHighlightColourSet
) {
2733 // override default fold margin highlight colour
2734 colourFMStripes
= vs
.foldmarginHighlightColour
.allocated
;
2737 pixmapSelPattern
->FillRectangle(rcPattern
, colourFMFill
);
2738 pixmapSelPattern
->PenColour(colourFMStripes
);
2739 for (int stripe
= 0; stripe
< patternSize
; stripe
++) {
2740 // Alternating 1 pixel stripes is same as checkerboard.
2741 pixmapSelPattern
->MoveTo(0, stripe
* 2);
2742 pixmapSelPattern
->LineTo(patternSize
, stripe
* 2 - patternSize
);
2746 if (!pixmapIndentGuide
->Initialised()) {
2747 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
2748 pixmapIndentGuide
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2749 pixmapIndentGuideHighlight
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2750 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
2751 pixmapIndentGuide
->FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
.allocated
);
2752 pixmapIndentGuide
->PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
2753 pixmapIndentGuideHighlight
->FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
.allocated
);
2754 pixmapIndentGuideHighlight
->PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
2755 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
2756 pixmapIndentGuide
->MoveTo(0, stripe
);
2757 pixmapIndentGuide
->LineTo(2, stripe
);
2758 pixmapIndentGuideHighlight
->MoveTo(0, stripe
);
2759 pixmapIndentGuideHighlight
->LineTo(2, stripe
);
2764 if (!pixmapLine
->Initialised()) {
2765 PRectangle rcClient
= GetClientRectangle();
2766 pixmapLine
->InitPixMap(rcClient
.Width(), vs
.lineHeight
,
2767 surfaceWindow
, wMain
.GetID());
2768 pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
2769 rcClient
.Height(), surfaceWindow
, wMain
.GetID());
2774 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
2775 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
2776 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
2779 RefreshPixMaps(surfaceWindow
);
2781 PRectangle rcClient
= GetClientRectangle();
2782 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
2783 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
2785 surfaceWindow
->SetPalette(&palette
, true);
2786 pixmapLine
->SetPalette(&palette
, !hasFocus
);
2788 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
2789 // The area to be painted plus one extra line is styled.
2790 // The extra line is to determine when a style change, such as starting a comment flows on to other lines.
2791 int lineStyleLast
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
2792 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
2793 int endPosPaint
= pdoc
->Length();
2794 if (lineStyleLast
< cs
.LinesDisplayed())
2795 endPosPaint
= pdoc
->LineStart(cs
.DocFromDisplay(lineStyleLast
+ 1));
2797 int xStart
= vs
.fixedColumnWidth
- xOffset
;
2800 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
2801 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
2803 // Ensure we are styled as far as we are painting.
2804 pdoc
->EnsureStyledTo(endPosPaint
);
2805 bool paintAbandonedByStyling
= paintState
== paintAbandoned
;
2808 needUpdateUI
= false;
2810 RefreshPixMaps(surfaceWindow
);
2813 // Call priority lines wrap on a window of lines which are likely
2814 // to rendered with the following paint (that is wrap the visible
2816 int startLineToWrap
= cs
.DocFromDisplay(topLine
) - 5;
2817 if (startLineToWrap
< 0)
2818 startLineToWrap
= -1;
2819 if (WrapLines(false, startLineToWrap
)) {
2820 // The wrapping process has changed the height of some lines so
2821 // abandon this paint for a complete repaint.
2822 if (AbandonPaint()) {
2825 RefreshPixMaps(surfaceWindow
); // In case pixmaps invalidated by scrollbar change
2827 PLATFORM_ASSERT(pixmapSelPattern
->Initialised());
2829 PaintSelMargin(surfaceWindow
, rcArea
);
2831 PRectangle rcRightMargin
= rcClient
;
2832 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
2833 if (rcArea
.Intersects(rcRightMargin
)) {
2834 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2837 if (paintState
== paintAbandoned
) {
2838 // Either styling or NotifyUpdateUI noticed that painting is needed
2839 // outside the current painting rectangle
2840 //Platform::DebugPrintf("Abandoning paint\n");
2841 if (wrapState
!= eWrapNone
) {
2842 if (paintAbandonedByStyling
) {
2843 // Styling has spilled over a line end, such as occurs by starting a multiline
2844 // comment. The width of subsequent text may have changed, so rewrap.
2845 NeedWrapping(cs
.DocFromDisplay(topLine
));
2850 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
2853 if (rcArea
.right
> vs
.fixedColumnWidth
) {
2855 Surface
*surface
= surfaceWindow
;
2857 surface
= pixmapLine
;
2858 PLATFORM_ASSERT(pixmapLine
->Initialised());
2860 surface
->SetUnicodeMode(IsUnicodeMode());
2861 surface
->SetDBCSMode(CodePage());
2863 int visibleLine
= topLine
+ screenLinePaintFirst
;
2865 int posCaret
= currentPos
;
2868 int lineCaret
= pdoc
->LineFromPosition(posCaret
);
2870 // Remove selection margin from drawing area so text will not be drawn
2871 // on it in unbuffered mode.
2872 PRectangle rcTextArea
= rcClient
;
2873 rcTextArea
.left
= vs
.fixedColumnWidth
;
2874 rcTextArea
.right
-= vs
.rightMarginWidth
;
2875 surfaceWindow
->SetClip(rcTextArea
);
2877 // Loop on visible lines
2878 //double durLayout = 0.0;
2879 //double durPaint = 0.0;
2880 //double durCopy = 0.0;
2881 //ElapsedTime etWhole;
2882 int lineDocPrevious
= -1; // Used to avoid laying out one document line multiple times
2883 AutoLineLayout
ll(llc
, 0);
2884 SelectionLineIterator
lineIterator(this);
2885 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
2887 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
2888 // Only visible lines should be handled by the code within the loop
2889 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
2890 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
2891 int subLine
= visibleLine
- lineStartSet
;
2893 // Copy this line and its styles from the document into local arrays
2894 // and determine the x position at which each character starts.
2896 if (lineDoc
!= lineDocPrevious
) {
2898 // For rectangular selection this accesses the layout cache so should be after layout returned.
2899 lineIterator
.SetAt(lineDoc
);
2900 ll
.Set(RetrieveLineLayout(lineDoc
));
2901 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
2902 lineDocPrevious
= lineDoc
;
2904 //durLayout += et.Duration(true);
2907 if (selType
== selStream
) {
2908 ll
->selStart
= SelectionStart();
2909 ll
->selEnd
= SelectionEnd();
2911 ll
->selStart
= lineIterator
.startPos
;
2912 ll
->selEnd
= lineIterator
.endPos
;
2914 ll
->containsCaret
= lineDoc
== lineCaret
;
2915 if (hideSelection
) {
2918 ll
->containsCaret
= false;
2921 GetHotSpotRange(ll
->hsStart
, ll
->hsEnd
);
2923 PRectangle rcLine
= rcClient
;
2925 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
2927 Range
rangeLine(pdoc
->LineStart(lineDoc
), pdoc
->LineStart(lineDoc
+ 1));
2928 // Highlight the current braces if any
2929 ll
->SetBracesHighlight(rangeLine
, braces
, static_cast<char>(bracesMatchStyle
),
2930 highlightGuideColumn
* vs
.spaceWidth
);
2933 DrawLine(surface
, vs
, lineDoc
, visibleLine
, xStart
, rcLine
, ll
, subLine
);
2934 //durPaint += et.Duration(true);
2936 // Restore the previous styles for the brace highlights in case layout is in cache.
2937 ll
->RestoreBracesHighlight(rangeLine
, braces
);
2939 bool expanded
= cs
.GetExpanded(lineDoc
);
2940 if ((foldFlags
& SC_FOLDFLAG_BOX
) == 0) {
2941 // Paint the line above the fold
2942 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_EXPANDED
))
2944 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_CONTRACTED
))) {
2945 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2946 PRectangle rcFoldLine
= rcLine
;
2947 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2948 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2951 // Paint the line below the fold
2952 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_EXPANDED
))
2954 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2955 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2956 PRectangle rcFoldLine
= rcLine
;
2957 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2958 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2962 int FoldLevelCurr
= (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2963 int FoldLevelPrev
= (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2964 int FoldLevelFlags
= (pdoc
->GetLevel(lineDoc
) & ~SC_FOLDLEVELNUMBERMASK
) & ~(0xFFF0000);
2965 int indentationStep
= pdoc
->IndentSize();
2966 // Draw line above fold
2967 if ((FoldLevelPrev
< FoldLevelCurr
)
2969 (FoldLevelFlags
& SC_FOLDLEVELBOXHEADERFLAG
2971 (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELBOXFOOTERFLAG
) == 0)) {
2972 PRectangle rcFoldLine
= rcLine
;
2973 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2974 rcFoldLine
.left
+= xStart
+ FoldLevelCurr
* vs
.spaceWidth
* indentationStep
- 1;
2975 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2978 // Line below the fold (or below a contracted fold)
2979 if (FoldLevelFlags
& SC_FOLDLEVELBOXFOOTERFLAG
2981 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2982 PRectangle rcFoldLine
= rcLine
;
2983 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2984 rcFoldLine
.left
+= xStart
+ (FoldLevelCurr
) * vs
.spaceWidth
* indentationStep
- 1;
2985 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2988 PRectangle rcBoxLine
= rcLine
;
2989 // Draw vertical line for every fold level
2990 for (int i
= 0; i
<= FoldLevelCurr
; i
++) {
2991 rcBoxLine
.left
= xStart
+ i
* vs
.spaceWidth
* indentationStep
- 1;
2992 rcBoxLine
.right
= rcBoxLine
.left
+ 1;
2993 surface
->FillRectangle(rcBoxLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2998 if (lineDoc
== lineCaret
) {
2999 int offset
= Platform::Minimum(posCaret
- rangeLine
.start
, ll
->maxLineLength
);
3000 if ((offset
>= ll
->LineStart(subLine
)) &&
3001 ((offset
< ll
->LineStart(subLine
+ 1)) || offset
== ll
->numCharsInLine
)) {
3002 int xposCaret
= ll
->positions
[offset
] - ll
->positions
[ll
->LineStart(subLine
)] + xStart
;
3004 if (actualWrapVisualStartIndent
!= 0) {
3005 int lineStart
= ll
->LineStart(subLine
);
3006 if (lineStart
!= 0) // Wrapped
3007 xposCaret
+= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
3009 int widthOverstrikeCaret
;
3010 if (posCaret
== pdoc
->Length()) { // At end of document
3011 widthOverstrikeCaret
= vs
.aveCharWidth
;
3012 } else if ((posCaret
- rangeLine
.start
) >= ll
->numCharsInLine
) { // At end of line
3013 widthOverstrikeCaret
= vs
.aveCharWidth
;
3015 widthOverstrikeCaret
= ll
->positions
[offset
+ 1] - ll
->positions
[offset
];
3017 if (widthOverstrikeCaret
< 3) // Make sure its visible
3018 widthOverstrikeCaret
= 3;
3019 if (((caret
.active
&& caret
.on
) || (posDrag
>= 0)) && xposCaret
>= 0) {
3020 PRectangle rcCaret
= rcLine
;
3021 int caretWidthOffset
= 0;
3022 if ((offset
> 0) && (vs
.caretWidth
> 1))
3023 caretWidthOffset
= 1; // Move back so overlaps both character cells.
3025 rcCaret
.left
= xposCaret
- caretWidthOffset
;
3026 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
3029 rcCaret
.top
= rcCaret
.bottom
- 2;
3030 rcCaret
.left
= xposCaret
+ 1;
3031 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
3033 rcCaret
.left
= xposCaret
- caretWidthOffset
;
3034 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
3037 surface
->FillRectangle(rcCaret
, vs
.caretcolour
.allocated
);
3043 Point
from(vs
.fixedColumnWidth
, 0);
3044 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
3045 rcClient
.right
, yposScreen
+ vs
.lineHeight
);
3046 surfaceWindow
->Copy(rcCopyArea
, from
, *pixmapLine
);
3048 //durCopy += et.Duration(true);
3051 if (!bufferedDraw
) {
3052 ypos
+= vs
.lineHeight
;
3055 yposScreen
+= vs
.lineHeight
;
3060 //if (durPaint < 0.00000001)
3061 // durPaint = 0.00000001;
3063 // Right column limit indicator
3064 PRectangle rcBeyondEOF
= rcClient
;
3065 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
3066 rcBeyondEOF
.right
= rcBeyondEOF
.right
;
3067 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
3068 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
3069 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
3070 if (vs
.edgeState
== EDGE_LINE
) {
3071 int edgeX
= theEdge
* vs
.spaceWidth
;
3072 rcBeyondEOF
.left
= edgeX
+ xStart
;
3073 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
3074 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
.allocated
);
3077 //Platform::DebugPrintf(
3078 //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
3079 //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
3084 // Space (3 space characters) between line numbers and text when printing.
3085 #define lineNumberPrintSpace " "
3087 ColourDesired
InvertedLight(ColourDesired orig
) {
3088 unsigned int r
= orig
.GetRed();
3089 unsigned int g
= orig
.GetGreen();
3090 unsigned int b
= orig
.GetBlue();
3091 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
3092 unsigned int il
= 0xff - l
;
3094 return ColourDesired(0xff, 0xff, 0xff);
3098 return ColourDesired(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
3101 // This is mostly copied from the Paint method but with some things omitted
3102 // such as the margin markers, line numbers, selection and caret
3103 // Should be merged back into a combined Draw method.
3104 long Editor::FormatRange(bool draw
, RangeToFormat
*pfr
) {
3108 AutoSurface
surface(pfr
->hdc
, this);
3111 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this);
3112 if (!surfaceMeasure
) {
3116 ViewStyle
vsPrint(vs
);
3118 // Modify the view style for printing as do not normally want any of the transient features to be printed
3119 // Printing supports only the line number margin.
3120 int lineNumberIndex
= -1;
3121 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
3122 if ((vsPrint
.ms
[margin
].style
== SC_MARGIN_NUMBER
) && (vsPrint
.ms
[margin
].width
> 0)) {
3123 lineNumberIndex
= margin
;
3125 vsPrint
.ms
[margin
].width
= 0;
3128 vsPrint
.showMarkedLines
= false;
3129 vsPrint
.fixedColumnWidth
= 0;
3130 vsPrint
.zoomLevel
= printMagnification
;
3131 vsPrint
.viewIndentationGuides
= false;
3132 // Don't show the selection when printing
3133 vsPrint
.selbackset
= false;
3134 vsPrint
.selforeset
= false;
3135 vsPrint
.selAlpha
= SC_ALPHA_NOALPHA
;
3136 vsPrint
.whitespaceBackgroundSet
= false;
3137 vsPrint
.whitespaceForegroundSet
= false;
3138 vsPrint
.showCaretLineBackground
= false;
3140 // Set colours for printing according to users settings
3141 for (int sty
= 0;sty
<= STYLE_MAX
;sty
++) {
3142 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
3143 vsPrint
.styles
[sty
].fore
.desired
= InvertedLight(vsPrint
.styles
[sty
].fore
.desired
);
3144 vsPrint
.styles
[sty
].back
.desired
= InvertedLight(vsPrint
.styles
[sty
].back
.desired
);
3145 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
3146 vsPrint
.styles
[sty
].fore
.desired
= ColourDesired(0, 0, 0);
3147 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3148 } else if (printColourMode
== SC_PRINT_COLOURONWHITE
) {
3149 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3150 } else if (printColourMode
== SC_PRINT_COLOURONWHITEDEFAULTBG
) {
3151 if (sty
<= STYLE_DEFAULT
) {
3152 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3156 // White background for the line numbers
3157 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3159 vsPrint
.Refresh(*surfaceMeasure
);
3160 // Ensure colours are set up
3161 vsPrint
.RefreshColourPalette(palette
, true);
3162 vsPrint
.RefreshColourPalette(palette
, false);
3163 // Determining width must hapen after fonts have been realised in Refresh
3164 int lineNumberWidth
= 0;
3165 if (lineNumberIndex
>= 0) {
3166 lineNumberWidth
= surfaceMeasure
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3167 "99999" lineNumberPrintSpace
, 5 + istrlen(lineNumberPrintSpace
));
3168 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
3171 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
3172 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
3173 if (linePrintLast
< linePrintStart
)
3174 linePrintLast
= linePrintStart
;
3175 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
);
3176 if (linePrintLast
> linePrintMax
)
3177 linePrintLast
= linePrintMax
;
3178 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
3179 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
3180 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
3181 int endPosPrint
= pdoc
->Length();
3182 if (linePrintLast
< pdoc
->LinesTotal())
3183 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
3185 // Ensure we are styled to where we are formatting.
3186 pdoc
->EnsureStyledTo(endPosPrint
);
3188 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
+ lineNumberWidth
;
3189 int ypos
= pfr
->rc
.top
;
3191 int lineDoc
= linePrintStart
;
3193 int nPrintPos
= pfr
->chrg
.cpMin
;
3194 int visibleLine
= 0;
3195 int widthPrint
= pfr
->rc
.Width() - lineNumberWidth
;
3196 if (printWrapState
== eWrapNone
)
3197 widthPrint
= LineLayout::wrapWidthInfinite
;
3199 while (lineDoc
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
3201 // When printing, the hdc and hdcTarget may be the same, so
3202 // changing the state of surfaceMeasure may change the underlying
3203 // state of surface. Therefore, any cached state is discarded before
3204 // using each surface.
3205 surfaceMeasure
->FlushCachedState();
3207 // Copy this line and its styles from the document into local arrays
3208 // and determine the x position at which each character starts.
3209 LineLayout
ll(8000);
3210 LayoutLine(lineDoc
, surfaceMeasure
, vsPrint
, &ll
, widthPrint
);
3214 ll
.containsCaret
= false;
3217 rcLine
.left
= pfr
->rc
.left
+ lineNumberWidth
;
3219 rcLine
.right
= pfr
->rc
.right
- 1;
3220 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3222 // When document line is wrapped over multiple display lines, find where
3223 // to start printing from to ensure a particular position is on the first
3224 // line of the page.
3225 if (visibleLine
== 0) {
3226 int startWithinLine
= nPrintPos
- pdoc
->LineStart(lineDoc
);
3227 for (int iwl
= 0; iwl
< ll
.lines
- 1; iwl
++) {
3228 if (ll
.LineStart(iwl
) <= startWithinLine
&& ll
.LineStart(iwl
+ 1) >= startWithinLine
) {
3233 if (ll
.lines
> 1 && startWithinLine
>= ll
.LineStart(ll
.lines
- 1)) {
3234 visibleLine
= -(ll
.lines
- 1);
3238 if (draw
&& lineNumberWidth
&&
3239 (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) &&
3240 (visibleLine
>= 0)) {
3242 sprintf(number
, "%d" lineNumberPrintSpace
, lineDoc
+ 1);
3243 PRectangle rcNumber
= rcLine
;
3244 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
3246 rcNumber
.left
-= surfaceMeasure
->WidthText(
3247 vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
3248 surface
->FlushCachedState();
3249 surface
->DrawTextNoClip(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3250 ypos
+ vsPrint
.maxAscent
, number
, istrlen(number
),
3251 vsPrint
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
3252 vsPrint
.styles
[STYLE_LINENUMBER
].back
.allocated
);
3256 surface
->FlushCachedState();
3258 for (int iwl
= 0; iwl
< ll
.lines
; iwl
++) {
3259 if (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) {
3260 if (visibleLine
>= 0) {
3263 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3264 DrawLine(surface
, vsPrint
, lineDoc
, visibleLine
, xStart
, rcLine
, &ll
, iwl
);
3266 ypos
+= vsPrint
.lineHeight
;
3269 if (iwl
== ll
.lines
- 1)
3270 nPrintPos
= pdoc
->LineStart(lineDoc
+ 1);
3272 nPrintPos
+= ll
.LineStart(iwl
+ 1) - ll
.LineStart(iwl
);
3282 int Editor::TextWidth(int style
, const char *text
) {
3284 AutoSurface
surface(this);
3286 return surface
->WidthText(vs
.styles
[style
].font
, text
, istrlen(text
));
3292 // Empty method is overridden on GTK+ to show / hide scrollbars
3293 void Editor::ReconfigureScrollBars() {}
3295 void Editor::SetScrollBars() {
3298 int nMax
= MaxScrollPos();
3299 int nPage
= LinesOnScreen();
3300 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
3305 // TODO: ensure always showing as many lines as possible
3306 // May not be, if, for example, window made larger
3307 if (topLine
> MaxScrollPos()) {
3308 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
3309 SetVerticalScrollPos();
3313 if (!AbandonPaint())
3316 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
3319 void Editor::ChangeSize() {
3322 if (wrapState
!= eWrapNone
) {
3323 PRectangle rcTextArea
= GetClientRectangle();
3324 rcTextArea
.left
= vs
.fixedColumnWidth
;
3325 rcTextArea
.right
-= vs
.rightMarginWidth
;
3326 if (wrapWidth
!= rcTextArea
.Width()) {
3333 void Editor::AddChar(char ch
) {
3340 void Editor::AddCharUTF(char *s
, unsigned int len
, bool treatAsDBCS
) {
3341 bool wasSelection
= currentPos
!= anchor
;
3343 bool charReplaceAction
= false;
3344 if (inOverstrike
&& !wasSelection
&& !RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3345 if (currentPos
< (pdoc
->Length())) {
3346 if (!IsEOLChar(pdoc
->CharAt(currentPos
))) {
3347 charReplaceAction
= true;
3348 pdoc
->BeginUndoAction();
3349 pdoc
->DelChar(currentPos
);
3353 if (pdoc
->InsertString(currentPos
, s
, len
)) {
3354 SetEmptySelection(currentPos
+ len
);
3356 if (charReplaceAction
) {
3357 pdoc
->EndUndoAction();
3359 EnsureCaretVisible();
3360 // Avoid blinking during rapid typing:
3361 ShowCaretAtCurrentPosition();
3367 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
3368 static_cast<unsigned char>(s
[1]));
3370 int byte
= static_cast<unsigned char>(s
[0]);
3371 if ((byte
< 0xC0) || (1 == len
)) {
3372 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
3373 // characters when not in UTF-8 mode.
3374 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
3375 // characters representing themselves.
3377 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
3378 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
3379 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
3381 int byte2
= static_cast<unsigned char>(s
[1]);
3382 if ((byte2
& 0xC0) == 0x80) {
3383 // Two-byte-character lead-byte followed by a trail-byte.
3384 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
3386 // A two-byte-character lead-byte not followed by trail-byte
3387 // represents itself.
3388 } else if (byte
< 0xF0) {
3389 int byte2
= static_cast<unsigned char>(s
[1]);
3390 int byte3
= static_cast<unsigned char>(s
[2]);
3391 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
3392 // Three-byte-character lead byte followed by two trail bytes.
3393 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
3396 // A three-byte-character lead-byte not followed by two trail-bytes
3397 // represents itself.
3404 void Editor::ClearSelection() {
3405 if (!SelectionContainsProtected()) {
3406 int startPos
= SelectionStart();
3407 if (selType
== selStream
) {
3408 unsigned int chars
= SelectionEnd() - startPos
;
3410 pdoc
->BeginUndoAction();
3411 pdoc
->DeleteChars(startPos
, chars
);
3412 pdoc
->EndUndoAction();
3415 pdoc
->BeginUndoAction();
3416 SelectionLineIterator
lineIterator(this, false);
3417 while (lineIterator
.Iterate()) {
3418 startPos
= lineIterator
.startPos
;
3419 unsigned int chars
= lineIterator
.endPos
- startPos
;
3421 pdoc
->DeleteChars(startPos
, chars
);
3424 pdoc
->EndUndoAction();
3425 selType
= selStream
;
3427 SetEmptySelection(startPos
);
3431 void Editor::ClearAll() {
3432 pdoc
->BeginUndoAction();
3433 if (0 != pdoc
->Length()) {
3434 pdoc
->DeleteChars(0, pdoc
->Length());
3436 if (!pdoc
->IsReadOnly()) {
3439 pdoc
->EndUndoAction();
3443 SetVerticalScrollPos();
3444 InvalidateStyleRedraw();
3447 void Editor::ClearDocumentStyle() {
3448 pdoc
->StartStyling(0, '\377');
3449 pdoc
->SetStyleFor(pdoc
->Length(), 0);
3451 pdoc
->ClearLevels();
3454 void Editor::Cut() {
3455 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
3461 void Editor::PasteRectangular(int pos
, const char *ptr
, int len
) {
3462 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
3466 int xInsert
= XFromPosition(currentPos
);
3467 int line
= pdoc
->LineFromPosition(currentPos
);
3468 bool prevCr
= false;
3469 pdoc
->BeginUndoAction();
3470 for (int i
= 0; i
< len
; i
++) {
3471 if (IsEOLChar(ptr
[i
])) {
3472 if ((ptr
[i
] == '\r') || (!prevCr
))
3474 if (line
>= pdoc
->LinesTotal()) {
3475 if (pdoc
->eolMode
!= SC_EOL_LF
)
3476 pdoc
->InsertChar(pdoc
->Length(), '\r');
3477 if (pdoc
->eolMode
!= SC_EOL_CR
)
3478 pdoc
->InsertChar(pdoc
->Length(), '\n');
3480 // Pad the end of lines with spaces if required
3481 currentPos
= PositionFromLineX(line
, xInsert
);
3482 if ((XFromPosition(currentPos
) < xInsert
) && (i
+ 1 < len
)) {
3483 for (int i
= 0; i
< xInsert
- XFromPosition(currentPos
); i
++) {
3484 pdoc
->InsertChar(currentPos
, ' ');
3488 prevCr
= ptr
[i
] == '\r';
3490 pdoc
->InsertString(currentPos
, ptr
+ i
, 1);
3495 pdoc
->EndUndoAction();
3496 SetEmptySelection(pos
);
3499 bool Editor::CanPaste() {
3500 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
3503 void Editor::Clear() {
3504 if (currentPos
== anchor
) {
3505 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3511 SetEmptySelection(currentPos
);
3514 void Editor::SelectAll() {
3515 SetSelection(0, pdoc
->Length());
3519 void Editor::Undo() {
3520 if (pdoc
->CanUndo()) {
3522 int newPos
= pdoc
->Undo();
3524 SetEmptySelection(newPos
);
3525 EnsureCaretVisible();
3529 void Editor::Redo() {
3530 if (pdoc
->CanRedo()) {
3531 int newPos
= pdoc
->Redo();
3533 SetEmptySelection(newPos
);
3534 EnsureCaretVisible();
3538 void Editor::DelChar() {
3539 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3540 pdoc
->DelChar(currentPos
);
3542 // Avoid blinking during rapid typing:
3543 ShowCaretAtCurrentPosition();
3546 void Editor::DelCharBack(bool allowLineStartDeletion
) {
3547 if (currentPos
== anchor
) {
3548 if (!RangeContainsProtected(currentPos
- 1, currentPos
)) {
3549 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
3550 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != currentPos
)) {
3551 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3552 pdoc
->GetColumn(currentPos
) > 0 && pdoc
->backspaceUnindents
) {
3553 pdoc
->BeginUndoAction();
3554 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3555 int indentationStep
= pdoc
->IndentSize();
3556 if (indentation
% indentationStep
== 0) {
3557 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3559 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- (indentation
% indentationStep
));
3561 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
3562 pdoc
->EndUndoAction();
3564 pdoc
->DelCharBack(currentPos
);
3570 SetEmptySelection(currentPos
);
3572 // Avoid blinking during rapid typing:
3573 ShowCaretAtCurrentPosition();
3576 void Editor::NotifyFocus(bool) {}
3578 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
3579 SCNotification scn
= {0};
3580 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
3581 scn
.position
= endStyleNeeded
;
3585 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
3586 NotifyStyleToNeeded(endStyleNeeded
);
3589 void Editor::NotifyChar(int ch
) {
3590 SCNotification scn
= {0};
3591 scn
.nmhdr
.code
= SCN_CHARADDED
;
3594 if (recordingMacro
) {
3596 txt
[0] = static_cast<char>(ch
);
3598 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
3602 void Editor::NotifySavePoint(bool isSavePoint
) {
3603 SCNotification scn
= {0};
3605 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
3607 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
3612 void Editor::NotifyModifyAttempt() {
3613 SCNotification scn
= {0};
3614 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
3618 void Editor::NotifyDoubleClick(Point
, bool) {
3619 SCNotification scn
= {0};
3620 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
3624 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3625 SCNotification scn
= {0};
3626 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
3627 scn
.position
= position
;
3628 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3629 (alt
? SCI_ALT
: 0);
3633 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3634 SCNotification scn
= {0};
3635 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
3636 scn
.position
= position
;
3637 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3638 (alt
? SCI_ALT
: 0);
3642 void Editor::NotifyUpdateUI() {
3643 SCNotification scn
= {0};
3644 scn
.nmhdr
.code
= SCN_UPDATEUI
;
3648 void Editor::NotifyPainted() {
3649 SCNotification scn
= {0};
3650 scn
.nmhdr
.code
= SCN_PAINTED
;
3654 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
3655 int marginClicked
= -1;
3657 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
3658 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
3659 marginClicked
= margin
;
3660 x
+= vs
.ms
[margin
].width
;
3662 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
3663 SCNotification scn
= {0};
3664 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
3665 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3666 (alt
? SCI_ALT
: 0);
3667 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
3668 scn
.margin
= marginClicked
;
3676 void Editor::NotifyNeedShown(int pos
, int len
) {
3677 SCNotification scn
= {0};
3678 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
3684 void Editor::NotifyDwelling(Point pt
, bool state
) {
3685 SCNotification scn
= {0};
3686 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
3687 scn
.position
= PositionFromLocationClose(pt
);
3693 void Editor::NotifyZoom() {
3694 SCNotification scn
= {0};
3695 scn
.nmhdr
.code
= SCN_ZOOM
;
3699 // Notifications from document
3700 void Editor::NotifyModifyAttempt(Document
*, void *) {
3701 //Platform::DebugPrintf("** Modify Attempt\n");
3702 NotifyModifyAttempt();
3705 void Editor::NotifyMove(int position
) {
3706 SCNotification scn
= {0};
3707 scn
.nmhdr
.code
= SCN_POSCHANGED
;
3708 scn
.position
= position
;
3712 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
3713 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
3714 NotifySavePoint(atSavePoint
);
3717 void Editor::CheckModificationForWrap(DocModification mh
) {
3718 if (mh
.modificationType
& (SC_MOD_INSERTTEXT
|SC_MOD_DELETETEXT
)) {
3719 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
3720 if (wrapState
!= eWrapNone
) {
3721 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
3722 int lines
= Platform::Maximum(0, mh
.linesAdded
);
3723 NeedWrapping(lineDoc
, lineDoc
+ lines
+ 1);
3728 // Move a position so it is still after the same character as before the insertion.
3729 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
3730 if (position
> startInsertion
) {
3731 return position
+ length
;
3736 // Move a position so it is still after the same character as before the deletion if that
3737 // character is still present else after the previous surviving character.
3738 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
3739 if (position
> startDeletion
) {
3740 int endDeletion
= startDeletion
+ length
;
3741 if (position
> endDeletion
) {
3742 return position
- length
;
3744 return startDeletion
;
3751 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
3752 needUpdateUI
= true;
3753 if (paintState
== painting
) {
3754 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
3756 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
3757 pdoc
->IncrementStyleClock();
3758 if (paintState
== notPainting
) {
3759 if (mh
.position
< pdoc
->LineStart(topLine
)) {
3760 // Styling performed before this view
3763 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3766 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
3768 // Move selection and brace highlights
3769 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
3770 currentPos
= MovePositionForInsertion(currentPos
, mh
.position
, mh
.length
);
3771 anchor
= MovePositionForInsertion(anchor
, mh
.position
, mh
.length
);
3772 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
3773 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
3774 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
3775 currentPos
= MovePositionForDeletion(currentPos
, mh
.position
, mh
.length
);
3776 anchor
= MovePositionForDeletion(anchor
, mh
.position
, mh
.length
);
3777 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
3778 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
3780 if (cs
.LinesDisplayed() < cs
.LinesInDoc()) {
3781 // Some lines are hidden so may need shown.
3782 // TODO: check if the modified area is hidden.
3783 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
3784 NotifyNeedShown(mh
.position
, 0);
3785 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
3786 NotifyNeedShown(mh
.position
, mh
.length
);
3789 if (mh
.linesAdded
!= 0) {
3790 // Update contraction state for inserted and removed lines
3791 // lineOfPos should be calculated in context of state before modification, shouldn't it
3792 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
3793 if (mh
.linesAdded
> 0) {
3794 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
3796 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
3799 CheckModificationForWrap(mh
);
3800 if (mh
.linesAdded
!= 0) {
3801 // Avoid scrolling of display if change before current display
3802 if (mh
.position
< posTopLine
&& !CanDeferToLastStep(mh
)) {
3803 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
3804 if (newTop
!= topLine
) {
3806 SetVerticalScrollPos();
3810 //Platform::DebugPrintf("** %x Doc Changed\n", this);
3811 // TODO: could invalidate from mh.startModification to end of screen
3812 //InvalidateRange(mh.position, mh.position + mh.length);
3813 if (paintState
== notPainting
&& !CanDeferToLastStep(mh
)) {
3817 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
3818 // mh.position, mh.position + mh.length);
3819 if (paintState
== notPainting
&& mh
.length
&& !CanEliminate(mh
)) {
3820 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3825 if (mh
.linesAdded
!= 0 && !CanDeferToLastStep(mh
)) {
3829 if (mh
.modificationType
& SC_MOD_CHANGEMARKER
) {
3830 if ((paintState
== notPainting
) || !PaintContainsMargin()) {
3831 if (mh
.modificationType
& SC_MOD_CHANGEFOLD
) {
3832 // Fold changes can affect the drawing of following lines so redraw whole margin
3835 RedrawSelMargin(mh
.line
);
3840 // NOW pay the piper WRT "deferred" visual updates
3841 if (IsLastStep(mh
)) {
3846 // If client wants to see this modification
3847 if (mh
.modificationType
& modEventMask
) {
3848 if ((mh
.modificationType
& SC_MOD_CHANGESTYLE
) == 0) {
3849 // Real modification made to text of document.
3850 NotifyChange(); // Send EN_CHANGE
3853 SCNotification scn
= {0};
3854 scn
.nmhdr
.code
= SCN_MODIFIED
;
3855 scn
.position
= mh
.position
;
3856 scn
.modificationType
= mh
.modificationType
;
3858 scn
.length
= mh
.length
;
3859 scn
.linesAdded
= mh
.linesAdded
;
3861 scn
.foldLevelNow
= mh
.foldLevelNow
;
3862 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
3867 void Editor::NotifyDeleted(Document
*, void *) {
3871 void Editor::NotifyMacroRecord(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
3873 // Enumerates all macroable messages
3879 case SCI_REPLACESEL
:
3881 case SCI_INSERTTEXT
:
3882 case SCI_APPENDTEXT
:
3887 case SCI_SEARCHANCHOR
:
3888 case SCI_SEARCHNEXT
:
3889 case SCI_SEARCHPREV
:
3891 case SCI_LINEDOWNEXTEND
:
3893 case SCI_PARADOWNEXTEND
:
3895 case SCI_LINEUPEXTEND
:
3897 case SCI_PARAUPEXTEND
:
3899 case SCI_CHARLEFTEXTEND
:
3901 case SCI_CHARRIGHTEXTEND
:
3903 case SCI_WORDLEFTEXTEND
:
3905 case SCI_WORDRIGHTEXTEND
:
3906 case SCI_WORDPARTLEFT
:
3907 case SCI_WORDPARTLEFTEXTEND
:
3908 case SCI_WORDPARTRIGHT
:
3909 case SCI_WORDPARTRIGHTEXTEND
:
3910 case SCI_WORDLEFTEND
:
3911 case SCI_WORDLEFTENDEXTEND
:
3912 case SCI_WORDRIGHTEND
:
3913 case SCI_WORDRIGHTENDEXTEND
:
3915 case SCI_HOMEEXTEND
:
3917 case SCI_LINEENDEXTEND
:
3919 case SCI_HOMEWRAPEXTEND
:
3920 case SCI_LINEENDWRAP
:
3921 case SCI_LINEENDWRAPEXTEND
:
3922 case SCI_DOCUMENTSTART
:
3923 case SCI_DOCUMENTSTARTEXTEND
:
3924 case SCI_DOCUMENTEND
:
3925 case SCI_DOCUMENTENDEXTEND
:
3926 case SCI_STUTTEREDPAGEUP
:
3927 case SCI_STUTTEREDPAGEUPEXTEND
:
3928 case SCI_STUTTEREDPAGEDOWN
:
3929 case SCI_STUTTEREDPAGEDOWNEXTEND
:
3931 case SCI_PAGEUPEXTEND
:
3933 case SCI_PAGEDOWNEXTEND
:
3934 case SCI_EDITTOGGLEOVERTYPE
:
3936 case SCI_DELETEBACK
:
3941 case SCI_VCHOMEEXTEND
:
3942 case SCI_VCHOMEWRAP
:
3943 case SCI_VCHOMEWRAPEXTEND
:
3944 case SCI_DELWORDLEFT
:
3945 case SCI_DELWORDRIGHT
:
3946 case SCI_DELLINELEFT
:
3947 case SCI_DELLINERIGHT
:
3950 case SCI_LINEDELETE
:
3951 case SCI_LINETRANSPOSE
:
3952 case SCI_LINEDUPLICATE
:
3955 case SCI_LINESCROLLDOWN
:
3956 case SCI_LINESCROLLUP
:
3957 case SCI_DELETEBACKNOTLINE
:
3958 case SCI_HOMEDISPLAY
:
3959 case SCI_HOMEDISPLAYEXTEND
:
3960 case SCI_LINEENDDISPLAY
:
3961 case SCI_LINEENDDISPLAYEXTEND
:
3962 case SCI_SETSELECTIONMODE
:
3963 case SCI_LINEDOWNRECTEXTEND
:
3964 case SCI_LINEUPRECTEXTEND
:
3965 case SCI_CHARLEFTRECTEXTEND
:
3966 case SCI_CHARRIGHTRECTEXTEND
:
3967 case SCI_HOMERECTEXTEND
:
3968 case SCI_VCHOMERECTEXTEND
:
3969 case SCI_LINEENDRECTEXTEND
:
3970 case SCI_PAGEUPRECTEXTEND
:
3971 case SCI_PAGEDOWNRECTEXTEND
:
3972 case SCI_SELECTIONDUPLICATE
:
3975 // Filter out all others like display changes. Also, newlines are redundant
3976 // with char insert messages.
3979 // printf("Filtered out %ld of macro recording\n", iMessage);
3983 // Send notification
3984 SCNotification scn
= {0};
3985 scn
.nmhdr
.code
= SCN_MACRORECORD
;
3986 scn
.message
= iMessage
;
3987 scn
.wParam
= wParam
;
3988 scn
.lParam
= lParam
;
3993 * Force scroll and keep position relative to top of window.
3995 * If stuttered = true and not already at first/last row, move to first/last row of window.
3996 * If stuttered = true and already at first/last row, scroll as normal.
3998 void Editor::PageMove(int direction
, selTypes sel
, bool stuttered
) {
3999 int topLineNew
, newPos
;
4001 // I consider only the caretYSlop, and ignore the caretYPolicy-- is that a problem?
4002 int currentLine
= pdoc
->LineFromPosition(currentPos
);
4003 int topStutterLine
= topLine
+ caretYSlop
;
4004 int bottomStutterLine
= topLine
+ LinesToScroll() - caretYSlop
;
4006 if (stuttered
&& (direction
< 0 && currentLine
> topStutterLine
)) {
4007 topLineNew
= topLine
;
4008 newPos
= PositionFromLocation(Point(lastXChosen
, vs
.lineHeight
* caretYSlop
));
4010 } else if (stuttered
&& (direction
> 0 && currentLine
< bottomStutterLine
)) {
4011 topLineNew
= topLine
;
4012 newPos
= PositionFromLocation(Point(lastXChosen
, vs
.lineHeight
* (LinesToScroll() - caretYSlop
)));
4015 Point pt
= LocationFromPosition(currentPos
);
4017 topLineNew
= Platform::Clamp(
4018 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
4019 newPos
= PositionFromLocation(
4020 Point(lastXChosen
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())));
4023 if (topLineNew
!= topLine
) {
4024 SetTopLine(topLineNew
);
4025 MovePositionTo(newPos
, sel
);
4027 SetVerticalScrollPos();
4029 MovePositionTo(newPos
, sel
);
4033 void Editor::ChangeCaseOfSelection(bool makeUpperCase
) {
4034 pdoc
->BeginUndoAction();
4035 int startCurrent
= currentPos
;
4036 int startAnchor
= anchor
;
4037 if (selType
== selStream
) {
4038 pdoc
->ChangeCase(Range(SelectionStart(), SelectionEnd()),
4040 SetSelection(startCurrent
, startAnchor
);
4042 SelectionLineIterator
lineIterator(this, false);
4043 while (lineIterator
.Iterate()) {
4045 Range(lineIterator
.startPos
, lineIterator
.endPos
),
4048 // Would be nicer to keep the rectangular selection but this is complex
4049 SetEmptySelection(startCurrent
);
4051 pdoc
->EndUndoAction();
4054 void Editor::LineTranspose() {
4055 int line
= pdoc
->LineFromPosition(currentPos
);
4057 int startPrev
= pdoc
->LineStart(line
- 1);
4058 int endPrev
= pdoc
->LineEnd(line
- 1);
4059 int start
= pdoc
->LineStart(line
);
4060 int end
= pdoc
->LineEnd(line
);
4061 int startNext
= pdoc
->LineStart(line
+ 1);
4062 if (end
< pdoc
->Length()) {
4064 char *thisLine
= CopyRange(start
, end
);
4065 pdoc
->DeleteChars(start
, end
- start
);
4066 if (pdoc
->InsertString(startPrev
, thisLine
, end
- start
)) {
4067 MovePositionTo(startPrev
+ end
- start
);
4071 // Last line so line has no line end
4072 char *thisLine
= CopyRange(start
, end
);
4073 char *prevEnd
= CopyRange(endPrev
, start
);
4074 pdoc
->DeleteChars(endPrev
, end
- endPrev
);
4075 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
4076 if (pdoc
->InsertString(startPrev
+ end
- start
, prevEnd
, start
- endPrev
)) {
4077 MovePositionTo(startPrev
+ end
- endPrev
);
4086 void Editor::Duplicate(bool forLine
) {
4087 int start
= SelectionStart();
4088 int end
= SelectionEnd();
4093 int line
= pdoc
->LineFromPosition(currentPos
);
4094 start
= pdoc
->LineStart(line
);
4095 end
= pdoc
->LineEnd(line
);
4097 char *text
= CopyRange(start
, end
);
4099 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
4100 pdoc
->InsertString(end
, eol
);
4101 pdoc
->InsertString(end
+ istrlen(eol
), text
, end
- start
);
4103 pdoc
->InsertString(end
, text
, end
- start
);
4108 void Editor::CancelModes() {
4109 moveExtendsSelection
= false;
4112 void Editor::NewLine() {
4114 const char *eol
= "\n";
4115 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
4117 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
4119 } // else SC_EOL_LF -> "\n" already set
4120 if (pdoc
->InsertString(currentPos
, eol
)) {
4121 SetEmptySelection(currentPos
+ istrlen(eol
));
4128 EnsureCaretVisible();
4129 // Avoid blinking during rapid typing:
4130 ShowCaretAtCurrentPosition();
4133 void Editor::CursorUpOrDown(int direction
, selTypes sel
) {
4134 Point pt
= LocationFromPosition(currentPos
);
4135 int posNew
= PositionFromLocation(
4136 Point(lastXChosen
, pt
.y
+ direction
* vs
.lineHeight
));
4137 if (direction
< 0) {
4138 // Line wrapping may lead to a location on the same line, so
4139 // seek back if that is the case.
4140 // There is an equivalent case when moving down which skips
4141 // over a line but as that does not trap the user it is fine.
4142 Point ptNew
= LocationFromPosition(posNew
);
4143 while ((posNew
> 0) && (pt
.y
== ptNew
.y
)) {
4145 ptNew
= LocationFromPosition(posNew
);
4148 MovePositionTo(posNew
, sel
);
4151 void Editor::ParaUpOrDown(int direction
, selTypes sel
) {
4152 int lineDoc
, savedPos
= currentPos
;
4154 MovePositionTo(direction
> 0 ? pdoc
->ParaDown(currentPos
) : pdoc
->ParaUp(currentPos
), sel
);
4155 lineDoc
= pdoc
->LineFromPosition(currentPos
);
4156 if (direction
> 0) {
4157 if (currentPos
>= pdoc
->Length() && !cs
.GetVisible(lineDoc
)) {
4159 MovePositionTo(pdoc
->LineEndPosition(savedPos
));
4164 } while (!cs
.GetVisible(lineDoc
));
4167 int Editor::StartEndDisplayLine(int pos
, bool start
) {
4169 int line
= pdoc
->LineFromPosition(pos
);
4170 AutoSurface
surface(this);
4171 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
4172 int posRet
= INVALID_POSITION
;
4173 if (surface
&& ll
) {
4174 unsigned int posLineStart
= pdoc
->LineStart(line
);
4175 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
4176 int posInLine
= pos
- posLineStart
;
4177 if (posInLine
<= ll
->maxLineLength
) {
4178 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
4179 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
4181 posRet
= ll
->LineStart(subLine
) + posLineStart
;
4183 if (subLine
== ll
->lines
- 1)
4184 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
;
4186 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
- 1;
4192 if (posRet
== INVALID_POSITION
) {
4199 int Editor::KeyCommand(unsigned int iMessage
) {
4204 case SCI_LINEDOWNEXTEND
:
4205 CursorUpOrDown(1, selStream
);
4207 case SCI_LINEDOWNRECTEXTEND
:
4208 CursorUpOrDown(1, selRectangle
);
4213 case SCI_PARADOWNEXTEND
:
4214 ParaUpOrDown(1, selStream
);
4216 case SCI_LINESCROLLDOWN
:
4217 ScrollTo(topLine
+ 1);
4218 MoveCaretInsideView(false);
4223 case SCI_LINEUPEXTEND
:
4224 CursorUpOrDown(-1, selStream
);
4226 case SCI_LINEUPRECTEXTEND
:
4227 CursorUpOrDown(-1, selRectangle
);
4232 case SCI_PARAUPEXTEND
:
4233 ParaUpOrDown(-1, selStream
);
4235 case SCI_LINESCROLLUP
:
4236 ScrollTo(topLine
- 1);
4237 MoveCaretInsideView(false);
4240 if (SelectionEmpty() || moveExtendsSelection
) {
4241 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1));
4243 MovePositionTo(SelectionStart());
4247 case SCI_CHARLEFTEXTEND
:
4248 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), selStream
);
4251 case SCI_CHARLEFTRECTEXTEND
:
4252 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), selRectangle
);
4256 if (SelectionEmpty() || moveExtendsSelection
) {
4257 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1));
4259 MovePositionTo(SelectionEnd());
4263 case SCI_CHARRIGHTEXTEND
:
4264 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), selStream
);
4267 case SCI_CHARRIGHTRECTEXTEND
:
4268 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), selRectangle
);
4272 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1));
4275 case SCI_WORDLEFTEXTEND
:
4276 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1), selStream
);
4280 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1));
4283 case SCI_WORDRIGHTEXTEND
:
4284 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1), selStream
);
4288 case SCI_WORDLEFTEND
:
4289 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, -1), -1));
4292 case SCI_WORDLEFTENDEXTEND
:
4293 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, -1), -1), selStream
);
4296 case SCI_WORDRIGHTEND
:
4297 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, 1), 1));
4300 case SCI_WORDRIGHTENDEXTEND
:
4301 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, 1), 1), selStream
);
4306 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)));
4309 case SCI_HOMEEXTEND
:
4310 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), selStream
);
4313 case SCI_HOMERECTEXTEND
:
4314 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), selRectangle
);
4318 MovePositionTo(pdoc
->LineEndPosition(currentPos
));
4321 case SCI_LINEENDEXTEND
:
4322 MovePositionTo(pdoc
->LineEndPosition(currentPos
), selStream
);
4325 case SCI_LINEENDRECTEXTEND
:
4326 MovePositionTo(pdoc
->LineEndPosition(currentPos
), selRectangle
);
4329 case SCI_HOMEWRAP
: {
4330 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4331 if (currentPos
<= homePos
)
4332 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
4333 MovePositionTo(homePos
);
4337 case SCI_HOMEWRAPEXTEND
: {
4338 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4339 if (currentPos
<= homePos
)
4340 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
4341 MovePositionTo(homePos
, selStream
);
4345 case SCI_LINEENDWRAP
: {
4346 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
4347 int realEndPos
= pdoc
->LineEndPosition(currentPos
);
4348 if (endPos
> realEndPos
// if moved past visible EOLs
4349 || currentPos
>= endPos
) // if at end of display line already
4350 endPos
= realEndPos
;
4351 MovePositionTo(endPos
);
4355 case SCI_LINEENDWRAPEXTEND
: {
4356 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
4357 int realEndPos
= pdoc
->LineEndPosition(currentPos
);
4358 if (endPos
> realEndPos
// if moved past visible EOLs
4359 || currentPos
>= endPos
) // if at end of display line already
4360 endPos
= realEndPos
;
4361 MovePositionTo(endPos
, selStream
);
4365 case SCI_DOCUMENTSTART
:
4369 case SCI_DOCUMENTSTARTEXTEND
:
4370 MovePositionTo(0, selStream
);
4373 case SCI_DOCUMENTEND
:
4374 MovePositionTo(pdoc
->Length());
4377 case SCI_DOCUMENTENDEXTEND
:
4378 MovePositionTo(pdoc
->Length(), selStream
);
4381 case SCI_STUTTEREDPAGEUP
:
4382 PageMove(-1, noSel
, true);
4384 case SCI_STUTTEREDPAGEUPEXTEND
:
4385 PageMove(-1, selStream
, true);
4387 case SCI_STUTTEREDPAGEDOWN
:
4388 PageMove(1, noSel
, true);
4390 case SCI_STUTTEREDPAGEDOWNEXTEND
:
4391 PageMove(1, selStream
, true);
4396 case SCI_PAGEUPEXTEND
:
4397 PageMove(-1, selStream
);
4399 case SCI_PAGEUPRECTEXTEND
:
4400 PageMove(-1, selRectangle
);
4405 case SCI_PAGEDOWNEXTEND
:
4406 PageMove(1, selStream
);
4408 case SCI_PAGEDOWNRECTEXTEND
:
4409 PageMove(1, selRectangle
);
4411 case SCI_EDITTOGGLEOVERTYPE
:
4412 inOverstrike
= !inOverstrike
;
4414 ShowCaretAtCurrentPosition();
4417 case SCI_CANCEL
: // Cancel any modes - handled in subclass
4418 // Also unselect text
4421 case SCI_DELETEBACK
:
4426 EnsureCaretVisible();
4428 case SCI_DELETEBACKNOTLINE
:
4433 EnsureCaretVisible();
4440 EnsureCaretVisible();
4447 EnsureCaretVisible();
4456 MovePositionTo(pdoc
->VCHomePosition(currentPos
));
4459 case SCI_VCHOMEEXTEND
:
4460 MovePositionTo(pdoc
->VCHomePosition(currentPos
), selStream
);
4463 case SCI_VCHOMERECTEXTEND
:
4464 MovePositionTo(pdoc
->VCHomePosition(currentPos
), selRectangle
);
4467 case SCI_VCHOMEWRAP
: {
4468 int homePos
= pdoc
->VCHomePosition(currentPos
);
4469 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4470 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
4471 homePos
= viewLineStart
;
4473 MovePositionTo(homePos
);
4477 case SCI_VCHOMEWRAPEXTEND
: {
4478 int homePos
= pdoc
->VCHomePosition(currentPos
);
4479 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4480 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
4481 homePos
= viewLineStart
;
4483 MovePositionTo(homePos
, selStream
);
4488 if (vs
.zoomLevel
< 20) {
4490 InvalidateStyleRedraw();
4495 if (vs
.zoomLevel
> -10) {
4497 InvalidateStyleRedraw();
4501 case SCI_DELWORDLEFT
: {
4502 int startWord
= pdoc
->NextWordStart(currentPos
, -1);
4503 pdoc
->DeleteChars(startWord
, currentPos
- startWord
);
4507 case SCI_DELWORDRIGHT
: {
4508 int endWord
= pdoc
->NextWordStart(currentPos
, 1);
4509 pdoc
->DeleteChars(currentPos
, endWord
- currentPos
);
4512 case SCI_DELLINELEFT
: {
4513 int line
= pdoc
->LineFromPosition(currentPos
);
4514 int start
= pdoc
->LineStart(line
);
4515 pdoc
->DeleteChars(start
, currentPos
- start
);
4519 case SCI_DELLINERIGHT
: {
4520 int line
= pdoc
->LineFromPosition(currentPos
);
4521 int end
= pdoc
->LineEnd(line
);
4522 pdoc
->DeleteChars(currentPos
, end
- currentPos
);
4525 case SCI_LINECOPY
: {
4526 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4527 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4528 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
4529 pdoc
->LineStart(lineEnd
+ 1));
4533 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4534 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4535 int start
= pdoc
->LineStart(lineStart
);
4536 int end
= pdoc
->LineStart(lineEnd
+ 1);
4537 SetSelection(start
, end
);
4542 case SCI_LINEDELETE
: {
4543 int line
= pdoc
->LineFromPosition(currentPos
);
4544 int start
= pdoc
->LineStart(line
);
4545 int end
= pdoc
->LineStart(line
+ 1);
4546 pdoc
->DeleteChars(start
, end
- start
);
4549 case SCI_LINETRANSPOSE
:
4552 case SCI_LINEDUPLICATE
:
4555 case SCI_SELECTIONDUPLICATE
:
4559 ChangeCaseOfSelection(false);
4562 ChangeCaseOfSelection(true);
4564 case SCI_WORDPARTLEFT
:
4565 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1));
4568 case SCI_WORDPARTLEFTEXTEND
:
4569 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1), selStream
);
4572 case SCI_WORDPARTRIGHT
:
4573 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1));
4576 case SCI_WORDPARTRIGHTEXTEND
:
4577 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1), selStream
);
4580 case SCI_HOMEDISPLAY
:
4581 MovePositionTo(MovePositionSoVisible(
4582 StartEndDisplayLine(currentPos
, true), -1));
4585 case SCI_HOMEDISPLAYEXTEND
:
4586 MovePositionTo(MovePositionSoVisible(
4587 StartEndDisplayLine(currentPos
, true), -1), selStream
);
4590 case SCI_LINEENDDISPLAY
:
4591 MovePositionTo(MovePositionSoVisible(
4592 StartEndDisplayLine(currentPos
, false), 1));
4595 case SCI_LINEENDDISPLAYEXTEND
:
4596 MovePositionTo(MovePositionSoVisible(
4597 StartEndDisplayLine(currentPos
, false), 1), selStream
);
4604 int Editor::KeyDefault(int, int) {
4608 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
4610 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4611 (alt
? SCI_ALT
: 0);
4612 int msg
= kmap
.Find(key
, modifiers
);
4616 return WndProc(msg
, 0, 0);
4620 return KeyDefault(key
, modifiers
);
4624 void Editor::SetWhitespaceVisible(int view
) {
4625 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(view
);
4628 int Editor::GetWhitespaceVisible() {
4629 return vs
.viewWhitespace
;
4632 void Editor::Indent(bool forwards
) {
4633 //Platform::DebugPrintf("INdent %d\n", forwards);
4634 int lineOfAnchor
= pdoc
->LineFromPosition(anchor
);
4635 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
4636 if (lineOfAnchor
== lineCurrentPos
) {
4638 pdoc
->BeginUndoAction();
4640 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
4642 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4643 int indentationStep
= pdoc
->IndentSize();
4644 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
+ indentationStep
- indentation
% indentationStep
);
4645 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4647 if (pdoc
->useTabs
) {
4648 pdoc
->InsertChar(currentPos
, '\t');
4649 SetEmptySelection(currentPos
+ 1);
4651 int numSpaces
= (pdoc
->tabInChars
) -
4652 (pdoc
->GetColumn(currentPos
) % (pdoc
->tabInChars
));
4654 numSpaces
= pdoc
->tabInChars
;
4655 for (int i
= 0; i
< numSpaces
; i
++) {
4656 pdoc
->InsertChar(currentPos
+ i
, ' ');
4658 SetEmptySelection(currentPos
+ numSpaces
);
4661 pdoc
->EndUndoAction();
4663 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
4665 pdoc
->BeginUndoAction();
4666 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4667 int indentationStep
= pdoc
->IndentSize();
4668 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
4669 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4670 pdoc
->EndUndoAction();
4672 int newColumn
= ((pdoc
->GetColumn(currentPos
) - 1) / pdoc
->tabInChars
) *
4676 int newPos
= currentPos
;
4677 while (pdoc
->GetColumn(newPos
) > newColumn
)
4679 SetEmptySelection(newPos
);
4683 int anchorPosOnLine
= anchor
- pdoc
->LineStart(lineOfAnchor
);
4684 int currentPosPosOnLine
= currentPos
- pdoc
->LineStart(lineCurrentPos
);
4685 // Multiple lines selected so indent / dedent
4686 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
4687 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
4688 if (pdoc
->LineStart(lineBottomSel
) == anchor
|| pdoc
->LineStart(lineBottomSel
) == currentPos
)
4689 lineBottomSel
--; // If not selecting any characters on a line, do not indent
4690 pdoc
->BeginUndoAction();
4691 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
4692 pdoc
->EndUndoAction();
4693 if (lineOfAnchor
< lineCurrentPos
) {
4694 if (currentPosPosOnLine
== 0)
4695 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4697 SetSelection(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
4699 if (anchorPosOnLine
== 0)
4700 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4702 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
4708 * Search of a text in the document, in the given range.
4709 * @return The position of the found text, -1 if not found.
4711 long Editor::FindText(
4712 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4713 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4714 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
4716 TextToFind
*ft
= reinterpret_cast<TextToFind
*>(lParam
);
4717 int lengthFound
= istrlen(ft
->lpstrText
);
4718 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
4719 (wParam
& SCFIND_MATCHCASE
) != 0,
4720 (wParam
& SCFIND_WHOLEWORD
) != 0,
4721 (wParam
& SCFIND_WORDSTART
) != 0,
4722 (wParam
& SCFIND_REGEXP
) != 0,
4723 (wParam
& SCFIND_POSIX
) != 0,
4726 ft
->chrgText
.cpMin
= pos
;
4727 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
4733 * Relocatable search support : Searches relative to current selection
4734 * point and sets the selection to the found text range with
4738 * Anchor following searches at current selection start: This allows
4739 * multiple incremental interactive searches to be macro recorded
4740 * while still setting the selection to found text so the find/select
4741 * operation is self-contained.
4743 void Editor::SearchAnchor() {
4744 searchAnchor
= SelectionStart();
4748 * Find text from current search anchor: Must call @c SearchAnchor first.
4749 * Used for next text and previous text requests.
4750 * @return The position of the found text, -1 if not found.
4752 long Editor::SearchText(
4753 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
4754 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4755 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4756 sptr_t lParam
) { ///< The text to search for.
4758 const char *txt
= reinterpret_cast<char *>(lParam
);
4760 int lengthFound
= istrlen(txt
);
4761 if (iMessage
== SCI_SEARCHNEXT
) {
4762 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
4763 (wParam
& SCFIND_MATCHCASE
) != 0,
4764 (wParam
& SCFIND_WHOLEWORD
) != 0,
4765 (wParam
& SCFIND_WORDSTART
) != 0,
4766 (wParam
& SCFIND_REGEXP
) != 0,
4767 (wParam
& SCFIND_POSIX
) != 0,
4770 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
4771 (wParam
& SCFIND_MATCHCASE
) != 0,
4772 (wParam
& SCFIND_WHOLEWORD
) != 0,
4773 (wParam
& SCFIND_WORDSTART
) != 0,
4774 (wParam
& SCFIND_REGEXP
) != 0,
4775 (wParam
& SCFIND_POSIX
) != 0,
4780 SetSelection(pos
, pos
+ lengthFound
);
4787 * Search for text in the target range of the document.
4788 * @return The position of the found text, -1 if not found.
4790 long Editor::SearchInTarget(const char *text
, int length
) {
4791 int lengthFound
= length
;
4792 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
4793 (searchFlags
& SCFIND_MATCHCASE
) != 0,
4794 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
4795 (searchFlags
& SCFIND_WORDSTART
) != 0,
4796 (searchFlags
& SCFIND_REGEXP
) != 0,
4797 (searchFlags
& SCFIND_POSIX
) != 0,
4801 targetEnd
= pos
+ lengthFound
;
4806 void Editor::GoToLine(int lineNo
) {
4807 if (lineNo
> pdoc
->LinesTotal())
4808 lineNo
= pdoc
->LinesTotal();
4811 SetEmptySelection(pdoc
->LineStart(lineNo
));
4812 ShowCaretAtCurrentPosition();
4813 EnsureCaretVisible();
4816 static bool Close(Point pt1
, Point pt2
) {
4817 if (abs(pt1
.x
- pt2
.x
) > 3)
4819 if (abs(pt1
.y
- pt2
.y
) > 3)
4824 char *Editor::CopyRange(int start
, int end
) {
4827 int len
= end
- start
;
4828 text
= new char[len
+ 1];
4830 for (int i
= 0; i
< len
; i
++) {
4831 text
[i
] = pdoc
->CharAt(start
+ i
);
4839 void Editor::CopySelectionFromRange(SelectionText
*ss
, int start
, int end
) {
4840 ss
->Set(CopyRange(start
, end
), end
- start
+ 1,
4841 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4844 void Editor::CopySelectionRange(SelectionText
*ss
) {
4845 if (selType
== selStream
) {
4846 CopySelectionFromRange(ss
, SelectionStart(), SelectionEnd());
4850 SelectionLineIterator
lineIterator(this);
4851 while (lineIterator
.Iterate()) {
4852 size
+= lineIterator
.endPos
- lineIterator
.startPos
;
4853 if (selType
!= selLines
) {
4855 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
4861 text
= new char[size
+ 1];
4864 lineIterator
.Reset();
4865 while (lineIterator
.Iterate()) {
4866 for (int i
= lineIterator
.startPos
;
4867 i
< lineIterator
.endPos
;
4869 text
[j
++] = pdoc
->CharAt(i
);
4871 if (selType
!= selLines
) {
4872 if (pdoc
->eolMode
!= SC_EOL_LF
) {
4875 if (pdoc
->eolMode
!= SC_EOL_CR
) {
4883 ss
->Set(text
, size
+ 1, pdoc
->dbcsCodePage
,
4884 vs
.styles
[STYLE_DEFAULT
].characterSet
, selType
== selRectangle
);
4888 void Editor::CopyRangeToClipboard(int start
, int end
) {
4889 start
= pdoc
->ClampPositionIntoDocument(start
);
4890 end
= pdoc
->ClampPositionIntoDocument(end
);
4891 SelectionText selectedText
;
4892 selectedText
.Set(CopyRange(start
, end
), end
- start
+ 1,
4893 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4894 CopyToClipboard(selectedText
);
4897 void Editor::CopyText(int length
, const char *text
) {
4898 SelectionText selectedText
;
4899 selectedText
.Copy(text
, length
+ 1,
4900 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4901 CopyToClipboard(selectedText
);
4904 void Editor::SetDragPosition(int newPos
) {
4906 newPos
= MovePositionOutsideChar(newPos
, 1);
4909 if (posDrag
!= newPos
) {
4918 void Editor::DisplayCursor(Window::Cursor c
) {
4919 if (cursorMode
== SC_CURSORNORMAL
)
4922 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
4925 void Editor::StartDrag() {
4926 // Always handled by subclasses
4927 //SetMouseCapture(true);
4928 //DisplayCursor(Window::cursorArrow);
4931 void Editor::DropAt(int position
, const char *value
, bool moving
, bool rectangular
) {
4932 //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
4934 dropWentOutside
= false;
4936 int positionWasInSelection
= PositionInSelection(position
);
4938 bool positionOnEdgeOfSelection
=
4939 (position
== SelectionStart()) || (position
== SelectionEnd());
4941 if ((!inDragDrop
) || !(0 == positionWasInSelection
) ||
4942 (positionOnEdgeOfSelection
&& !moving
)) {
4944 int selStart
= SelectionStart();
4945 int selEnd
= SelectionEnd();
4947 pdoc
->BeginUndoAction();
4949 int positionAfterDeletion
= position
;
4950 if (inDragDrop
&& moving
) {
4951 // Remove dragged out text
4952 if (rectangular
|| selType
== selLines
) {
4953 SelectionLineIterator
lineIterator(this);
4954 while (lineIterator
.Iterate()) {
4955 if (position
>= lineIterator
.startPos
) {
4956 if (position
> lineIterator
.endPos
) {
4957 positionAfterDeletion
-= lineIterator
.endPos
- lineIterator
.startPos
;
4959 positionAfterDeletion
-= position
- lineIterator
.startPos
;
4964 if (position
> selStart
) {
4965 positionAfterDeletion
-= selEnd
- selStart
;
4970 position
= positionAfterDeletion
;
4973 PasteRectangular(position
, value
, istrlen(value
));
4974 pdoc
->EndUndoAction();
4975 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
4976 SetEmptySelection(position
);
4978 position
= MovePositionOutsideChar(position
, currentPos
- position
);
4979 if (pdoc
->InsertString(position
, value
)) {
4980 SetSelection(position
+ istrlen(value
), position
);
4982 pdoc
->EndUndoAction();
4984 } else if (inDragDrop
) {
4985 SetEmptySelection(position
);
4990 * @return -1 if given position is before the selection,
4991 * 1 if position is after the selection,
4992 * 0 if position is inside the selection,
4994 int Editor::PositionInSelection(int pos
) {
4995 pos
= MovePositionOutsideChar(pos
, currentPos
- pos
);
4996 if (pos
< SelectionStart()) {
4999 if (pos
> SelectionEnd()) {
5002 if (selType
== selStream
) {
5005 SelectionLineIterator
lineIterator(this);
5006 lineIterator
.SetAt(pdoc
->LineFromPosition(pos
));
5007 if (pos
< lineIterator
.startPos
) {
5009 } else if (pos
> lineIterator
.endPos
) {
5017 bool Editor::PointInSelection(Point pt
) {
5018 int pos
= PositionFromLocation(pt
);
5019 if (0 == PositionInSelection(pos
)) {
5020 // Probably inside, but we must make a finer test
5021 int selStart
, selEnd
;
5022 if (selType
== selStream
) {
5023 selStart
= SelectionStart();
5024 selEnd
= SelectionEnd();
5026 SelectionLineIterator
lineIterator(this);
5027 lineIterator
.SetAt(pdoc
->LineFromPosition(pos
));
5028 selStart
= lineIterator
.startPos
;
5029 selEnd
= lineIterator
.endPos
;
5031 if (pos
== selStart
) {
5032 // see if just before selection
5033 Point locStart
= LocationFromPosition(pos
);
5034 if (pt
.x
< locStart
.x
) {
5038 if (pos
== selEnd
) {
5039 // see if just after selection
5040 Point locEnd
= LocationFromPosition(pos
);
5041 if (pt
.x
> locEnd
.x
) {
5050 bool Editor::PointInSelMargin(Point pt
) {
5051 // Really means: "Point in a margin"
5052 if (vs
.fixedColumnWidth
> 0) { // There is a margin
5053 PRectangle rcSelMargin
= GetClientRectangle();
5054 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
5055 return rcSelMargin
.Contains(pt
);
5061 void Editor::LineSelection(int lineCurrent_
, int lineAnchor_
) {
5062 if (lineAnchor_
< lineCurrent_
) {
5063 SetSelection(pdoc
->LineStart(lineCurrent_
+ 1),
5064 pdoc
->LineStart(lineAnchor_
));
5065 } else if (lineAnchor_
> lineCurrent_
) {
5066 SetSelection(pdoc
->LineStart(lineCurrent_
),
5067 pdoc
->LineStart(lineAnchor_
+ 1));
5068 } else { // Same line, select it
5069 SetSelection(pdoc
->LineStart(lineAnchor_
+ 1),
5070 pdoc
->LineStart(lineAnchor_
));
5074 void Editor::DwellEnd(bool mouseMoved
) {
5076 ticksToDwell
= dwellDelay
;
5078 ticksToDwell
= SC_TIME_FOREVER
;
5079 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
5081 NotifyDwelling(ptMouseLast
, dwelling
);
5085 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
5086 //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
5088 int newPos
= PositionFromLocation(pt
);
5089 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
5091 moveExtendsSelection
= false;
5093 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
5097 bool inSelMargin
= PointInSelMargin(pt
);
5098 if (shift
& !inSelMargin
) {
5099 SetSelection(newPos
);
5101 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
5102 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
5103 SetMouseCapture(true);
5104 SetEmptySelection(newPos
);
5105 bool doubleClick
= false;
5106 // Stop mouse button bounce changing selection type
5107 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
5108 if (selectionType
== selChar
) {
5109 selectionType
= selWord
;
5111 } else if (selectionType
== selWord
) {
5112 selectionType
= selLine
;
5114 selectionType
= selChar
;
5115 originalAnchorPos
= currentPos
;
5119 if (selectionType
== selWord
) {
5120 if (currentPos
>= originalAnchorPos
) { // Moved forward
5121 SetSelection(pdoc
->ExtendWordSelect(currentPos
, 1),
5122 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
5123 } else { // Moved backward
5124 SetSelection(pdoc
->ExtendWordSelect(currentPos
, -1),
5125 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
5127 } else if (selectionType
== selLine
) {
5128 lineAnchor
= LineFromLocation(pt
);
5129 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
5130 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
5132 SetEmptySelection(currentPos
);
5134 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
5136 NotifyDoubleClick(pt
, shift
);
5137 if (PositionIsHotspot(newPos
))
5138 NotifyHotSpotDoubleClicked(newPos
, shift
, ctrl
, alt
);
5140 } else { // Single click
5142 selType
= selStream
;
5145 lastClickTime
= curTime
;
5149 lineAnchor
= LineFromLocation(pt
);
5150 // Single click in margin: select whole line
5151 LineSelection(lineAnchor
, lineAnchor
);
5152 SetSelection(pdoc
->LineStart(lineAnchor
+ 1),
5153 pdoc
->LineStart(lineAnchor
));
5155 // Single shift+click in margin: select from line anchor to clicked line
5156 if (anchor
> currentPos
)
5157 lineAnchor
= pdoc
->LineFromPosition(anchor
- 1);
5159 lineAnchor
= pdoc
->LineFromPosition(anchor
);
5160 int lineStart
= LineFromLocation(pt
);
5161 LineSelection(lineStart
, lineAnchor
);
5162 //lineAnchor = lineStart; // Keep the same anchor for ButtonMove
5165 SetDragPosition(invalidPosition
);
5166 SetMouseCapture(true);
5167 selectionType
= selLine
;
5169 if (PointIsHotspot(pt
)) {
5170 NotifyHotSpotClicked(newPos
, shift
, ctrl
, alt
);
5173 inDragDrop
= PointInSelection(pt
) && !SelectionEmpty();
5176 SetMouseCapture(false);
5177 SetDragPosition(newPos
);
5178 CopySelectionRange(&drag
);
5181 SetDragPosition(invalidPosition
);
5182 SetMouseCapture(true);
5184 SetEmptySelection(newPos
);
5186 selType
= alt
? selRectangle
: selStream
;
5187 selectionType
= selChar
;
5188 originalAnchorPos
= currentPos
;
5189 SetRectangularRange();
5193 lastClickTime
= curTime
;
5195 ShowCaretAtCurrentPosition();
5198 bool Editor::PositionIsHotspot(int position
) {
5199 return vs
.styles
[pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
].hotspot
;
5202 bool Editor::PointIsHotspot(Point pt
) {
5203 int pos
= PositionFromLocationClose(pt
);
5204 if (pos
== INVALID_POSITION
)
5206 return PositionIsHotspot(pos
);
5209 void Editor::SetHotSpotRange(Point
*pt
) {
5211 int pos
= PositionFromLocation(*pt
);
5213 // If we don't limit this to word characters then the
5214 // range can encompass more than the run range and then
5215 // the underline will not be drawn properly.
5216 int hsStart_
= pdoc
->ExtendStyleRange(pos
, -1, vs
.hotspotSingleLine
);
5217 int hsEnd_
= pdoc
->ExtendStyleRange(pos
, 1, vs
.hotspotSingleLine
);
5219 // Only invalidate the range if the hotspot range has changed...
5220 if (hsStart_
!= hsStart
|| hsEnd_
!= hsEnd
) {
5221 if (hsStart
!= -1) {
5222 InvalidateRange(hsStart
, hsEnd
);
5226 InvalidateRange(hsStart
, hsEnd
);
5229 if (hsStart
!= -1) {
5230 int hsStart_
= hsStart
;
5234 InvalidateRange(hsStart_
, hsEnd_
);
5242 void Editor::GetHotSpotRange(int& hsStart_
, int& hsEnd_
) {
5247 void Editor::ButtonMove(Point pt
) {
5248 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
5252 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
5253 if (HaveMouseCapture()) {
5255 // Slow down autoscrolling/selection
5256 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
5257 if (autoScrollTimer
.ticksToWait
> 0)
5259 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
5262 int movePos
= PositionFromLocation(pt
);
5263 movePos
= MovePositionOutsideChar(movePos
, currentPos
- movePos
);
5265 SetDragPosition(movePos
);
5267 if (selectionType
== selChar
) {
5268 SetSelection(movePos
);
5269 } else if (selectionType
== selWord
) {
5270 // Continue selecting by word
5271 if (movePos
== originalAnchorPos
) { // Didn't move
5272 // No need to do anything. Previously this case was lumped
5273 // in with "Moved forward", but that can be harmful in this
5274 // case: a handler for the NotifyDoubleClick re-adjusts
5275 // the selection for a fancier definition of "word" (for
5276 // example, in Perl it is useful to include the leading
5277 // '$', '%' or '@' on variables for word selection). In this
5278 // the ButtonMove() called via Tick() for auto-scrolling
5279 // could result in the fancier word selection adjustment
5281 } else if (movePos
> originalAnchorPos
) { // Moved forward
5282 SetSelection(pdoc
->ExtendWordSelect(movePos
, 1),
5283 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
5284 } else { // Moved backward
5285 SetSelection(pdoc
->ExtendWordSelect(movePos
, -1),
5286 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
5289 // Continue selecting by line
5290 int lineMove
= LineFromLocation(pt
);
5291 LineSelection(lineMove
, lineAnchor
);
5294 // While dragging to make rectangular selection, we don't want the current
5295 // position to jump to the end of smaller or empty lines.
5296 //xEndSelect = pt.x - vs.fixedColumnWidth + xOffset;
5297 xEndSelect
= XFromPosition(movePos
);
5300 PRectangle rcClient
= GetClientRectangle();
5301 if (pt
.y
> rcClient
.bottom
) {
5302 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
5304 lineMove
= cs
.DisplayFromDoc(pdoc
->LinesTotal() - 1);
5306 ScrollTo(lineMove
- LinesOnScreen() + 5);
5308 } else if (pt
.y
< rcClient
.top
) {
5309 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
5310 ScrollTo(lineMove
- 5);
5313 EnsureCaretVisible(false, false, true);
5315 if (hsStart
!= -1 && !PositionIsHotspot(movePos
))
5316 SetHotSpotRange(NULL
);
5319 if (vs
.fixedColumnWidth
> 0) { // There is a margin
5320 if (PointInSelMargin(pt
)) {
5321 DisplayCursor(Window::cursorReverseArrow
);
5322 return; // No need to test for selection
5325 // Display regular (drag) cursor over selection
5326 if (PointInSelection(pt
) && !SelectionEmpty()) {
5327 DisplayCursor(Window::cursorArrow
);
5328 } else if (PointIsHotspot(pt
)) {
5329 DisplayCursor(Window::cursorHand
);
5330 SetHotSpotRange(&pt
);
5332 DisplayCursor(Window::cursorText
);
5333 SetHotSpotRange(NULL
);
5338 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
5339 //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
5340 if (HaveMouseCapture()) {
5341 if (PointInSelMargin(pt
)) {
5342 DisplayCursor(Window::cursorReverseArrow
);
5344 DisplayCursor(Window::cursorText
);
5345 SetHotSpotRange(NULL
);
5348 SetMouseCapture(false);
5349 int newPos
= PositionFromLocation(pt
);
5350 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
5352 int selStart
= SelectionStart();
5353 int selEnd
= SelectionEnd();
5354 if (selStart
< selEnd
) {
5357 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5358 SetSelection(newPos
, newPos
+ drag
.len
);
5360 } else if (newPos
< selStart
) {
5361 pdoc
->DeleteChars(selStart
, drag
.len
);
5362 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5363 SetSelection(newPos
, newPos
+ drag
.len
);
5365 } else if (newPos
> selEnd
) {
5366 pdoc
->DeleteChars(selStart
, drag
.len
);
5368 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5369 SetSelection(newPos
, newPos
+ drag
.len
);
5372 SetEmptySelection(newPos
);
5376 selectionType
= selChar
;
5379 if (selectionType
== selChar
) {
5380 SetSelection(newPos
);
5383 SetRectangularRange();
5384 lastClickTime
= curTime
;
5387 if (selType
== selStream
) {
5391 EnsureCaretVisible(false);
5395 // Called frequently to perform background UI including
5396 // caret blinking and automatic scrolling.
5397 void Editor::Tick() {
5398 if (HaveMouseCapture()) {
5400 ButtonMove(ptMouseLast
);
5402 if (caret
.period
> 0) {
5403 timer
.ticksToWait
-= timer
.tickSize
;
5404 if (timer
.ticksToWait
<= 0) {
5405 caret
.on
= !caret
.on
;
5406 timer
.ticksToWait
= caret
.period
;
5412 if ((dwellDelay
< SC_TIME_FOREVER
) &&
5413 (ticksToDwell
> 0) &&
5414 (!HaveMouseCapture())) {
5415 ticksToDwell
-= timer
.tickSize
;
5416 if (ticksToDwell
<= 0) {
5418 NotifyDwelling(ptMouseLast
, dwelling
);
5423 bool Editor::Idle() {
5427 bool wrappingDone
= wrapState
== eWrapNone
;
5429 if (!wrappingDone
) {
5430 // Wrap lines during idle.
5431 WrapLines(false, -1);
5433 if (wrapStart
== wrapEnd
)
5434 wrappingDone
= true;
5437 // Add more idle things to do here, but make sure idleDone is
5438 // set correctly before the function returns. returning
5439 // false will stop calling this idle funtion until SetIdle() is
5442 idleDone
= wrappingDone
; // && thatDone && theOtherThingDone...
5447 void Editor::SetFocusState(bool focusState
) {
5448 hasFocus
= focusState
;
5449 NotifyFocus(hasFocus
);
5451 ShowCaretAtCurrentPosition();
5458 bool Editor::PaintContains(PRectangle rc
) {
5459 return rcPaint
.Contains(rc
);
5462 bool Editor::PaintContainsMargin() {
5463 PRectangle rcSelMargin
= GetClientRectangle();
5464 rcSelMargin
.right
= vs
.fixedColumnWidth
;
5465 return PaintContains(rcSelMargin
);
5468 void Editor::CheckForChangeOutsidePaint(Range r
) {
5469 if (paintState
== painting
&& !paintingAllText
) {
5470 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
5474 PRectangle rcRange
= RectangleFromRange(r
.start
, r
.end
);
5475 PRectangle rcText
= GetTextRectangle();
5476 if (rcRange
.top
< rcText
.top
) {
5477 rcRange
.top
= rcText
.top
;
5479 if (rcRange
.bottom
> rcText
.bottom
) {
5480 rcRange
.bottom
= rcText
.bottom
;
5483 if (!PaintContains(rcRange
)) {
5489 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
5490 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
5491 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
5492 CheckForChangeOutsidePaint(Range(braces
[0]));
5493 CheckForChangeOutsidePaint(Range(pos0
));
5496 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
5497 CheckForChangeOutsidePaint(Range(braces
[1]));
5498 CheckForChangeOutsidePaint(Range(pos1
));
5501 bracesMatchStyle
= matchStyle
;
5502 if (paintState
== notPainting
) {
5508 void Editor::SetDocPointer(Document
*document
) {
5509 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
5510 pdoc
->RemoveWatcher(this, 0);
5512 if (document
== NULL
) {
5513 pdoc
= new Document();
5519 // Ensure all positions within document
5520 selType
= selStream
;
5526 braces
[0] = invalidPosition
;
5527 braces
[1] = invalidPosition
;
5529 // Reset the contraction state to fully shown.
5531 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
5535 pdoc
->AddWatcher(this, 0);
5541 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
5543 void Editor::Expand(int &line
, bool doExpand
) {
5544 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5546 while (line
<= lineMaxSubord
) {
5548 cs
.SetVisible(line
, line
, true);
5549 int level
= pdoc
->GetLevel(line
);
5550 if (level
& SC_FOLDLEVELHEADERFLAG
) {
5551 if (doExpand
&& cs
.GetExpanded(line
)) {
5554 Expand(line
, false);
5562 void Editor::ToggleContraction(int line
) {
5564 if ((pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) == 0) {
5565 line
= pdoc
->GetFoldParent(line
);
5570 if (cs
.GetExpanded(line
)) {
5571 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5572 cs
.SetExpanded(line
, 0);
5573 if (lineMaxSubord
> line
) {
5574 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
5576 int lineCurrent
= pdoc
->LineFromPosition(currentPos
);
5577 if (lineCurrent
> line
&& lineCurrent
<= lineMaxSubord
) {
5578 // This does not re-expand the fold
5579 EnsureCaretVisible();
5587 if (!(cs
.GetVisible(line
))) {
5588 EnsureLineVisible(line
, false);
5591 cs
.SetExpanded(line
, 1);
5600 * Recurse up from this line to find any folds that prevent this line from being visible
5601 * and unfold them all.
5603 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
5605 // In case in need of wrapping to ensure DisplayFromDoc works.
5606 WrapLines(true, -1);
5608 if (!cs
.GetVisible(lineDoc
)) {
5609 int lineParent
= pdoc
->GetFoldParent(lineDoc
);
5610 if (lineParent
>= 0) {
5611 if (lineDoc
!= lineParent
)
5612 EnsureLineVisible(lineParent
, enforcePolicy
);
5613 if (!cs
.GetExpanded(lineParent
)) {
5614 cs
.SetExpanded(lineParent
, 1);
5615 Expand(lineParent
, true);
5621 if (enforcePolicy
) {
5622 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
5623 if (visiblePolicy
& VISIBLE_SLOP
) {
5624 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
5625 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
5626 SetVerticalScrollPos();
5628 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
5629 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
5630 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
5631 SetVerticalScrollPos();
5635 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
5636 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
5637 SetVerticalScrollPos();
5644 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
5645 pdoc
->BeginUndoAction();
5647 length
= istrlen(text
);
5648 if (replacePatterns
) {
5649 text
= pdoc
->SubstituteByPosition(text
, &length
);
5653 if (targetStart
!= targetEnd
)
5654 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
5655 targetEnd
= targetStart
;
5656 pdoc
->InsertString(targetStart
, text
, length
);
5657 targetEnd
= targetStart
+ length
;
5658 pdoc
->EndUndoAction();
5662 bool Editor::IsUnicodeMode() const {
5663 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
5666 int Editor::CodePage() const {
5668 return pdoc
->dbcsCodePage
;
5673 int Editor::WrapCount(int line
) {
5674 AutoSurface
surface(this);
5675 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
5677 if (surface
&& ll
) {
5678 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
5685 static bool ValidMargin(unsigned long wParam
) {
5686 return wParam
< ViewStyle::margins
;
5689 static char *CharPtrFromSPtr(sptr_t lParam
) {
5690 return reinterpret_cast<char *>(lParam
);
5693 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5694 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
5696 // Optional macro recording hook
5698 NotifyMacroRecord(iMessage
, wParam
, lParam
);
5704 return pdoc
->Length() + 1;
5707 char *ptr
= CharPtrFromSPtr(lParam
);
5708 unsigned int iChar
= 0;
5709 for (; iChar
< wParam
- 1; iChar
++)
5710 ptr
[iChar
] = pdoc
->CharAt(iChar
);
5718 pdoc
->BeginUndoAction();
5719 pdoc
->DeleteChars(0, pdoc
->Length());
5720 SetEmptySelection(0);
5721 pdoc
->InsertString(0, CharPtrFromSPtr(lParam
));
5722 pdoc
->EndUndoAction();
5726 case SCI_GETTEXTLENGTH
:
5727 return pdoc
->Length();
5739 CopyRangeToClipboard(wParam
, lParam
);
5743 CopyText(wParam
, CharPtrFromSPtr(lParam
));
5751 EnsureCaretVisible();
5757 EnsureCaretVisible();
5766 return (pdoc
->CanUndo() && !pdoc
->IsReadOnly()) ? 1 : 0;
5768 case SCI_EMPTYUNDOBUFFER
:
5769 pdoc
->DeleteUndoHistory();
5772 case SCI_GETFIRSTVISIBLELINE
:
5775 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
5776 int lineStart
= pdoc
->LineStart(wParam
);
5777 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
5779 return lineEnd
- lineStart
;
5781 char *ptr
= CharPtrFromSPtr(lParam
);
5783 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
5784 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5789 case SCI_GETLINECOUNT
:
5790 if (pdoc
->LinesTotal() == 0)
5793 return pdoc
->LinesTotal();
5796 return !pdoc
->IsSavePoint();
5799 int nStart
= static_cast<int>(wParam
);
5800 int nEnd
= static_cast<int>(lParam
);
5802 nEnd
= pdoc
->Length();
5804 nStart
= nEnd
; // Remove selection
5805 selType
= selStream
;
5806 SetSelection(nEnd
, nStart
);
5807 EnsureCaretVisible();
5811 case SCI_GETSELTEXT
: {
5813 if (selType
== selStream
) {
5814 return 1 + SelectionEnd() - SelectionStart();
5816 // TODO: why is selLines handled the slow way?
5818 int extraCharsPerLine
= 0;
5819 if (selType
!= selLines
)
5820 extraCharsPerLine
= (pdoc
->eolMode
== SC_EOL_CRLF
) ? 2 : 1;
5821 SelectionLineIterator
lineIterator(this);
5822 while (lineIterator
.Iterate()) {
5823 size
+= lineIterator
.endPos
+ extraCharsPerLine
- lineIterator
.startPos
;
5829 SelectionText selectedText
;
5830 CopySelectionRange(&selectedText
);
5831 char *ptr
= CharPtrFromSPtr(lParam
);
5833 if (selectedText
.len
) {
5834 for (; iChar
< selectedText
.len
; iChar
++)
5835 ptr
[iChar
] = selectedText
.s
[iChar
];
5842 case SCI_LINEFROMPOSITION
:
5843 if (static_cast<int>(wParam
) < 0)
5845 return pdoc
->LineFromPosition(wParam
);
5847 case SCI_POSITIONFROMLINE
:
5848 if (static_cast<int>(wParam
) < 0)
5849 wParam
= pdoc
->LineFromPosition(SelectionStart());
5851 return 0; // Even if there is no text, there is a first line that starts at 0
5852 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
5854 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
5856 return pdoc
->LineStart(wParam
);
5858 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
5859 case SCI_LINELENGTH
:
5860 if ((static_cast<int>(wParam
) < 0) ||
5861 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
5863 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
5865 case SCI_REPLACESEL
: {
5868 pdoc
->BeginUndoAction();
5870 char *replacement
= CharPtrFromSPtr(lParam
);
5871 pdoc
->InsertString(currentPos
, replacement
);
5872 pdoc
->EndUndoAction();
5873 SetEmptySelection(currentPos
+ istrlen(replacement
));
5874 EnsureCaretVisible();
5878 case SCI_SETTARGETSTART
:
5879 targetStart
= wParam
;
5882 case SCI_GETTARGETSTART
:
5885 case SCI_SETTARGETEND
:
5889 case SCI_GETTARGETEND
:
5892 case SCI_TARGETFROMSELECTION
:
5893 if (currentPos
< anchor
) {
5894 targetStart
= currentPos
;
5897 targetStart
= anchor
;
5898 targetEnd
= currentPos
;
5902 case SCI_REPLACETARGET
:
5903 PLATFORM_ASSERT(lParam
);
5904 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), wParam
);
5906 case SCI_REPLACETARGETRE
:
5907 PLATFORM_ASSERT(lParam
);
5908 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), wParam
);
5910 case SCI_SEARCHINTARGET
:
5911 PLATFORM_ASSERT(lParam
);
5912 return SearchInTarget(CharPtrFromSPtr(lParam
), wParam
);
5914 case SCI_SETSEARCHFLAGS
:
5915 searchFlags
= wParam
;
5918 case SCI_GETSEARCHFLAGS
:
5921 case SCI_POSITIONBEFORE
:
5922 return pdoc
->MovePositionOutsideChar(wParam
-1, -1, true);
5924 case SCI_POSITIONAFTER
:
5925 return pdoc
->MovePositionOutsideChar(wParam
+1, 1, true);
5927 case SCI_LINESCROLL
:
5928 ScrollTo(topLine
+ lParam
);
5929 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
5932 case SCI_SETXOFFSET
:
5934 SetHorizontalScrollPos();
5938 case SCI_GETXOFFSET
:
5941 case SCI_CHOOSECARETX
:
5945 case SCI_SCROLLCARET
:
5946 EnsureCaretVisible();
5949 case SCI_SETREADONLY
:
5950 pdoc
->SetReadOnly(wParam
!= 0);
5953 case SCI_GETREADONLY
:
5954 return pdoc
->IsReadOnly();
5959 case SCI_POINTXFROMPOSITION
:
5963 Point pt
= LocationFromPosition(lParam
);
5967 case SCI_POINTYFROMPOSITION
:
5971 Point pt
= LocationFromPosition(lParam
);
5976 return FindText(wParam
, lParam
);
5978 case SCI_GETTEXTRANGE
: {
5981 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
5982 int cpMax
= tr
->chrg
.cpMax
;
5984 cpMax
= pdoc
->Length();
5985 PLATFORM_ASSERT(cpMax
<= pdoc
->Length());
5986 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
5987 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
5988 // Spec says copied text is terminated with a NUL
5989 tr
->lpstrText
[len
] = '\0';
5990 return len
; // Not including NUL
5993 case SCI_HIDESELECTION
:
5994 hideSelection
= wParam
!= 0;
5998 case SCI_FORMATRANGE
:
5999 return FormatRange(wParam
!= 0, reinterpret_cast<RangeToFormat
*>(lParam
));
6001 case SCI_GETMARGINLEFT
:
6002 return vs
.leftMarginWidth
;
6004 case SCI_GETMARGINRIGHT
:
6005 return vs
.rightMarginWidth
;
6007 case SCI_SETMARGINLEFT
:
6008 vs
.leftMarginWidth
= lParam
;
6009 InvalidateStyleRedraw();
6012 case SCI_SETMARGINRIGHT
:
6013 vs
.rightMarginWidth
= lParam
;
6014 InvalidateStyleRedraw();
6017 // Control specific mesages
6022 pdoc
->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam
), wParam
);
6023 SetEmptySelection(currentPos
+ wParam
);
6027 case SCI_ADDSTYLEDTEXT
: {
6030 pdoc
->InsertStyledString(CurrentPosition() * 2, CharPtrFromSPtr(lParam
), wParam
);
6031 SetEmptySelection(currentPos
+ wParam
/ 2);
6035 case SCI_INSERTTEXT
: {
6038 int insertPos
= wParam
;
6039 if (static_cast<int>(wParam
) == -1)
6040 insertPos
= CurrentPosition();
6041 int newCurrent
= CurrentPosition();
6042 char *sz
= CharPtrFromSPtr(lParam
);
6043 pdoc
->InsertString(insertPos
, sz
);
6044 if (newCurrent
> insertPos
)
6045 newCurrent
+= istrlen(sz
);
6046 SetEmptySelection(newCurrent
);
6050 case SCI_APPENDTEXT
:
6051 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), wParam
);
6058 case SCI_CLEARDOCUMENTSTYLE
:
6059 ClearDocumentStyle();
6062 case SCI_SETUNDOCOLLECTION
:
6063 pdoc
->SetUndoCollection(wParam
!= 0);
6066 case SCI_GETUNDOCOLLECTION
:
6067 return pdoc
->IsCollectingUndo();
6069 case SCI_BEGINUNDOACTION
:
6070 pdoc
->BeginUndoAction();
6073 case SCI_ENDUNDOACTION
:
6074 pdoc
->EndUndoAction();
6077 case SCI_GETCARETPERIOD
:
6078 return caret
.period
;
6080 case SCI_SETCARETPERIOD
:
6081 caret
.period
= wParam
;
6084 case SCI_SETWORDCHARS
: {
6085 pdoc
->SetDefaultCharClasses(false);
6088 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccWord
);
6092 case SCI_SETWHITESPACECHARS
: {
6095 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccSpace
);
6099 case SCI_SETCHARSDEFAULT
:
6100 pdoc
->SetDefaultCharClasses(true);
6104 return pdoc
->Length();
6107 pdoc
->Allocate(wParam
);
6111 return pdoc
->CharAt(wParam
);
6113 case SCI_SETCURRENTPOS
:
6114 SetSelection(wParam
, anchor
);
6117 case SCI_GETCURRENTPOS
:
6121 SetSelection(currentPos
, wParam
);
6127 case SCI_SETSELECTIONSTART
:
6128 SetSelection(Platform::Maximum(currentPos
, wParam
), wParam
);
6131 case SCI_GETSELECTIONSTART
:
6132 return Platform::Minimum(anchor
, currentPos
);
6134 case SCI_SETSELECTIONEND
:
6135 SetSelection(wParam
, Platform::Minimum(anchor
, wParam
));
6138 case SCI_GETSELECTIONEND
:
6139 return Platform::Maximum(anchor
, currentPos
);
6141 case SCI_SETPRINTMAGNIFICATION
:
6142 printMagnification
= wParam
;
6145 case SCI_GETPRINTMAGNIFICATION
:
6146 return printMagnification
;
6148 case SCI_SETPRINTCOLOURMODE
:
6149 printColourMode
= wParam
;
6152 case SCI_GETPRINTCOLOURMODE
:
6153 return printColourMode
;
6155 case SCI_SETPRINTWRAPMODE
:
6156 printWrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
6159 case SCI_GETPRINTWRAPMODE
:
6160 return printWrapState
;
6162 case SCI_GETSTYLEAT
:
6163 if (static_cast<int>(wParam
) >= pdoc
->Length())
6166 return pdoc
->StyleAt(wParam
);
6176 case SCI_SETSAVEPOINT
:
6177 pdoc
->SetSavePoint();
6180 case SCI_GETSTYLEDTEXT
: {
6183 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
6185 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
6186 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
6187 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
6189 tr
->lpstrText
[iPlace
] = '\0';
6190 tr
->lpstrText
[iPlace
+ 1] = '\0';
6195 return (pdoc
->CanRedo() && !pdoc
->IsReadOnly()) ? 1 : 0;
6197 case SCI_MARKERLINEFROMHANDLE
:
6198 return pdoc
->LineFromHandle(wParam
);
6200 case SCI_MARKERDELETEHANDLE
:
6201 pdoc
->DeleteMarkFromHandle(wParam
);
6205 return vs
.viewWhitespace
;
6208 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
6212 case SCI_POSITIONFROMPOINT
:
6213 return PositionFromLocation(Point(wParam
, lParam
));
6215 case SCI_POSITIONFROMPOINTCLOSE
:
6216 return PositionFromLocationClose(Point(wParam
, lParam
));
6223 SetEmptySelection(wParam
);
6224 EnsureCaretVisible();
6228 case SCI_GETCURLINE
: {
6229 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
6230 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
6231 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
6233 return 1 + lineEnd
- lineStart
;
6235 PLATFORM_ASSERT(wParam
> 0);
6236 char *ptr
= CharPtrFromSPtr(lParam
);
6237 unsigned int iPlace
= 0;
6238 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
6239 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
6242 return currentPos
- lineStart
;
6245 case SCI_GETENDSTYLED
:
6246 return pdoc
->GetEndStyled();
6248 case SCI_GETEOLMODE
:
6249 return pdoc
->eolMode
;
6251 case SCI_SETEOLMODE
:
6252 pdoc
->eolMode
= wParam
;
6255 case SCI_STARTSTYLING
:
6256 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
6259 case SCI_SETSTYLING
:
6260 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
6263 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
6266 pdoc
->SetStyles(wParam
, CharPtrFromSPtr(lParam
));
6269 case SCI_SETBUFFEREDDRAW
:
6270 bufferedDraw
= wParam
!= 0;
6273 case SCI_GETBUFFEREDDRAW
:
6274 return bufferedDraw
;
6276 case SCI_GETTWOPHASEDRAW
:
6277 return twoPhaseDraw
;
6279 case SCI_SETTWOPHASEDRAW
:
6280 twoPhaseDraw
= wParam
!= 0;
6281 InvalidateStyleRedraw();
6284 case SCI_SETTABWIDTH
:
6286 pdoc
->tabInChars
= wParam
;
6287 if (pdoc
->indentInChars
== 0)
6288 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6290 InvalidateStyleRedraw();
6293 case SCI_GETTABWIDTH
:
6294 return pdoc
->tabInChars
;
6297 pdoc
->indentInChars
= wParam
;
6298 if (pdoc
->indentInChars
!= 0)
6299 pdoc
->actualIndentInChars
= pdoc
->indentInChars
;
6301 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6302 InvalidateStyleRedraw();
6306 return pdoc
->indentInChars
;
6308 case SCI_SETUSETABS
:
6309 pdoc
->useTabs
= wParam
!= 0;
6310 InvalidateStyleRedraw();
6313 case SCI_GETUSETABS
:
6314 return pdoc
->useTabs
;
6316 case SCI_SETLINEINDENTATION
:
6317 pdoc
->SetLineIndentation(wParam
, lParam
);
6320 case SCI_GETLINEINDENTATION
:
6321 return pdoc
->GetLineIndentation(wParam
);
6323 case SCI_GETLINEINDENTPOSITION
:
6324 return pdoc
->GetLineIndentPosition(wParam
);
6326 case SCI_SETTABINDENTS
:
6327 pdoc
->tabIndents
= wParam
!= 0;
6330 case SCI_GETTABINDENTS
:
6331 return pdoc
->tabIndents
;
6333 case SCI_SETBACKSPACEUNINDENTS
:
6334 pdoc
->backspaceUnindents
= wParam
!= 0;
6337 case SCI_GETBACKSPACEUNINDENTS
:
6338 return pdoc
->backspaceUnindents
;
6340 case SCI_SETMOUSEDWELLTIME
:
6341 dwellDelay
= wParam
;
6342 ticksToDwell
= dwellDelay
;
6345 case SCI_GETMOUSEDWELLTIME
:
6348 case SCI_WORDSTARTPOSITION
:
6349 return pdoc
->ExtendWordSelect(wParam
, -1, lParam
!= 0);
6351 case SCI_WORDENDPOSITION
:
6352 return pdoc
->ExtendWordSelect(wParam
, 1, lParam
!= 0);
6354 case SCI_SETWRAPMODE
:
6357 wrapState
= eWrapWord
;
6360 wrapState
= eWrapChar
;
6363 wrapState
= eWrapNone
;
6367 InvalidateStyleRedraw();
6368 ReconfigureScrollBars();
6371 case SCI_GETWRAPMODE
:
6374 case SCI_SETWRAPVISUALFLAGS
:
6375 wrapVisualFlags
= wParam
;
6376 actualWrapVisualStartIndent
= wrapVisualStartIndent
;
6377 if ((wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) && (actualWrapVisualStartIndent
== 0))
6378 actualWrapVisualStartIndent
= 1; // must indent to show start visual
6379 InvalidateStyleRedraw();
6380 ReconfigureScrollBars();
6383 case SCI_GETWRAPVISUALFLAGS
:
6384 return wrapVisualFlags
;
6386 case SCI_SETWRAPVISUALFLAGSLOCATION
:
6387 wrapVisualFlagsLocation
= wParam
;
6388 InvalidateStyleRedraw();
6391 case SCI_GETWRAPVISUALFLAGSLOCATION
:
6392 return wrapVisualFlagsLocation
;
6394 case SCI_SETWRAPSTARTINDENT
:
6395 wrapVisualStartIndent
= wParam
;
6396 actualWrapVisualStartIndent
= wrapVisualStartIndent
;
6397 if ((wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) && (actualWrapVisualStartIndent
== 0))
6398 actualWrapVisualStartIndent
= 1; // must indent to show start visual
6399 InvalidateStyleRedraw();
6400 ReconfigureScrollBars();
6403 case SCI_GETWRAPSTARTINDENT
:
6404 return wrapVisualStartIndent
;
6406 case SCI_SETLAYOUTCACHE
:
6407 llc
.SetLevel(wParam
);
6410 case SCI_GETLAYOUTCACHE
:
6411 return llc
.GetLevel();
6413 case SCI_SETSCROLLWIDTH
:
6414 PLATFORM_ASSERT(wParam
> 0);
6415 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
6416 scrollWidth
= wParam
;
6421 case SCI_GETSCROLLWIDTH
:
6428 case SCI_LINESSPLIT
:
6433 PLATFORM_ASSERT(wParam
<= STYLE_MAX
);
6434 PLATFORM_ASSERT(lParam
);
6435 return TextWidth(wParam
, CharPtrFromSPtr(lParam
));
6437 case SCI_TEXTHEIGHT
:
6438 return vs
.lineHeight
;
6440 case SCI_SETENDATLASTLINE
:
6441 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
6442 if (endAtLastLine
!= (wParam
!= 0)) {
6443 endAtLastLine
= wParam
!= 0;
6448 case SCI_GETENDATLASTLINE
:
6449 return endAtLastLine
;
6451 case SCI_SETCARETSTICKY
:
6452 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
6453 if (caretSticky
!= (wParam
!= 0)) {
6454 caretSticky
= wParam
!= 0;
6458 case SCI_GETCARETSTICKY
:
6461 case SCI_TOGGLECARETSTICKY
:
6462 caretSticky
= !caretSticky
;
6466 return pdoc
->GetColumn(wParam
);
6468 case SCI_FINDCOLUMN
:
6469 return pdoc
->FindColumn(wParam
, lParam
);
6471 case SCI_SETHSCROLLBAR
:
6472 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
6473 horizontalScrollBarVisible
= wParam
!= 0;
6475 ReconfigureScrollBars();
6479 case SCI_GETHSCROLLBAR
:
6480 return horizontalScrollBarVisible
;
6482 case SCI_SETVSCROLLBAR
:
6483 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
6484 verticalScrollBarVisible
= wParam
!= 0;
6486 ReconfigureScrollBars();
6490 case SCI_GETVSCROLLBAR
:
6491 return verticalScrollBarVisible
;
6493 case SCI_SETINDENTATIONGUIDES
:
6494 vs
.viewIndentationGuides
= wParam
!= 0;
6498 case SCI_GETINDENTATIONGUIDES
:
6499 return vs
.viewIndentationGuides
;
6501 case SCI_SETHIGHLIGHTGUIDE
:
6502 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
6503 highlightGuideColumn
= wParam
;
6508 case SCI_GETHIGHLIGHTGUIDE
:
6509 return highlightGuideColumn
;
6511 case SCI_GETLINEENDPOSITION
:
6512 return pdoc
->LineEnd(wParam
);
6514 case SCI_SETCODEPAGE
:
6515 if (ValidCodePage(wParam
)) {
6516 pdoc
->dbcsCodePage
= wParam
;
6517 InvalidateStyleRedraw();
6521 case SCI_GETCODEPAGE
:
6522 return pdoc
->dbcsCodePage
;
6524 case SCI_SETUSEPALETTE
:
6525 palette
.allowRealization
= wParam
!= 0;
6526 InvalidateStyleRedraw();
6529 case SCI_GETUSEPALETTE
:
6530 return palette
.allowRealization
;
6532 // Marker definition and setting
6533 case SCI_MARKERDEFINE
:
6534 if (wParam
<= MARKER_MAX
)
6535 vs
.markers
[wParam
].markType
= lParam
;
6536 InvalidateStyleData();
6539 case SCI_MARKERSETFORE
:
6540 if (wParam
<= MARKER_MAX
)
6541 vs
.markers
[wParam
].fore
.desired
= ColourDesired(lParam
);
6542 InvalidateStyleData();
6545 case SCI_MARKERSETBACK
:
6546 if (wParam
<= MARKER_MAX
)
6547 vs
.markers
[wParam
].back
.desired
= ColourDesired(lParam
);
6548 InvalidateStyleData();
6551 case SCI_MARKERSETALPHA
:
6552 if (wParam
<= MARKER_MAX
)
6553 vs
.markers
[wParam
].alpha
= lParam
;
6554 InvalidateStyleRedraw();
6556 case SCI_MARKERADD
: {
6557 int markerID
= pdoc
->AddMark(wParam
, lParam
);
6560 case SCI_MARKERADDSET
:
6562 pdoc
->AddMarkSet(wParam
, lParam
);
6565 case SCI_MARKERDELETE
:
6566 pdoc
->DeleteMark(wParam
, lParam
);
6569 case SCI_MARKERDELETEALL
:
6570 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
6574 return pdoc
->GetMark(wParam
);
6576 case SCI_MARKERNEXT
: {
6577 int lt
= pdoc
->LinesTotal();
6578 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
6579 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6585 case SCI_MARKERPREVIOUS
: {
6586 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
6587 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6593 case SCI_MARKERDEFINEPIXMAP
:
6594 if (wParam
<= MARKER_MAX
) {
6595 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
6597 InvalidateStyleData();
6601 case SCI_SETMARGINTYPEN
:
6602 if (ValidMargin(wParam
)) {
6603 vs
.ms
[wParam
].style
= lParam
;
6604 InvalidateStyleRedraw();
6608 case SCI_GETMARGINTYPEN
:
6609 if (ValidMargin(wParam
))
6610 return vs
.ms
[wParam
].style
;
6614 case SCI_SETMARGINWIDTHN
:
6615 if (ValidMargin(wParam
)) {
6616 // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
6617 if (vs
.ms
[wParam
].width
!= lParam
) {
6618 vs
.ms
[wParam
].width
= lParam
;
6619 InvalidateStyleRedraw();
6624 case SCI_GETMARGINWIDTHN
:
6625 if (ValidMargin(wParam
))
6626 return vs
.ms
[wParam
].width
;
6630 case SCI_SETMARGINMASKN
:
6631 if (ValidMargin(wParam
)) {
6632 vs
.ms
[wParam
].mask
= lParam
;
6633 InvalidateStyleRedraw();
6637 case SCI_GETMARGINMASKN
:
6638 if (ValidMargin(wParam
))
6639 return vs
.ms
[wParam
].mask
;
6643 case SCI_SETMARGINSENSITIVEN
:
6644 if (ValidMargin(wParam
)) {
6645 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
6646 InvalidateStyleRedraw();
6650 case SCI_GETMARGINSENSITIVEN
:
6651 if (ValidMargin(wParam
))
6652 return vs
.ms
[wParam
].sensitive
? 1 : 0;
6656 case SCI_STYLECLEARALL
:
6658 InvalidateStyleRedraw();
6661 case SCI_STYLESETFORE
:
6662 if (wParam
<= STYLE_MAX
) {
6663 vs
.styles
[wParam
].fore
.desired
= ColourDesired(lParam
);
6664 InvalidateStyleRedraw();
6667 case SCI_STYLESETBACK
:
6668 if (wParam
<= STYLE_MAX
) {
6669 vs
.styles
[wParam
].back
.desired
= ColourDesired(lParam
);
6670 InvalidateStyleRedraw();
6673 case SCI_STYLESETBOLD
:
6674 if (wParam
<= STYLE_MAX
) {
6675 vs
.styles
[wParam
].bold
= lParam
!= 0;
6676 InvalidateStyleRedraw();
6679 case SCI_STYLESETITALIC
:
6680 if (wParam
<= STYLE_MAX
) {
6681 vs
.styles
[wParam
].italic
= lParam
!= 0;
6682 InvalidateStyleRedraw();
6685 case SCI_STYLESETEOLFILLED
:
6686 if (wParam
<= STYLE_MAX
) {
6687 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
6688 InvalidateStyleRedraw();
6691 case SCI_STYLESETSIZE
:
6692 if (wParam
<= STYLE_MAX
) {
6693 vs
.styles
[wParam
].size
= lParam
;
6694 InvalidateStyleRedraw();
6697 case SCI_STYLESETFONT
:
6700 if (wParam
<= STYLE_MAX
) {
6701 vs
.SetStyleFontName(wParam
, CharPtrFromSPtr(lParam
));
6702 InvalidateStyleRedraw();
6705 case SCI_STYLESETUNDERLINE
:
6706 if (wParam
<= STYLE_MAX
) {
6707 vs
.styles
[wParam
].underline
= lParam
!= 0;
6708 InvalidateStyleRedraw();
6711 case SCI_STYLESETCASE
:
6712 if (wParam
<= STYLE_MAX
) {
6713 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
6714 InvalidateStyleRedraw();
6717 case SCI_STYLESETCHARACTERSET
:
6718 if (wParam
<= STYLE_MAX
) {
6719 vs
.styles
[wParam
].characterSet
= lParam
;
6720 InvalidateStyleRedraw();
6723 case SCI_STYLESETVISIBLE
:
6724 if (wParam
<= STYLE_MAX
) {
6725 vs
.styles
[wParam
].visible
= lParam
!= 0;
6726 InvalidateStyleRedraw();
6729 case SCI_STYLESETCHANGEABLE
:
6730 if (wParam
<= STYLE_MAX
) {
6731 vs
.styles
[wParam
].changeable
= lParam
!= 0;
6732 InvalidateStyleRedraw();
6735 case SCI_STYLESETHOTSPOT
:
6736 if (wParam
<= STYLE_MAX
) {
6737 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
6738 InvalidateStyleRedraw();
6742 case SCI_STYLERESETDEFAULT
:
6743 vs
.ResetDefaultStyle();
6744 InvalidateStyleRedraw();
6746 case SCI_SETSTYLEBITS
:
6747 pdoc
->SetStylingBits(wParam
);
6750 case SCI_GETSTYLEBITS
:
6751 return pdoc
->stylingBits
;
6753 case SCI_SETLINESTATE
:
6754 return pdoc
->SetLineState(wParam
, lParam
);
6756 case SCI_GETLINESTATE
:
6757 return pdoc
->GetLineState(wParam
);
6759 case SCI_GETMAXLINESTATE
:
6760 return pdoc
->GetMaxLineState();
6762 case SCI_GETCARETLINEVISIBLE
:
6763 return vs
.showCaretLineBackground
;
6764 case SCI_SETCARETLINEVISIBLE
:
6765 vs
.showCaretLineBackground
= wParam
!= 0;
6766 InvalidateStyleRedraw();
6768 case SCI_GETCARETLINEBACK
:
6769 return vs
.caretLineBackground
.desired
.AsLong();
6770 case SCI_SETCARETLINEBACK
:
6771 vs
.caretLineBackground
.desired
= wParam
;
6772 InvalidateStyleRedraw();
6774 case SCI_GETCARETLINEBACKALPHA
:
6775 return vs
.caretLineAlpha
;
6776 case SCI_SETCARETLINEBACKALPHA
:
6777 vs
.caretLineAlpha
= wParam
;
6778 InvalidateStyleRedraw();
6783 case SCI_VISIBLEFROMDOCLINE
:
6784 return cs
.DisplayFromDoc(wParam
);
6786 case SCI_DOCLINEFROMVISIBLE
:
6787 return cs
.DocFromDisplay(wParam
);
6790 return WrapCount(wParam
);
6792 case SCI_SETFOLDLEVEL
: {
6793 int prev
= pdoc
->SetLevel(wParam
, lParam
);
6799 case SCI_GETFOLDLEVEL
:
6800 return pdoc
->GetLevel(wParam
);
6802 case SCI_GETLASTCHILD
:
6803 return pdoc
->GetLastChild(wParam
, lParam
);
6805 case SCI_GETFOLDPARENT
:
6806 return pdoc
->GetFoldParent(wParam
);
6809 cs
.SetVisible(wParam
, lParam
, true);
6815 cs
.SetVisible(wParam
, lParam
, false);
6820 case SCI_GETLINEVISIBLE
:
6821 return cs
.GetVisible(wParam
);
6823 case SCI_SETFOLDEXPANDED
:
6824 if (cs
.SetExpanded(wParam
, lParam
!= 0)) {
6829 case SCI_GETFOLDEXPANDED
:
6830 return cs
.GetExpanded(wParam
);
6832 case SCI_SETFOLDFLAGS
:
6837 case SCI_TOGGLEFOLD
:
6838 ToggleContraction(wParam
);
6841 case SCI_ENSUREVISIBLE
:
6842 EnsureLineVisible(wParam
, false);
6845 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
6846 EnsureLineVisible(wParam
, true);
6849 case SCI_SEARCHANCHOR
:
6853 case SCI_SEARCHNEXT
:
6854 case SCI_SEARCHPREV
:
6855 return SearchText(iMessage
, wParam
, lParam
);
6857 #ifdef INCLUDE_DEPRECATED_FEATURES
6858 case SCI_SETCARETPOLICY
: // Deprecated
6859 caretXPolicy
= caretYPolicy
= wParam
;
6860 caretXSlop
= caretYSlop
= lParam
;
6864 case SCI_SETXCARETPOLICY
:
6865 caretXPolicy
= wParam
;
6866 caretXSlop
= lParam
;
6869 case SCI_SETYCARETPOLICY
:
6870 caretYPolicy
= wParam
;
6871 caretYSlop
= lParam
;
6874 case SCI_SETVISIBLEPOLICY
:
6875 visiblePolicy
= wParam
;
6876 visibleSlop
= lParam
;
6879 case SCI_LINESONSCREEN
:
6880 return LinesOnScreen();
6882 case SCI_SETSELFORE
:
6883 vs
.selforeset
= wParam
!= 0;
6884 vs
.selforeground
.desired
= ColourDesired(lParam
);
6885 InvalidateStyleRedraw();
6888 case SCI_SETSELBACK
:
6889 vs
.selbackset
= wParam
!= 0;
6890 vs
.selbackground
.desired
= ColourDesired(lParam
);
6891 InvalidateStyleRedraw();
6894 case SCI_SETSELALPHA
:
6895 vs
.selAlpha
= wParam
;
6896 InvalidateStyleRedraw();
6899 case SCI_GETSELALPHA
:
6902 case SCI_SETWHITESPACEFORE
:
6903 vs
.whitespaceForegroundSet
= wParam
!= 0;
6904 vs
.whitespaceForeground
.desired
= ColourDesired(lParam
);
6905 InvalidateStyleRedraw();
6908 case SCI_SETWHITESPACEBACK
:
6909 vs
.whitespaceBackgroundSet
= wParam
!= 0;
6910 vs
.whitespaceBackground
.desired
= ColourDesired(lParam
);
6911 InvalidateStyleRedraw();
6914 case SCI_SETCARETFORE
:
6915 vs
.caretcolour
.desired
= ColourDesired(wParam
);
6916 InvalidateStyleRedraw();
6919 case SCI_GETCARETFORE
:
6920 return vs
.caretcolour
.desired
.AsLong();
6922 case SCI_SETCARETWIDTH
:
6925 else if (wParam
>= 3)
6928 vs
.caretWidth
= wParam
;
6929 InvalidateStyleRedraw();
6932 case SCI_GETCARETWIDTH
:
6933 return vs
.caretWidth
;
6935 case SCI_ASSIGNCMDKEY
:
6936 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6937 Platform::HighShortFromLong(wParam
), lParam
);
6940 case SCI_CLEARCMDKEY
:
6941 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6942 Platform::HighShortFromLong(wParam
), SCI_NULL
);
6945 case SCI_CLEARALLCMDKEYS
:
6949 case SCI_INDICSETSTYLE
:
6950 if (wParam
<= INDIC_MAX
) {
6951 vs
.indicators
[wParam
].style
= lParam
;
6952 InvalidateStyleRedraw();
6956 case SCI_INDICGETSTYLE
:
6957 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
6959 case SCI_INDICSETFORE
:
6960 if (wParam
<= INDIC_MAX
) {
6961 vs
.indicators
[wParam
].fore
.desired
= ColourDesired(lParam
);
6962 InvalidateStyleRedraw();
6966 case SCI_INDICGETFORE
:
6967 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
6970 case SCI_LINEDOWNEXTEND
:
6972 case SCI_PARADOWNEXTEND
:
6974 case SCI_LINEUPEXTEND
:
6976 case SCI_PARAUPEXTEND
:
6978 case SCI_CHARLEFTEXTEND
:
6980 case SCI_CHARRIGHTEXTEND
:
6982 case SCI_WORDLEFTEXTEND
:
6984 case SCI_WORDRIGHTEXTEND
:
6985 case SCI_WORDLEFTEND
:
6986 case SCI_WORDLEFTENDEXTEND
:
6987 case SCI_WORDRIGHTEND
:
6988 case SCI_WORDRIGHTENDEXTEND
:
6990 case SCI_HOMEEXTEND
:
6992 case SCI_LINEENDEXTEND
:
6994 case SCI_HOMEWRAPEXTEND
:
6995 case SCI_LINEENDWRAP
:
6996 case SCI_LINEENDWRAPEXTEND
:
6997 case SCI_DOCUMENTSTART
:
6998 case SCI_DOCUMENTSTARTEXTEND
:
6999 case SCI_DOCUMENTEND
:
7000 case SCI_DOCUMENTENDEXTEND
:
7002 case SCI_STUTTEREDPAGEUP
:
7003 case SCI_STUTTEREDPAGEUPEXTEND
:
7004 case SCI_STUTTEREDPAGEDOWN
:
7005 case SCI_STUTTEREDPAGEDOWNEXTEND
:
7008 case SCI_PAGEUPEXTEND
:
7010 case SCI_PAGEDOWNEXTEND
:
7011 case SCI_EDITTOGGLEOVERTYPE
:
7013 case SCI_DELETEBACK
:
7019 case SCI_VCHOMEEXTEND
:
7020 case SCI_VCHOMEWRAP
:
7021 case SCI_VCHOMEWRAPEXTEND
:
7024 case SCI_DELWORDLEFT
:
7025 case SCI_DELWORDRIGHT
:
7026 case SCI_DELLINELEFT
:
7027 case SCI_DELLINERIGHT
:
7030 case SCI_LINEDELETE
:
7031 case SCI_LINETRANSPOSE
:
7032 case SCI_LINEDUPLICATE
:
7035 case SCI_LINESCROLLDOWN
:
7036 case SCI_LINESCROLLUP
:
7037 case SCI_WORDPARTLEFT
:
7038 case SCI_WORDPARTLEFTEXTEND
:
7039 case SCI_WORDPARTRIGHT
:
7040 case SCI_WORDPARTRIGHTEXTEND
:
7041 case SCI_DELETEBACKNOTLINE
:
7042 case SCI_HOMEDISPLAY
:
7043 case SCI_HOMEDISPLAYEXTEND
:
7044 case SCI_LINEENDDISPLAY
:
7045 case SCI_LINEENDDISPLAYEXTEND
:
7046 case SCI_LINEDOWNRECTEXTEND
:
7047 case SCI_LINEUPRECTEXTEND
:
7048 case SCI_CHARLEFTRECTEXTEND
:
7049 case SCI_CHARRIGHTRECTEXTEND
:
7050 case SCI_HOMERECTEXTEND
:
7051 case SCI_VCHOMERECTEXTEND
:
7052 case SCI_LINEENDRECTEXTEND
:
7053 case SCI_PAGEUPRECTEXTEND
:
7054 case SCI_PAGEDOWNRECTEXTEND
:
7055 case SCI_SELECTIONDUPLICATE
:
7056 return KeyCommand(iMessage
);
7058 case SCI_BRACEHIGHLIGHT
:
7059 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
7062 case SCI_BRACEBADLIGHT
:
7063 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
7066 case SCI_BRACEMATCH
:
7067 // wParam is position of char to find brace for,
7068 // lParam is maximum amount of text to restyle to find it
7069 return pdoc
->BraceMatch(wParam
, lParam
);
7071 case SCI_GETVIEWEOL
:
7074 case SCI_SETVIEWEOL
:
7075 vs
.viewEOL
= wParam
!= 0;
7076 InvalidateStyleRedraw();
7080 vs
.zoomLevel
= wParam
;
7081 InvalidateStyleRedraw();
7086 return vs
.zoomLevel
;
7088 case SCI_GETEDGECOLUMN
:
7091 case SCI_SETEDGECOLUMN
:
7093 InvalidateStyleRedraw();
7096 case SCI_GETEDGEMODE
:
7097 return vs
.edgeState
;
7099 case SCI_SETEDGEMODE
:
7100 vs
.edgeState
= wParam
;
7101 InvalidateStyleRedraw();
7104 case SCI_GETEDGECOLOUR
:
7105 return vs
.edgecolour
.desired
.AsLong();
7107 case SCI_SETEDGECOLOUR
:
7108 vs
.edgecolour
.desired
= ColourDesired(wParam
);
7109 InvalidateStyleRedraw();
7112 case SCI_GETDOCPOINTER
:
7113 return reinterpret_cast<sptr_t
>(pdoc
);
7115 case SCI_SETDOCPOINTER
:
7117 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
7120 case SCI_CREATEDOCUMENT
: {
7121 Document
*doc
= new Document();
7125 return reinterpret_cast<sptr_t
>(doc
);
7128 case SCI_ADDREFDOCUMENT
:
7129 (reinterpret_cast<Document
*>(lParam
))->AddRef();
7132 case SCI_RELEASEDOCUMENT
:
7133 (reinterpret_cast<Document
*>(lParam
))->Release();
7136 case SCI_SETMODEVENTMASK
:
7137 modEventMask
= wParam
;
7140 case SCI_GETMODEVENTMASK
:
7141 return modEventMask
;
7143 case SCI_CONVERTEOLS
:
7144 pdoc
->ConvertLineEnds(wParam
);
7145 SetSelection(currentPos
, anchor
); // Ensure selection inside document
7148 case SCI_SETLENGTHFORENCODE
:
7149 lengthForEncode
= wParam
;
7152 case SCI_SELECTIONISRECTANGLE
:
7153 return selType
== selRectangle
? 1 : 0;
7155 case SCI_SETSELECTIONMODE
: {
7158 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selStream
);
7159 selType
= selStream
;
7161 case SC_SEL_RECTANGLE
:
7162 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selRectangle
);
7163 selType
= selRectangle
;
7166 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selLines
);
7170 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selStream
);
7171 selType
= selStream
;
7173 InvalidateSelection(currentPos
, anchor
);
7175 case SCI_GETSELECTIONMODE
:
7178 return SC_SEL_STREAM
;
7180 return SC_SEL_RECTANGLE
;
7182 return SC_SEL_LINES
;
7184 return SC_SEL_STREAM
;
7186 case SCI_GETLINESELSTARTPOSITION
: {
7187 SelectionLineIterator
lineIterator(this);
7188 lineIterator
.SetAt(wParam
);
7189 return lineIterator
.startPos
;
7191 case SCI_GETLINESELENDPOSITION
: {
7192 SelectionLineIterator
lineIterator(this);
7193 lineIterator
.SetAt(wParam
);
7194 return lineIterator
.endPos
;
7197 case SCI_SETOVERTYPE
:
7198 inOverstrike
= wParam
!= 0;
7201 case SCI_GETOVERTYPE
:
7202 return inOverstrike
? 1 : 0;
7205 SetFocusState(wParam
!= 0);
7212 errorStatus
= wParam
;
7218 case SCI_SETMOUSEDOWNCAPTURES
:
7219 mouseDownCaptures
= wParam
!= 0;
7222 case SCI_GETMOUSEDOWNCAPTURES
:
7223 return mouseDownCaptures
;
7226 cursorMode
= wParam
;
7227 DisplayCursor(Window::cursorText
);
7233 case SCI_SETCONTROLCHARSYMBOL
:
7234 controlCharSymbol
= wParam
;
7237 case SCI_GETCONTROLCHARSYMBOL
:
7238 return controlCharSymbol
;
7240 case SCI_STARTRECORD
:
7241 recordingMacro
= true;
7244 case SCI_STOPRECORD
:
7245 recordingMacro
= false;
7248 case SCI_MOVECARETINSIDEVIEW
:
7249 MoveCaretInsideView();
7252 case SCI_SETFOLDMARGINCOLOUR
:
7253 vs
.foldmarginColourSet
= wParam
!= 0;
7254 vs
.foldmarginColour
.desired
= ColourDesired(lParam
);
7255 InvalidateStyleRedraw();
7258 case SCI_SETFOLDMARGINHICOLOUR
:
7259 vs
.foldmarginHighlightColourSet
= wParam
!= 0;
7260 vs
.foldmarginHighlightColour
.desired
= ColourDesired(lParam
);
7261 InvalidateStyleRedraw();
7264 case SCI_SETHOTSPOTACTIVEFORE
:
7265 vs
.hotspotForegroundSet
= wParam
!= 0;
7266 vs
.hotspotForeground
.desired
= ColourDesired(lParam
);
7267 InvalidateStyleRedraw();
7270 case SCI_SETHOTSPOTACTIVEBACK
:
7271 vs
.hotspotBackgroundSet
= wParam
!= 0;
7272 vs
.hotspotBackground
.desired
= ColourDesired(lParam
);
7273 InvalidateStyleRedraw();
7276 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
7277 vs
.hotspotUnderline
= wParam
!= 0;
7278 InvalidateStyleRedraw();
7281 case SCI_SETHOTSPOTSINGLELINE
:
7282 vs
.hotspotSingleLine
= wParam
!= 0;
7283 InvalidateStyleRedraw();
7286 case SCI_SETPASTECONVERTENDINGS
:
7287 convertPastes
= wParam
!= 0;
7290 case SCI_GETPASTECONVERTENDINGS
:
7291 return convertPastes
? 1 : 0;
7294 return DefWndProc(iMessage
, wParam
, lParam
);
7296 //Platform::DebugPrintf("end wnd proc\n");